Merge: Make tests agnostic about TLS v1.x.
Merged from upstream commit #1150.
Test only change. Ensures tests neither use nor assume anything
about whether TLSv.1 are enabled or supported. As such it is
suitable for backporting to historic Android test suites where
vendors may have disabled TLS v1.x by editing the default arrays.
However by being agnostic it does not enforce that TLS v1.x are
available if expected. A further change will provide an API for
that, but which is not suitable for backporting as it will
require non-test changes.
A lot of the tidy-up is around RenegotiationTest and its
TestUtils methods, which are only tested on OpenJDK builds.
Bug: 288058920
Bug: 288062754
Test: atest MtsLibcoreTestCases (with and without TLS v1.x enabled)
Change-Id: If8c48afcd1a6a417d1410ce4335f16cac3abd191
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
deleted file mode 100644
index 57ca5f5..0000000
--- a/.github/workflows/ci.yml
+++ /dev/null
@@ -1,313 +0,0 @@
-name: Continuous integration
-
-on:
- push:
- pull_request:
- schedule:
- # Run every day at midnight UTC
- - cron: '0 0 * * *'
-
-jobs:
- boringssl_clone:
- # This step ensures that all builders have the same version of BoringSSL
- runs-on: ubuntu-latest
-
- steps:
- - name: Clone BoringSSL repo
- run: |
- git clone --depth 1 --filter=blob:none --no-checkout https://github.com/google/boringssl.git "${{ runner.temp }}/boringssl"
- echo Using BoringSSL commit: $(cd "${{ runner.temp }}/boringssl"; git rev-parse HEAD)
-
- - name: Archive BoringSSL source
- uses: actions/upload-artifact@v1
- with:
- name: boringssl-source
- path: ${{ runner.temp }}/boringssl
-
- build:
- needs: boringssl_clone
-
- strategy:
- fail-fast: false
- matrix:
- platform: [ubuntu-latest, macos-latest, windows-latest]
- include:
- - platform: ubuntu-latest
- tools_url: https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip
- - platform: macos-latest
- tools_url: https://dl.google.com/android/repository/commandlinetools-mac-9477386_latest.zip
- - platform: windows-latest
- tools_url: https://dl.google.com/android/repository/commandlinetools-win-9477386_latest.zip
-
- runs-on: ${{ matrix.platform }}
-
- steps:
- - name: Set up JDK 11 for toolchains
- uses: actions/setup-java@v1.4.3
- with:
- java-version: 11
-
- - name: Set runner-specific environment variables
- shell: bash
- run: |
- echo "ANDROID_HOME=${{ runner.temp }}/android-sdk" >> $GITHUB_ENV
- echo "ANDROID_SDK_ROOT=${{ runner.temp }}/android-sdk" >> $GITHUB_ENV
- echo "BORINGSSL_HOME=${{ runner.temp }}/boringssl" >> $GITHUB_ENV
- echo "SDKMANAGER=${{ runner.temp }}/android-sdk/cmdline-tools/bin/sdkmanager" >> $GITHUB_ENV
- echo "M2_REPO=${{ runner.temp }}/m2" >> $GITHUB_ENV
-
- - uses: actions/checkout@v2
-
- - name: Setup Linux environment
- if: runner.os == 'Linux'
- run: |
- echo "CC=clang" >> $GITHUB_ENV
- echo "CXX=clang++" >> $GITHUB_ENV
-
- sudo dpkg --add-architecture i386
- sudo add-apt-repository ppa:openjdk-r/ppa
- sudo apt-get -qq update
- sudo apt-get -qq install -y --no-install-recommends \
- gcc-multilib \
- g++-multilib \
- ninja-build \
- openjdk-11-jre-headless
-
- - name: Setup macOS environment
- if: runner.os == 'macOS'
- run: |
- brew update || echo update failed
- brew install ninja || echo update failed
-
- - name: install Go
- uses: actions/setup-go@v1
- with:
- go-version: '1.19.3'
-
- - name: Setup Windows environment
- if: runner.os == 'Windows'
- run: |
- choco install nasm -y
- choco install ninja -y
-
- - name: Fetch BoringSSL source
- uses: actions/download-artifact@v1
- with:
- name: boringssl-source
- path: ${{ runner.temp }}/boringssl
-
- - name: Checkout BoringSSL master branch
- shell: bash
- run: |
- cd "$BORINGSSL_HOME"
- git checkout --progress --force -B master
-
- - name: Build BoringSSL x86 and ARM MacOS
- if: runner.os == 'macOS'
- env:
- # For compatibility, but 10.15 target requires 16-byte stack alignment.
- MACOSX_DEPLOYMENT_TARGET: 10.11
- run: |
- mkdir -p "$BORINGSSL_HOME/build.x86"
- pushd "$BORINGSSL_HOME/build.x86"
- cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES=x86_64 -GNinja ..
- ninja
- popd
-
- mkdir -p "$BORINGSSL_HOME/build.arm"
- pushd "$BORINGSSL_HOME/build.arm"
- cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES=arm64 -GNinja ..
- ninja
- popd
-
- - name: Build BoringSSL 64-bit Linux
- if: runner.os == 'Linux'
- run: |
- mkdir -p "$BORINGSSL_HOME/build64"
- pushd "$BORINGSSL_HOME/build64"
- cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -DCMAKE_BUILD_TYPE=Release -GNinja ..
- ninja
- popd
-
- - name: Build BoringSSL 64-bit Windows
- if: runner.os == 'Windows'
- run: |
- cd $Env:BORINGSSL_HOME
-
- & $Env:GITHUB_WORKSPACE\.github\workflows\vsenv.ps1 -arch x64 -hostArch x64
- mkdir build64
- pushd build64
- cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS_RELEASE=/MT -DCMAKE_CXX_FLAGS_RELEASE=/MT -GNinja ..
- ninja
- popd
-
- - name: Setup Android environment
- shell: bash
- if: runner.os == 'Linux'
- run: |
- cd "${{ runner.temp }}"
- curl -L "${{ matrix.tools_url }}" -o android-tools.zip
- mkdir -p "$ANDROID_HOME"
- unzip -q android-tools.zip -d "$ANDROID_HOME"
- yes | "$SDKMANAGER" --sdk_root="$ANDROID_HOME" --licenses || true
- "$SDKMANAGER" --sdk_root="$ANDROID_HOME" tools
- "$SDKMANAGER" --sdk_root="$ANDROID_HOME" platform-tools
- "$SDKMANAGER" --sdk_root="$ANDROID_HOME" 'build-tools;30.0.3'
- "$SDKMANAGER" --sdk_root="$ANDROID_HOME" 'platforms;android-26'
- "$SDKMANAGER" --sdk_root="$ANDROID_HOME" 'extras;android;m2repository'
- "$SDKMANAGER" --sdk_root="$ANDROID_HOME" 'ndk;25.2.9519653'
- "$SDKMANAGER" --sdk_root="$ANDROID_HOME" 'cmake;3.22.1'
-
- - name: Build with Gradle
- shell: bash
- run: ./gradlew assemble -PcheckErrorQueue
-
- - name: Test with Gradle
- shell: bash
- run: ./gradlew test -PcheckErrorQueue
-
- - name: Other checks with Gradle
- shell: bash
- run: ./gradlew check -PcheckErrorQueue
-
- - name: Publish to local Maven repo
- shell: bash
- run: ./gradlew publishToMavenLocal -Dmaven.repo.local="$M2_REPO"
-
- - name: Upload Maven respository
- uses: actions/upload-artifact@v1
- with:
- name: m2repo-${{ runner.os }}
- path: ${{ runner.temp }}/m2
-
- - name: Build test JAR with dependencies
- if: runner.os == 'Linux'
- shell: bash
- run: ./gradlew :conscrypt-openjdk:testJar -PcheckErrorQueue
-
- - name: Upload test JAR with dependencies
- if: runner.os == 'Linux'
- uses: actions/upload-artifact@v2
- with:
- name: testjar
- path: openjdk/build/libs/conscrypt-openjdk-*-tests.jar
- if-no-files-found: error
-
- uberjar:
- needs: build
-
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v2
-
- - name: Set runner-specific environment variables
- shell: bash
- run: |
- echo "M2_REPO=${{ runner.temp }}/m2" >> $GITHUB_ENV
- echo "BORINGSSL_HOME=${{ runner.temp }}/boringssl" >> $GITHUB_ENV
-
- - name: Fetch BoringSSL source
- uses: actions/download-artifact@v1
- with:
- name: boringssl-source
- path: ${{ runner.temp }}/boringssl
-
- - name: Make fake BoringSSL directories
- shell: bash
- run: |
- # TODO: remove this when the check is only performed when building.
- # BoringSSL is not needed during the UberJAR build, but the
- # assertion to check happens regardless of whether the project
- # needs it.
- mkdir -p "${{ runner.temp }}/boringssl/build64"
- mkdir -p "${{ runner.temp }}/boringssl/include"
-
- - name: Download Maven repository for Linux
- uses: actions/download-artifact@v1
- with:
- name: m2repo-Linux
- path: ${{ runner.temp }}/m2
-
- - name: Download Maven repository for MacOS
- uses: actions/download-artifact@v1
- with:
- name: m2repo-macOS
- path: ${{ runner.temp }}/m2
-
- - name: Download Maven repository for Windows
- uses: actions/download-artifact@v1
- with:
- name: m2repo-Windows
- path: ${{ runner.temp }}/m2
-
- - name: Build UberJAR with Gradle
- shell: bash
- run: |
- ./gradlew :conscrypt-openjdk-uber:build -Dorg.conscrypt.openjdk.buildUberJar=true -Dmaven.repo.local="$M2_REPO"
-
- - name: Publish UberJAR to Maven Local
- shell: bash
- run: |
- ./gradlew :conscrypt-openjdk-uber:publishToMavenLocal -Dorg.conscrypt.openjdk.buildUberJar=true -Dmaven.repo.local="$M2_REPO"
-
- - name: Upload Maven respository
- uses: actions/upload-artifact@v1
- with:
- name: m2repo-uber
- path: ${{ runner.temp }}/m2
-
- openjdk-test:
- needs: uberjar
-
- strategy:
- fail-fast: false
- matrix:
- platform: [ubuntu-latest, macos-latest, windows-latest]
- java: [8, 9, 11]
- include:
- - java: 8
- suite_class: "org.conscrypt.Conscrypt(OpenJdk)?Suite"
- - java: 9
- suite_class: "org.conscrypt.Conscrypt(OpenJdk)?Suite"
- - java: 11
- suite_class: "org.conscrypt.Conscrypt(OpenJdk)?Suite"
-
- runs-on: ${{ matrix.platform }}
-
- steps:
- - name: Set up Java
- uses: actions/setup-java@v1
- with:
- java-version: ${{ matrix.java }}
-
- - name: Download UberJAR
- uses: actions/download-artifact@v2
- with:
- name: m2repo-uber
- path: m2
-
- - name: Download Test JAR with Dependencies
- uses: actions/download-artifact@v2
- with:
- name: testjar
- path: testjar
-
- - name: Download JUnit runner
- shell: bash
- run: mvn org.apache.maven.plugins:maven-dependency-plugin:3.1.2:copy -Dartifact=org.junit.platform:junit-platform-console-standalone:1.6.2 -DoutputDirectory=. -Dmdep.stripVersion=true
-
- - name: Run JUnit tests
- shell: bash
- run: |
- DIR="$(find m2/org/conscrypt/conscrypt-openjdk-uber -maxdepth 1 -mindepth 1 -type d -print)"
- VERSION="${DIR##*/}"
- TESTJAR="$(find testjar -name '*-tests.jar')"
- java -jar junit-platform-console-standalone.jar -cp "$DIR/conscrypt-openjdk-uber-$VERSION.jar:$TESTJAR" -n='${{ matrix.suite_class }}' --scan-classpath --reports-dir=results --fail-if-no-tests
-
- - name: Archive test results
- if: ${{ always() }}
- uses: actions/upload-artifact@v2
- with:
- name: test-results-${{ matrix.platform }}-${{ matrix.java }}
- path: results
diff --git a/.github/workflows/vsenv.ps1 b/.github/workflows/vsenv.ps1
deleted file mode 100644
index 9f2e039..0000000
--- a/.github/workflows/vsenv.ps1
+++ /dev/null
@@ -1,38 +0,0 @@
-<#
-Copyright (c) Daan De Meyer
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-#>
-
-param (
- [string]$arch = "x64",
- [string]$hostArch = "x64"
- )
-
-$vswherePath = "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"
-$vsInstallationPath = & "$vswherePath" -latest -property installationPath
-$vsDevCmdPath = "`"$vsInstallationPath\Common7\Tools\vsdevcmd.bat`""
-$command = "$vsDevCmdPath -no_logo -arch=$arch -host_arch=$hostArch"
-
-# https://github.com/microsoft/vswhere/wiki/Start-Developer-Command-Prompt
-& "${env:COMSPEC}" /s /c "$command && set" | ForEach-Object {
- $name, $value = $_ -split '=', 2
- Write-Output "Adding $name=$value to env"
- set-content env:\"$name" $value
-}
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..80212d8
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,774 @@
+//
+// Copyright (C) 2016 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.
+//
+
+package {
+ default_visibility: [
+ ":__subpackages__",
+ ],
+ default_applicable_licenses: ["external_conscrypt_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+//
+// large-scale-change included anything that looked like it might be a license
+// text as a license_text. e.g. LICENSE, NOTICE, COPYING etc.
+//
+// Please consider removing redundant or irrelevant files from 'license_text:'.
+// See: http://go/android-license-faq
+license {
+ name: "external_conscrypt_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ "legacy_unencumbered",
+ ],
+ license_text: [
+ "LICENSE",
+ "NOTICE",
+ "licenses/**/*",
+ ],
+}
+
+//
+// Definitions for building the Conscrypt Java library, native code,
+// and associated tests.
+//
+
+// Conscrypt is divided into subdirectories.
+//
+// The structure is:
+//
+// constants/
+// src/gen # Generates NativeConstants.java.
+// common/
+// src/main/java # Common Java source for all platforms.
+// src/jni/
+// main # Common C++ source for all platforms.
+// unbundled # C++ source used for OpenJDK and unbundled Android.
+// src/test/java # Common test files for all platforms.
+// android/
+// src/main/java # Java source for unbundled Android.
+// openjdk/
+// src/main/java # Java source for OpenJDK.
+// src/test
+// java/ # Java source for common tests.
+// resources/ # Support files for tests
+// platform/
+// src/main/java # Java source for bundled Android.
+// src/test
+// java/ # Java source for bundled tests.
+//
+
+cc_defaults {
+ name: "conscrypt_global",
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wunused",
+ ],
+
+ srcs: [
+ "common/src/jni/main/cpp/conscrypt/compatibility_close_monitor.cc",
+ "common/src/jni/main/cpp/conscrypt/jniload.cc",
+ "common/src/jni/main/cpp/conscrypt/jniutil.cc",
+ "common/src/jni/main/cpp/conscrypt/native_crypto.cc",
+ "common/src/jni/main/cpp/conscrypt/netutil.cc",
+ ],
+
+ header_libs: ["jni_headers"],
+
+ local_include_dirs: [
+ "common/src/jni/main/include",
+ ],
+
+ compile_multilib: "both",
+ stl: "c++_static",
+}
+
+cc_defaults {
+ name: "conscrypt_unbundled-jni-defaults",
+
+ local_include_dirs: [
+ "common/src/jni/unbundled/include",
+ ],
+
+ header_libs: ["jni_headers"],
+
+ shared_libs: [
+ "liblog",
+ ],
+
+ static_libs: [
+ "libssl",
+ "libcrypto_static",
+ ],
+
+ sdk_version: "9",
+}
+
+cc_library {
+ name: "libconscrypt_jni",
+ defaults: [
+ "conscrypt_global",
+ "conscrypt_unbundled-jni-defaults",
+ ],
+}
+
+cc_library_host_shared {
+ name: "libconscrypt_openjdk_jni",
+ visibility: [
+ "//build/make/tools/signapk",
+ "//tools/apksig",
+ "//vendor:__subpackages__",
+ ],
+ defaults: ["conscrypt_global"],
+
+ cflags: [
+ "-DCONSCRYPT_OPENJDK",
+ ],
+
+ local_include_dirs: [
+ "common/src/jni/unbundled/include",
+ ],
+
+ static_libs: [
+ "libssl",
+ "libcrypto_static",
+ ],
+
+ // TODO: b/26097626. ASAN breaks use of this library in JVM.
+ // Re-enable sanitization when the issue with making clients of this library
+ // preload ASAN runtime is resolved. Without that, clients are getting runtime
+ // errors due to unresolved ASAN symbols, such as
+ // __asan_option_detect_stack_use_after_return.
+ sanitize: {
+ never: true,
+ },
+
+ stl: "libc++_static",
+
+ // The post-build signing tools need signapk.jar and its shared libs
+ multilib: {
+ lib64: {
+ dist: {
+ targets: ["droidcore"],
+ },
+ },
+ },
+}
+
+cc_binary_host {
+ name: "conscrypt_generate_constants",
+ srcs: ["constants/src/gen/cpp/generate_constants.cc"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libcrypto",
+ "libssl",
+ ],
+}
+
+genrule {
+ name: "conscrypt-unbundled_generated_constants",
+ out: ["org/conscrypt/NativeConstants.java"],
+ cmd: "$(location conscrypt_generate_constants) > $(out)",
+ tools: ["conscrypt_generate_constants"],
+}
+
+genrule {
+ name: "conscrypt_generated_constants",
+ out: ["com/android/org/conscrypt/NativeConstants.java"],
+ cmd: "$(location conscrypt_generate_constants) com.android.org.conscrypt > $(out)",
+ tools: ["conscrypt_generate_constants"],
+}
+
+filegroup {
+ name: "conscrypt_java_files",
+ srcs: [
+ "repackaged/common/src/main/java/**/*.java",
+ "repackaged/platform/src/main/java/**/*.java",
+ ":conscrypt_generated_constants",
+ ],
+}
+
+filegroup {
+ name: "conscrypt_public_api_files",
+ srcs: ["publicapi/src/main/java/**/*.java"],
+ path: "publicapi/src/main/java",
+}
+
+// Create the conscrypt library from the source produced by the srcgen/generate_android_src.sh
+// script.
+java_library {
+ name: "conscrypt",
+ visibility: [
+ "//device:__subpackages__",
+ ":__subpackages__",
+ ],
+ apex_available: [
+ "com.android.conscrypt",
+ "test_com.android.conscrypt",
+ ],
+ // Conscrypt should support Q
+ min_sdk_version: "29",
+
+ installable: true,
+ // Hostdex is only for ART testing on host: ART build file has its
+ // own hostdex support for conscrypt.
+ hostdex: false,
+
+ srcs: [
+ ":conscrypt_java_files",
+ ":conscrypt_public_api_files",
+ ],
+
+ libs: ["unsupportedappusage"],
+
+ // Conscrypt can be updated independently from the other core libraries so it must only depend
+ // on public SDK and intra-core APIs.
+ sdk_version: "none",
+ system_modules: "art-module-intra-core-api-stubs-system-modules",
+ patch_module: "java.base",
+
+ target: {
+ // boringssl_self_test needed in both /system/bin and /apex/com.android.conscrypt/bin
+ // prng_seeder is only needed in /system/bin
+ // The required directive is here rather than under boringssl to avoid circular
+ // dependencies.
+ android: {
+ required: [
+ "boringssl_self_test",
+ "prng_seeder",
+ ],
+ },
+ },
+
+ permitted_packages: [
+ "android.net.ssl",
+ "com.android.org.conscrypt",
+ ],
+}
+
+// Java library for use on host, e.g. by robolectric.
+java_library {
+ name: "conscrypt-for-host",
+ visibility: [
+ "//art/build",
+ "//external/robolectric-shadows",
+ "//external/robolectric",
+ "//frameworks/layoutlib",
+ ],
+ static_libs: [
+ "conscrypt",
+ ],
+ sdk_version: "none",
+ system_modules: "none",
+}
+
+// Referenced implicitly from conscrypt.module.platform.api.
+filegroup {
+ name: "conscrypt.module.platform.api.api.public.latest",
+ srcs: [
+ "api/platform/last-api.txt",
+ ],
+}
+
+// Referenced implicitly from conscrypt.module.platform.api.
+filegroup {
+ name: "conscrypt.module.platform.api-removed.api.public.latest",
+ srcs: [
+ "api/platform/last-removed.txt",
+ ],
+}
+
+// Referenced implicitly from conscrypt.module.platform.api.
+filegroup {
+ name: "conscrypt.module.platform.api-incompatibilities.api.public.latest",
+ srcs: [
+ "api/platform/last-incompatibilities.txt",
+ ],
+}
+
+// A library containing the core platform API stubs of the Conscrypt module.
+//
+// Core platform APIs are only intended for use of other parts of the platform, not the
+// core library modules.
+//
+// The API specification .txt files managed by this only contain the additional
+// classes/members that are in the platform API but which are not in the public
+// API.
+//
+// Note that this entire API surface is considered stable in the sense described in
+// libcore/mmodules/core_platform_api/Android.bp.
+java_sdk_library {
+ name: "conscrypt.module.platform.api",
+ visibility: [
+ "//build/soong/java/core-libraries",
+ "//external/wycheproof",
+ // Visibility for prebuilt conscrypt-module-sdk from the prebuilt of
+ // this module.
+ // TODO(b/155921753): Restrict this when prebuilts are in their proper
+ // locations.
+ "//prebuilts:__subpackages__",
+
+ // DO NOT REMOVE: Legacy visibility, needed for snapshots that are
+ // generated for the S build.
+ "//libcore/mmodules/core_platform_api",
+ ],
+ srcs: [
+ ":conscrypt_java_files",
+ ],
+ api_dir: "api/platform",
+ api_only: true,
+ api_lint: {
+ enabled: true,
+ },
+ droiddoc_options: [
+ "--hide-annotation libcore.api.Hide",
+ "--show-single-annotation libcore.api.CorePlatformApi\\(status=libcore.api.CorePlatformApi.Status.STABLE\\)",
+ ],
+ hostdex: true,
+
+ sdk_version: "none",
+ system_modules: "art-module-lib-api-stubs-system-modules",
+
+ dist_group: "android",
+ dist_stem: "conscrypt-coreplatform",
+ // TODO: remove this when Conscrypt's @CorePlatformApi has been migrated to @SystemApi
+ unsafe_ignore_missing_latest_api: true,
+}
+
+// A library containing the public API stubs of the Conscrypt module.
+java_sdk_library {
+ name: "conscrypt.module.public.api",
+ visibility: [
+ "//build/soong/java/core-libraries",
+ "//frameworks/base",
+ "//frameworks/base/api",
+ "//packages/modules/common/sdk",
+ // TODO(b/165823103): Remove visiblity for IPsec once CorePlatformApi is available
+ "//packages/modules/IPsec",
+ // Visibility for prebuilt art-module-host-exports from the prebuilt of
+ // this module.
+ // TODO(b/155921753): Restrict this when prebuilts are in their proper
+ // locations.
+ "//prebuilts:__subpackages__",
+
+ // DO NOT REMOVE: Legacy visibility, needed for snapshots that are
+ // generated for the S build.
+ "//libcore",
+ ],
+ srcs: [
+ ":conscrypt_public_api_files",
+ ],
+
+ // The base name for the artifacts that are automatically published to the
+ // dist and which end up in one of the sub-directories of prebuilts/sdk.
+ // As long as this matches the name of the artifacts in prebuilts/sdk then
+ // the API will be checked for compatibility against the latest released
+ // version of the API.
+ dist_stem: "conscrypt",
+
+ public: {
+ enabled: true,
+ },
+ system: {
+ enabled: true,
+ },
+ module_lib: {
+ enabled: true,
+ },
+
+ api_dir: "api/public",
+ api_only: true,
+
+ // Emit nullability annotations from the source to the stub files.
+ annotations_enabled: true,
+
+ java_version: "1.9",
+
+ sdk_version: "none",
+ system_modules: "art-module-public-api-stubs-system-modules",
+ dist_group: "android",
+}
+
+// Referenced implicitly from conscrypt.module.intra.core.api.
+filegroup {
+ name: "conscrypt.module.intra.core.api.api.public.latest",
+ srcs: [
+ "api/intra/last-api.txt",
+ ],
+}
+
+// Referenced implicitly from conscrypt.module.intra.core.api.
+filegroup {
+ name: "conscrypt.module.intra.core.api-removed.api.public.latest",
+ srcs: [
+ "api/intra/last-removed.txt",
+ ],
+}
+
+// Referenced implicitly from conscrypt.module.intra.core.api.
+filegroup {
+ name: "conscrypt.module.intra.core.api-incompatibilities.api.public.latest",
+ srcs: [
+ "api/intra/last-incompatibilities.txt",
+ ],
+}
+
+// A library containing the intra-core API stubs of the Conscrypt module.
+//
+// Intra-core APIs are only intended for the use of other core library modules.
+//
+// The API specification .txt files managed by this only contain the additional
+// classes/members that are in the intra-core API but which are not the public API.
+java_sdk_library {
+ name: "conscrypt.module.intra.core.api",
+ visibility: [
+ "//external/okhttp",
+ "//libcore:__subpackages__",
+ // Visibility for prebuilt conscrypt-module-sdk from the prebuilt of
+ // this module.
+ // TODO(b/155921753): Restrict this when prebuilts are in their proper
+ // locations.
+ "//prebuilts:__subpackages__",
+ ],
+ srcs: [
+ ":conscrypt_java_files",
+ ":conscrypt_public_api_files",
+ ],
+ api_dir: "api/intra",
+ api_only: true,
+ droiddoc_options: [
+ "--hide-annotation libcore.api.Hide",
+ "--show-single-annotation libcore.api.IntraCoreApi",
+ ],
+
+ sdk_version: "none",
+ system_modules: "art-module-intra-core-api-stubs-system-modules",
+
+ // Don't copy any output files to the dist.
+ no_dist: true,
+}
+
+// Platform conscrypt crypto JNI library
+cc_defaults {
+ name: "libjavacrypto-defaults",
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wunused",
+ "-fvisibility=hidden",
+ ],
+
+ srcs: ["common/src/jni/main/cpp/**/*.cc"],
+ header_libs: ["jni_headers"],
+ local_include_dirs: ["common/src/jni/main/include"],
+}
+
+// Platform conscrypt crypto JNI library
+cc_library_shared {
+ name: "libjavacrypto",
+ host_supported: true,
+ defaults: ["libjavacrypto-defaults"],
+
+ cflags: ["-DJNI_JARJAR_PREFIX=com/android/"],
+ header_libs: ["libnativehelper_header_only"],
+ shared_libs: ["liblog"],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ android: {
+ runtime_libs: ["libandroidio"],
+ shared_libs: [
+ "libcrypto",
+ "libssl",
+ ],
+ },
+ not_windows: {
+ runtime_libs: ["libandroidio"],
+ // Link libcrypto and libssl statically on host, to ensure they stay current in
+ // the prebuilt that's included in conscrypt-module-test-exports.
+ static_libs: [
+ "libcrypto",
+ "libssl",
+ ],
+ },
+ },
+ apex_available: [
+ "com.android.conscrypt",
+ "test_com.android.conscrypt",
+ ],
+ min_sdk_version: "29",
+}
+
+// Unbundled Conscrypt jar for use by signapk and apksigner tool
+//
+// Builds against standard host libraries.
+//
+// This does not use java_library_host as that does not support the
+// min_sdk_version property which needs to be set to make sure that this
+// library is added to the sdk snapshot correctly.
+java_library {
+ name: "conscrypt-unbundled",
+ visibility: [
+ "//build/make/tools/signapk",
+ "//tools/apksig",
+ "//external/robolectric:__subpackages__",
+ ],
+ device_supported: false,
+ host_supported: true,
+ srcs: [
+ "common/src/main/java/**/*.java",
+ "openjdk/src/main/java/**/*.java",
+ ":conscrypt-unbundled_generated_constants",
+ ],
+ javacflags: ["-XDignore.symbol.file"],
+ java_version: "1.8",
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ // Make sure that this will be added to the sdk snapshot for S.
+ min_sdk_version: "S",
+}
+
+// Static unbundled Conscrypt crypto JNI library
+cc_library_static {
+ name: "libconscrypt_static",
+ defaults: ["libjavacrypto-defaults"],
+
+ cflags: [
+ "-DJNI_JARJAR_PREFIX=com/google/android/gms/",
+ "-DCONSCRYPT_UNBUNDLED",
+ "-DSTATIC_LIB",
+ ],
+
+ local_include_dirs: ["common/src/jni/unbundled/include"],
+
+ static_libs: [
+ "libssl",
+ "libcrypto_static",
+ ],
+ sdk_version: "9",
+ stl: "c++_shared",
+}
+
+// Make the conscrypt-tests library.
+java_test {
+ name: "conscrypt-tests",
+ visibility: [
+ "//cts/tests/libcore/luni",
+ "//external/conscrypt/apex/tests",
+ ],
+ hostdex: true,
+ srcs: [
+ "repackaged/platform/src/test/java/**/*.java",
+ "repackaged/common/src/test/java/**/*.java",
+ "repackaged/testing/src/main/java/**/*.java",
+ "publicapi/src/test/java/**/*.java",
+ ],
+ java_resource_dirs: [
+ // Resource directories do not need repackaging.
+ "openjdk/src/test/resources",
+ "common/src/test/resources",
+ ],
+
+ sdk_version: "none",
+ system_modules: "art-module-intra-core-api-stubs-system-modules",
+ libs: [
+ "conscrypt",
+ "core-test-rules",
+ "junit",
+ "mockito-target-minus-junit4",
+ "framework-statsd.stubs.module_lib",
+ ],
+
+ static_libs: [
+ "bouncycastle-unbundled",
+ "bouncycastle-bcpkix-unbundled",
+ "bouncycastle-ocsp-unbundled",
+ ],
+ javacflags: [
+ "-Xmaxwarns 9999999",
+ //"-Xlint:all",
+ //"-Xlint:-serial,-deprecation,-unchecked",
+ ],
+
+ target: {
+ host: {
+ required: ["libjavacrypto"],
+ },
+ darwin: {
+ // required module "libjavacrypto" is disabled on darwin
+ enabled: false,
+ },
+ },
+ java_version: "1.8",
+}
+
+// Make the conscrypt-benchmarks library.
+java_test {
+ name: "conscrypt-benchmarks",
+ srcs: [
+ "repackaged/testing/src/main/java/**/*.java",
+ "repackaged/benchmark-base/src/main/java/**/*.java",
+ "repackaged/benchmark-android/src/main/java/**/*.java",
+ ],
+ sdk_version: "none",
+ system_modules: "art-module-intra-core-api-stubs-system-modules",
+ libs: [
+ "conscrypt",
+ "junit",
+ "bouncycastle-unbundled",
+ "bouncycastle-bcpkix-unbundled",
+ "bouncycastle-ocsp-unbundled",
+ "caliper-api-target",
+ ],
+
+ javacflags: [
+ "-Xmaxwarns 9999999",
+ //"-Xlint:all",
+ //"-Xlint:-serial,-deprecation,-unchecked",
+ ],
+
+ target: {
+ host: {
+ required: ["libjavacrypto"],
+ },
+ darwin: {
+ // required module "libjavacrypto" is disabled on darwin
+ enabled: false,
+ },
+ },
+ java_version: "1.8",
+}
+
+// Device SDK exposed by the Conscrypt module.
+sdk {
+ name: "conscrypt-module-sdk",
+ apexes: [
+ // Adds exportable dependencies of the APEX to the sdk,
+ // e.g. *classpath_fragments.
+ "com.android.conscrypt",
+ ],
+ java_sdk_libs: [
+ "conscrypt.module.intra.core.api",
+ ],
+ native_shared_libs: [
+ "libconscrypt_jni",
+ ],
+}
+
+// Host tools exported by the Conscrypt module.
+module_exports {
+ name: "conscrypt-module-host-exports",
+ host_supported: true,
+ device_supported: false,
+ java_libs: [
+ "conscrypt-unbundled",
+ ],
+ native_shared_libs: [
+ "libconscrypt_openjdk_jni",
+ ],
+}
+
+// Test libraries exposed by the Conscrypt module.
+module_exports {
+ name: "conscrypt-module-test-exports",
+ host_supported: true,
+ target: {
+ android: {
+ java_libs: [
+ // For use by robolectric and ART tests.
+ "conscrypt-for-host",
+ ],
+ java_tests: [
+ // For use by CTS
+ "conscrypt-tests",
+ ],
+ native_shared_libs: [
+ "libjavacrypto",
+ ],
+ },
+ darwin: {
+ enabled: false,
+ },
+ // For use by ART tests on host.
+ not_windows: {
+ native_shared_libs: [
+ "libjavacrypto",
+ ],
+ },
+ },
+}
+
+java_api_contribution {
+ name: "conscrypt-module-intra-core-stubs",
+ api_surface: "intra-core",
+ api_file: "api/intra/current.txt",
+ visibility: [
+ "//build/orchestrator/apis",
+ ],
+}
+
+java_api_contribution {
+ name: "conscrypt-module-public-stubs",
+ api_surface: "public",
+ api_file: "api/public/current.txt",
+ visibility: [
+ "//build/orchestrator/apis",
+ ],
+}
+
+java_api_contribution {
+ name: "conscrypt-module-platform-stubs",
+ api_surface: "core-platform",
+ api_file: "api/platform/current.txt",
+ visibility: [
+ "//build/orchestrator/apis",
+ ],
+}
+
+java_api_contribution {
+ name: "conscrypt-module-lib-stubs",
+ api_surface: "module-lib",
+ api_file: "api/public/module-lib-current.txt",
+ visibility: [
+ "//build/orchestrator/apis",
+ ],
+}
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..d97975c
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,3 @@
+third_party {
+ license_type: NOTICE
+}
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..73617ea
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 684135
+include platform/libcore:/OWNERS
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 4c8d137..7d08c6f 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,3 +1,8 @@
[Builtin Hooks]
commit_msg_test_field = true
clang_format = true
+bpfmt = true
+
+[Hook Scripts]
+
+hidden_api_txt_checksorted_hook = ${REPO_ROOT}/tools/platform-compat/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
diff --git a/README.android b/README.android
new file mode 100644
index 0000000..1b2919c
--- /dev/null
+++ b/README.android
@@ -0,0 +1,12 @@
+Conscrypt in Android is made up of the contents of the Conscrypt
+GitHub repo (https://github.com/google/conscrypt) plus some
+Android-specific additions. Specifically, the following are
+Android-only:
+
+Android.bp
+OWNERS
+README.android
+apex/...
+publicapi/...
+repackaged/...
+srcgen/...
diff --git a/apex/Android.bp b/apex/Android.bp
new file mode 100644
index 0000000..970752d
--- /dev/null
+++ b/apex/Android.bp
@@ -0,0 +1,267 @@
+// 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.
+
+// Defaults shared between real and test versions of the APEX.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "external_conscrypt_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["external_conscrypt_license"],
+}
+
+apex_defaults {
+ name: "com.android.conscrypt-defaults",
+ androidManifest: ":com.android.conscrypt-androidManifest",
+ compile_multilib: "both",
+ bootclasspath_fragments: ["com.android.conscrypt-bootclasspath-fragment"],
+ jni_libs: ["libjavacrypto"],
+ prebuilts: ["current_sdkinfo"],
+ multilib: {
+ both: {
+ binaries: ["boringssl_self_test"],
+ },
+ },
+ key: "apex.conscrypt.key",
+ certificate: ":com.android.conscrypt.certificate",
+ // Indicates that pre-installed version of this apex can be compressed.
+ // Whether it actually will be compressed is controlled on per-device basis.
+ compressible: true,
+
+ // IMPORTANT: q-launched-dcla-enabled-apex-module enables the build system to make
+ // sure the package compatible to Android 10 in two ways:
+ // - build the APEX package compatible to Android 10
+ // so that the package can be installed.
+ // - build artifacts (lib/javalib/bin) against Android 10 SDK
+ // so that the artifacts can run.
+ defaults: ["q-launched-dcla-enabled-apex-module"],
+}
+
+filegroup {
+ name: "com.android.conscrypt-androidManifest",
+ srcs: ["AndroidManifest.xml"],
+}
+
+apex_key {
+ name: "apex.conscrypt.key",
+ public_key: "com.android.conscrypt.avbpubkey",
+ private_key: "com.android.conscrypt.pem",
+}
+
+android_app_certificate {
+ name: "com.android.conscrypt.certificate",
+ certificate: "com.android.conscrypt",
+}
+
+prebuilt_etc {
+ name: "com.android.conscrypt.ld.config.txt",
+ src: "ld.config.txt",
+ filename: "ld.config.txt",
+ installable: false,
+}
+
+// Production APEX
+apex {
+ name: "com.android.conscrypt",
+ visibility: [
+ "//external/conscrypt",
+ "//vendor:__subpackages__",
+ ],
+ defaults: ["com.android.conscrypt-defaults"],
+ manifest: "apex_manifest.json",
+ binaries: ["boringssl_self_test"],
+ prebuilts: [
+ "com.android.conscrypt.ld.config.txt",
+ "target-cacert-apex-01419da9.0",
+ "target-cacert-apex-04f60c28.0",
+ "target-cacert-apex-0d69c7e1.0",
+ "target-cacert-apex-10531352.0",
+ "target-cacert-apex-1ae85e5e.0",
+ "target-cacert-apex-1b0f7e5c.0",
+ "target-cacert-apex-1df5a75f.0",
+ "target-cacert-apex-1e1eab7c.0",
+ "target-cacert-apex-1e8e7201.0",
+ "target-cacert-apex-1ec40989.0",
+ "target-cacert-apex-1f58a078.0",
+ "target-cacert-apex-219d9499.0",
+ "target-cacert-apex-23f4c490.0",
+ "target-cacert-apex-252252d2.0",
+ "target-cacert-apex-2add47b6.0",
+ "target-cacert-apex-2d9dafe4.0",
+ "target-cacert-apex-302904dd.0",
+ "target-cacert-apex-304d27c3.0",
+ "target-cacert-apex-31188b5e.0",
+ "target-cacert-apex-33ee480d.0",
+ "target-cacert-apex-35105088.0",
+ "target-cacert-apex-399e7759.0",
+ "target-cacert-apex-3ad48a91.0",
+ "target-cacert-apex-3c860d51.0",
+ "target-cacert-apex-3c899c73.0",
+ "target-cacert-apex-3c9a4d3b.0",
+ "target-cacert-apex-3e7271e8.0",
+ "target-cacert-apex-41a3f684.0",
+ "target-cacert-apex-455f1b52.0",
+ "target-cacert-apex-48a195d8.0",
+ "target-cacert-apex-4be590e0.0",
+ "target-cacert-apex-4c3982f2.0",
+ "target-cacert-apex-5046c355.0",
+ "target-cacert-apex-52b525c7.0",
+ "target-cacert-apex-53a1b57a.0",
+ "target-cacert-apex-583d0756.0",
+ "target-cacert-apex-5a3f0ff8.0",
+ "target-cacert-apex-5acf816d.0",
+ "target-cacert-apex-5f47b495.0",
+ "target-cacert-apex-5f9a69fa.0",
+ "target-cacert-apex-5fdd185d.0",
+ "target-cacert-apex-60afe812.0",
+ "target-cacert-apex-6187b673.0",
+ "target-cacert-apex-63a2c897.0",
+ "target-cacert-apex-69105f4f.0",
+ "target-cacert-apex-6b03dec0.0",
+ "target-cacert-apex-6f7454b3.0",
+ "target-cacert-apex-75680d2e.0",
+ "target-cacert-apex-76579174.0",
+ "target-cacert-apex-7892ad52.0",
+ "target-cacert-apex-7a7c655d.0",
+ "target-cacert-apex-7a819ef2.0",
+ "target-cacert-apex-81b9768f.0",
+ "target-cacert-apex-82223c44.0",
+ "target-cacert-apex-83e9984f.0",
+ "target-cacert-apex-85cde254.0",
+ "target-cacert-apex-86212b19.0",
+ "target-cacert-apex-869fbf79.0",
+ "target-cacert-apex-8794b4e3.0",
+ "target-cacert-apex-882de061.0",
+ "target-cacert-apex-88950faa.0",
+ "target-cacert-apex-89c02a45.0",
+ "target-cacert-apex-8d6437c3.0",
+ "target-cacert-apex-9282e51c.0",
+ "target-cacert-apex-9339512a.0",
+ "target-cacert-apex-93851c9e.0",
+ "target-cacert-apex-9479c8c3.0",
+ "target-cacert-apex-9576d26b.0",
+ "target-cacert-apex-9591a472.0",
+ "target-cacert-apex-95aff9e3.0",
+ "target-cacert-apex-9685a493.0",
+ "target-cacert-apex-985c1f52.0",
+ "target-cacert-apex-99e1b953.0",
+ "target-cacert-apex-9aef356c.0",
+ "target-cacert-apex-9d6523ce.0",
+ "target-cacert-apex-a2c66da8.0",
+ "target-cacert-apex-a3896b44.0",
+ "target-cacert-apex-a716d4ed.0",
+ "target-cacert-apex-a81e292b.0",
+ "target-cacert-apex-a9d40e02.0",
+ "target-cacert-apex-ab5346f4.0",
+ "target-cacert-apex-ab59055e.0",
+ "target-cacert-apex-b0ed035a.0",
+ "target-cacert-apex-b0f3e76e.0",
+ "target-cacert-apex-b30d5fda.0",
+ "target-cacert-apex-b3fb433b.0",
+ "target-cacert-apex-b74d2bd5.0",
+ "target-cacert-apex-b7db1890.0",
+ "target-cacert-apex-b872f2b4.0",
+ "target-cacert-apex-b92fd57f.0",
+ "target-cacert-apex-b936d1c6.0",
+ "target-cacert-apex-bc3f2570.0",
+ "target-cacert-apex-bd43e1dd.0",
+ "target-cacert-apex-bdacca6f.0",
+ "target-cacert-apex-bf64f35b.0",
+ "target-cacert-apex-c44cc0c0.0",
+ "target-cacert-apex-c491639e.0",
+ "target-cacert-apex-c559d742.0",
+ "target-cacert-apex-c7f1359b.0",
+ "target-cacert-apex-c90bc37d.0",
+ "target-cacert-apex-cb1c3204.0",
+ "target-cacert-apex-ccc52f49.0",
+ "target-cacert-apex-cf701eeb.0",
+ "target-cacert-apex-d06393bb.0",
+ "target-cacert-apex-d16a5865.0",
+ "target-cacert-apex-d16a5865.1",
+ "target-cacert-apex-d18e9066.0",
+ "target-cacert-apex-d39b0a2c.0",
+ "target-cacert-apex-d41b5e2a.0",
+ "target-cacert-apex-d4c339cb.0",
+ "target-cacert-apex-d59297b8.0",
+ "target-cacert-apex-d7746a63.0",
+ "target-cacert-apex-d96b65e2.0",
+ "target-cacert-apex-da7377f6.0",
+ "target-cacert-apex-dbc54cab.0",
+ "target-cacert-apex-dbff3a01.0",
+ "target-cacert-apex-dc99f41e.0",
+ "target-cacert-apex-dfc0fe80.0",
+ "target-cacert-apex-e13665f9.0",
+ "target-cacert-apex-e442e424.0",
+ "target-cacert-apex-e48193cf.0",
+ "target-cacert-apex-e7c037b4.0",
+ "target-cacert-apex-e8651083.0",
+ "target-cacert-apex-ed39abd0.0",
+ "target-cacert-apex-edcbddb5.0",
+ "target-cacert-apex-ee532fd5.0",
+ "target-cacert-apex-f013ecaf.0",
+ "target-cacert-apex-f058632f.0",
+ "target-cacert-apex-f0cd152c.0",
+ "target-cacert-apex-f459871d.0",
+ "target-cacert-apex-f8fc53da.0",
+ "target-cacert-apex-fb5fa911.0",
+ "target-cacert-apex-fd08c599.0",
+ "target-cacert-apex-fde84897.0",
+ ],
+}
+
+// Encapsulate the contributions made by the com.android.conscrypt to the bootclasspath.
+bootclasspath_fragment {
+ name: "com.android.conscrypt-bootclasspath-fragment",
+ contents: ["conscrypt"],
+ apex_available: ["com.android.conscrypt"],
+ // The bootclasspath_fragments that provide APIs on which this depends.
+ fragments: [
+ {
+ apex: "com.android.art",
+ module: "art-bootclasspath-fragment",
+ },
+ ],
+ // The APIs provided by this fragment.
+ api: {
+ stub_libs: [
+ "conscrypt.module.public.api",
+ ],
+ },
+ // The core platform APIs provided by this fragment.
+ core_platform_api: {
+ stub_libs: [
+ "conscrypt.module.platform.api",
+ ],
+ },
+ // Additional hidden API flags that override the default flags derived
+ // from the api stub libraries.
+ hidden_api: {
+ max_target_o_low_priority: ["hiddenapi/hiddenapi-max-target-o-low-priority.txt"],
+
+ // This module does not contain any split packages.
+ split_packages: [],
+
+ // The following packages and all their subpackages currently only
+ // contain classes from this bootclasspath_fragment. Listing a package
+ // here won't prevent other bootclasspath modules from adding classes in
+ // any of those packages but it will prevent them from adding those
+ // classes into an API surface, e.g. public, system, etc.. Doing so will
+ // result in a build failure due to inconsistent flags.
+ package_prefixes: [
+ "android.net.ssl",
+ "com.android.org.conscrypt",
+ ],
+ },
+}
diff --git a/apex/AndroidManifest.xml b/apex/AndroidManifest.xml
new file mode 100644
index 0000000..a38cb9b
--- /dev/null
+++ b/apex/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.conscrypt">
+ <!-- APEX does not have classes.dex -->
+ <application android:hasCode="false" />
+ <!--
+ * API levels the Conscrypt APEX is known to work with.
+ -->
+ <!-- TODO: Uncomment this when the R API level is fixed. b/148281152 -->
+ <!--uses-sdk
+ android:minSdkVersion="29"
+ android:maxSdkVersion="29"
+ android:targetSdkVersion="29"
+ />
+ -->
+</manifest>
diff --git a/apex/apex_manifest.json b/apex/apex_manifest.json
new file mode 100644
index 0000000..3fd42bd
--- /dev/null
+++ b/apex/apex_manifest.json
@@ -0,0 +1,7 @@
+{
+ "name": "com.android.conscrypt",
+
+ // Placeholder module version to be replaced during build.
+ // Do not change!
+ "version": 0
+}
diff --git a/apex/ca-certificates/Android.bp b/apex/ca-certificates/Android.bp
new file mode 100644
index 0000000..e109a94
--- /dev/null
+++ b/apex/ca-certificates/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2022 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.
+
+// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE
+// CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE
+// DEPENDING ON IT IN YOUR PROJECT. ***
+package {
+ default_applicable_licenses: ["apex_ca-certificates_license"],
+}
+
+// See: http://go/android-license-faq
+license {
+ name: "apex_ca-certificates_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "legacy_by_exception_only", // by exception only
+ ],
+ license_text: [],
+}
+
+// This is a temporary solution for adding certificates to the apex.
+ca_certificates_apex {
+ name: "cacerts_apex",
+ src_dir: "files",
+ dest_dir: "",
+ module_name_prefix: "target-cacert-apex-",
+}
diff --git a/apex/ca-certificates/METADATA b/apex/ca-certificates/METADATA
new file mode 100644
index 0000000..b7a7487
--- /dev/null
+++ b/apex/ca-certificates/METADATA
@@ -0,0 +1,8 @@
+# *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE
+# CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE
+# DEPENDING ON IT IN YOUR PROJECT. ***
+third_party {
+ license_note: "Quo Vadis Certificate Policy in files/5cf9d536.0 references:\n"
+ " Quo Vadis Certificate Holder Agreement"
+ license_type: BY_EXCEPTION_ONLY
+}
diff --git a/apex/ca-certificates/OWNERS b/apex/ca-certificates/OWNERS
new file mode 100644
index 0000000..b6dcf05
--- /dev/null
+++ b/apex/ca-certificates/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 684135
+include platform/external/conscrypt:/OWNERS
+
+# Only for emergency escalations, do not send reviews here:
+bdc@google.com
+
diff --git a/apex/ca-certificates/README.cacerts b/apex/ca-certificates/README.cacerts
new file mode 100755
index 0000000..ca5c570
--- /dev/null
+++ b/apex/ca-certificates/README.cacerts
@@ -0,0 +1,7 @@
+The filenames in the cacerts directory are in the format of <hash>.<n>
+where "hash" is the subject hash produced by:
+
+ openssl x509 -subject_hash_old -in filename
+
+and the "n" is a unique integer identifier starting at 0 to deal
+with collisions. See OpenSSL's c_rehash manpage for details.
diff --git a/apex/ca-certificates/files/01419da9.0 b/apex/ca-certificates/files/01419da9.0
new file mode 100644
index 0000000..3b9b885
--- /dev/null
+++ b/apex/ca-certificates/files/01419da9.0
@@ -0,0 +1,57 @@
+-----BEGIN CERTIFICATE-----
+MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw
+CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD
+VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw
+MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV
+UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy
+b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq
+hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR
+ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb
+hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E
+BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3
+FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV
+L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB
+iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 66:f2:3d:af:87:de:8b:b1:4a:ea:0c:57:31:01:c2:ec
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=US, O=Microsoft Corporation, CN=Microsoft ECC Root Certificate Authority 2017
+ Validity
+ Not Before: Dec 18 23:06:45 2019 GMT
+ Not After : Jul 18 23:16:04 2042 GMT
+ Subject: C=US, O=Microsoft Corporation, CN=Microsoft ECC Root Certificate Authority 2017
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:d4:bc:3d:02:42:75:41:13:23:cd:80:04:86:02:
+ 51:2f:6a:a8:81:62:0b:65:cc:f6:ca:9d:1e:6f:4a:
+ 66:51:a2:03:d9:9d:91:fa:b6:16:b1:8c:6e:de:7c:
+ cd:db:79:a6:2f:ce:bb:ce:71:2f:e5:a5:ab:28:ec:
+ 63:04:66:99:f8:fa:f2:93:10:05:e1:81:28:42:e3:
+ c6:68:f4:e6:1b:84:60:4a:89:af:ed:79:0f:3b:ce:
+ f1:f6:44:f5:01:78:c0
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ C8:CB:99:72:70:52:0C:F8:E6:BE:B2:04:57:29:2A:CF:42:10:ED:35
+ 1.3.6.1.4.1.311.21.1:
+ ...
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:65:02:30:58:f2:4d:ea:0c:f9:5f:5e:ee:60:29:cb:3a:f2:
+ db:d6:32:84:19:3f:7c:d5:2f:c2:b1:cc:93:ae:50:bb:09:32:
+ c6:c6:ed:7e:c9:36:94:12:e4:68:85:06:a2:1b:d0:2f:02:31:
+ 00:99:e9:16:b4:0e:fa:56:48:d4:a4:30:16:91:78:db:54:8c:
+ 65:01:8a:e7:50:66:c2:31:b7:39:ba:b8:1a:22:07:4e:fc:6b:
+ 54:16:20:ff:2b:b5:e7:4c:0c:4d:a6:4f:73
+SHA1 Fingerprint=99:9A:64:C3:7F:F4:7D:9F:AB:95:F1:47:69:89:14:60:EE:C4:C3:C5
diff --git a/apex/ca-certificates/files/04f60c28.0 b/apex/ca-certificates/files/04f60c28.0
new file mode 100644
index 0000000..7629375
--- /dev/null
+++ b/apex/ca-certificates/files/04f60c28.0
@@ -0,0 +1,56 @@
+-----BEGIN CERTIFICATE-----
+MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL
+MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl
+eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT
+JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx
+MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
+Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg
+VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm
+aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo
+I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng
+o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G
+A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB
+zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW
+RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 5c:8b:99:c5:5a:94:c5:d2:71:56:de:cd:89:80:cc:26
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=US, ST=New Jersey, L=Jersey City, O=The USERTRUST Network, CN=USERTrust ECC Certification Authority
+ Validity
+ Not Before: Feb 1 00:00:00 2010 GMT
+ Not After : Jan 18 23:59:59 2038 GMT
+ Subject: C=US, ST=New Jersey, L=Jersey City, O=The USERTRUST Network, CN=USERTrust ECC Certification Authority
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:1a:ac:54:5a:a9:f9:68:23:e7:7a:d5:24:6f:53:
+ c6:5a:d8:4b:ab:c6:d5:b6:d1:e6:73:71:ae:dd:9c:
+ d6:0c:61:fd:db:a0:89:03:b8:05:14:ec:57:ce:ee:
+ 5d:3f:e2:21:b3:ce:f7:d4:8a:79:e0:a3:83:7e:2d:
+ 97:d0:61:c4:f1:99:dc:25:91:63:ab:7f:30:a3:b4:
+ 70:e2:c7:a1:33:9c:f3:bf:2e:5c:53:b1:5f:b3:7d:
+ 32:7f:8a:34:e3:79:79
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 3A:E1:09:86:D4:CF:19:C2:96:76:74:49:76:DC:E0:35:C6:63:63:9A
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:65:02:30:36:67:a1:16:08:dc:e4:97:00:41:1d:4e:be:e1:
+ 63:01:cf:3b:aa:42:11:64:a0:9d:94:39:02:11:79:5c:7b:1d:
+ fa:64:b9:ee:16:42:b3:bf:8a:c2:09:c4:ec:e4:b1:4d:02:31:
+ 00:e9:2a:61:47:8c:52:4a:4b:4e:18:70:f6:d6:44:d6:6e:f5:
+ 83:ba:6d:58:bd:24:d9:56:48:ea:ef:c4:a2:46:81:88:6a:3a:
+ 46:d1:a9:9b:4d:c9:61:da:d1:5d:57:6a:18
+SHA1 Fingerprint=D1:CB:CA:5D:B2:D5:2A:7F:69:3B:67:4D:E5:F0:5A:1D:0C:95:7D:F0
diff --git a/apex/ca-certificates/files/0d69c7e1.0 b/apex/ca-certificates/files/0d69c7e1.0
new file mode 100644
index 0000000..ca0e2af
--- /dev/null
+++ b/apex/ca-certificates/files/0d69c7e1.0
@@ -0,0 +1,48 @@
+-----BEGIN CERTIFICATE-----
+MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD
+VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh
+bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw
+MTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0g
+UjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wWTAT
+BgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkWymOx
+uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV
+HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/
++wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147
+bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 02:03:e5:7e:f5:3f:93:fd:a5:09:21:b2:a6
+ Signature Algorithm: ecdsa-with-SHA256
+ Issuer: OU=GlobalSign ECC Root CA - R4, O=GlobalSign, CN=GlobalSign
+ Validity
+ Not Before: Nov 13 00:00:00 2012 GMT
+ Not After : Jan 19 03:14:07 2038 GMT
+ Subject: OU=GlobalSign ECC Root CA - R4, O=GlobalSign, CN=GlobalSign
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (256 bit)
+ pub:
+ 04:b8:c6:79:d3:8f:6c:25:0e:9f:2e:39:19:1c:03:
+ a4:ae:9a:e5:39:07:09:16:ca:63:b1:b9:86:f8:8a:
+ 57:c1:57:ce:42:fa:73:a1:f7:65:42:ff:1e:c1:00:
+ b2:6e:73:0e:ff:c7:21:e5:18:a4:aa:d9:71:3f:a8:
+ d4:b9:ce:8c:1d
+ ASN1 OID: prime256v1
+ NIST CURVE: P-256
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 54:B0:7B:AD:45:B8:E2:40:7F:FB:0A:6E:FB:BE:33:C9:3C:A3:84:D5
+ Signature Algorithm: ecdsa-with-SHA256
+ Signature Value:
+ 30:44:02:20:22:4f:74:72:b9:60:af:f1:e6:9c:a0:16:05:50:
+ 5f:c3:5e:3b:6e:61:74:ef:be:01:c4:be:18:48:59:61:82:32:
+ 02:20:26:9d:54:63:40:de:37:60:50:cf:c8:d8:ed:9d:82:ae:
+ 37:98:bc:a3:8f:4c:4c:a9:34:2b:6c:ef:fb:95:9b:26
+SHA1 Fingerprint=6B:A0:B0:98:E1:71:EF:5A:AD:FE:48:15:80:77:10:F4:BD:6F:0B:28
diff --git a/apex/ca-certificates/files/10531352.0 b/apex/ca-certificates/files/10531352.0
new file mode 100644
index 0000000..47135a3
--- /dev/null
+++ b/apex/ca-certificates/files/10531352.0
@@ -0,0 +1,82 @@
+-----BEGIN CERTIFICATE-----
+MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
+HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
+ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
+MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD
+VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy
+ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy
+dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p
+OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2
+8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K
+Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe
+hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk
+6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw
+DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q
+AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI
+bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB
+ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z
+qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
+iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn
+0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN
+sSi6
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 0 (0x0)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Services Root Certificate Authority - G2
+ Validity
+ Not Before: Sep 1 00:00:00 2009 GMT
+ Not After : Dec 31 23:59:59 2037 GMT
+ Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Services Root Certificate Authority - G2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:d5:0c:3a:c4:2a:f9:4e:e2:f5:be:19:97:5f:8e:
+ 88:53:b1:1f:3f:cb:cf:9f:20:13:6d:29:3a:c8:0f:
+ 7d:3c:f7:6b:76:38:63:d9:36:60:a8:9b:5e:5c:00:
+ 80:b2:2f:59:7f:f6:87:f9:25:43:86:e7:69:1b:52:
+ 9a:90:e1:71:e3:d8:2d:0d:4e:6f:f6:c8:49:d9:b6:
+ f3:1a:56:ae:2b:b6:74:14:eb:cf:fb:26:e3:1a:ba:
+ 1d:96:2e:6a:3b:58:94:89:47:56:ff:25:a0:93:70:
+ 53:83:da:84:74:14:c3:67:9e:04:68:3a:df:8e:40:
+ 5a:1d:4a:4e:cf:43:91:3b:e7:56:d6:00:70:cb:52:
+ ee:7b:7d:ae:3a:e7:bc:31:f9:45:f6:c2:60:cf:13:
+ 59:02:2b:80:cc:34:47:df:b9:de:90:65:6d:02:cf:
+ 2c:91:a6:a6:e7:de:85:18:49:7c:66:4e:a3:3a:6d:
+ a9:b5:ee:34:2e:ba:0d:03:b8:33:df:47:eb:b1:6b:
+ 8d:25:d9:9b:ce:81:d1:45:46:32:96:70:87:de:02:
+ 0e:49:43:85:b6:6c:73:bb:64:ea:61:41:ac:c9:d4:
+ 54:df:87:2f:c7:22:b2:26:cc:9f:59:54:68:9f:fc:
+ be:2a:2f:c4:55:1c:75:40:60:17:85:02:55:39:8b:
+ 7f:05
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 9C:5F:00:DF:AA:01:D7:30:2B:38:88:A2:B8:6D:4A:9C:F2:11:91:83
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 4b:36:a6:84:77:69:dd:3b:19:9f:67:23:08:6f:0e:61:c9:fd:
+ 84:dc:5f:d8:36:81:cd:d8:1b:41:2d:9f:60:dd:c7:1a:68:d9:
+ d1:6e:86:e1:88:23:cf:13:de:43:cf:e2:34:b3:04:9d:1f:29:
+ d5:bf:f8:5e:c8:d5:c1:bd:ee:92:6f:32:74:f2:91:82:2f:bd:
+ 82:42:7a:ad:2a:b7:20:7d:4d:bc:7a:55:12:c2:15:ea:bd:f7:
+ 6a:95:2e:6c:74:9f:cf:1c:b4:f2:c5:01:a3:85:d0:72:3e:ad:
+ 73:ab:0b:9b:75:0c:6d:45:b7:8e:94:ac:96:37:b5:a0:d0:8f:
+ 15:47:0e:e3:e8:83:dd:8f:fd:ef:41:01:77:cc:27:a9:62:85:
+ 33:f2:37:08:ef:71:cf:77:06:de:c8:19:1d:88:40:cf:7d:46:
+ 1d:ff:1e:c7:e1:ce:ff:23:db:c6:fa:8d:55:4e:a9:02:e7:47:
+ 11:46:3e:f4:fd:bd:7b:29:26:bb:a9:61:62:37:28:b6:2d:2a:
+ f6:10:86:64:c9:70:a7:d2:ad:b7:29:70:79:ea:3c:da:63:25:
+ 9f:fd:68:b7:30:ec:70:fb:75:8a:b7:6d:60:67:b2:1e:c8:b9:
+ e9:d8:a8:6f:02:8b:67:0d:4d:26:57:71:da:20:fc:c1:4a:50:
+ 8d:b1:28:ba
+SHA1 Fingerprint=92:5A:8F:8D:2C:6D:04:E0:66:5F:59:6A:FF:22:D8:63:E8:25:6F:3F
diff --git a/apex/ca-certificates/files/1ae85e5e.0 b/apex/ca-certificates/files/1ae85e5e.0
new file mode 100644
index 0000000..4ecb118
--- /dev/null
+++ b/apex/ca-certificates/files/1ae85e5e.0
@@ -0,0 +1,51 @@
+-----BEGIN CERTIFICATE-----
+MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD
+VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf
+BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3
+YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x
+NzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYDVQQGEwJVUzERMA8G
+A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0
+d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF
+Q0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqG
+SM49AwEHA0IABH77bOYj43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoN
+FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w
+DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw
+CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh
+DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 0d:6a:5f:08:3f:28:5c:3e:51:95:df:5d
+ Signature Algorithm: ecdsa-with-SHA256
+ Issuer: C=US, ST=Illinois, L=Chicago, O=Trustwave Holdings, Inc., CN=Trustwave Global ECC P256 Certification Authority
+ Validity
+ Not Before: Aug 23 19:35:10 2017 GMT
+ Not After : Aug 23 19:35:10 2042 GMT
+ Subject: C=US, ST=Illinois, L=Chicago, O=Trustwave Holdings, Inc., CN=Trustwave Global ECC P256 Certification Authority
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (256 bit)
+ pub:
+ 04:7e:fb:6c:e6:23:e3:73:32:08:ca:60:e6:53:9c:
+ ba:74:8d:18:b0:78:90:52:80:dd:38:c0:4a:1d:d1:
+ a8:cc:93:a4:97:06:38:ca:0d:15:62:c6:8e:01:2a:
+ 65:9d:aa:df:34:91:2e:81:c1:e4:33:92:31:c4:fd:
+ 09:3a:a6:3f:ad
+ ASN1 OID: prime256v1
+ NIST CURVE: P-256
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ A3:41:06:AC:90:6D:D1:4A:EB:75:A5:4A:10:99:B3:B1:A1:8B:4A:F7
+ Signature Algorithm: ecdsa-with-SHA256
+ Signature Value:
+ 30:44:02:20:07:e6:54:da:0e:a0:5a:b2:ae:11:9f:87:c5:b6:
+ ff:69:de:25:be:f8:a0:b7:08:f3:44:ce:2a:df:08:21:0c:37:
+ 02:20:2d:26:03:a0:05:bd:6b:d1:f6:5c:f8:65:cc:86:6d:b3:
+ 9c:34:48:63:84:09:c5:8d:77:1a:e2:cc:9c:e1:74:7b
+SHA1 Fingerprint=B4:90:82:DD:45:0C:BE:8B:5B:B1:66:D3:E2:A4:08:26:CD:ED:42:CF
diff --git a/apex/ca-certificates/files/1b0f7e5c.0 b/apex/ca-certificates/files/1b0f7e5c.0
new file mode 100644
index 0000000..188e578
--- /dev/null
+++ b/apex/ca-certificates/files/1b0f7e5c.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA
+MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD
+VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy
+MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt
+c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ
+OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG
+vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud
+316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo
+0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE
+y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF
+zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE
++cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN
+I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs
+x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa
+ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC
+4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
+HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4
+7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg
+JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti
+2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk
+pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF
+FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt
+rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk
+ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5
+u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP
+4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6
+N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3
+vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 11:d2:bb:b9:d7:23:18:9e:40:5f:0a:9d:2d:d0:df:25:67:d1
+ Signature Algorithm: sha384WithRSAEncryption
+ Issuer: C=BE, O=GlobalSign nv-sa, CN=GlobalSign Root R46
+ Validity
+ Not Before: Mar 20 00:00:00 2019 GMT
+ Not After : Mar 20 00:00:00 2046 GMT
+ Subject: C=BE, O=GlobalSign nv-sa, CN=GlobalSign Root R46
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:ac:ac:74:32:e8:b3:65:e5:ba:ed:43:26:1d:a6:
+ 89:0d:45:ba:29:88:b2:a4:1d:63:dd:d3:c1:2c:09:
+ 57:89:39:a1:55:e9:67:34:77:0c:6e:e4:55:1d:52:
+ 25:d2:13:6b:5e:e1:1d:a9:b7:7d:89:32:5f:0d:9e:
+ 9f:2c:7a:63:60:40:1f:a6:b0:b6:78:8f:99:54:96:
+ 08:58:ae:e4:06:bc:62:05:02:16:bf:af:a8:23:03:
+ b6:94:0f:bc:6e:6c:c2:cb:d5:a6:bb:0c:e9:f6:c1:
+ 02:fb:21:de:66:dd:17:ab:74:42:ef:f0:74:2f:25:
+ f4:ea:6b:55:5b:90:db:9d:df:5e:87:0a:40:fb:ad:
+ 19:6b:fb:f7:ca:60:88:de:da:c1:8f:d6:ae:d5:7f:
+ d4:3c:83:ee:d7:16:4c:83:45:33:6b:27:d0:86:d0:
+ 1c:2d:6b:f3:ab:7d:f1:85:a9:f5:28:d2:ad:ef:f3:
+ 84:4b:1c:87:fc:13:a3:3a:72:a2:5a:11:2b:d6:27:
+ 71:27:ed:81:2d:6d:66:81:92:87:b4:1b:58:7a:cc:
+ 3f:0a:fa:46:4f:4d:78:5c:f8:2b:48:e3:04:84:cb:
+ 5d:f6:b4:6a:b3:65:fc:42:9e:51:26:23:20:cb:3d:
+ 14:f9:81:ed:65:16:00:4f:1a:64:97:66:08:cf:8c:
+ 7b:e3:2b:c0:9d:f9:14:f2:1b:f1:56:6a:16:bf:2c:
+ 85:85:cd:78:38:9a:eb:42:6a:02:34:18:83:17:4e:
+ 94:56:f8:b6:82:b5:f3:96:dd:3d:f3:be:7f:20:77:
+ 3e:7b:19:23:6b:2c:d4:72:73:43:57:7d:e0:f8:d7:
+ 69:4f:17:36:04:f9:c0:90:60:37:45:de:e6:0c:d8:
+ 74:8d:ae:9c:a2:6d:74:5d:42:be:06:f5:d9:64:6e:
+ 02:10:ac:89:b0:4c:3b:07:4d:40:7e:24:c5:8a:98:
+ 82:79:8e:a4:a7:82:20:8d:23:fa:27:71:c9:df:c6:
+ 41:74:a0:4d:f6:91:16:dc:46:8c:5f:29:63:31:59:
+ 71:0c:d8:6f:c2:b6:32:7d:fb:e6:5d:53:a6:7e:15:
+ fc:bb:75:7c:5d:ec:f8:f6:17:1c:ec:c7:6b:19:cb:
+ f3:7b:f0:2b:07:a5:d9:6c:79:54:76:6c:9d:1c:a6:
+ 6e:0e:e9:79:0c:a8:23:6a:a3:df:1b:30:31:9f:b1:
+ 54:7b:fe:6a:cb:66:aa:dc:65:d0:a2:9e:4a:9a:07:
+ 21:6b:81:8f:db:c4:59:fa:de:22:c0:04:9c:e3:aa:
+ 5b:36:93:e8:3d:bd:7a:a1:9d:0b:76:b1:0b:c7:9d:
+ fd:cf:98:a8:06:c2:f8:2a:a3:a1:83:a0:b7:25:72:
+ a5:02:e3
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 03:5C:AB:73:81:87:A8:CC:B0:A6:D5:94:E2:36:96:49:FF:05:99:2C
+ Signature Algorithm: sha384WithRSAEncryption
+ Signature Value:
+ 7c:78:ec:f6:02:2c:bb:5b:7e:92:2b:5d:39:dc:be:d8:1d:a2:
+ 42:33:4d:f9:ef:a4:2a:3b:44:69:1e:ac:d9:45:a3:4e:3c:a7:
+ d8:24:51:b2:54:1c:93:4e:c4:ef:7b:93:85:60:26:ea:09:48:
+ e0:f5:bb:c7:e9:68:d2:bb:6a:31:71:cc:79:ae:11:a8:f0:99:
+ fd:e5:1f:bc:2f:a8:cc:57:eb:76:c4:21:a6:47:53:55:4d:68:
+ bf:05:a4:ee:d7:26:ab:62:da:43:37:4b:e2:c6:b5:e5:b2:83:
+ 19:3a:c7:d3:db:4d:9e:08:7a:f3:ee:cf:3e:62:fb:ac:e8:60:
+ cc:d1:c7:a1:5c:83:45:c4:45:cc:f3:17:6b:14:c9:04:02:3e:
+ d2:24:a6:79:e9:1e:ce:a2:e7:c1:59:15:9f:1d:e2:4b:9a:3e:
+ 9f:76:08:2d:6b:d8:ba:57:14:da:83:ea:fe:8c:55:e9:d0:4e:
+ a9:cc:77:31:b1:44:11:7a:5c:b1:3e:d3:14:45:15:18:62:24:
+ 13:d2:cb:4d:ce:5c:83:c1:36:f2:10:b5:0e:88:6d:b8:e1:56:
+ 9f:89:de:96:66:39:47:64:2c:6e:4d:ae:62:7b:bf:60:74:19:
+ b8:56:ac:92:ac:16:32:ed:ad:68:55:fe:98:ba:d3:34:de:f4:
+ c9:61:c3:0e:86:f6:4b:84:60:ee:0d:7b:b5:32:58:79:91:55:
+ 2c:81:43:b3:74:1f:7a:aa:25:9e:1d:d7:a1:8b:b9:cd:42:2e:
+ 04:a4:66:83:4d:89:35:b6:6c:a8:36:4a:79:21:78:22:d0:42:
+ bc:d1:40:31:90:a1:be:04:cf:ca:67:ed:f5:f0:80:d3:60:c9:
+ 83:2a:22:05:d0:07:3b:52:bf:0c:9e:aa:2b:f9:bb:e6:1f:8f:
+ 25:ba:85:8d:17:1e:02:fe:5d:50:04:57:cf:fe:2d:bc:ef:5c:
+ c0:1a:ab:b6:9f:24:c6:df:73:68:48:90:2c:14:f4:3f:52:1a:
+ e4:d2:cb:14:c3:61:69:cf:e2:f9:18:c5:ba:33:9f:14:a3:04:
+ 5d:b9:71:f7:b5:94:d8:f6:33:c1:5a:c1:34:8b:7c:9b:dd:93:
+ 3a:e7:13:a2:70:61:9f:af:8f:eb:d8:c5:75:f8:33:66:d4:74:
+ 67:3a:37:77:9c:e7:dd:a4:0f:76:43:66:8a:43:f2:9f:fb:0c:
+ 42:78:63:d1:e2:0f:6f:7b:d4:a1:3d:74:97:85:b7:48:39:41:
+ d6:20:fc:d0:3a:b3:fa:e8:6f:c4:8a:ba:71:37:be:8b:97:b1:
+ 78:31:4f:b3:e7:b6:03:13:ce:54:9d:ae:25:59:cc:7f:35:5f:
+ 08:f7:40:45:31:78:2a:7a
+SHA1 Fingerprint=53:A2:B0:4B:CA:6B:D6:45:E6:39:8A:8E:C4:0D:D2:BF:77:C3:A2:90
diff --git a/apex/ca-certificates/files/1df5a75f.0 b/apex/ca-certificates/files/1df5a75f.0
new file mode 100644
index 0000000..1724f20
--- /dev/null
+++ b/apex/ca-certificates/files/1df5a75f.0
@@ -0,0 +1,88 @@
+-----BEGIN CERTIFICATE-----
+MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF
+MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD
+bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha
+ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM
+HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03
+UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42
+tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R
+ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM
+lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp
+/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G
+A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G
+A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj
+dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy
+MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl
+cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js
+L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL
+BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni
+acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
+o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K
+zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8
+PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y
+Johw1+qRzT65ysCQblrGXnRl11z+o+I=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 623603 (0x983f3)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=DE, O=D-Trust GmbH, CN=D-TRUST Root Class 3 CA 2 2009
+ Validity
+ Not Before: Nov 5 08:35:58 2009 GMT
+ Not After : Nov 5 08:35:58 2029 GMT
+ Subject: C=DE, O=D-Trust GmbH, CN=D-TRUST Root Class 3 CA 2 2009
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:d3:b2:4a:cf:7a:47:ef:75:9b:23:fa:3a:2f:d6:
+ 50:45:89:35:3a:c6:6b:db:fe:db:00:68:a8:e0:03:
+ 11:1d:37:50:08:9f:4d:4a:68:94:35:b3:53:d1:94:
+ 63:a7:20:56:af:de:51:78:ec:2a:3d:f3:48:48:50:
+ 3e:0a:df:46:55:8b:27:6d:c3:10:4d:0d:91:52:43:
+ d8:87:e0:5d:4e:36:b5:21:ca:5f:39:40:04:5f:5b:
+ 7e:cc:a3:c6:2b:a9:40:1e:d9:36:84:d6:48:f3:92:
+ 1e:34:46:20:24:c1:a4:51:8e:4a:1a:ef:50:3f:69:
+ 5d:19:7f:45:c3:c7:01:8f:51:c9:23:e8:72:ae:b4:
+ bc:56:09:7f:12:cb:1c:b1:af:29:90:0a:c9:55:cc:
+ 0f:d3:b4:1a:ed:47:35:5a:4a:ed:9c:73:04:21:d0:
+ aa:bd:0c:13:b5:00:ca:26:6c:c4:6b:0c:94:5a:95:
+ 94:da:50:9a:f1:ff:a5:2b:66:31:a4:c9:38:a0:df:
+ 1d:1f:b8:09:2e:f3:a7:e8:67:52:ab:95:1f:e0:46:
+ 3e:d8:a4:c3:ca:5a:c5:31:80:e8:48:9a:9f:94:69:
+ fe:19:dd:d8:73:7c:81:ca:96:de:8e:ed:b3:32:05:
+ 65:84:34:e6:e6:fd:57:10:b5:5f:76:bf:2f:b0:10:
+ 0d:c5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ FD:DA:14:C4:9F:30:DE:21:BD:1E:42:39:FC:AB:63:23:49:E0:F1:84
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 CRL Distribution Points:
+ Full Name:
+ URI:ldap://directory.d-trust.net/CN=D-TRUST%20Root%20Class%203%20CA%202%202009,O=D-Trust%20GmbH,C=DE?certificaterevocationlist
+ Full Name:
+ URI:http://www.d-trust.net/crl/d-trust_root_class_3_ca_2_2009.crl
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 7f:97:db:30:c8:df:a4:9c:7d:21:7a:80:70:ce:14:12:69:88:
+ 14:95:60:44:01:ac:b2:e9:30:4f:9b:50:c2:66:d8:7e:8d:30:
+ b5:70:31:e9:e2:69:c7:f3:70:db:20:15:86:d0:0d:f0:be:ac:
+ 01:75:84:ce:7e:9f:4d:bf:b7:60:3b:9c:f3:ca:1d:e2:5e:68:
+ d8:a3:9d:97:e5:40:60:d2:36:21:fe:d0:b4:b8:17:da:74:a3:
+ 7f:d4:df:b0:98:02:ac:6f:6b:6b:2c:25:24:72:a1:65:ee:25:
+ 5a:e5:e6:32:e7:f2:df:ab:49:fa:f3:90:69:23:db:04:d9:e7:
+ 5c:58:fc:65:d4:97:be:cc:fc:2e:0a:cc:25:2a:35:04:f8:60:
+ 91:15:75:3d:41:ff:23:1f:19:c8:6c:eb:82:53:04:a6:e4:4c:
+ 22:4d:8d:8c:ba:ce:5b:73:ec:64:54:50:6d:d1:9c:55:fb:69:
+ c3:36:c3:8c:bc:3c:85:a6:6b:0a:26:0d:e0:93:98:60:ae:7e:
+ c6:24:97:8a:61:5f:91:8e:66:92:09:87:36:cd:8b:9b:2d:3e:
+ f6:51:d4:50:d4:59:28:bd:83:f2:cc:28:7b:53:86:6d:d8:26:
+ 88:70:d7:ea:91:cd:3e:b9:ca:c0:90:6e:5a:c6:5e:74:65:d7:
+ 5c:fe:a3:e2
+SHA1 Fingerprint=58:E8:AB:B0:36:15:33:FB:80:F7:9B:1B:6D:29:D3:FF:8D:5F:00:F0
diff --git a/apex/ca-certificates/files/1e1eab7c.0 b/apex/ca-certificates/files/1e1eab7c.0
new file mode 100644
index 0000000..ba034a9
--- /dev/null
+++ b/apex/ca-certificates/files/1e1eab7c.0
@@ -0,0 +1,81 @@
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx
+KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd
+BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl
+YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1
+OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy
+aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50
+ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN
+8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/
+RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4
+hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5
+ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM
+EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj
+QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1
+A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy
+WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ
+1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30
+6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT
+91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml
+e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p
+TpPDpFQUWw==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=DE, O=T-Systems Enterprise Services GmbH, OU=T-Systems Trust Center, CN=T-TeleSec GlobalRoot Class 3
+ Validity
+ Not Before: Oct 1 10:29:56 2008 GMT
+ Not After : Oct 1 23:59:59 2033 GMT
+ Subject: C=DE, O=T-Systems Enterprise Services GmbH, OU=T-Systems Trust Center, CN=T-TeleSec GlobalRoot Class 3
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:bd:75:93:f0:62:22:6f:24:ae:e0:7a:76:ac:7d:
+ bd:d9:24:d5:b8:b7:fc:cd:f0:42:e0:eb:78:88:56:
+ 5e:9b:9a:54:1d:4d:0c:8a:f6:d3:cf:70:f4:52:b5:
+ d8:93:04:e3:46:86:71:41:4a:2b:f0:2a:2c:55:03:
+ d6:48:c3:e0:39:38:ed:f2:5c:3c:3f:44:bc:93:3d:
+ 61:ab:4e:cd:0d:be:f0:20:27:58:0e:44:7f:04:1a:
+ 87:a5:d7:96:14:36:90:d0:49:7b:a1:75:fb:1a:6b:
+ 73:b1:f8:ce:a9:09:2c:f2:53:d5:c3:14:44:b8:86:
+ a5:f6:8b:2b:39:da:a3:33:54:d9:fa:72:1a:f7:22:
+ 15:1c:88:91:6b:7f:66:e5:c3:6a:80:b0:24:f3:df:
+ 86:45:88:fd:19:7f:75:87:1f:1f:b1:1b:0a:73:24:
+ 5b:b9:65:e0:2c:54:c8:60:d3:66:17:3f:e1:cc:54:
+ 33:73:91:02:3a:a6:7f:7b:76:39:a2:1f:96:b6:38:
+ ae:b5:c8:93:74:1d:9e:b9:b4:e5:60:9d:2f:56:d1:
+ e0:eb:5e:5b:4c:12:70:0c:6c:44:20:ab:11:d8:f4:
+ 19:f6:d2:9c:52:37:e7:fa:b6:c2:31:3b:4a:d4:14:
+ 99:ad:c7:1a:f5:5d:5f:fa:07:b8:7c:0d:1f:d6:83:
+ 1e:b3
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ B5:03:F7:76:3B:61:82:6A:12:AA:18:53:EB:03:21:94:BF:FE:CE:CA
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 56:3d:ef:94:d5:bd:da:73:b2:58:be:ae:90:ad:98:27:97:fe:
+ 01:b1:b0:52:00:b8:4d:e4:1b:21:74:1b:7e:c0:ee:5e:69:2a:
+ 25:af:5c:d6:1d:da:d2:79:c9:f3:97:29:e0:86:87:de:04:59:
+ 0f:f1:59:d4:64:85:4b:99:af:25:04:1e:c9:46:a9:97:de:82:
+ b2:1b:70:9f:9c:f6:af:71:31:dd:7b:05:a5:2c:d3:b9:ca:47:
+ f6:ca:f2:f6:e7:ad:b9:48:3f:bc:16:b7:c1:6d:f4:ea:09:af:
+ ec:f3:b5:e7:05:9e:a6:1e:8a:53:51:d6:93:81:cc:74:93:f6:
+ b9:da:a6:25:05:74:79:5a:7e:40:3e:82:4b:26:11:30:6e:e1:
+ 3f:41:c7:47:00:35:d5:f5:d3:f7:54:3e:81:3d:da:49:6a:9a:
+ b3:ef:10:3d:e6:eb:6f:d1:c8:22:47:cb:cc:cf:01:31:92:d9:
+ 18:e3:22:be:09:1e:1a:3e:5a:b2:e4:6b:0c:54:7a:7d:43:4e:
+ b8:89:a5:7b:d7:a2:3d:96:86:cc:f2:26:34:2d:6a:92:9d:9a:
+ 1a:d0:30:e2:5d:4e:04:b0:5f:8b:20:7e:77:c1:3d:95:82:d1:
+ 46:9a:3b:3c:78:b8:6f:a1:d0:0d:64:a2:78:1e:29:4e:93:c3:
+ a4:54:14:5b
+SHA1 Fingerprint=55:A6:72:3E:CB:F2:EC:CD:C3:23:74:70:19:9D:2A:BE:11:E3:81:D1
diff --git a/apex/ca-certificates/files/1e8e7201.0 b/apex/ca-certificates/files/1e8e7201.0
new file mode 100644
index 0000000..dec7cc6
--- /dev/null
+++ b/apex/ca-certificates/files/1e8e7201.0
@@ -0,0 +1,80 @@
+-----BEGIN CERTIFICATE-----
+MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
+A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
+Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
+MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
+A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
+RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
+gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
+KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
+QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
+XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
+DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
+LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
+RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
+jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
+6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
+mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
+Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
+WD9f
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 04:00:00:00:00:01:21:58:53:08:a2
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: OU=GlobalSign Root CA - R3, O=GlobalSign, CN=GlobalSign
+ Validity
+ Not Before: Mar 18 10:00:00 2009 GMT
+ Not After : Mar 18 10:00:00 2029 GMT
+ Subject: OU=GlobalSign Root CA - R3, O=GlobalSign, CN=GlobalSign
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:cc:25:76:90:79:06:78:22:16:f5:c0:83:b6:84:
+ ca:28:9e:fd:05:76:11:c5:ad:88:72:fc:46:02:43:
+ c7:b2:8a:9d:04:5f:24:cb:2e:4b:e1:60:82:46:e1:
+ 52:ab:0c:81:47:70:6c:dd:64:d1:eb:f5:2c:a3:0f:
+ 82:3d:0c:2b:ae:97:d7:b6:14:86:10:79:bb:3b:13:
+ 80:77:8c:08:e1:49:d2:6a:62:2f:1f:5e:fa:96:68:
+ df:89:27:95:38:9f:06:d7:3e:c9:cb:26:59:0d:73:
+ de:b0:c8:e9:26:0e:83:15:c6:ef:5b:8b:d2:04:60:
+ ca:49:a6:28:f6:69:3b:f6:cb:c8:28:91:e5:9d:8a:
+ 61:57:37:ac:74:14:dc:74:e0:3a:ee:72:2f:2e:9c:
+ fb:d0:bb:bf:f5:3d:00:e1:06:33:e8:82:2b:ae:53:
+ a6:3a:16:73:8c:dd:41:0e:20:3a:c0:b4:a7:a1:e9:
+ b2:4f:90:2e:32:60:e9:57:cb:b9:04:92:68:68:e5:
+ 38:26:60:75:b2:9f:77:ff:91:14:ef:ae:20:49:fc:
+ ad:40:15:48:d1:02:31:61:19:5e:b8:97:ef:ad:77:
+ b7:64:9a:7a:bf:5f:c1:13:ef:9b:62:fb:0d:6c:e0:
+ 54:69:16:a9:03:da:6e:e9:83:93:71:76:c6:69:85:
+ 82:17
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 8F:F0:4B:7F:A8:2E:45:24:AE:4D:50:FA:63:9A:8B:DE:E2:DD:1B:BC
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 4b:40:db:c0:50:aa:fe:c8:0c:ef:f7:96:54:45:49:bb:96:00:
+ 09:41:ac:b3:13:86:86:28:07:33:ca:6b:e6:74:b9:ba:00:2d:
+ ae:a4:0a:d3:f5:f1:f1:0f:8a:bf:73:67:4a:83:c7:44:7b:78:
+ e0:af:6e:6c:6f:03:29:8e:33:39:45:c3:8e:e4:b9:57:6c:aa:
+ fc:12:96:ec:53:c6:2d:e4:24:6c:b9:94:63:fb:dc:53:68:67:
+ 56:3e:83:b8:cf:35:21:c3:c9:68:fe:ce:da:c2:53:aa:cc:90:
+ 8a:e9:f0:5d:46:8c:95:dd:7a:58:28:1a:2f:1d:de:cd:00:37:
+ 41:8f:ed:44:6d:d7:53:28:97:7e:f3:67:04:1e:15:d7:8a:96:
+ b4:d3:de:4c:27:a4:4c:1b:73:73:76:f4:17:99:c2:1f:7a:0e:
+ e3:2d:08:ad:0a:1c:2c:ff:3c:ab:55:0e:0f:91:7e:36:eb:c3:
+ 57:49:be:e1:2e:2d:7c:60:8b:c3:41:51:13:23:9d:ce:f7:32:
+ 6b:94:01:a8:99:e7:2c:33:1f:3a:3b:25:d2:86:40:ce:3b:2c:
+ 86:78:c9:61:2f:14:ba:ee:db:55:6f:df:84:ee:05:09:4d:bd:
+ 28:d8:72:ce:d3:62:50:65:1e:eb:92:97:83:31:d9:b3:b5:ca:
+ 47:58:3f:5f
+SHA1 Fingerprint=D6:9B:56:11:48:F0:1C:77:C5:45:78:C1:09:26:DF:5B:85:69:76:AD
diff --git a/apex/ca-certificates/files/1ec40989.0 b/apex/ca-certificates/files/1ec40989.0
new file mode 100644
index 0000000..7585d96
--- /dev/null
+++ b/apex/ca-certificates/files/1ec40989.0
@@ -0,0 +1,124 @@
+-----BEGIN CERTIFICATE-----
+MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkG
+A1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkw
+FwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYx
+MDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9u
+aXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMIICIjANBgkq
+hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWiD59b
+RatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9Z
+YybNpyrOVPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3
+QWPKzv9pj2gOlTblzLmMCcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPw
+yJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCmfecqQjuCgGOlYx8ZzHyyZqjC0203b+J+
+BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKAA1GqtH6qRNdDYfOiaxaJ
+SaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9ORJitHHmkH
+r96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj0
+4KlGDfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9Me
+dKZssCz3AwyIDMvUclOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIw
+q7ejMZdnrY8XD2zHc+0klGvIg5rQmjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2
+nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1UdIwQYMBaAFNwu
+H9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA
+VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJC
+XtzoRlgHNQIw4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd
+6IwPS3BD0IL/qMy/pJTAvoe9iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf
++I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS8cE54+X1+NZK3TTN+2/BT+MAi1bi
+kvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2HcqtbepBEX4tdJP7
+wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxSvTOB
+TI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6C
+MUO+1918oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn
+4rnvyOL2NSl6dPrFf4IFYqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+I
+aFvowdlxfv1k7/9nR4hYJS8+hge9+6jlgqispdNpQ80xiEmEU5LAsTkbOYMBMMTy
+qfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 5a:4b:bd:5a:fb:4f:8a:5b:fa:65:e5
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=AT, O=e-commerce monitoring GmbH, CN=GLOBALTRUST 2020
+ Validity
+ Not Before: Feb 10 00:00:00 2020 GMT
+ Not After : Jun 10 00:00:00 2040 GMT
+ Subject: C=AT, O=e-commerce monitoring GmbH, CN=GLOBALTRUST 2020
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:ae:2e:56:ad:1b:1c:ef:f6:95:8f:a0:77:1b:2b:
+ d3:63:8f:84:4d:45:a2:0f:9f:5b:45:ab:59:7b:51:
+ 34:f9:ec:8b:8a:78:c5:dd:6b:af:bd:c4:df:93:45:
+ 1e:bf:91:38:0b:ae:0e:16:e7:41:73:f8:db:bb:d1:
+ b8:51:e0:cb:83:3b:73:38:6e:77:8a:0f:59:63:26:
+ cd:a7:2a:ce:54:fb:b8:e2:c0:7c:47:ce:60:7c:3f:
+ b2:73:f2:c0:19:b6:8a:92:87:35:0d:90:28:a2:e4:
+ 15:04:63:3e:ba:af:ee:7c:5e:cc:a6:8b:50:b2:38:
+ f7:41:63:ca:ce:ff:69:8f:68:0e:95:36:e5:cc:b9:
+ 8c:09:ca:4b:dd:31:90:96:c8:cc:1f:fd:56:96:34:
+ db:8e:1c:ea:2c:be:85:2e:63:dd:aa:a9:95:d3:fd:
+ 29:95:13:f0:c8:98:93:d9:2d:16:47:90:11:83:a2:
+ 3a:22:a2:28:57:a2:eb:fe:c0:8c:28:a0:a6:7d:e7:
+ 2a:42:3b:82:80:63:a5:63:1f:19:cc:7c:b2:66:a8:
+ c2:d3:6d:37:6f:e2:7e:06:51:d9:45:84:1f:12:ce:
+ 24:52:64:85:0b:48:80:4e:87:b1:22:22:30:aa:eb:
+ ae:be:e0:02:e0:40:e8:b0:42:80:03:51:aa:b4:7e:
+ aa:44:d7:43:61:f3:a2:6b:16:89:49:a4:a3:a4:2b:
+ 8a:02:c4:78:f4:68:8a:c1:e4:7a:36:b1:6f:1b:96:
+ 1b:77:49:8d:d4:c9:06:72:8f:cf:53:e3:dc:17:85:
+ 20:4a:dc:98:27:d3:91:26:2b:47:1e:69:07:af:de:
+ a2:e4:e4:d4:6b:0b:b3:5e:7c:d4:24:80:47:29:69:
+ 3b:6e:e8:ac:fd:40:eb:d8:ed:71:71:2b:f2:e8:58:
+ 1d:eb:41:97:22:c5:1f:d4:39:d0:27:8f:87:e3:18:
+ f4:e0:a9:46:0d:f5:74:3a:82:2e:d0:6e:2c:91:a3:
+ 31:5c:3b:46:ea:7b:04:10:56:5e:80:1d:f5:a5:65:
+ e8:82:fc:e2:07:8c:62:45:f5:20:de:46:70:86:a1:
+ bc:93:d3:1e:74:a6:6c:b0:2c:f7:03:0c:88:0c:cb:
+ d4:72:53:86:bc:60:46:f3:98:6a:c2:f1:bf:43:f9:
+ 70:20:77:ca:37:41:79:55:52:63:8d:5b:12:9f:c5:
+ 68:c4:88:9d:ac:f2:30:ab:b7:a3:31:97:67:ad:8f:
+ 17:0f:6c:c7:73:ed:24:94:6b:c8:83:9a:d0:9a:37:
+ 49:04:ab:b1:16:c8:6c:49:49:2d:ab:a1:d0:8c:92:
+ f2:41:4a:79:21:25:db:63:d7:b6:9c:a7:7e:42:69:
+ fb:3a:63
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ DC:2E:1F:D1:61:37:79:E4:AB:D5:D5:B3:12:71:68:3D:6A:68:9C:22
+ X509v3 Authority Key Identifier:
+ DC:2E:1F:D1:61:37:79:E4:AB:D5:D5:B3:12:71:68:3D:6A:68:9C:22
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 91:f0:42:02:68:40:ee:c3:68:c0:54:2f:df:ec:62:c3:c3:9e:
+ 8a:a0:31:28:aa:83:8e:a4:56:96:12:10:86:56:ba:97:72:d2:
+ 54:30:7c:ad:19:d5:1d:68:6f:fb:14:42:d8:8d:0e:f3:b5:d1:
+ a5:e3:02:42:5e:dc:e8:46:58:07:35:02:30:e0:bc:74:4a:c1:
+ 43:2a:ff:db:1a:d0:b0:af:6c:c3:fd:cb:b3:f5:7f:6d:03:2e:
+ 59:56:9d:2d:2d:35:8c:b2:d6:43:17:2c:92:0a:cb:5d:e8:8c:
+ 0f:4b:70:43:d0:82:ff:a8:cc:bf:a4:94:c0:be:87:bd:8a:e3:
+ 93:7b:c6:8f:9b:16:9d:27:65:bc:7a:c5:42:82:6c:5c:07:d0:
+ a9:c1:88:60:44:e9:98:85:16:5f:f8:8f:ca:01:10:ce:25:c3:
+ f9:60:1b:a0:c5:97:c3:d3:2c:88:31:a2:bd:30:ec:d0:d0:c0:
+ 12:f1:c1:39:e3:e5:f5:f8:d6:4a:dd:34:cd:fb:6f:c1:4f:e3:
+ 00:8b:56:e2:92:f7:28:b2:42:77:72:23:67:c7:3f:11:15:b2:
+ c4:03:05:be:bb:11:7b:0a:bf:a8:6e:e7:ff:58:43:cf:9b:67:
+ a0:80:07:b6:1d:ca:ad:6d:ea:41:11:7e:2d:74:93:fb:c2:bc:
+ be:51:44:c5:ef:68:25:27:80:e3:c8:a0:d4:12:ec:d9:a5:37:
+ 1d:37:7c:b4:91:ca:da:d4:b1:96:81:ef:68:5c:76:10:49:af:
+ 7e:a5:37:80:b1:1c:52:bd:33:81:4c:8f:f9:dd:65:d9:14:cd:
+ 8a:25:58:f4:e2:c5:83:a5:09:90:d4:6c:14:63:b5:40:df:eb:
+ c0:fc:c4:58:7e:0d:14:16:87:54:27:6e:56:e4:70:84:b8:6c:
+ 32:12:7e:82:31:43:be:d7:dd:7c:a1:ad:ae:d6:ab:20:12:ef:
+ 0a:c3:10:8c:49:96:35:dc:0b:75:5e:b1:4f:d5:4f:34:0e:11:
+ 20:07:75:43:45:e9:a3:11:da:ac:a3:99:c2:b6:79:27:e2:b9:
+ ef:c8:e2:f6:35:29:7a:74:fa:c5:7f:82:05:62:a6:0a:ea:68:
+ b2:79:47:06:6e:f2:57:a8:15:33:c6:f7:78:4a:3d:42:7b:6b:
+ 7e:fe:f7:46:ea:d1:eb:8e:ef:88:68:5b:e8:c1:d9:71:7e:fd:
+ 64:ef:ff:67:47:88:58:25:2f:3e:86:07:bd:fb:a8:e5:82:a8:
+ ac:a5:d3:69:43:cd:31:88:49:84:53:92:c0:b1:39:1b:39:83:
+ 01:30:c4:f2:a9:fa:d0:03:bd:72:37:60:56:1f:36:7c:bd:39:
+ 91:f5:6d:0d:bf:7b:d7:92
+SHA1 Fingerprint=D0:67:C1:13:51:01:0C:AA:D0:C7:6A:65:37:31:16:26:4F:53:71:A2
diff --git a/apex/ca-certificates/files/1f58a078.0 b/apex/ca-certificates/files/1f58a078.0
new file mode 100644
index 0000000..7f39ee9
--- /dev/null
+++ b/apex/ca-certificates/files/1f58a078.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL
+BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc
+BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00
+MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
+aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG
+SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf
+qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW
+n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym
+c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+
+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1
+o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j
+IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq
+IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz
+8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh
+vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l
+7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG
+cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
+BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD
+ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66
+AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC
+roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga
+W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n
+lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE
++V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV
+csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd
+dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg
+KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM
+HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4
+WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 44:57:34:24:5b:81:89:9b:35:f2:ce:b8:2b:3b:5b:a7:26:f0:75:28
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 2 G3
+ Validity
+ Not Before: Jan 12 18:59:32 2012 GMT
+ Not After : Jan 12 18:59:32 2042 GMT
+ Subject: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 2 G3
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:a1:ae:25:b2:01:18:dc:57:88:3f:46:eb:f9:af:
+ e2:eb:23:71:e2:9a:d1:61:66:21:5f:aa:af:27:51:
+ e5:6e:1b:16:d4:2d:7d:50:b0:53:77:bd:78:3a:60:
+ e2:64:02:9b:7c:86:9b:d6:1a:8e:ad:ff:1f:15:7f:
+ d5:95:1e:12:cb:e6:14:84:04:c1:df:36:b3:16:9f:
+ 8a:e3:c9:db:98:34:ce:d8:33:17:28:46:fc:a7:c9:
+ f0:d2:b4:d5:4d:09:72:49:f9:f2:87:e3:a9:da:7d:
+ a1:7d:6b:b2:3a:25:a9:6d:52:44:ac:f8:be:6e:fb:
+ dc:a6:73:91:90:61:a6:03:14:20:f2:e7:87:a3:88:
+ ad:ad:a0:8c:ff:a6:0b:25:52:25:e7:16:01:d5:cb:
+ b8:35:81:0c:a3:3b:f0:e1:e1:fc:5a:5d:ce:80:71:
+ 6d:f8:49:ab:3e:3b:ba:b8:d7:80:01:fb:a5:eb:5b:
+ b3:c5:5e:60:2a:31:a0:af:37:e8:20:3a:9f:a8:32:
+ 2c:0c:cc:09:1d:d3:9e:8e:5d:bc:4c:98:ee:c5:1a:
+ 68:7b:ec:53:a6:e9:14:35:a3:df:cd:80:9f:0c:48:
+ fb:1c:f4:f1:bf:4a:b8:fa:d5:8c:71:4a:c7:1f:ad:
+ fe:41:9a:b3:83:5d:f2:84:56:ef:a5:57:43:ce:29:
+ ad:8c:ab:55:bf:c4:fb:5b:01:dd:23:21:a1:58:00:
+ 8e:c3:d0:6a:13:ed:13:e3:12:2b:80:dc:67:e6:95:
+ b2:cd:1e:22:6e:2a:f8:41:d4:f2:ca:14:07:8d:8a:
+ 55:12:c6:69:f5:b8:86:68:2f:53:5e:b0:d2:aa:21:
+ c1:98:e6:30:e3:67:55:c7:9b:6e:ac:19:a8:55:a6:
+ 45:06:d0:23:3a:db:eb:65:5d:2a:11:11:f0:3b:4f:
+ ca:6d:f4:34:c4:71:e4:ff:00:5a:f6:5c:ae:23:60:
+ 85:73:f1:e4:10:b1:25:ae:d5:92:bb:13:c1:0c:e0:
+ 39:da:b4:39:57:b5:ab:35:aa:72:21:3b:83:35:e7:
+ 31:df:7a:21:6e:b8:32:08:7d:1d:32:91:15:4a:62:
+ 72:cf:e3:77:a1:bc:d5:11:1b:76:01:67:08:e0:41:
+ 0b:c3:eb:15:6e:f8:a4:19:d9:a2:ab:af:e2:27:52:
+ 56:2b:02:8a:2c:14:24:f9:bf:42:02:bf:26:c8:c6:
+ 8f:e0:6e:38:7d:53:2d:e5:ed:98:b3:95:63:68:7f:
+ f9:35:f4:df:88:c5:60:35:92:c0:7c:69:1c:61:95:
+ 16:d0:eb:de:0b:af:3e:04:10:45:65:58:50:38:af:
+ 48:f2:59:b6:16:f2:3c:0d:90:02:c6:70:2e:01:ad:
+ 3c:15:d7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ ED:E7:6F:76:5A:BF:60:EC:49:5B:C6:A5:77:BB:72:16:71:9B:C4:3D
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 91:df:80:3f:43:09:7e:71:c2:f7:eb:b3:88:8f:e1:51:b2:bc:
+ 3d:75:f9:28:5d:c8:bc:99:9b:7b:5d:aa:e5:ca:e1:0a:f7:e8:
+ b2:d3:9f:dd:67:31:7e:ba:01:aa:c7:6a:41:3b:90:d4:08:5c:
+ b2:60:6a:90:f0:c8:ce:03:62:f9:8b:ed:fb:6e:2a:dc:06:4d:
+ 3c:29:0f:89:16:8a:58:4c:48:0f:e8:84:61:ea:3c:72:a6:77:
+ e4:42:ae:88:a3:43:58:79:7e:ae:ca:a5:53:0d:a9:3d:70:bd:
+ 20:19:61:a4:6c:38:fc:43:32:e1:c1:47:ff:f8:ec:f1:11:22:
+ 32:96:9c:c2:f6:5b:69:96:7b:20:0c:43:41:9a:5b:f6:59:19:
+ 88:de:55:88:37:51:0b:78:5c:0a:1e:a3:42:fd:c7:9d:88:0f:
+ c0:f2:78:02:24:54:93:af:89:87:88:c9:4a:80:1d:ea:d0:6e:
+ 3e:61:2e:36:bb:35:0e:27:96:fd:66:34:3b:61:72:73:f1:16:
+ 5c:47:06:54:49:00:7a:58:12:b0:0a:ef:85:fd:b1:b8:33:75:
+ 6a:93:1c:12:e6:60:5e:6f:1d:7f:c9:1f:23:cb:84:61:9f:1e:
+ 82:44:f9:5f:ad:62:55:24:9a:52:98:ed:51:e7:a1:7e:97:3a:
+ e6:2f:1f:11:da:53:80:2c:85:9e:ab:35:10:db:22:5f:6a:c5:
+ 5e:97:53:f2:32:02:09:30:a3:58:f0:0d:01:d5:72:c6:b1:7c:
+ 69:7b:c3:f5:36:45:cc:61:6e:5e:4c:94:c5:5e:ae:e8:0e:5e:
+ 8b:bf:f7:cd:e0:ed:a1:0e:1b:33:ee:54:18:fe:0f:be:ef:7e:
+ 84:6b:43:e3:70:98:db:5d:75:b2:0d:59:07:85:15:23:39:d6:
+ f1:df:a9:26:0f:d6:48:c7:b3:a6:22:f5:33:37:5a:95:47:9f:
+ 7b:ba:18:15:6f:ff:d6:14:64:83:49:d2:0a:67:21:db:0f:35:
+ 63:60:28:22:e3:b1:95:83:cd:85:a6:dd:2f:0f:e7:67:52:6e:
+ bb:2f:85:7c:f5:4a:73:e7:c5:3e:c0:bd:21:12:05:3f:fc:b7:
+ 03:49:02:5b:c8:25:e6:e2:54:38:f5:79:87:8c:1d:53:b2:4e:
+ 85:7b:06:38:c7:2c:f8:f8:b0:72:8d:25:e5:77:52:f4:03:1c:
+ 48:a6:50:5f:88:20:30:6e:f2:82:43:ab:3d:97:84:e7:53:fb:
+ 21:c1:4f:0f:22:9a:86:b8:59:2a:f6:47:3d:19:88:2d:e8:85:
+ e1:9e:ec:85:08:6a:b1:6c:34:c9:1d:ec:48:2b:3b:78:ed:66:
+ c4:8e:79:69:83:de:7f:8c
+SHA1 Fingerprint=09:3C:61:F3:8B:8B:DC:7D:55:DF:75:38:02:05:00:E1:25:F5:C8:36
diff --git a/apex/ca-certificates/files/219d9499.0 b/apex/ca-certificates/files/219d9499.0
new file mode 100644
index 0000000..a0fc258
--- /dev/null
+++ b/apex/ca-certificates/files/219d9499.0
@@ -0,0 +1,84 @@
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
+MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
+YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
+MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
+ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
+MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
+ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
+PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
+wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
+EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
+avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
+sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
+/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
+IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
+ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
+OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
+TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
+HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
+dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
+ReYNnyicsbkqWletNw+vHX/bvZ8=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 0 (0x0)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority
+ Validity
+ Not Before: Jun 29 17:06:20 2004 GMT
+ Not After : Jun 29 17:06:20 2034 GMT
+ Subject: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:de:9d:d7:ea:57:18:49:a1:5b:eb:d7:5f:48:86:
+ ea:be:dd:ff:e4:ef:67:1c:f4:65:68:b3:57:71:a0:
+ 5e:77:bb:ed:9b:49:e9:70:80:3d:56:18:63:08:6f:
+ da:f2:cc:d0:3f:7f:02:54:22:54:10:d8:b2:81:d4:
+ c0:75:3d:4b:7f:c7:77:c3:3e:78:ab:1a:03:b5:20:
+ 6b:2f:6a:2b:b1:c5:88:7e:c4:bb:1e:b0:c1:d8:45:
+ 27:6f:aa:37:58:f7:87:26:d7:d8:2d:f6:a9:17:b7:
+ 1f:72:36:4e:a6:17:3f:65:98:92:db:2a:6e:5d:a2:
+ fe:88:e0:0b:de:7f:e5:8d:15:e1:eb:cb:3a:d5:e2:
+ 12:a2:13:2d:d8:8e:af:5f:12:3d:a0:08:05:08:b6:
+ 5c:a5:65:38:04:45:99:1e:a3:60:60:74:c5:41:a5:
+ 72:62:1b:62:c5:1f:6f:5f:1a:42:be:02:51:65:a8:
+ ae:23:18:6a:fc:78:03:a9:4d:7f:80:c3:fa:ab:5a:
+ fc:a1:40:a4:ca:19:16:fe:b2:c8:ef:5e:73:0d:ee:
+ 77:bd:9a:f6:79:98:bc:b1:07:67:a2:15:0d:dd:a0:
+ 58:c6:44:7b:0a:3e:62:28:5f:ba:41:07:53:58:cf:
+ 11:7e:38:74:c5:f8:ff:b5:69:90:8f:84:74:ea:97:
+ 1b:af
+ Exponent: 3 (0x3)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ D2:C4:B0:D2:91:D4:4C:11:71:B3:61:CB:3D:A1:FE:DD:A8:6A:D4:E3
+ X509v3 Authority Key Identifier:
+ keyid:D2:C4:B0:D2:91:D4:4C:11:71:B3:61:CB:3D:A1:FE:DD:A8:6A:D4:E3
+ DirName:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
+ serial:00
+ X509v3 Basic Constraints:
+ CA:TRUE
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 32:4b:f3:b2:ca:3e:91:fc:12:c6:a1:07:8c:8e:77:a0:33:06:
+ 14:5c:90:1e:18:f7:08:a6:3d:0a:19:f9:87:80:11:6e:69:e4:
+ 96:17:30:ff:34:91:63:72:38:ee:cc:1c:01:a3:1d:94:28:a4:
+ 31:f6:7a:c4:54:d7:f6:e5:31:58:03:a2:cc:ce:62:db:94:45:
+ 73:b5:bf:45:c9:24:b5:d5:82:02:ad:23:79:69:8d:b8:b6:4d:
+ ce:cf:4c:ca:33:23:e8:1c:88:aa:9d:8b:41:6e:16:c9:20:e5:
+ 89:9e:cd:3b:da:70:f7:7e:99:26:20:14:54:25:ab:6e:73:85:
+ e6:9b:21:9d:0a:6c:82:0e:a8:f8:c2:0c:fa:10:1e:6c:96:ef:
+ 87:0d:c4:0f:61:8b:ad:ee:83:2b:95:f8:8e:92:84:72:39:eb:
+ 20:ea:83:ed:83:cd:97:6e:08:bc:eb:4e:26:b6:73:2b:e4:d3:
+ f6:4c:fe:26:71:e2:61:11:74:4a:ff:57:1a:87:0f:75:48:2e:
+ cf:51:69:17:a0:02:12:61:95:d5:d1:40:b2:10:4c:ee:c4:ac:
+ 10:43:a6:a5:9e:0a:d5:95:62:9a:0d:cf:88:82:c5:32:0c:e4:
+ 2b:9f:45:e6:0d:9f:28:9c:b1:b9:2a:5a:57:ad:37:0f:af:1d:
+ 7f:db:bd:9f
+SHA1 Fingerprint=27:96:BA:E6:3F:18:01:E2:77:26:1B:A0:D7:77:70:02:8F:20:EE:E4
diff --git a/apex/ca-certificates/files/23f4c490.0 b/apex/ca-certificates/files/23f4c490.0
new file mode 100644
index 0000000..c5f3221
--- /dev/null
+++ b/apex/ca-certificates/files/23f4c490.0
@@ -0,0 +1,84 @@
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
+MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
+U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
+NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
+ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
+ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
+DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
+8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
+X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
+K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
+1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
+A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
+zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
+YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
+bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
+DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
+L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
+eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
+xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
+VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
+WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 0 (0x0)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority
+ Validity
+ Not Before: Jun 29 17:39:16 2004 GMT
+ Not After : Jun 29 17:39:16 2034 GMT
+ Subject: C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b7:32:c8:fe:e9:71:a6:04:85:ad:0c:11:64:df:
+ ce:4d:ef:c8:03:18:87:3f:a1:ab:fb:3c:a6:9f:f0:
+ c3:a1:da:d4:d8:6e:2b:53:90:fb:24:a4:3e:84:f0:
+ 9e:e8:5f:ec:e5:27:44:f5:28:a6:3f:7b:de:e0:2a:
+ f0:c8:af:53:2f:9e:ca:05:01:93:1e:8f:66:1c:39:
+ a7:4d:fa:5a:b6:73:04:25:66:eb:77:7f:e7:59:c6:
+ 4a:99:25:14:54:eb:26:c7:f3:7f:19:d5:30:70:8f:
+ af:b0:46:2a:ff:ad:eb:29:ed:d7:9f:aa:04:87:a3:
+ d4:f9:89:a5:34:5f:db:43:91:82:36:d9:66:3c:b1:
+ b8:b9:82:fd:9c:3a:3e:10:c8:3b:ef:06:65:66:7a:
+ 9b:19:18:3d:ff:71:51:3c:30:2e:5f:be:3d:77:73:
+ b2:5d:06:6c:c3:23:56:9a:2b:85:26:92:1c:a7:02:
+ b3:e4:3f:0d:af:08:79:82:b8:36:3d:ea:9c:d3:35:
+ b3:bc:69:ca:f5:cc:9d:e8:fd:64:8d:17:80:33:6e:
+ 5e:4a:5d:99:c9:1e:87:b4:9d:1a:c0:d5:6e:13:35:
+ 23:5e:df:9b:5f:3d:ef:d6:f7:76:c2:ea:3e:bb:78:
+ 0d:1c:42:67:6b:04:d8:f8:d6:da:6f:8b:f2:44:a0:
+ 01:ab
+ Exponent: 3 (0x3)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ BF:5F:B7:D1:CE:DD:1F:86:F4:5B:55:AC:DC:D7:10:C2:0E:A9:88:E7
+ X509v3 Authority Key Identifier:
+ keyid:BF:5F:B7:D1:CE:DD:1F:86:F4:5B:55:AC:DC:D7:10:C2:0E:A9:88:E7
+ DirName:/C=US/O=Starfield Technologies, Inc./OU=Starfield Class 2 Certification Authority
+ serial:00
+ X509v3 Basic Constraints:
+ CA:TRUE
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 05:9d:3f:88:9d:d1:c9:1a:55:a1:ac:69:f3:f3:59:da:9b:01:
+ 87:1a:4f:57:a9:a1:79:09:2a:db:f7:2f:b2:1e:cc:c7:5e:6a:
+ d8:83:87:a1:97:ef:49:35:3e:77:06:41:58:62:bf:8e:58:b8:
+ 0a:67:3f:ec:b3:dd:21:66:1f:c9:54:fa:72:cc:3d:4c:40:d8:
+ 81:af:77:9e:83:7a:bb:a2:c7:f5:34:17:8e:d9:11:40:f4:fc:
+ 2c:2a:4d:15:7f:a7:62:5d:2e:25:d3:00:0b:20:1a:1d:68:f9:
+ 17:b8:f4:bd:8b:ed:28:59:dd:4d:16:8b:17:83:c8:b2:65:c7:
+ 2d:7a:a5:aa:bc:53:86:6d:dd:57:a4:ca:f8:20:41:0b:68:f0:
+ f4:fb:74:be:56:5d:7a:79:f5:f9:1d:85:e3:2d:95:be:f5:71:
+ 90:43:cc:8d:1f:9a:00:0a:87:29:e9:55:22:58:00:23:ea:e3:
+ 12:43:29:5b:47:08:dd:8c:41:6a:65:06:a8:e5:21:aa:41:b4:
+ 95:21:95:b9:7d:d1:34:ab:13:d6:ad:bc:dc:e2:3d:39:cd:bd:
+ 3e:75:70:a1:18:59:03:c9:22:b4:8f:9c:d5:5e:2a:d7:a5:b6:
+ d4:0a:6d:f8:b7:40:11:46:9a:1f:79:0e:62:bf:0f:97:ec:e0:
+ 2f:1f:17:94
+SHA1 Fingerprint=AD:7E:1C:28:B0:64:EF:8F:60:03:40:20:14:C3:D0:E3:37:0E:B5:8A
diff --git a/apex/ca-certificates/files/252252d2.0 b/apex/ca-certificates/files/252252d2.0
new file mode 100644
index 0000000..1b9acdb
--- /dev/null
+++ b/apex/ca-certificates/files/252252d2.0
@@ -0,0 +1,54 @@
+-----BEGIN CERTIFICATE-----
+MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp
+Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2
+MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ
+bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG
+ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS
+7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp
+0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS
+B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49
+BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ
+LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4
+DXZDjC5Ty3zfDBeWUA==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 09:e0:93:65:ac:f7:d9:c8:b9:3e:1c:0b:04:2a:2e:f3
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=US, O=DigiCert, Inc., CN=DigiCert TLS ECC P384 Root G5
+ Validity
+ Not Before: Jan 15 00:00:00 2021 GMT
+ Not After : Jan 14 23:59:59 2046 GMT
+ Subject: C=US, O=DigiCert, Inc., CN=DigiCert TLS ECC P384 Root G5
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:c1:44:a1:cf:11:97:50:9a:de:23:82:35:07:cd:
+ d0:cb:18:9d:d2:f1:7f:77:35:4f:3b:dd:94:72:52:
+ ed:c2:3b:f8:ec:fa:7b:6b:58:20:ec:99:ae:c9:fc:
+ 68:b3:75:b9:db:09:ec:c8:13:f5:4e:c6:0a:1d:66:
+ 30:4c:bb:1f:47:0a:3c:61:10:42:29:7c:a5:08:0e:
+ e0:22:e9:d3:35:68:ce:9b:63:9f:84:b5:99:4d:58:
+ a0:8e:f5:54:e7:95:c9
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ C1:51:45:50:59:AB:3E:E7:2C:5A:FA:20:22:12:07:80:88:7C:11:6A
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:65:02:31:00:89:6a:8d:47:e7:ec:fc:6e:55:03:d9:67:6c:
+ 26:4e:83:c6:fd:c9:fb:2b:13:bc:b7:7a:8c:b4:65:d2:69:69:
+ 63:13:63:3b:26:50:2e:01:a1:79:06:91:9d:48:bf:c2:be:02:
+ 30:47:c3:15:7b:b1:a0:91:99:49:93:a8:3c:7c:e8:46:06:8b:
+ 2c:f2:31:00:94:9d:62:c8:89:bd:19:84:14:e9:a5:fb:01:b8:
+ 0d:76:43:8c:2e:53:cb:7c:df:0c:17:96:50
+SHA1 Fingerprint=17:F3:DE:5E:9F:0F:19:E9:8E:F6:1F:32:26:6E:20:C4:07:AE:30:EE
diff --git a/apex/ca-certificates/files/2add47b6.0 b/apex/ca-certificates/files/2add47b6.0
new file mode 100644
index 0000000..5c21ce7
--- /dev/null
+++ b/apex/ca-certificates/files/2add47b6.0
@@ -0,0 +1,54 @@
+-----BEGIN CERTIFICATE-----
+MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk
+MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH
+bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
+DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
+QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
+MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc
+8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke
+hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI
+KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg
+515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO
+xwy8p2Fp8fc74SrL+SvzZpA3
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 60:59:49:e0:26:2e:bb:55:f9:0a:77:8a:71:f9:4a:d8:6c
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: OU=GlobalSign ECC Root CA - R5, O=GlobalSign, CN=GlobalSign
+ Validity
+ Not Before: Nov 13 00:00:00 2012 GMT
+ Not After : Jan 19 03:14:07 2038 GMT
+ Subject: OU=GlobalSign ECC Root CA - R5, O=GlobalSign, CN=GlobalSign
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:47:45:0e:96:fb:7d:5d:bf:e9:39:d1:21:f8:9f:
+ 0b:b6:d5:7b:1e:92:3a:48:59:1c:f0:62:31:2d:c0:
+ 7a:28:fe:1a:a7:5c:b3:b6:cc:97:e7:45:d4:58:fa:
+ d1:77:6d:43:a2:c0:87:65:34:0a:1f:7a:dd:eb:3c:
+ 33:a1:c5:9d:4d:a4:6f:41:95:38:7f:c9:1e:84:eb:
+ d1:9e:49:92:87:94:87:0c:3a:85:4a:66:9f:9d:59:
+ 93:4d:97:61:06:86:4a
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 3D:E6:29:48:9B:EA:07:CA:21:44:4A:26:DE:6E:DE:D2:83:D0:9F:59
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:65:02:31:00:e5:69:12:c9:6e:db:c6:31:ba:09:41:e1:97:
+ f8:fb:fd:9a:e2:7d:12:c9:ed:7c:64:d3:cb:05:25:8b:56:d9:
+ a0:e7:5e:5d:4e:0b:83:9c:5b:76:29:a0:09:26:21:6a:62:02:
+ 30:71:d2:b5:8f:5c:ea:3b:e1:78:09:85:a8:75:92:3b:c8:5c:
+ fd:48:ef:0d:74:22:a8:08:e2:6e:c5:49:ce:c7:0c:bc:a7:61:
+ 69:f1:f7:3b:e1:2a:cb:f9:2b:f3:66:90:37
+SHA1 Fingerprint=1F:24:C6:30:CD:A4:18:EF:20:69:FF:AD:4F:DD:5F:46:3A:1B:69:AA
diff --git a/apex/ca-certificates/files/2d9dafe4.0 b/apex/ca-certificates/files/2d9dafe4.0
new file mode 100644
index 0000000..d6542df
--- /dev/null
+++ b/apex/ca-certificates/files/2d9dafe4.0
@@ -0,0 +1,120 @@
+-----BEGIN CERTIFICATE-----
+MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd
+MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg
+Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow
+TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw
+HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB
+BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y
+ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E
+N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9
+tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX
+0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c
+/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X
+KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY
+zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS
+O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D
+34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP
+K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3
+AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv
+Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj
+QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV
+cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS
+IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2
+HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa
+O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv
+033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u
+dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE
+kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41
+3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD
+u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq
+4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=NO, O=Buypass AS-983163327, CN=Buypass Class 3 Root CA
+ Validity
+ Not Before: Oct 26 08:28:58 2010 GMT
+ Not After : Oct 26 08:28:58 2040 GMT
+ Subject: C=NO, O=Buypass AS-983163327, CN=Buypass Class 3 Root CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:a5:da:0a:95:16:50:e3:95:f2:5e:9d:76:31:06:
+ 32:7a:9b:f1:10:76:b8:00:9a:b5:52:36:cd:24:47:
+ b0:9f:18:64:bc:9a:f6:fa:d5:79:d8:90:62:4c:22:
+ 2f:de:38:3d:d6:e0:a8:e9:1c:2c:db:78:11:e9:8e:
+ 68:51:15:72:c7:f3:33:87:e4:a0:5d:0b:5c:e0:57:
+ 07:2a:30:f5:cd:c4:37:77:28:4d:18:91:e6:bf:d5:
+ 52:fd:71:2d:70:3e:e7:c6:c4:8a:e3:f0:28:0b:f4:
+ 76:98:a1:8b:87:55:b2:3a:13:fc:b7:3e:27:37:8e:
+ 22:e3:a8:4f:2a:ef:60:bb:3d:b7:39:c3:0e:01:47:
+ 99:5d:12:4f:db:43:fa:57:a1:ed:f9:9d:be:11:47:
+ 26:5b:13:98:ab:5d:16:8a:b0:37:1c:57:9d:45:ff:
+ 88:96:36:bf:bb:ca:07:7b:6f:87:63:d7:d0:32:6a:
+ d6:5d:6c:0c:f1:b3:6e:39:e2:6b:31:2e:39:00:27:
+ 14:de:38:c0:ec:19:66:86:12:e8:9d:72:16:13:64:
+ 52:c7:a9:37:1c:fd:82:30:ed:84:18:1d:f4:ae:5c:
+ ff:70:13:00:eb:b1:f5:33:7a:4b:d6:55:f8:05:8d:
+ 4b:69:b0:f5:b3:28:36:5c:14:c4:51:73:4d:6b:0b:
+ f1:34:07:db:17:39:d7:dc:28:7b:6b:f5:9f:f3:2e:
+ c1:4f:17:2a:10:f3:cc:ca:e8:eb:fd:6b:ab:2e:9a:
+ 9f:2d:82:6e:04:d4:52:01:93:2d:3d:86:fc:7e:fc:
+ df:ef:42:1d:a6:6b:ef:b9:20:c6:f7:bd:a0:a7:95:
+ fd:a7:e6:89:24:d8:cc:8c:34:6c:e2:23:2f:d9:12:
+ 1a:21:b9:55:91:6f:0b:91:79:19:0c:ad:40:88:0b:
+ 70:e2:7a:d2:0e:d8:68:48:bb:82:13:39:10:58:e9:
+ d8:2a:07:c6:12:db:58:db:d2:3b:55:10:47:05:15:
+ 67:62:7e:18:63:a6:46:3f:09:0e:54:32:5e:bf:0d:
+ 62:7a:27:ef:80:e8:db:d9:4b:06:5a:37:5a:25:d0:
+ 08:12:77:d4:6f:09:50:97:3d:c8:1d:c3:df:8c:45:
+ 30:56:c6:d3:64:ab:66:f3:c0:5e:96:9c:c3:c4:ef:
+ c3:7c:6b:8b:3a:79:7f:b3:49:cf:3d:e2:89:9f:a0:
+ 30:4b:85:b9:9c:94:24:79:8f:7d:6b:a9:45:68:0f:
+ 2b:d0:f1:da:1c:cb:69:b8:ca:49:62:6d:c8:d0:63:
+ 62:dd:60:0f:58:aa:8f:a1:bc:05:a5:66:a2:cf:1b:
+ 76:b2:84:64:b1:4c:39:52:c0:30:ba:f0:8c:4b:02:
+ b0:b6:b7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 47:B8:CD:FF:E5:6F:EE:F8:B2:EC:2F:4E:0E:F9:25:B0:8E:3C:6B:C3
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 00:20:23:41:35:04:90:c2:40:62:60:ef:e2:35:4c:d7:3f:ac:
+ e2:34:90:b8:a1:6f:76:fa:16:16:a4:48:37:2c:e9:90:c2:f2:
+ 3c:f8:0a:9f:d8:81:e5:bb:5b:da:25:2c:a4:a7:55:71:24:32:
+ f6:c8:0b:f2:bc:6a:f8:93:ac:b2:07:c2:5f:9f:db:cc:c8:8a:
+ aa:be:6a:6f:e1:49:10:cc:31:d7:80:bb:bb:c8:d8:a2:0e:64:
+ 57:ea:a2:f5:c2:a9:31:15:d2:20:6a:ec:fc:22:01:28:cf:86:
+ b8:80:1e:a9:cc:11:a5:3c:f2:16:b3:47:9d:fc:d2:80:21:c4:
+ cb:d0:47:70:41:a1:ca:83:19:08:2c:6d:f2:5d:77:9c:8a:14:
+ 13:d4:36:1c:92:f0:e5:06:37:dc:a6:e6:90:9b:38:8f:5c:6b:
+ 1b:46:86:43:42:5f:3e:01:07:53:54:5d:65:7d:f7:8a:73:a1:
+ 9a:54:5a:1f:29:43:14:27:c2:85:0f:b5:88:7b:1a:3b:94:b7:
+ 1d:60:a7:b5:9c:e7:29:69:57:5a:9b:93:7a:43:30:1b:03:d7:
+ 62:c8:40:a6:aa:fc:64:e4:4a:d7:91:53:01:a8:20:88:6e:9c:
+ 5f:44:b9:cb:60:81:34:ec:6f:d3:7d:da:48:5f:eb:b4:90:bc:
+ 2d:a9:1c:0b:ac:1c:d5:a2:68:20:80:04:d6:fc:b1:8f:2f:bb:
+ 4a:31:0d:4a:86:1c:eb:e2:36:29:26:f5:da:d8:c4:f2:75:61:
+ cf:7e:ae:76:63:4a:7a:40:65:93:87:f8:1e:80:8c:86:e5:86:
+ d6:8f:0e:fc:53:2c:60:e8:16:61:1a:a2:3e:43:7b:cd:39:60:
+ 54:6a:f5:f2:89:26:01:68:83:48:a2:33:e8:c9:04:91:b2:11:
+ 34:11:3e:ea:d0:43:19:1f:03:93:90:0c:ff:51:3d:57:f4:41:
+ 6e:e1:cb:a0:be:eb:c9:63:cd:6d:cc:e4:f8:36:aa:68:9d:ed:
+ bd:5d:97:70:44:0d:b6:0e:35:dc:e1:0c:5d:bb:a0:51:94:cb:
+ 7e:16:eb:11:2f:a3:92:45:c8:4c:71:d9:bc:c9:99:52:57:46:
+ 2f:50:cf:bd:35:69:f4:3d:15:ce:06:a5:2c:0f:3e:f6:81:ba:
+ 94:bb:c3:bb:bf:65:78:d2:86:79:ff:49:3b:1a:83:0c:f0:de:
+ 78:ec:c8:f2:4d:4c:1a:de:82:29:f8:c1:5a:da:ed:ee:e6:27:
+ 5e:e8:45:d0:9d:1c:51:a8:68:ab:44:e3:d0:8b:6a:e3:f8:3b:
+ bb:dc:4d:d7:64:f2:51:be:e6:aa:ab:5a:e9:31:ee:06:bc:73:
+ bf:13:62:0a:9f:c7:b9:97
+SHA1 Fingerprint=DA:FA:F7:FA:66:84:EC:06:8F:14:50:BD:C7:C2:81:A5:BC:A9:64:57
diff --git a/apex/ca-certificates/files/302904dd.0 b/apex/ca-certificates/files/302904dd.0
new file mode 100644
index 0000000..286ca6c
--- /dev/null
+++ b/apex/ca-certificates/files/302904dd.0
@@ -0,0 +1,136 @@
+-----BEGIN CERTIFICATE-----
+MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw
+WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw
+MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x
+MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD
+VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX
+BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
+ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO
+ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M
+CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu
+I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm
+TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh
+C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf
+ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz
+IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT
+Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k
+JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5
+hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB
+GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
+FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of
+1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov
+L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo
+dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr
+aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq
+hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L
+6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG
+HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6
+0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB
+lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi
+o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1
+gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v
+faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63
+Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh
+jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw
+3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ ca:e9:1b:89:f1:55:03:0d:a3:e6:41:6d:c4:e3:a6:e1
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=FR, O=Dhimyotis, OU=0002 48146308100036, CN=Certigna Root CA
+ Validity
+ Not Before: Oct 1 08:32:27 2013 GMT
+ Not After : Oct 1 08:32:27 2033 GMT
+ Subject: C=FR, O=Dhimyotis, OU=0002 48146308100036, CN=Certigna Root CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:cd:18:39:65:1a:59:b1:ea:64:16:0e:8c:94:24:
+ 95:7c:83:d3:c5:39:26:dc:0c:ef:16:57:8d:d7:d8:
+ ac:a3:42:7f:82:ca:ed:cd:5b:db:0e:b7:2d:ed:45:
+ 08:17:b2:d9:b3:cb:d6:17:52:72:28:db:8e:4e:9e:
+ 8a:b6:0b:f9:9e:84:9a:4d:76:de:22:29:5c:d2:b3:
+ d2:06:3e:30:39:a9:74:a3:92:56:1c:a1:6f:4c:0a:
+ 20:6d:9f:23:7a:b4:c6:da:2c:e4:1d:2c:dc:b3:28:
+ d0:13:f2:4c:4e:02:49:a1:54:40:9e:e6:e5:05:a0:
+ 2d:84:c8:ff:98:6c:d0:eb:8a:1a:84:08:1e:b7:68:
+ 23:ee:23:d5:70:ce:6d:51:69:10:ee:a1:7a:c2:d1:
+ 22:31:c2:82:85:d2:f2:55:76:50:7c:25:7a:c9:84:
+ 5c:0b:ac:dd:42:4e:2b:e7:82:a2:24:89:cb:90:b2:
+ d0:ee:23:ba:66:4c:bb:62:a4:f9:53:5a:64:7b:7c:
+ 98:fa:a3:48:9e:0f:95:ae:a7:18:f4:6a:ec:2e:03:
+ 45:af:f0:74:f8:2a:cd:7a:5d:d1:be:44:26:32:29:
+ f1:f1:f5:6c:cc:7e:02:21:0b:9f:6f:a4:3f:be:9d:
+ 53:e2:cf:7d:a9:2c:7c:58:1a:97:e1:3d:37:37:18:
+ 66:28:d2:40:c5:51:8a:8c:c3:2d:ce:53:88:24:58:
+ 64:30:16:c5:aa:e0:d6:0a:a6:40:df:78:f6:f5:04:
+ 7c:69:13:84:bc:d1:d1:a7:06:cf:01:f7:68:c0:a8:
+ 57:bb:3a:61:ad:04:8c:93:e3:ad:fc:f0:db:44:6d:
+ 59:dc:49:59:ae:ac:9a:99:36:30:41:7b:76:33:22:
+ 87:a3:c2:92:86:6e:f9:70:ee:ae:87:87:95:1b:c4:
+ 7a:bd:31:f3:d4:d2:e5:99:ff:be:48:ec:75:f5:78:
+ 16:1d:a6:70:c1:7f:3c:1b:a1:92:fb:cf:c8:3c:d6:
+ c5:93:0a:8f:f5:55:3a:76:95:ce:59:98:8a:09:95:
+ 77:32:9a:83:ba:2c:04:3a:97:bd:d4:2f:be:d7:6c:
+ 9b:a2:ca:7d:6d:26:c9:55:d5:cf:c3:79:52:08:09:
+ 99:07:24:2d:64:25:6b:a6:21:69:9b:6a:dd:74:4d:
+ 6b:97:7a:41:bd:ab:17:f9:90:17:48:8f:36:f9:2d:
+ d5:c5:db:ee:aa:85:45:41:fa:cd:3a:45:b1:68:e6:
+ 36:4c:9b:90:57:ec:23:b9:87:08:c2:c4:09:f1:97:
+ 86:2a:28:4d:e2:74:c0:da:c4:8c:db:df:e2:a1:17:
+ 59:ce:24:59:74:31:da:7f:fd:30:6d:d9:dc:e1:6a:
+ e1:fc:5f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 18:87:56:E0:6E:77:EE:24:35:3C:4E:73:9A:1F:D6:E1:E2:79:7E:2B
+ X509v3 Authority Key Identifier:
+ 18:87:56:E0:6E:77:EE:24:35:3C:4E:73:9A:1F:D6:E1:E2:79:7E:2B
+ X509v3 Certificate Policies:
+ Policy: X509v3 Any Policy
+ CPS: https://wwww.certigna.fr/autorites/
+ X509v3 CRL Distribution Points:
+ Full Name:
+ URI:http://crl.certigna.fr/certignarootca.crl
+ Full Name:
+ URI:http://crl.dhimyotis.com/certignarootca.crl
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 94:b8:9e:4f:f0:e3:95:08:22:e7:cd:68:41:f7:1c:55:d5:7c:
+ 00:e2:2d:3a:89:5d:68:38:2f:51:22:0b:4a:8d:cb:e9:bb:5d:
+ 3e:bb:5c:3d:b1:28:fe:e4:53:55:13:cf:a1:90:1b:02:1d:5f:
+ 66:46:09:33:28:e1:0d:24:97:70:d3:10:1f:ea:64:57:96:bb:
+ 5d:da:e7:c4:8c:4f:4c:64:46:1d:5c:87:e3:59:de:42:d1:9b:
+ a8:7e:a6:89:dd:8f:1c:c9:30:82:ed:3b:9c:cd:c0:e9:19:e0:
+ 6a:d8:02:75:37:ab:f7:34:28:28:91:f2:04:0a:4f:35:e3:60:
+ 26:01:fa:d0:11:8c:f9:11:6a:ee:af:3d:c3:50:d3:8f:5f:33:
+ 79:3c:86:a8:73:45:90:8c:20:b6:72:73:17:23:be:07:65:e5:
+ 78:92:0d:ba:01:c0:eb:8c:1c:66:bf:ac:86:77:01:94:0d:9c:
+ e6:e9:39:8d:1f:a6:51:8c:99:0c:39:77:e1:b4:9b:fa:1c:67:
+ 57:6f:6a:6a:8e:a9:2b:4c:57:79:7a:57:22:cf:cd:5f:63:46:
+ 8d:5c:59:3a:86:f8:32:47:62:a3:67:0d:18:91:dc:fb:a6:6b:
+ f5:48:61:73:23:59:8e:02:a7:bc:44:ea:f4:49:9d:f1:54:58:
+ f9:60:af:da:18:a4:2f:28:45:dc:7a:a0:88:86:5d:f3:3b:e7:
+ ff:29:35:80:fc:64:43:94:e6:e3:1c:6f:be:ad:0e:2a:63:99:
+ 2b:c9:7e:85:f6:71:e8:06:03:95:fe:de:8f:48:1c:5a:d4:92:
+ e8:2b:ee:e7:31:db:ba:04:6a:87:98:e7:c5:5f:ef:7d:a7:22:
+ f7:01:d8:4d:f9:89:d0:0e:9a:05:59:a4:9e:98:d9:6f:2b:ca:
+ 70:be:64:c2:55:a3:f4:e9:af:c3:92:29:dc:88:16:24:99:3c:
+ 8d:26:98:b6:5b:b7:cc:ce:b7:37:07:fd:26:d9:98:85:24:ff:
+ 59:23:03:9a:ed:9d:9d:a8:e4:5e:38:ce:d7:52:0d:6f:d2:3f:
+ 6d:b1:05:6b:49:ce:8a:91:46:73:f4:f6:2f:f0:a8:73:77:0e:
+ 65:ac:a1:8d:66:52:69:7e:4b:68:0c:c7:1e:37:27:83:a5:8c:
+ c7:02:e4:14:cd:49:01:b0:73:b3:fd:c6:90:3a:6f:d2:6c:ed:
+ 3b:ee:ec:91:be:a2:43:5d:8b:00:4a:66:25:44:70:de:40:0f:
+ f8:7c:15:f7:a2:ce:3c:d7:5e:13:8c:81:17:18:17:d1:bd:f1:
+ 77:10:3a:d4:65:39:c1:27:ac:57:2c:25:54:ff:a2:da:4f:8a:
+ 61:39:5e:ae:3d:4a:8c:bd
+SHA1 Fingerprint=2D:0D:52:14:FF:9E:AD:99:24:01:74:20:47:6E:6C:85:27:27:F5:43
diff --git a/apex/ca-certificates/files/304d27c3.0 b/apex/ca-certificates/files/304d27c3.0
new file mode 100644
index 0000000..b3ef145
--- /dev/null
+++ b/apex/ca-certificates/files/304d27c3.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9
+MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH
+bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x
+CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds
+b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr
+b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9
+kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm
+VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R
+VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc
+C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj
+tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY
+D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv
+j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl
+NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6
+iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP
+O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/
+BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV
+ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj
+L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5
+1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl
+1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU
+b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV
+PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj
+y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb
+EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg
+DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI
++Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy
+YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX
+UB+K+wb1whnw0A==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 5d:df:b1:da:5a:a3:ed:5d:be:5a:65:20:65:03:90:ef
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=CN, O=UniTrust, CN=UCA Global G2 Root
+ Validity
+ Not Before: Mar 11 00:00:00 2016 GMT
+ Not After : Dec 31 00:00:00 2040 GMT
+ Subject: C=CN, O=UniTrust, CN=UCA Global G2 Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:c5:e6:2b:6f:7c:ef:26:05:27:a3:81:24:da:6f:
+ cb:01:f9:99:9a:a9:32:c2:22:87:61:41:91:3b:cb:
+ c3:68:1b:06:c5:4c:a9:2b:c1:67:17:22:1d:2b:ed:
+ f9:29:89:93:a2:78:bd:92:6b:a0:a3:0d:a2:7e:ca:
+ 93:b3:a6:d1:8c:35:d5:75:f9:17:f6:cf:45:c5:e5:
+ 7a:ec:77:93:a0:8f:23:ae:0e:1a:03:7f:be:d4:d0:
+ ed:2e:7b:ab:46:23:5b:ff:2c:e6:54:7a:94:c0:2a:
+ 15:f0:c9:8d:b0:7a:3b:24:e1:d7:68:e2:31:3c:06:
+ 33:46:b6:54:11:a6:a5:2f:22:54:2a:58:0d:01:02:
+ f1:fa:15:51:67:6c:c0:fa:d7:b6:1b:7f:d1:56:88:
+ 2f:1a:3a:8d:3b:bb:82:11:e0:47:00:d0:52:87:ab:
+ fb:86:7e:0f:24:6b:40:9d:34:67:bc:8d:c7:2d:86:
+ 6f:79:3e:8e:a9:3c:17:4b:7f:b0:99:e3:b0:71:60:
+ dc:0b:f5:64:c3:ce:43:bc:6d:71:b9:d2:de:27:5b:
+ 8a:e8:d8:c6:ae:e1:59:7d:cf:28:2d:35:b8:95:56:
+ 1a:f1:b2:58:4b:b7:12:37:c8:7c:b3:ed:4b:80:e1:
+ 8d:fa:32:23:b6:6f:b7:48:95:08:b1:44:4e:85:8c:
+ 3a:02:54:20:2f:df:bf:57:4f:3b:3a:90:21:d7:c1:
+ 26:35:54:20:ec:c7:3f:47:ec:ef:5a:bf:4b:7a:c1:
+ ad:3b:17:50:5c:62:d8:0f:4b:4a:dc:2b:fa:6e:bc:
+ 73:92:cd:ec:c7:50:e8:41:96:d7:a9:7e:6d:d8:e9:
+ 1d:8f:8a:b5:b9:58:92:ba:4a:92:2b:0c:56:fd:80:
+ eb:08:f0:5e:29:6e:1b:1c:0c:af:8f:93:89:ad:db:
+ bd:a3:9e:21:ca:89:19:ec:df:b5:c3:1a:eb:16:fe:
+ 78:36:4c:d6:6e:d0:3e:17:1c:90:17:6b:26:ba:fb:
+ 7a:2f:bf:11:1c:18:0e:2d:73:03:8f:a0:e5:35:a0:
+ 5a:e2:4c:75:1d:71:e1:39:38:53:78:40:cc:83:93:
+ d7:0a:9e:9d:5b:8f:8a:e4:e5:e0:48:e4:48:b2:47:
+ cd:4e:2a:75:2a:7b:f2:22:f6:c9:be:09:91:96:57:
+ 7a:88:88:ac:ee:70:ac:f9:dc:29:e3:0c:1c:3b:12:
+ 4e:44:d6:a7:4e:b0:26:c8:f3:d9:1a:97:91:68:ea:
+ ef:8d:46:06:d2:56:45:58:9a:3c:0c:0f:83:b8:05:
+ 25:c3:39:cf:3b:a4:34:89:b7:79:12:2f:47:c5:e7:
+ a9:97:69:fc:a6:77:67:b5:df:7b:f1:7a:65:15:e4:
+ 61:56:65
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 81:C4:8C:CC:F5:E4:30:FF:A5:0C:08:5F:8C:15:67:21:74:01:DF:DF
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 13:65:22:f5:8e:2b:ad:44:e4:cb:ff:b9:68:e6:c3:80:48:3d:
+ 04:7b:fa:23:2f:7a:ed:36:da:b2:ce:6d:f6:e6:9e:e5:5f:58:
+ 8f:cb:37:32:a1:c8:65:b6:ae:38:3d:35:1b:3e:bc:3b:b6:04:
+ d0:bc:f9:49:f5:9b:f7:85:c5:36:b6:cb:bc:f8:c8:39:d5:e4:
+ 5f:07:bd:15:54:97:74:ca:ca:ed:4f:ba:ba:64:76:9f:81:b8:
+ 84:45:49:4c:8d:6f:a2:eb:b1:cc:d1:c3:94:da:44:c2:e6:e2:
+ ea:18:e8:a2:1f:27:05:ba:d7:e5:d6:a9:cd:dd:ef:76:98:8d:
+ 00:0e:cd:1b:fa:03:b7:8e:80:58:0e:27:3f:52:fb:94:a2:ca:
+ 5e:65:c9:d6:84:da:b9:35:71:f3:26:c0:4f:77:e6:81:27:d2:
+ 77:3b:9a:14:6f:79:f4:f6:d0:e1:d3:94:ba:d0:57:51:bd:27:
+ 05:0d:c1:fd:c8:12:30:ee:6f:8d:11:2b:08:9d:d4:d4:bf:80:
+ 45:14:9a:88:44:da:30:ea:b4:a7:e3:ee:ef:5b:82:d5:3e:d6:
+ ad:78:92:db:5c:3c:f3:d8:ad:fa:b8:6b:7f:c4:36:28:b6:02:
+ 15:8a:54:2c:9c:b0:17:73:8e:d0:37:a3:14:3c:98:95:00:0c:
+ 29:05:5b:9e:49:49:b1:5f:c7:e3:cb:cf:27:65:8e:35:17:b7:
+ 57:c8:30:d9:41:5b:b9:14:b6:e8:c2:0f:94:31:a7:94:98:cc:
+ 6a:eb:b5:e1:27:f5:10:a8:01:e8:8e:12:62:e8:88:cc:b5:7f:
+ 46:97:c0:9b:10:66:38:1a:36:46:5f:22:68:3d:df:c9:c6:13:
+ 27:ab:53:06:ac:a2:3c:86:06:65:6f:b1:7e:b1:29:44:9a:a3:
+ ba:49:69:28:69:8f:d7:e5:5f:ad:04:86:64:6f:1a:a0:0c:c5:
+ 08:62:ce:80:a3:d0:f3:ec:68:de:be:33:c7:17:5b:7f:80:c4:
+ 4c:4c:b1:a6:84:8a:c3:3b:b8:09:cd:14:81:ba:18:e3:54:57:
+ 36:fe:db:2f:7c:47:a1:3a:33:c8:f9:58:3b:44:4f:b1:ca:02:
+ 89:04:96:28:68:c5:4b:b8:26:89:bb:d6:33:2f:50:d5:fe:9a:
+ 89:ba:18:32:92:54:c6:5b:e0:9d:f9:5e:e5:0d:22:9b:f6:da:
+ e2:c8:21:b2:62:21:aa:86:40:b2:2e:64:d3:5f:c8:e3:7e:11:
+ 67:45:1f:05:fe:e3:a2:ef:b3:a8:b3:f3:7d:8f:f8:0c:1f:22:
+ 1f:2d:70:b4:b8:01:34:76:30:00:e5:23:78:a7:56:d7:50:1f:
+ 8a:fb:06:f5:c2:19:f0:d0
+SHA1 Fingerprint=28:F9:78:16:19:7A:FF:18:25:18:AA:44:FE:C1:A0:CE:5C:B6:4C:8A
diff --git a/apex/ca-certificates/files/31188b5e.0 b/apex/ca-certificates/files/31188b5e.0
new file mode 100644
index 0000000..99d80eb
--- /dev/null
+++ b/apex/ca-certificates/files/31188b5e.0
@@ -0,0 +1,84 @@
+-----BEGIN CERTIFICATE-----
+MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx
+GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp
+bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w
+KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0
+BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy
+dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG
+EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll
+IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU
+QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT
+TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg
+LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7
+a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr
+LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr
+N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X
+YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/
+iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f
+AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH
+V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
+BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh
+AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf
+IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4
+lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c
+8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf
+lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=TR, L=Gebze - Kocaeli, O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK, OU=Kamu Sertifikasyon Merkezi - Kamu SM, CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1
+ Validity
+ Not Before: Nov 25 08:25:55 2013 GMT
+ Not After : Oct 25 08:25:55 2043 GMT
+ Subject: C=TR, L=Gebze - Kocaeli, O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK, OU=Kamu Sertifikasyon Merkezi - Kamu SM, CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:af:75:30:33:aa:bb:6b:d3:99:2c:12:37:84:d9:
+ 8d:7b:97:80:d3:6e:e7:ff:9b:50:95:3e:90:95:56:
+ 42:d7:19:7c:26:84:8d:92:fa:01:1d:3a:0f:e2:64:
+ 38:b7:8c:bc:e8:88:f9:8b:24:ab:2e:a3:f5:37:e4:
+ 40:8e:18:25:79:83:75:1f:3b:ff:6c:a8:c5:c6:56:
+ f8:b4:ed:8a:44:a3:ab:6c:4c:fc:1d:d0:dc:ef:68:
+ bd:cf:e4:aa:ce:f0:55:f7:a2:34:d4:83:6b:37:7c:
+ 1c:c2:fe:b5:03:ec:57:ce:bc:b4:b5:c5:ed:00:0f:
+ 53:37:2a:4d:f4:4f:0c:83:fb:86:cf:cb:fe:8c:4e:
+ bd:87:f9:a7:8b:21:57:9c:7a:df:03:67:89:2c:9d:
+ 97:61:a7:10:b8:55:90:7f:0e:2d:27:38:74:df:e7:
+ fd:da:4e:12:e3:4d:15:22:02:c8:e0:e0:fc:0f:ad:
+ 8a:d7:c9:54:50:cc:3b:0f:ca:16:80:84:d0:51:56:
+ c3:8e:56:7f:89:22:33:2f:e6:85:0a:bd:a5:a8:1b:
+ 36:de:d3:dc:2c:6d:3b:c7:13:bd:59:23:2c:e6:e5:
+ a4:f7:d8:0b:ed:ea:90:40:44:a8:95:bb:93:d5:d0:
+ 80:34:b6:46:78:0e:1f:00:93:46:e1:ee:e9:f9:ec:
+ 4f:17
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 65:3F:C7:8A:86:C6:3C:DD:3C:54:5C:35:F8:3A:ED:52:0C:47:57:C8
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 2a:3f:e1:f1:32:8e:ae:e1:98:5c:4b:5e:cf:6b:1e:6a:09:d2:
+ 22:a9:12:c7:5e:57:7d:73:56:64:80:84:7a:93:e4:09:b9:10:
+ cd:9f:2a:27:e1:00:77:be:48:c8:35:a8:81:9f:e4:b8:2c:c9:
+ 7f:0e:b0:d2:4b:37:5d:ea:b9:d5:0b:5e:34:bd:f4:73:29:c3:
+ ed:26:15:9c:7e:08:53:8a:58:8d:d0:4b:28:df:c1:b3:df:20:
+ f3:f9:e3:e3:3a:df:cc:9c:94:d8:4e:4f:c3:6b:17:b7:f7:72:
+ e8:ad:66:33:b5:25:53:ab:e0:f8:4c:a9:9d:fd:f2:0d:ba:ae:
+ b9:d9:aa:c6:6b:f9:93:bb:ae:ab:b8:97:3c:03:1a:ba:43:c6:
+ 96:b9:45:72:38:b3:a7:a1:96:3d:91:7b:7e:c0:21:53:4c:87:
+ ed:f2:0b:54:95:51:93:d5:22:a5:0d:8a:f1:93:0e:3e:54:0e:
+ b0:d8:c9:4e:dc:f2:31:32:56:ea:64:f9:ea:b5:9d:16:66:42:
+ 72:f3:7f:d3:b1:31:43:fc:a4:8e:17:f1:6d:23:ab:94:66:f8:
+ ad:fb:0f:08:6e:26:2d:7f:17:07:09:b2:8c:fb:50:c0:9f:96:
+ 8d:cf:b6:fd:00:9d:5a:14:9a:bf:02:44:f5:c1:c2:9f:22:5e:
+ a2:0f:a1:e3
+SHA1 Fingerprint=31:43:64:9B:EC:CE:27:EC:ED:3A:3F:0B:8F:0D:E4:E8:91:DD:EE:CA
diff --git a/apex/ca-certificates/files/33ee480d.0 b/apex/ca-certificates/files/33ee480d.0
new file mode 100644
index 0000000..3c1c297
--- /dev/null
+++ b/apex/ca-certificates/files/33ee480d.0
@@ -0,0 +1,125 @@
+-----BEGIN CERTIFICATE-----
+MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE
+BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK
+DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz
+OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv
+dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv
+bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN
+AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R
+xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX
+qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC
+C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3
+6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh
+/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF
+YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E
+JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc
+US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8
+ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm
++Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi
+M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV
+HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G
+A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV
+cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc
+Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs
+PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/
+q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0
+cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr
+a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I
+H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y
+K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu
+nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf
+oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY
+Ic2wBlX7Jz9TkHCpBB5XJ7k=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 8875640296558310041 (0x7b2c9bd316803299)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=Texas, L=Houston, O=SSL Corporation, CN=SSL.com Root Certification Authority RSA
+ Validity
+ Not Before: Feb 12 17:39:39 2016 GMT
+ Not After : Feb 12 17:39:39 2041 GMT
+ Subject: C=US, ST=Texas, L=Houston, O=SSL Corporation, CN=SSL.com Root Certification Authority RSA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:f9:0f:dd:a3:2b:7d:cb:d0:2a:fe:ec:67:85:a6:
+ e7:2e:1b:ba:77:e1:e3:f5:af:a4:ec:fa:4a:5d:91:
+ c4:57:47:6b:18:77:6b:76:f2:fd:93:e4:3d:0f:c2:
+ 16:9e:0b:66:c3:56:94:9e:17:83:85:ce:56:ef:f2:
+ 16:fd:00:62:f5:22:09:54:e8:65:17:4e:41:b9:e0:
+ 4f:46:97:aa:1b:c8:b8:6e:62:5e:69:b1:5f:db:2a:
+ 02:7e:fc:6c:ca:f3:41:d8:ed:d0:e8:fc:3f:61:48:
+ ed:b0:03:14:1d:10:0e:4b:19:e0:bb:4e:ec:86:65:
+ ff:36:f3:5e:67:02:0b:9d:86:55:61:fd:7a:38:ed:
+ fe:e2:19:00:b7:6f:a1:50:62:75:74:3c:a0:fa:c8:
+ 25:92:b4:6e:7a:22:c7:f8:1e:a1:e3:b2:dd:91:31:
+ ab:2b:1d:04:ff:a5:4a:04:37:e9:85:a4:33:2b:fd:
+ e2:d6:55:34:7c:19:a4:4a:68:c7:b2:a8:d3:b7:ca:
+ a1:93:88:eb:c1:97:bc:8c:f9:1d:d9:22:84:24:74:
+ c7:04:3d:6a:a9:29:93:cc:eb:b8:5b:e1:fe:5f:25:
+ aa:34:58:c8:c1:23:54:9d:1b:98:11:c3:38:9c:7e:
+ 3d:86:6c:a5:0f:40:86:7c:02:f4:5c:02:4f:28:cb:
+ ae:71:9f:0f:3a:c8:33:fe:11:25:35:ea:fc:ba:c5:
+ 60:3d:d9:7c:18:d5:b2:a9:d3:75:78:03:72:22:ca:
+ 3a:c3:1f:ef:2c:e5:2e:a9:fa:9e:2c:b6:51:46:fd:
+ af:03:d6:ea:60:68:ea:85:16:36:6b:85:e9:1e:c0:
+ b3:dd:c4:24:dc:80:2a:81:41:6d:94:3e:c8:e0:c9:
+ 81:41:00:9e:5e:bf:7f:c5:08:98:a2:18:2c:42:40:
+ b3:f9:6f:38:27:4b:4e:80:f4:3d:81:47:e0:88:7c:
+ ea:1c:ce:b5:75:5c:51:2e:1c:2b:7f:1a:72:28:e7:
+ 00:b5:d1:74:c6:d7:e4:9f:ad:07:93:b6:53:35:35:
+ fc:37:e4:c3:f6:5d:16:be:21:73:de:92:0a:f8:a0:
+ 63:6a:bc:96:92:6a:3e:f8:bc:65:55:9b:de:f5:0d:
+ 89:26:04:fc:25:1a:a6:25:69:cb:c2:6d:ca:7c:e2:
+ 59:5f:97:ac:eb:ef:2e:c8:bc:d7:1b:59:3c:2b:cc:
+ f2:19:c8:93:6b:27:63:19:cf:fc:e9:26:f8:ca:71:
+ 9b:7f:93:fe:34:67:84:4e:99:eb:fc:b3:78:09:33:
+ 70:ba:66:a6:76:ed:1b:73:eb:1a:a5:0d:c4:22:13:
+ 20:94:56:0a:4e:2c:6c:4e:b1:fd:cf:9c:09:ba:a2:
+ 33:ed:87
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ DD:04:09:07:A2:F5:7A:7D:52:53:12:92:95:EE:38:80:25:0D:A6:59
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Authority Key Identifier:
+ DD:04:09:07:A2:F5:7A:7D:52:53:12:92:95:EE:38:80:25:0D:A6:59
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 20:18:11:94:29:fb:26:9d:1c:1e:1e:70:61:f1:95:72:93:71:
+ 24:ad:68:93:58:8e:32:af:1b:b3:70:03:fc:25:2b:74:85:90:
+ 3d:78:6a:f4:b9:8b:a5:97:3b:b5:18:91:bb:1e:a7:f9:40:5b:
+ 91:f9:55:99:af:1e:11:d0:5c:1d:a7:66:e3:b1:94:07:0c:32:
+ 39:a6:ea:1b:b0:79:d8:1d:9c:70:44:e3:8a:dd:c4:f9:95:1f:
+ 8a:38:43:3f:01:85:a5:47:a7:3d:46:b2:bc:e5:22:68:f7:7b:
+ 9c:d8:2c:3e:0a:21:c8:2d:33:ac:bf:c5:81:99:31:74:c1:75:
+ 71:c5:be:b1:f0:23:45:f4:9d:6b:fc:19:63:9d:a3:bc:04:c6:
+ 18:0b:25:bb:53:89:0f:b3:80:50:de:45:ee:44:7f:ab:94:78:
+ 64:98:d3:f6:28:dd:87:d8:70:65:74:fb:0e:b9:13:eb:a7:0f:
+ 61:a9:32:96:cc:de:bb:ed:63:4c:18:bb:a9:40:f7:a0:54:6e:
+ 20:88:71:75:18:ea:7a:b4:34:72:e0:23:27:77:5c:b6:90:ea:
+ 86:25:40:ab:ef:33:0f:cb:9f:82:be:a2:20:fb:f6:b5:2d:1a:
+ e6:c2:85:b1:74:0f:fb:c8:65:02:a4:52:01:47:dd:49:22:c1:
+ bf:d8:eb:6b:ac:7e:de:ec:63:33:15:b7:23:08:8f:c6:0f:8d:
+ 41:5a:dd:8e:c5:b9:8f:e5:45:3f:78:db:ba:d2:1b:40:b1:fe:
+ 71:4d:3f:e0:81:a2:ba:5e:b4:ec:15:e0:93:dd:08:1f:7e:e1:
+ 55:99:0b:21:de:93:9e:0a:fb:e6:a3:49:bd:36:30:fe:e7:77:
+ b2:a0:75:97:b5:2d:81:88:17:65:20:f7:da:90:00:9f:c9:52:
+ cc:32:ca:35:7c:f5:3d:0f:d8:2b:d7:f5:26:6c:c9:06:34:96:
+ 16:ea:70:59:1a:32:79:79:0b:b6:88:7f:0f:52:48:3d:bf:6c:
+ d8:a2:44:2e:d1:4e:b7:72:58:d3:89:13:95:fe:44:ab:f8:d7:
+ 8b:1b:6e:9c:bc:2c:a0:5b:d5:6a:00:af:5f:37:e1:d5:fa:10:
+ 0b:98:9c:86:e7:26:8f:ce:f0:ec:6e:8a:57:0b:80:e3:4e:b2:
+ c0:a0:63:61:90:ba:55:68:37:74:6a:b6:92:db:9f:a1:86:22:
+ b6:65:27:0e:ec:b6:9f:42:60:e4:67:c2:b5:da:41:0b:c4:d3:
+ 8b:61:1b:bc:fa:1f:91:2b:d7:44:07:5e:ba:29:ac:d9:c5:e9:
+ ef:53:48:5a:eb:80:f1:28:58:21:cd:b0:06:55:fb:27:3f:53:
+ 90:70:a9:04:1e:57:27:b9
+SHA1 Fingerprint=B7:AB:33:08:D1:EA:44:77:BA:14:80:12:5A:6F:BD:A9:36:49:0C:BB
diff --git a/apex/ca-certificates/files/35105088.0 b/apex/ca-certificates/files/35105088.0
new file mode 100644
index 0000000..b1400fb
--- /dev/null
+++ b/apex/ca-certificates/files/35105088.0
@@ -0,0 +1,124 @@
+-----BEGIN CERTIFICATE-----
+MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
+iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
+cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
+BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw
+MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV
+BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
+aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy
+dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
+AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B
+3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY
+tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/
+Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2
+VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT
+79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6
+c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT
+Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l
+c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee
+UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE
+Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
+BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G
+A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF
+Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO
+VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3
+ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs
+8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR
+iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze
+Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ
+XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/
+qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB
+VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
+L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
+jjxDah2nGN59PRbxYvnKkKj9
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 01:fd:6d:30:fc:a3:ca:51:a8:1b:bc:64:0e:35:03:2d
+ Signature Algorithm: sha384WithRSAEncryption
+ Issuer: C=US, ST=New Jersey, L=Jersey City, O=The USERTRUST Network, CN=USERTrust RSA Certification Authority
+ Validity
+ Not Before: Feb 1 00:00:00 2010 GMT
+ Not After : Jan 18 23:59:59 2038 GMT
+ Subject: C=US, ST=New Jersey, L=Jersey City, O=The USERTRUST Network, CN=USERTrust RSA Certification Authority
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:80:12:65:17:36:0e:c3:db:08:b3:d0:ac:57:0d:
+ 76:ed:cd:27:d3:4c:ad:50:83:61:e2:aa:20:4d:09:
+ 2d:64:09:dc:ce:89:9f:cc:3d:a9:ec:f6:cf:c1:dc:
+ f1:d3:b1:d6:7b:37:28:11:2b:47:da:39:c6:bc:3a:
+ 19:b4:5f:a6:bd:7d:9d:a3:63:42:b6:76:f2:a9:3b:
+ 2b:91:f8:e2:6f:d0:ec:16:20:90:09:3e:e2:e8:74:
+ c9:18:b4:91:d4:62:64:db:7f:a3:06:f1:88:18:6a:
+ 90:22:3c:bc:fe:13:f0:87:14:7b:f6:e4:1f:8e:d4:
+ e4:51:c6:11:67:46:08:51:cb:86:14:54:3f:bc:33:
+ fe:7e:6c:9c:ff:16:9d:18:bd:51:8e:35:a6:a7:66:
+ c8:72:67:db:21:66:b1:d4:9b:78:03:c0:50:3a:e8:
+ cc:f0:dc:bc:9e:4c:fe:af:05:96:35:1f:57:5a:b7:
+ ff:ce:f9:3d:b7:2c:b6:f6:54:dd:c8:e7:12:3a:4d:
+ ae:4c:8a:b7:5c:9a:b4:b7:20:3d:ca:7f:22:34:ae:
+ 7e:3b:68:66:01:44:e7:01:4e:46:53:9b:33:60:f7:
+ 94:be:53:37:90:73:43:f3:32:c3:53:ef:db:aa:fe:
+ 74:4e:69:c7:6b:8c:60:93:de:c4:c7:0c:df:e1:32:
+ ae:cc:93:3b:51:78:95:67:8b:ee:3d:56:fe:0c:d0:
+ 69:0f:1b:0f:f3:25:26:6b:33:6d:f7:6e:47:fa:73:
+ 43:e5:7e:0e:a5:66:b1:29:7c:32:84:63:55:89:c4:
+ 0d:c1:93:54:30:19:13:ac:d3:7d:37:a7:eb:5d:3a:
+ 6c:35:5c:db:41:d7:12:da:a9:49:0b:df:d8:80:8a:
+ 09:93:62:8e:b5:66:cf:25:88:cd:84:b8:b1:3f:a4:
+ 39:0f:d9:02:9e:eb:12:4c:95:7c:f3:6b:05:a9:5e:
+ 16:83:cc:b8:67:e2:e8:13:9d:cc:5b:82:d3:4c:b3:
+ ed:5b:ff:de:e5:73:ac:23:3b:2d:00:bf:35:55:74:
+ 09:49:d8:49:58:1a:7f:92:36:e6:51:92:0e:f3:26:
+ 7d:1c:4d:17:bc:c9:ec:43:26:d0:bf:41:5f:40:a9:
+ 44:44:f4:99:e7:57:87:9e:50:1f:57:54:a8:3e:fd:
+ 74:63:2f:b1:50:65:09:e6:58:42:2e:43:1a:4c:b4:
+ f0:25:47:59:fa:04:1e:93:d4:26:46:4a:50:81:b2:
+ de:be:78:b7:fc:67:15:e1:c9:57:84:1e:0f:63:d6:
+ e9:62:ba:d6:5f:55:2e:ea:5c:c6:28:08:04:25:39:
+ b8:0e:2b:a9:f2:4c:97:1c:07:3f:0d:52:f5:ed:ef:
+ 2f:82:0f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 53:79:BF:5A:AA:2B:4A:CF:54:80:E1:D8:9B:C0:9D:F2:B2:03:66:CB
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha384WithRSAEncryption
+ Signature Value:
+ 5c:d4:7c:0d:cf:f7:01:7d:41:99:65:0c:73:c5:52:9f:cb:f8:
+ cf:99:06:7f:1b:da:43:15:9f:9e:02:55:57:96:14:f1:52:3c:
+ 27:87:94:28:ed:1f:3a:01:37:a2:76:fc:53:50:c0:84:9b:c6:
+ 6b:4e:ba:8c:21:4f:a2:8e:55:62:91:f3:69:15:d8:bc:88:e3:
+ c4:aa:0b:fd:ef:a8:e9:4b:55:2a:06:20:6d:55:78:29:19:ee:
+ 5f:30:5c:4b:24:11:55:ff:24:9a:6e:5e:2a:2b:ee:0b:4d:9f:
+ 7f:f7:01:38:94:14:95:43:07:09:fb:60:a9:ee:1c:ab:12:8c:
+ a0:9a:5e:a7:98:6a:59:6d:8b:3f:08:fb:c8:d1:45:af:18:15:
+ 64:90:12:0f:73:28:2e:c5:e2:24:4e:fc:58:ec:f0:f4:45:fe:
+ 22:b3:eb:2f:8e:d2:d9:45:61:05:c1:97:6f:a8:76:72:8f:8b:
+ 8c:36:af:bf:0d:05:ce:71:8d:e6:a6:6f:1f:6c:a6:71:62:c5:
+ d8:d0:83:72:0c:f1:67:11:89:0c:9c:13:4c:72:34:df:bc:d5:
+ 71:df:aa:71:dd:e1:b9:6c:8c:3c:12:5d:65:da:bd:57:12:b6:
+ 43:6b:ff:e5:de:4d:66:11:51:cf:99:ae:ec:17:b6:e8:71:91:
+ 8c:de:49:fe:dd:35:71:a2:15:27:94:1c:cf:61:e3:26:bb:6f:
+ a3:67:25:21:5d:e6:dd:1d:0b:2e:68:1b:3b:82:af:ec:83:67:
+ 85:d4:98:51:74:b1:b9:99:80:89:ff:7f:78:19:5c:79:4a:60:
+ 2e:92:40:ae:4c:37:2a:2c:c9:c7:62:c8:0e:5d:f7:36:5b:ca:
+ e0:25:25:01:b4:dd:1a:07:9c:77:00:3f:d0:dc:d5:ec:3d:d4:
+ fa:bb:3f:cc:85:d6:6f:7f:a9:2d:df:b9:02:f7:f5:97:9a:b5:
+ 35:da:c3:67:b0:87:4a:a9:28:9e:23:8e:ff:5c:27:6b:e1:b0:
+ 4f:f3:07:ee:00:2e:d4:59:87:cb:52:41:95:ea:f4:47:d7:ee:
+ 64:41:55:7c:8d:59:02:95:dd:62:9d:c2:b9:ee:5a:28:74:84:
+ a5:9b:b7:90:c7:0c:07:df:f5:89:36:74:32:d6:28:c1:b0:b0:
+ 0b:e0:9c:4c:c3:1c:d6:fc:e3:69:b5:47:46:81:2f:a2:82:ab:
+ d3:63:44:70:c4:8d:ff:2d:33:ba:ad:8f:7b:b5:70:88:ae:3e:
+ 19:cf:40:28:d8:fc:c8:90:bb:5d:99:22:f5:52:e6:58:c5:1f:
+ 88:31:43:ee:88:1d:d7:c6:8e:3c:43:6a:1d:a7:18:de:7d:3d:
+ 16:f1:62:f9:ca:90:a8:fd
+SHA1 Fingerprint=2B:8F:1B:57:33:0D:BB:A2:D0:7A:6C:51:F7:0E:E9:0D:DA:B9:AD:8E
diff --git a/apex/ca-certificates/files/399e7759.0 b/apex/ca-certificates/files/399e7759.0
new file mode 100644
index 0000000..7e4e05c
--- /dev/null
+++ b/apex/ca-certificates/files/399e7759.0
@@ -0,0 +1,83 @@
+-----BEGIN CERTIFICATE-----
+MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
+QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
+b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
+CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
+nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
+43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
+T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
+gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
+BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
+TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
+DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
+hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
+06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
+PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
+YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
+CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 08:3b:e0:56:90:42:46:b1:a1:75:6a:c9:59:91:c7:4a
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA
+ Validity
+ Not Before: Nov 10 00:00:00 2006 GMT
+ Not After : Nov 10 00:00:00 2031 GMT
+ Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:e2:3b:e1:11:72:de:a8:a4:d3:a3:57:aa:50:a2:
+ 8f:0b:77:90:c9:a2:a5:ee:12:ce:96:5b:01:09:20:
+ cc:01:93:a7:4e:30:b7:53:f7:43:c4:69:00:57:9d:
+ e2:8d:22:dd:87:06:40:00:81:09:ce:ce:1b:83:bf:
+ df:cd:3b:71:46:e2:d6:66:c7:05:b3:76:27:16:8f:
+ 7b:9e:1e:95:7d:ee:b7:48:a3:08:da:d6:af:7a:0c:
+ 39:06:65:7f:4a:5d:1f:bc:17:f8:ab:be:ee:28:d7:
+ 74:7f:7a:78:99:59:85:68:6e:5c:23:32:4b:bf:4e:
+ c0:e8:5a:6d:e3:70:bf:77:10:bf:fc:01:f6:85:d9:
+ a8:44:10:58:32:a9:75:18:d5:d1:a2:be:47:e2:27:
+ 6a:f4:9a:33:f8:49:08:60:8b:d4:5f:b4:3a:84:bf:
+ a1:aa:4a:4c:7d:3e:cf:4f:5f:6c:76:5e:a0:4b:37:
+ 91:9e:dc:22:e6:6d:ce:14:1a:8e:6a:cb:fe:cd:b3:
+ 14:64:17:c7:5b:29:9e:32:bf:f2:ee:fa:d3:0b:42:
+ d4:ab:b7:41:32:da:0c:d4:ef:f8:81:d5:bb:8d:58:
+ 3f:b5:1b:e8:49:28:a2:70:da:31:04:dd:f7:b2:16:
+ f2:4c:0a:4e:07:a8:ed:4a:3d:5e:b5:7f:a3:90:c3:
+ af:27
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55
+ X509v3 Authority Key Identifier:
+ 03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ cb:9c:37:aa:48:13:12:0a:fa:dd:44:9c:4f:52:b0:f4:df:ae:
+ 04:f5:79:79:08:a3:24:18:fc:4b:2b:84:c0:2d:b9:d5:c7:fe:
+ f4:c1:1f:58:cb:b8:6d:9c:7a:74:e7:98:29:ab:11:b5:e3:70:
+ a0:a1:cd:4c:88:99:93:8c:91:70:e2:ab:0f:1c:be:93:a9:ff:
+ 63:d5:e4:07:60:d3:a3:bf:9d:5b:09:f1:d5:8e:e3:53:f4:8e:
+ 63:fa:3f:a7:db:b4:66:df:62:66:d6:d1:6e:41:8d:f2:2d:b5:
+ ea:77:4a:9f:9d:58:e2:2b:59:c0:40:23:ed:2d:28:82:45:3e:
+ 79:54:92:26:98:e0:80:48:a8:37:ef:f0:d6:79:60:16:de:ac:
+ e8:0e:cd:6e:ac:44:17:38:2f:49:da:e1:45:3e:2a:b9:36:53:
+ cf:3a:50:06:f7:2e:e8:c4:57:49:6c:61:21:18:d5:04:ad:78:
+ 3c:2c:3a:80:6b:a7:eb:af:15:14:e9:d8:89:c1:b9:38:6c:e2:
+ 91:6c:8a:ff:64:b9:77:25:57:30:c0:1b:24:a3:e1:dc:e9:df:
+ 47:7c:b5:b4:24:08:05:30:ec:2d:bd:0b:bf:45:bf:50:b9:a9:
+ f3:eb:98:01:12:ad:c8:88:c6:98:34:5f:8d:0a:3c:c6:e9:d5:
+ 95:95:6d:de
+SHA1 Fingerprint=A8:98:5D:3A:65:E5:E5:C4:B2:D7:D6:6D:40:C6:DD:2F:B1:9C:54:36
diff --git a/apex/ca-certificates/files/3ad48a91.0 b/apex/ca-certificates/files/3ad48a91.0
new file mode 100644
index 0000000..91f73f9
--- /dev/null
+++ b/apex/ca-certificates/files/3ad48a91.0
@@ -0,0 +1,79 @@
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
+RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
+VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
+DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
+ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
+VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
+mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
+IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
+mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
+XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
+dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
+jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
+BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
+DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
+9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
+jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
+Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
+ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
+R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 33554617 (0x20000b9)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root
+ Validity
+ Not Before: May 12 18:46:00 2000 GMT
+ Not After : May 12 23:59:00 2025 GMT
+ Subject: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:a3:04:bb:22:ab:98:3d:57:e8:26:72:9a:b5:79:
+ d4:29:e2:e1:e8:95:80:b1:b0:e3:5b:8e:2b:29:9a:
+ 64:df:a1:5d:ed:b0:09:05:6d:db:28:2e:ce:62:a2:
+ 62:fe:b4:88:da:12:eb:38:eb:21:9d:c0:41:2b:01:
+ 52:7b:88:77:d3:1c:8f:c7:ba:b9:88:b5:6a:09:e7:
+ 73:e8:11:40:a7:d1:cc:ca:62:8d:2d:e5:8f:0b:a6:
+ 50:d2:a8:50:c3:28:ea:f5:ab:25:87:8a:9a:96:1c:
+ a9:67:b8:3f:0c:d5:f7:f9:52:13:2f:c2:1b:d5:70:
+ 70:f0:8f:c0:12:ca:06:cb:9a:e1:d9:ca:33:7a:77:
+ d6:f8:ec:b9:f1:68:44:42:48:13:d2:c0:c2:a4:ae:
+ 5e:60:fe:b6:a6:05:fc:b4:dd:07:59:02:d4:59:18:
+ 98:63:f5:a5:63:e0:90:0c:7d:5d:b2:06:7a:f3:85:
+ ea:eb:d4:03:ae:5e:84:3e:5f:ff:15:ed:69:bc:f9:
+ 39:36:72:75:cf:77:52:4d:f3:c9:90:2c:b9:3d:e5:
+ c9:23:53:3f:1f:24:98:21:5c:07:99:29:bd:c6:3a:
+ ec:e7:6e:86:3a:6b:97:74:63:33:bd:68:18:31:f0:
+ 78:8d:76:bf:fc:9e:8e:5d:2a:86:a7:4d:90:dc:27:
+ 1a:39
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0
+ X509v3 Basic Constraints: critical
+ CA:TRUE, pathlen:3
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 85:0c:5d:8e:e4:6f:51:68:42:05:a0:dd:bb:4f:27:25:84:03:
+ bd:f7:64:fd:2d:d7:30:e3:a4:10:17:eb:da:29:29:b6:79:3f:
+ 76:f6:19:13:23:b8:10:0a:f9:58:a4:d4:61:70:bd:04:61:6a:
+ 12:8a:17:d5:0a:bd:c5:bc:30:7c:d6:e9:0c:25:8d:86:40:4f:
+ ec:cc:a3:7e:38:c6:37:11:4f:ed:dd:68:31:8e:4c:d2:b3:01:
+ 74:ee:be:75:5e:07:48:1a:7f:70:ff:16:5c:84:c0:79:85:b8:
+ 05:fd:7f:be:65:11:a3:0f:c0:02:b4:f8:52:37:39:04:d5:a9:
+ 31:7a:18:bf:a0:2a:f4:12:99:f7:a3:45:82:e3:3c:5e:f5:9d:
+ 9e:b5:c8:9e:7c:2e:c8:a4:9e:4e:08:14:4b:6d:fd:70:6d:6b:
+ 1a:63:bd:64:e6:1f:b7:ce:f0:f2:9f:2e:bb:1b:b7:f2:50:88:
+ 73:92:c2:e2:e3:16:8d:9a:32:02:ab:8e:18:dd:e9:10:11:ee:
+ 7e:35:ab:90:af:3e:30:94:7a:d0:33:3d:a7:65:0f:f5:fc:8e:
+ 9e:62:cf:47:44:2c:01:5d:bb:1d:b5:32:d2:47:d2:38:2e:d0:
+ fe:81:dc:32:6a:1e:b5:ee:3c:d5:fc:e7:81:1d:19:c3:24:42:
+ ea:63:39:a9
+SHA1 Fingerprint=D4:DE:20:D0:5E:66:FC:53:FE:1A:50:88:2C:78:DB:28:52:CA:E4:74
diff --git a/apex/ca-certificates/files/3c860d51.0 b/apex/ca-certificates/files/3c860d51.0
new file mode 100644
index 0000000..ac50353
--- /dev/null
+++ b/apex/ca-certificates/files/3c860d51.0
@@ -0,0 +1,128 @@
+-----BEGIN CERTIFICATE-----
+MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
+BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln
+biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF
+MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT
+d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8
+76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+
+bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c
+6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE
+emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd
+MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt
+MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y
+MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y
+FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi
+aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM
+gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB
+qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7
+lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn
+8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov
+L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6
+45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO
+UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5
+O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC
+bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv
+GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a
+77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC
+hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3
+92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp
+Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w
+ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt
+Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ bb:40:1c:43:f5:5e:4f:b0
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=CH, O=SwissSign AG, CN=SwissSign Gold CA - G2
+ Validity
+ Not Before: Oct 25 08:30:35 2006 GMT
+ Not After : Oct 25 08:30:35 2036 GMT
+ Subject: C=CH, O=SwissSign AG, CN=SwissSign Gold CA - G2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:af:e4:ee:7e:8b:24:0e:12:6e:a9:50:2d:16:44:
+ 3b:92:92:5c:ca:b8:5d:84:92:42:13:2a:bc:65:57:
+ 82:40:3e:57:24:cd:50:8b:25:2a:b7:6f:fc:ef:a2:
+ d0:c0:1f:02:24:4a:13:96:8f:23:13:e6:28:58:00:
+ a3:47:c7:06:a7:84:23:2b:bb:bd:96:2b:7f:55:cc:
+ 8b:c1:57:1f:0e:62:65:0f:dd:3d:56:8a:73:da:ae:
+ 7e:6d:ba:81:1c:7e:42:8c:20:35:d9:43:4d:84:fa:
+ 84:db:52:2c:f3:0e:27:77:0b:6b:bf:11:2f:72:78:
+ 9f:2e:d8:3e:e6:18:37:5a:2a:72:f9:da:62:90:92:
+ 95:ca:1f:9c:e9:b3:3c:2b:cb:f3:01:13:bf:5a:cf:
+ c1:b5:0a:60:bd:dd:b5:99:64:53:b8:a0:96:b3:6f:
+ e2:26:77:91:8c:e0:62:10:02:9f:34:0f:a4:d5:92:
+ 33:51:de:be:8d:ba:84:7a:60:3c:6a:db:9f:2b:ec:
+ de:de:01:3f:6e:4d:e5:50:86:cb:b4:af:ed:44:40:
+ c5:ca:5a:8c:da:d2:2b:7c:a8:ee:be:a6:e5:0a:aa:
+ 0e:a5:df:05:52:b7:55:c7:22:5d:32:6a:97:97:63:
+ 13:db:c9:db:79:36:7b:85:3a:4a:c5:52:89:f9:24:
+ e7:9d:77:a9:82:ff:55:1c:a5:71:69:2b:d1:02:24:
+ f2:b3:26:d4:6b:da:04:55:e5:c1:0a:c7:6d:30:37:
+ 90:2a:e4:9e:14:33:5e:16:17:55:c5:5b:b5:cb:34:
+ 89:92:f1:9d:26:8f:a1:07:d4:c6:b2:78:50:db:0c:
+ 0c:0b:7c:0b:8c:41:d7:b9:e9:dd:8c:88:f7:a3:4d:
+ b2:32:cc:d8:17:da:cd:b7:ce:66:9d:d4:fd:5e:ff:
+ bd:97:3e:29:75:e7:7e:a7:62:58:af:25:34:a5:41:
+ c7:3d:bc:0d:50:ca:03:03:0f:08:5a:1f:95:73:78:
+ 62:bf:af:72:14:69:0e:a5:e5:03:0e:78:8e:26:28:
+ 42:f0:07:0b:62:20:10:67:39:46:fa:a9:03:cc:04:
+ 38:7a:66:ef:20:83:b5:8c:4a:56:8e:91:00:fc:8e:
+ 5c:82:de:88:a0:c3:e2:68:6e:7d:8d:ef:3c:dd:65:
+ f4:5d:ac:51:ef:24:80:ae:aa:56:97:6f:f9:ad:7d:
+ da:61:3f:98:77:3c:a5:91:b6:1c:8c:26:da:65:a2:
+ 09:6d:c1:e2:54:e3:b9:ca:4c:4c:80:8f:77:7b:60:
+ 9a:1e:df:b6:f2:48:1e:0e:ba:4e:54:6d:98:e0:e1:
+ a2:1a:a2:77:50:cf:c4:63:92:ec:47:19:9d:eb:e6:
+ 6b:ce:c1
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 5B:25:7B:96:A4:65:51:7E:B8:39:F3:C0:78:66:5E:E8:3A:E7:F0:EE
+ X509v3 Authority Key Identifier:
+ 5B:25:7B:96:A4:65:51:7E:B8:39:F3:C0:78:66:5E:E8:3A:E7:F0:EE
+ X509v3 Certificate Policies:
+ Policy: 2.16.756.1.89.1.2.1.1
+ CPS: http://repository.swisssign.com/
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 27:ba:e3:94:7c:f1:ae:c0:de:17:e6:e5:d8:d5:f5:54:b0:83:
+ f4:bb:cd:5e:05:7b:4f:9f:75:66:af:3c:e8:56:7e:fc:72:78:
+ 38:03:d9:2b:62:1b:00:b9:f8:e9:60:cd:cc:ce:51:8a:c7:50:
+ 31:6e:e1:4a:7e:18:2f:69:59:b6:3d:64:81:2b:e3:83:84:e6:
+ 22:87:8e:7d:e0:ee:02:99:61:b8:1e:f4:b8:2b:88:12:16:84:
+ c2:31:93:38:96:31:a6:b9:3b:53:3f:c3:24:93:56:5b:69:92:
+ ec:c5:c1:bb:38:00:e3:ec:17:a9:b8:dc:c7:7c:01:83:9f:32:
+ 47:ba:52:22:34:1d:32:7a:09:56:a7:7c:25:36:a9:3d:4b:da:
+ c0:82:6f:0a:bb:12:c8:87:4b:27:11:f9:1e:2d:c7:93:3f:9e:
+ db:5f:26:6b:52:d9:2e:8a:f1:14:c6:44:8d:15:a9:b7:bf:bd:
+ de:a6:1a:ee:ae:2d:fb:48:77:17:fe:bb:ec:af:18:f5:2a:51:
+ f0:39:84:97:95:6c:6e:1b:c3:2b:c4:74:60:79:25:b0:0a:27:
+ df:df:5e:d2:39:cf:45:7d:42:4b:df:b3:2c:1e:c5:c6:5d:ca:
+ 55:3a:a0:9c:69:9a:8f:da:ef:b2:b0:3c:9f:87:6c:12:2b:65:
+ 70:15:52:31:1a:24:cf:6f:31:23:50:1f:8c:4f:8f:23:c3:74:
+ 41:63:1c:55:a8:14:dd:3e:e0:51:50:cf:f1:1b:30:56:0e:92:
+ b0:82:85:d8:83:cb:22:64:bc:2d:b8:25:d5:54:a2:b8:06:ea:
+ ad:92:a4:24:a0:c1:86:b5:4a:13:6a:47:cf:2e:0b:56:95:54:
+ cb:ce:9a:db:6a:b4:a6:b2:db:41:08:86:27:77:f7:6a:a0:42:
+ 6c:0b:38:ce:d7:75:50:32:92:c2:df:2b:30:22:48:d0:d5:41:
+ 38:25:5d:a4:e9:5d:9f:c6:94:75:d0:45:fd:30:97:43:8f:90:
+ ab:0a:c7:86:73:60:4a:69:2d:de:a5:78:d7:06:da:6a:9e:4b:
+ 3e:77:3a:20:13:22:01:d0:bf:68:9e:63:60:6b:35:4d:0b:6d:
+ ba:a1:3d:c0:93:e0:7f:23:b3:55:ad:72:25:4e:46:f9:d2:16:
+ ef:b0:64:c1:01:9e:e9:ca:a0:6a:98:0e:cf:d8:60:f2:2f:49:
+ b8:e4:42:e1:38:35:16:f4:c8:6e:4f:f7:81:56:e8:ba:a3:be:
+ 23:af:ae:fd:6f:03:e0:02:3b:30:76:fa:1b:6d:41:cf:01:b1:
+ e9:b8:c9:66:f4:db:26:f3:3a:a4:74:f2:49:24:5b:c9:b0:d0:
+ 57:c1:fa:3e:7a:e1:97:c9
+SHA1 Fingerprint=D8:C5:38:8A:B7:30:1B:1B:6E:D4:7A:E6:45:25:3A:6F:9F:1A:27:61
diff --git a/apex/ca-certificates/files/3c899c73.0 b/apex/ca-certificates/files/3c899c73.0
new file mode 100644
index 0000000..dcabc24
--- /dev/null
+++ b/apex/ca-certificates/files/3c899c73.0
@@ -0,0 +1,57 @@
+-----BEGIN CERTIFICATE-----
+MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw
+CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91
+bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg
+Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ
+BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu
+ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS
+b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni
+eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W
+p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T
+rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV
+57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg
+Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 21:2a:56:0c:ae:da:0c:ab:40:45:bf:2b:a2:2d:3a:ea
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=CH, O=WISeKey, OU=OISTE Foundation Endorsed, CN=OISTE WISeKey Global Root GC CA
+ Validity
+ Not Before: May 9 09:48:34 2017 GMT
+ Not After : May 9 09:58:33 2042 GMT
+ Subject: C=CH, O=WISeKey, OU=OISTE Foundation Endorsed, CN=OISTE WISeKey Global Root GC CA
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:4c:e9:50:c0:c6:0f:72:18:bc:d8:f1:ba:b3:89:
+ e2:79:4a:a3:16:a7:6b:54:24:db:51:ff:ea:f4:09:
+ 24:c3:0b:22:9f:cb:6a:27:82:81:0d:d2:c0:af:31:
+ e4:74:82:6e:ca:25:d9:8c:75:9d:f1:db:d0:9a:a2:
+ 4b:21:7e:16:a7:63:90:d2:39:d4:b1:87:78:5f:18:
+ 96:0f:50:1b:35:37:0f:6a:c6:dc:d9:13:4d:a4:8e:
+ 90:37:e6:bd:5b:31:91
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 48:87:14:AC:E3:C3:9E:90:60:3A:D7:CA:89:EE:D3:AD:8C:B4:50:66
+ 1.3.6.1.4.1.311.21.1:
+ ...
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:65:02:30:26:c7:69:5b:dc:d5:e7:b2:e7:c8:0c:8c:8c:c3:
+ dd:79:8c:1b:63:d5:c9:52:94:4e:4d:82:4a:73:1e:b2:80:84:
+ a9:25:c0:4c:5a:6d:49:29:60:78:13:e2:7e:48:eb:64:02:31:
+ 00:db:34:20:32:08:ff:9a:49:02:b6:88:de:14:af:5d:6c:99:
+ 71:8d:1a:3f:8b:d7:e0:a2:36:86:1c:07:82:3a:76:53:fd:c2:
+ a2:ed:ef:7b:b0:80:4f:58:0f:4b:53:39:bd
+SHA1 Fingerprint=E0:11:84:5E:34:DE:BE:88:81:B9:9C:F6:16:26:D1:96:1F:C3:B9:31
diff --git a/apex/ca-certificates/files/3c9a4d3b.0 b/apex/ca-certificates/files/3c9a4d3b.0
new file mode 100644
index 0000000..2ff8139
--- /dev/null
+++ b/apex/ca-certificates/files/3c9a4d3b.0
@@ -0,0 +1,148 @@
+-----BEGIN CERTIFICATE-----
+MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE
+AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw
+CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ
+BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND
+VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb
+qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY
+HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo
+G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA
+lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr
+IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/
+0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH
+k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47
+4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO
+m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa
+cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl
+uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI
+KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls
+ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG
+AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2
+VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT
+VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG
+CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA
+cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA
+QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA
+7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA
+cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA
+QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA
+czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu
+aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt
+aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud
+DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF
+BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp
+D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU
+JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m
+AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD
+vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms
+tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH
+7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h
+I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA
+h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF
+d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H
+pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 6828503384748696800 (0x5ec3b7a6437fa4e0)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: CN=ACCVRAIZ1, OU=PKIACCV, O=ACCV, C=ES
+ Validity
+ Not Before: May 5 09:37:37 2011 GMT
+ Not After : Dec 31 09:37:37 2030 GMT
+ Subject: CN=ACCVRAIZ1, OU=PKIACCV, O=ACCV, C=ES
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:9b:a9:ab:bf:61:4a:97:af:2f:97:66:9a:74:5f:
+ d0:d9:96:fd:cf:e2:e4:66:ef:1f:1f:47:33:c2:44:
+ a3:df:9a:de:1f:b5:54:dd:15:7c:69:35:11:6f:bb:
+ c8:0c:8e:6a:18:1e:d8:8f:d9:16:bc:10:48:36:5c:
+ f0:63:b3:90:5a:5c:24:37:d7:a3:d6:cb:09:71:b9:
+ f1:01:72:84:b0:7d:db:4d:80:cd:fc:d3:6f:c9:f8:
+ da:b6:0e:82:d2:45:85:a8:1b:68:a8:3d:e8:f4:44:
+ 6c:bd:a1:c2:cb:03:be:8c:3e:13:00:84:df:4a:48:
+ c0:e3:22:0a:e8:e9:37:a7:18:4c:b1:09:0d:23:56:
+ 7f:04:4d:d9:17:84:18:a5:c8:da:40:94:73:eb:ce:
+ 0e:57:3c:03:81:3a:9d:0a:a1:57:43:69:ac:57:6d:
+ 79:90:78:e5:b5:b4:3b:d8:bc:4c:8d:28:a1:a7:a3:
+ a7:ba:02:4e:25:d1:2a:ae:ed:ae:03:22:b8:6b:20:
+ 0f:30:28:54:95:7f:e0:ee:ce:0a:66:9d:d1:40:2d:
+ 6e:22:af:9d:1a:c1:05:19:d2:6f:c0:f2:9f:f8:7b:
+ b3:02:42:fb:50:a9:1d:2d:93:0f:23:ab:c6:c1:0f:
+ 92:ff:d0:a2:15:f5:53:09:71:1c:ff:45:13:84:e6:
+ 26:5e:f8:e0:88:1c:0a:fc:16:b6:a8:73:06:b8:f0:
+ 63:84:02:a0:c6:5a:ec:e7:74:df:70:ae:a3:83:25:
+ ea:d6:c7:97:87:93:a7:c6:8a:8a:33:97:60:37:10:
+ 3e:97:3e:6e:29:15:d6:a1:0f:d1:88:2c:12:9f:6f:
+ aa:a4:c6:42:eb:41:a2:e3:95:43:d3:01:85:6d:8e:
+ bb:3b:f3:23:36:c7:fe:3b:e0:a1:25:07:48:ab:c9:
+ 89:74:ff:08:8f:80:bf:c0:96:65:f3:ee:ec:4b:68:
+ bd:9d:88:c3:31:b3:40:f1:e8:cf:f6:38:bb:9c:e4:
+ d1:7f:d4:e5:58:9b:7c:fa:d4:f3:0e:9b:75:91:e4:
+ ba:52:2e:19:7e:d1:f5:cd:5a:19:fc:ba:06:f6:fb:
+ 52:a8:4b:99:04:dd:f8:f9:b4:8b:50:a3:4e:62:89:
+ f0:87:24:fa:83:42:c1:87:fa:d5:2d:29:2a:5a:71:
+ 7a:64:6a:d7:27:60:63:0d:db:ce:49:f5:8d:1f:90:
+ 89:32:17:f8:73:43:b8:d2:5a:93:86:61:d6:e1:75:
+ 0a:ea:79:66:76:88:4f:71:eb:04:25:d6:0a:5a:7a:
+ 93:e5:b9:4b:17:40:0f:b1:b6:b9:f5:de:4f:dc:e0:
+ b3:ac:3b:11:70:60:84:4a:43:6e:99:20:c0:29:71:
+ 0a:c0:65
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ Authority Information Access:
+ CA Issuers - URI:http://www.accv.es/fileadmin/Archivos/certificados/raizaccv1.crt
+ OCSP - URI:http://ocsp.accv.es
+ X509v3 Subject Key Identifier:
+ D2:87:B4:E3:DF:37:27:93:55:F6:56:EA:81:E5:36:CC:8C:1E:3F:BD
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Authority Key Identifier:
+ D2:87:B4:E3:DF:37:27:93:55:F6:56:EA:81:E5:36:CC:8C:1E:3F:BD
+ X509v3 Certificate Policies:
+ Policy: X509v3 Any Policy
+ User Notice:
+ Explicit Text:
+ CPS: http://www.accv.es/legislacion_c.htm
+ X509v3 CRL Distribution Points:
+ Full Name:
+ URI:http://www.accv.es/fileadmin/Archivos/certificados/raizaccv1_der.crl
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Alternative Name:
+ email:accv@accv.es
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 97:31:02:9f:e7:fd:43:67:48:44:14:e4:29:87:ed:4c:28:66:
+ d0:8f:35:da:4d:61:b7:4a:97:4d:b5:db:90:e0:05:2e:0e:c6:
+ 79:d0:f2:97:69:0f:bd:04:47:d9:be:db:b5:29:da:9b:d9:ae:
+ a9:99:d5:d3:3c:30:93:f5:8d:a1:a8:fc:06:8d:44:f4:ca:16:
+ 95:7c:33:dc:62:8b:a8:37:f8:27:d8:09:2d:1b:ef:c8:14:27:
+ 20:a9:64:44:ff:2e:d6:75:aa:6c:4d:60:40:19:49:43:54:63:
+ da:e2:cc:ba:66:e5:4f:44:7a:5b:d9:6a:81:2b:40:d5:7f:f9:
+ 01:27:58:2c:c8:ed:48:91:7c:3f:a6:00:cf:c4:29:73:11:36:
+ de:86:19:3e:9d:ee:19:8a:1b:d5:b0:ed:8e:3d:9c:2a:c0:0d:
+ d8:3d:66:e3:3c:0d:bd:d5:94:5c:e2:e2:a7:35:1b:04:00:f6:
+ 3f:5a:8d:ea:43:bd:5f:89:1d:a9:c1:b0:cc:99:e2:4d:00:0a:
+ da:c9:27:5b:e7:13:90:5c:e4:f5:33:a2:55:6d:dc:e0:09:4d:
+ 2f:b1:26:5b:27:75:00:09:c4:62:77:29:08:5f:9e:59:ac:b6:
+ 7e:ad:9f:54:30:22:03:c1:1e:71:64:fe:f9:38:0a:96:18:dd:
+ 02:14:ac:23:cb:06:1c:1e:a4:7d:8d:0d:de:27:41:e8:ad:da:
+ 15:b7:b0:23:dd:2b:a8:d3:da:25:87:ed:e8:55:44:4d:88:f4:
+ 36:7e:84:9a:78:ac:f7:0e:56:49:0e:d6:33:25:d6:84:50:42:
+ 6c:20:12:1d:2a:d5:be:bc:f2:70:81:a4:70:60:be:05:b5:9b:
+ 9e:04:44:be:61:23:ac:e9:a5:24:8c:11:80:94:5a:a2:a2:b9:
+ 49:d2:c1:dc:d1:a7:ed:31:11:2c:9e:19:a6:ee:e1:55:e1:c0:
+ ea:cf:0d:84:e4:17:b7:a2:7c:a5:de:55:25:06:ee:cc:c0:87:
+ 5c:40:da:cc:95:3f:55:e0:35:c7:b8:84:be:b4:5d:cd:7a:83:
+ 01:72:ee:87:e6:5f:1d:ae:b5:85:c6:26:df:e6:c1:9a:e9:1e:
+ 02:47:9f:2a:a8:6d:a9:5b:cf:ec:45:77:7f:98:27:9a:32:5d:
+ 2a:e3:84:ee:c5:98:66:2f:96:20:1d:dd:d8:c3:27:d7:b0:f9:
+ fe:d9:7d:cd:d0:9f:8f:0b:14:58:51:9f:2f:8b:c3:38:2d:de:
+ e8:8f:d6:8d:87:a4:f5:56:43:16:99:2c:f4:a4:56:b4:34:b8:
+ 61:37:c9:c2:58:80:1b:a0:97:a1:fc:59:8d:e9:11:f6:d1:0f:
+ 4b:55:34:46:2a:8b:86:3b
+SHA1 Fingerprint=93:05:7A:88:15:C6:4F:CE:88:2F:FA:91:16:52:28:78:BC:53:64:17
diff --git a/apex/ca-certificates/files/3e7271e8.0 b/apex/ca-certificates/files/3e7271e8.0
new file mode 100644
index 0000000..36f03f5
--- /dev/null
+++ b/apex/ca-certificates/files/3e7271e8.0
@@ -0,0 +1,83 @@
+-----BEGIN CERTIFICATE-----
+MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
+RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
+bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5
+IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3
+MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3
+LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp
+YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG
+A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq
+K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe
+sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX
+MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT
+XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/
+HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH
+4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
+HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub
+j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo
+U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf
+zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b
+u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+
+bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er
+fF6adulZkMV8gzURZVE=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 946069240 (0x3863def8)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: O=Entrust.net, OU=www.entrust.net\/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048)
+ Validity
+ Not Before: Dec 24 17:50:51 1999 GMT
+ Not After : Jul 24 14:15:12 2029 GMT
+ Subject: O=Entrust.net, OU=www.entrust.net\/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048)
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:ad:4d:4b:a9:12:86:b2:ea:a3:20:07:15:16:64:
+ 2a:2b:4b:d1:bf:0b:4a:4d:8e:ed:80:76:a5:67:b7:
+ 78:40:c0:73:42:c8:68:c0:db:53:2b:dd:5e:b8:76:
+ 98:35:93:8b:1a:9d:7c:13:3a:0e:1f:5b:b7:1e:cf:
+ e5:24:14:1e:b1:81:a9:8d:7d:b8:cc:6b:4b:03:f1:
+ 02:0c:dc:ab:a5:40:24:00:7f:74:94:a1:9d:08:29:
+ b3:88:0b:f5:87:77:9d:55:cd:e4:c3:7e:d7:6a:64:
+ ab:85:14:86:95:5b:97:32:50:6f:3d:c8:ba:66:0c:
+ e3:fc:bd:b8:49:c1:76:89:49:19:fd:c0:a8:bd:89:
+ a3:67:2f:c6:9f:bc:71:19:60:b8:2d:e9:2c:c9:90:
+ 76:66:7b:94:e2:af:78:d6:65:53:5d:3c:d6:9c:b2:
+ cf:29:03:f9:2f:a4:50:b2:d4:48:ce:05:32:55:8a:
+ fd:b2:64:4c:0e:e4:98:07:75:db:7f:df:b9:08:55:
+ 60:85:30:29:f9:7b:48:a4:69:86:e3:35:3f:1e:86:
+ 5d:7a:7a:15:bd:ef:00:8e:15:22:54:17:00:90:26:
+ 93:bc:0e:49:68:91:bf:f8:47:d3:9d:95:42:c1:0e:
+ 4d:df:6f:26:cf:c3:18:21:62:66:43:70:d6:d5:c0:
+ 07:e1
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 55:E4:81:D1:11:80:BE:D8:89:B9:08:A3:31:F9:A1:24:09:16:B9:70
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 3b:9b:8f:56:9b:30:e7:53:99:7c:7a:79:a7:4d:97:d7:19:95:
+ 90:fb:06:1f:ca:33:7c:46:63:8f:96:66:24:fa:40:1b:21:27:
+ ca:e6:72:73:f2:4f:fe:31:99:fd:c8:0c:4c:68:53:c6:80:82:
+ 13:98:fa:b6:ad:da:5d:3d:f1:ce:6e:f6:15:11:94:82:0c:ee:
+ 3f:95:af:11:ab:0f:d7:2f:de:1f:03:8f:57:2c:1e:c9:bb:9a:
+ 1a:44:95:eb:18:4f:a6:1f:cd:7d:57:10:2f:9b:04:09:5a:84:
+ b5:6e:d8:1d:3a:e1:d6:9e:d1:6c:79:5e:79:1c:14:c5:e3:d0:
+ 4c:93:3b:65:3c:ed:df:3d:be:a6:e5:95:1a:c3:b5:19:c3:bd:
+ 5e:5b:bb:ff:23:ef:68:19:cb:12:93:27:5c:03:2d:6f:30:d0:
+ 1e:b6:1a:ac:de:5a:f7:d1:aa:a8:27:a6:fe:79:81:c4:79:99:
+ 33:57:ba:12:b0:a9:e0:42:6c:93:ca:56:de:fe:6d:84:0b:08:
+ 8b:7e:8d:ea:d7:98:21:c6:f3:e7:3c:79:2f:5e:9c:d1:4c:15:
+ 8d:e1:ec:22:37:cc:9a:43:0b:97:dc:80:90:8d:b3:67:9b:6f:
+ 48:08:15:56:cf:bf:f1:2b:7c:5e:9a:76:e9:59:90:c5:7c:83:
+ 35:11:65:51
+SHA1 Fingerprint=50:30:06:09:1D:97:D4:F5:AE:39:F7:CB:E7:92:7D:7D:65:2D:34:31
diff --git a/apex/ca-certificates/files/41a3f684.0 b/apex/ca-certificates/files/41a3f684.0
new file mode 100644
index 0000000..6fd6205
--- /dev/null
+++ b/apex/ca-certificates/files/41a3f684.0
@@ -0,0 +1,55 @@
+-----BEGIN CERTIFICATE-----
+MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw
+CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw
+JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT
+EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0
+WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT
+LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX
+BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE
+KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm
+Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj
+QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8
+EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J
+UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn
+nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 78:8f:27:5c:81:12:52:20:a5:04:d0:2d:dd:ba:73:f4
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=PL, O=Asseco Data Systems S.A., OU=Certum Certification Authority, CN=Certum EC-384 CA
+ Validity
+ Not Before: Mar 26 07:24:54 2018 GMT
+ Not After : Mar 26 07:24:54 2043 GMT
+ Subject: C=PL, O=Asseco Data Systems S.A., OU=Certum Certification Authority, CN=Certum EC-384 CA
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:c4:28:8e:ab:18:5b:6a:be:6e:64:37:63:e4:cd:
+ ec:ab:3a:f7:cc:a1:b8:0e:82:49:d7:86:29:9f:a1:
+ 94:f2:e3:60:78:98:81:78:06:4d:f2:ec:9a:0e:57:
+ 60:83:9f:b4:e6:17:2f:1a:b3:5d:02:5b:89:23:3c:
+ c2:11:05:2a:a7:88:13:18:f3:50:84:d7:bd:34:2c:
+ 27:89:55:ff:ce:4c:e7:df:a6:1f:28:c4:f0:54:c3:
+ b9:7c:b7:53:ad:eb:c2
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 8D:06:66:74:24:76:3A:F3:89:F7:BC:D6:BD:47:7D:2F:BC:10:5F:4B
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:65:02:30:03:55:2d:a6:e6:18:c4:7c:ef:c9:50:6e:c1:27:
+ 0f:9c:87:af:6e:d5:1b:08:18:bd:92:29:c1:ef:94:91:78:d2:
+ 3a:1c:55:89:62:e5:1b:09:1e:ba:64:6b:f1:76:b4:d4:02:31:
+ 00:b4:42:84:99:ff:ab:e7:9e:fb:91:97:27:5d:dc:b0:5b:30:
+ 71:ce:5e:38:1a:6a:d9:25:e7:ea:f7:61:92:56:f8:ea:da:36:
+ c2:87:65:96:2e:72:25:2f:7f:df:c3:13:c9
+SHA1 Fingerprint=F3:3E:78:3C:AC:DF:F4:A2:CC:AC:67:55:69:56:D7:E5:16:3C:E1:ED
diff --git a/apex/ca-certificates/files/455f1b52.0 b/apex/ca-certificates/files/455f1b52.0
new file mode 100644
index 0000000..ab55c73
--- /dev/null
+++ b/apex/ca-certificates/files/455f1b52.0
@@ -0,0 +1,83 @@
+-----BEGIN CERTIFICATE-----
+MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC
+VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50
+cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs
+IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz
+dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy
+NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu
+dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt
+dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0
+aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T
+RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN
+cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW
+wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1
+U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0
+jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN
+BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/
+jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ
+Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v
+1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R
+nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH
+VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1246989352 (0x4a538c28)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, O=Entrust, Inc., OU=See www.entrust.net\/legal-terms, OU=(c) 2009 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - G2
+ Validity
+ Not Before: Jul 7 17:25:54 2009 GMT
+ Not After : Dec 7 17:55:54 2030 GMT
+ Subject: C=US, O=Entrust, Inc., OU=See www.entrust.net\/legal-terms, OU=(c) 2009 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - G2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:ba:84:b6:72:db:9e:0c:6b:e2:99:e9:30:01:a7:
+ 76:ea:32:b8:95:41:1a:c9:da:61:4e:58:72:cf:fe:
+ f6:82:79:bf:73:61:06:0a:a5:27:d8:b3:5f:d3:45:
+ 4e:1c:72:d6:4e:32:f2:72:8a:0f:f7:83:19:d0:6a:
+ 80:80:00:45:1e:b0:c7:e7:9a:bf:12:57:27:1c:a3:
+ 68:2f:0a:87:bd:6a:6b:0e:5e:65:f3:1c:77:d5:d4:
+ 85:8d:70:21:b4:b3:32:e7:8b:a2:d5:86:39:02:b1:
+ b8:d2:47:ce:e4:c9:49:c4:3b:a7:de:fb:54:7d:57:
+ be:f0:e8:6e:c2:79:b2:3a:0b:55:e2:50:98:16:32:
+ 13:5c:2f:78:56:c1:c2:94:b3:f2:5a:e4:27:9a:9f:
+ 24:d7:c6:ec:d0:9b:25:82:e3:cc:c2:c4:45:c5:8c:
+ 97:7a:06:6b:2a:11:9f:a9:0a:6e:48:3b:6f:db:d4:
+ 11:19:42:f7:8f:07:bf:f5:53:5f:9c:3e:f4:17:2c:
+ e6:69:ac:4e:32:4c:62:77:ea:b7:e8:e5:bb:34:bc:
+ 19:8b:ae:9c:51:e7:b7:7e:b5:53:b1:33:22:e5:6d:
+ cf:70:3c:1a:fa:e2:9b:67:b6:83:f4:8d:a5:af:62:
+ 4c:4d:e0:58:ac:64:34:12:03:f8:b6:8d:94:63:24:
+ a4:71
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 6A:72:26:7A:D0:1E:EF:7D:E7:3B:69:51:D4:6C:8D:9F:90:12:66:AB
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 79:9f:1d:96:c6:b6:79:3f:22:8d:87:d3:87:03:04:60:6a:6b:
+ 9a:2e:59:89:73:11:ac:43:d1:f5:13:ff:8d:39:2b:c0:f2:bd:
+ 4f:70:8c:a9:2f:ea:17:c4:0b:54:9e:d4:1b:96:98:33:3c:a8:
+ ad:62:a2:00:76:ab:59:69:6e:06:1d:7e:c4:b9:44:8d:98:af:
+ 12:d4:61:db:0a:19:46:47:f3:eb:f7:63:c1:40:05:40:a5:d2:
+ b7:f4:b5:9a:36:bf:a9:88:76:88:04:55:04:2b:9c:87:7f:1a:
+ 37:3c:7e:2d:a5:1a:d8:d4:89:5e:ca:bd:ac:3d:6c:d8:6d:af:
+ d5:f3:76:0f:cd:3b:88:38:22:9d:6c:93:9a:c4:3d:bf:82:1b:
+ 65:3f:a6:0f:5d:aa:fc:e5:b2:15:ca:b5:ad:c6:bc:3d:d0:84:
+ e8:ea:06:72:b0:4d:39:32:78:bf:3e:11:9c:0b:a4:9d:9a:21:
+ f3:f0:9b:0b:30:78:db:c1:dc:87:43:fe:bc:63:9a:ca:c5:c2:
+ 1c:c9:c7:8d:ff:3b:12:58:08:e6:b6:3d:ec:7a:2c:4e:fb:83:
+ 96:ce:0c:3c:69:87:54:73:a4:73:c2:93:ff:51:10:ac:15:54:
+ 01:d8:fc:05:b1:89:a1:7f:74:83:9a:49:d7:dc:4e:7b:8a:48:
+ 6f:8b:45:f6
+SHA1 Fingerprint=8C:F4:27:FD:79:0C:3A:D1:66:06:8D:E8:1E:57:EF:BB:93:22:72:D4
diff --git a/apex/ca-certificates/files/48a195d8.0 b/apex/ca-certificates/files/48a195d8.0
new file mode 100644
index 0000000..a27ba9a
--- /dev/null
+++ b/apex/ca-certificates/files/48a195d8.0
@@ -0,0 +1,126 @@
+-----BEGIN CERTIFICATE-----
+MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4
+MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6
+ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD
+VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j
+b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq
+scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO
+xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H
+LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX
+uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD
+yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+
+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q
+rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN
+BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L
+hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB
+QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+
+HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu
+Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg
+QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB
+BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx
+MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA
+A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb
+laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56
+awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo
+JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw
+LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT
+VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk
+LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb
+UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/
+QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+
+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls
+QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ b0:b7:5a:16:48:5f:bf:e1:cb:f5:8b:d7:19:e6:7d
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=ES, O=IZENPE S.A., CN=Izenpe.com
+ Validity
+ Not Before: Dec 13 13:08:28 2007 GMT
+ Not After : Dec 13 08:27:25 2037 GMT
+ Subject: C=ES, O=IZENPE S.A., CN=Izenpe.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:c9:d3:7a:ca:0f:1e:ac:a7:86:e8:16:65:6a:b1:
+ c2:1b:45:32:71:95:d9:fe:10:5b:cc:af:e7:a5:79:
+ 01:8f:89:c3:ca:f2:55:71:f7:77:be:77:94:f3:72:
+ a4:2c:44:d8:9e:92:9b:14:3a:a1:e7:24:90:0a:0a:
+ 56:8e:c5:d8:26:94:e1:d9:48:e1:2d:3e:da:0a:72:
+ dd:a3:99:15:da:81:a2:87:f4:7b:6e:26:77:89:58:
+ ad:d6:eb:0c:b2:41:7a:73:6e:6d:db:7a:78:41:e9:
+ 08:88:12:7e:87:2e:66:11:63:6c:54:fb:3c:9d:72:
+ c0:bc:2e:ff:c2:b7:dd:0d:76:e3:3a:d7:f7:b4:68:
+ be:a2:f5:e3:81:6e:c1:46:6f:5d:8d:e0:4d:c6:54:
+ 55:89:1a:33:31:0a:b1:57:b9:a3:8a:98:c3:ec:3b:
+ 34:c5:95:41:69:7e:75:c2:3c:20:c5:61:ba:51:47:
+ a0:20:90:93:a1:90:4b:f3:4e:7c:85:45:54:9a:d1:
+ 05:26:41:b0:b5:4d:1d:33:be:c4:03:c8:25:7c:c1:
+ 70:db:3b:f4:09:2d:54:27:48:ac:2f:e1:c4:ac:3e:
+ c8:cb:92:4c:53:39:37:23:ec:d3:01:f9:e0:09:44:
+ 4d:4d:64:c0:e1:0d:5a:87:22:bc:ad:1b:a3:fe:26:
+ b5:15:f3:a7:fc:84:19:e9:ec:a1:88:b4:44:69:84:
+ 83:f3:89:d1:74:06:a9:cc:0b:d6:c2:de:27:85:50:
+ 26:ca:17:b8:c9:7a:87:56:2c:1a:01:1e:6c:be:13:
+ ad:10:ac:b5:24:f5:38:91:a1:d6:4b:da:f1:bb:d2:
+ de:47:b5:f1:bc:81:f6:59:6b:cf:19:53:e9:8d:15:
+ cb:4a:cb:a9:6f:44:e5:1b:41:cf:e1:86:a7:ca:d0:
+ 6a:9f:bc:4c:8d:06:33:5a:a2:85:e5:90:35:a0:62:
+ 5c:16:4e:f0:e3:a2:fa:03:1a:b4:2c:71:b3:58:2c:
+ de:7b:0b:db:1a:0f:eb:de:21:1f:06:77:06:03:b0:
+ c9:ef:99:fc:c0:b9:4f:0b:86:28:fe:d2:b9:ea:e3:
+ da:a5:c3:47:69:12:e0:db:f0:f6:19:8b:ed:7b:70:
+ d7:02:d6:ed:87:18:28:2c:04:24:4c:77:e4:48:8a:
+ 1a:c6:3b:9a:d4:0f:ca:fa:75:d2:01:40:5a:8d:79:
+ bf:8b:cf:4b:cf:aa:16:c1:95:e4:ad:4c:8a:3e:17:
+ 91:d4:b1:62:e5:82:e5:80:04:a4:03:7e:8d:bf:da:
+ 7f:a2:0f:97:4f:0c:d3:0d:fb:d7:d1:e5:72:7e:1c:
+ c8:77:ff:5b:9a:0f:b7:ae:05:46:e5:f1:a8:16:ec:
+ 47:a4:17
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Alternative Name:
+ email:info@izenpe.com, DirName:/O=IZENPE S.A. - CIF A01337260-RMerc.Vitoria-Gasteiz T1055 F62 S8/street=Avda del Mediterraneo Etorbidea 14 - 01010 Vitoria-Gasteiz
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 1D:1C:65:0E:A8:F2:25:7B:B4:91:CF:E4:B1:B1:E6:BD:55:74:6C:05
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 78:a6:0c:16:4a:9f:4c:88:3a:c0:cb:0e:a5:16:7d:9f:b9:48:
+ 5f:18:8f:0d:62:36:f6:cd:19:6b:ac:ab:d5:f6:91:7d:ae:71:
+ f3:3f:b3:0e:78:85:9b:95:a4:27:21:47:42:4a:7c:48:3a:f5:
+ 45:7c:b3:0c:8e:51:78:ac:95:13:de:c6:fd:7d:b8:1a:90:4c:
+ ab:92:03:c7:ed:42:01:ce:0f:d8:b1:fa:a2:92:e1:60:6d:ae:
+ 7a:6b:09:aa:c6:29:ee:68:49:67:30:80:24:7a:31:16:39:5b:
+ 7e:f1:1c:2e:dd:6c:09:ad:f2:31:c1:82:4e:b9:bb:f9:be:bf:
+ 2a:85:3f:c0:40:a3:3a:59:fc:59:4b:3c:28:24:db:b4:15:75:
+ ae:0d:88:ba:2e:73:c0:bd:58:87:e5:42:f2:eb:5e:ee:1e:30:
+ 22:99:cb:37:d1:c4:21:6c:81:ec:be:6d:26:e6:1c:e4:42:20:
+ 9e:47:b0:ac:83:59:70:2c:35:d6:af:36:34:b4:cd:3b:f8:32:
+ a8:ef:e3:78:89:fb:8d:45:2c:da:9c:b8:7e:40:1c:61:e7:3e:
+ a2:92:2c:4b:f2:cd:fa:98:b6:29:ff:f3:f2:7b:a9:1f:2e:a0:
+ 93:57:2b:de:85:03:f9:69:37:cb:9e:78:6a:05:b4:c5:31:78:
+ 89:ec:7a:a7:85:e1:b9:7b:3c:de:be:1e:79:84:ce:9f:70:0e:
+ 59:c2:35:2e:90:2a:31:d9:e4:45:7a:41:a4:2e:13:9b:34:0e:
+ 66:7b:49:ab:64:97:d0:46:c3:79:9d:72:50:63:a6:98:5b:06:
+ bd:48:6d:d8:39:83:70:e8:35:f0:05:d1:aa:bc:e3:db:c8:02:
+ ea:7c:fd:82:da:c2:5b:52:35:ae:98:3a:ad:ba:35:93:23:a7:
+ 1f:48:dd:35:46:98:b2:10:68:e4:a5:31:c2:0a:58:2e:19:81:
+ 10:c9:50:75:fc:ea:5a:16:ce:11:d7:ee:ef:50:88:2d:61:ff:
+ 3f:42:73:05:94:43:d5:8e:3c:4e:01:3a:19:a5:1f:46:4e:77:
+ d0:5d:e5:81:22:21:87:fe:94:7d:84:d8:93:ad:d6:68:43:48:
+ b2:db:eb:73:24:e7:91:7f:54:a4:b6:80:3e:9d:a3:3c:4c:72:
+ c2:57:c4:a0:d4:cc:38:27:ce:d5:06:9e:a2:48:d9:e9:9f:ce:
+ 82:70:36:93:9a:3b:df:96:21:e3:59:b7:0c:da:91:37:f0:fd:
+ 59:5a:b3:99:c8:69:6c:43:26:01:35:63:60:55:89:03:3a:75:
+ d8:ba:4a:d9:54:ff:ee:de:80:d8:2d:d1:38:d5:5e:2d:0b:98:
+ 7d:3e:6c:db:fc:26:88:c7
+SHA1 Fingerprint=2F:78:3D:25:52:18:A7:4A:65:39:71:B5:2C:A2:9C:45:15:6F:E9:19
diff --git a/apex/ca-certificates/files/4be590e0.0 b/apex/ca-certificates/files/4be590e0.0
new file mode 100644
index 0000000..4503b51
--- /dev/null
+++ b/apex/ca-certificates/files/4be590e0.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN
+MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu
+VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN
+MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0
+MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7
+ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy
+RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS
+bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF
+/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R
+3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw
+EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy
+9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V
+GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ
+2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV
+WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD
+W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
+BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN
+AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj
+t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV
+DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9
+TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G
+lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW
+mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df
+WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5
++bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ
+tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA
+GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv
+8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 0a:01:42:80:00:00:01:45:23:cf:46:7c:00:00:00:02
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, O=IdenTrust, CN=IdenTrust Public Sector Root CA 1
+ Validity
+ Not Before: Jan 16 17:53:32 2014 GMT
+ Not After : Jan 16 17:53:32 2034 GMT
+ Subject: C=US, O=IdenTrust, CN=IdenTrust Public Sector Root CA 1
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:b6:22:94:fc:a4:48:af:e8:47:6b:0a:fb:27:76:
+ e4:f2:3f:8a:3b:7a:4a:2c:31:2a:8c:8d:b0:a9:c3:
+ 31:6b:a8:77:76:84:26:b6:ac:81:42:0d:08:eb:55:
+ 58:bb:7a:f8:bc:65:7d:f2:a0:6d:8b:a8:47:e9:62:
+ 76:1e:11:ee:08:14:d1:b2:44:16:f4:ea:d0:fa:1e:
+ 2f:5e:db:cb:73:41:ae:bc:00:b0:4a:2b:40:b2:ac:
+ e1:3b:4b:c2:2d:9d:e4:a1:9b:ec:1a:3a:1e:f0:08:
+ b3:d0:e4:24:35:07:9f:9c:b4:c9:52:6d:db:07:ca:
+ 8f:b5:5b:f0:83:f3:4f:c7:2d:a5:c8:ad:cb:95:20:
+ a4:31:28:57:58:5a:e4:8d:1b:9a:ab:9e:0d:0c:f2:
+ 0a:33:39:22:39:0a:97:2e:f3:53:77:b9:44:45:fd:
+ 84:cb:36:20:81:59:2d:9a:6f:6d:48:48:61:ca:4c:
+ df:53:d1:af:52:bc:44:9f:ab:2f:6b:83:72:ef:75:
+ 80:da:06:33:1b:5d:c8:da:63:c6:4d:cd:ac:66:31:
+ cd:d1:de:3e:87:10:36:e1:b9:a4:7a:ef:60:50:b2:
+ cb:ca:a6:56:e0:37:af:ab:34:13:39:25:e8:39:66:
+ e4:98:7a:aa:12:98:9c:59:66:86:3e:ad:f1:b0:ca:
+ 3e:06:0f:7b:f0:11:4b:37:a0:44:6d:7b:cb:a8:8c:
+ 71:f4:d5:b5:91:36:cc:f0:15:c6:2b:de:51:17:b1:
+ 97:4c:50:3d:b1:95:59:7c:05:7d:2d:21:d5:00:bf:
+ 01:67:a2:5e:7b:a6:5c:f2:f7:22:f1:90:0d:93:db:
+ aa:44:51:66:cc:7d:76:03:eb:6a:a8:2a:38:19:97:
+ 76:0d:6b:8a:61:f9:bc:f6:ee:76:fd:70:2b:dd:29:
+ 3c:f8:0a:1e:5b:42:1c:8b:56:2f:55:1b:1c:a1:2e:
+ b5:c7:16:e6:f8:aa:3c:92:8e:69:b6:01:c1:b5:86:
+ 9d:89:0f:0b:38:94:54:e8:ea:dc:9e:3d:25:bc:53:
+ 26:ed:d5:ab:39:aa:c5:40:4c:54:ab:b2:b4:d9:d9:
+ f8:d7:72:db:1c:bc:6d:bd:65:5f:ef:88:35:2a:66:
+ 2f:ee:f6:b3:65:f0:33:8d:7c:98:41:69:46:0f:43:
+ 1c:69:fa:9b:b5:d0:61:6a:cd:ca:4b:d9:4c:90:46:
+ ab:15:59:a1:47:54:29:2e:83:28:5f:1c:c2:a2:ab:
+ 72:17:00:06:8e:45:ec:8b:e2:33:3d:7f:da:19:44:
+ e4:62:72:c3:df:22:c6:f2:56:d4:dd:5f:95:72:ed:
+ 6d:5f:f7:48:03:5b:fd:c5:2a:a0:f6:73:23:84:10:
+ 1b:01:e7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ E3:71:E0:9E:D8:A7:42:D9:DB:71:91:6B:94:93:EB:C3:A3:D1:14:A3
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 47:fa:dd:0a:b0:11:91:38:ad:4d:5d:f7:e5:0e:97:54:19:82:
+ 48:87:54:8c:aa:64:99:d8:5a:fe:88:01:c5:58:a5:99:b1:23:
+ 54:23:b7:6a:1d:20:57:e5:01:62:41:17:d3:09:db:75:cb:6e:
+ 54:90:75:fe:1a:9f:81:0a:c2:dd:d7:f7:09:d0:5b:72:15:e4:
+ 1e:09:6a:3d:33:f3:21:9a:e6:15:7e:ad:51:d5:0d:10:ed:7d:
+ 42:c0:8f:ee:c0:9a:08:d5:41:d6:5c:0e:21:69:6e:80:61:0e:
+ 15:c0:b8:cf:c5:49:12:52:cc:be:3a:cc:d4:2e:38:05:de:35:
+ fd:1f:6f:b8:80:68:98:3d:4d:a0:ca:40:65:d2:73:7c:f5:8b:
+ d9:0a:95:3f:d8:3f:23:6d:1a:d1:2a:24:19:d9:85:b3:17:ef:
+ 78:6e:a9:58:d1:23:d3:c7:13:ed:72:25:7f:5d:b1:73:70:d0:
+ 7f:06:97:09:84:29:80:61:1d:fa:5e:ff:73:ac:a0:e3:89:b8:
+ 1c:71:15:c6:de:31:7f:12:dc:e1:6d:9b:af:e7:e8:9f:75:78:
+ 4c:ab:46:3b:9a:ce:bf:05:18:5d:4d:15:3c:16:9a:19:50:04:
+ 9a:b2:9a:6f:65:8b:52:5f:3c:58:04:28:25:c0:66:61:31:7e:
+ b9:e0:75:b9:1a:a8:81:d6:72:17:b3:c5:03:31:35:11:78:78:
+ a2:e0:e9:30:8c:7f:80:df:58:df:3c:ba:27:96:e2:80:34:6d:
+ e3:98:d3:64:27:ac:48:7e:28:77:5c:c6:25:61:25:f8:85:0c:
+ 65:fa:c4:32:2f:a5:98:05:e4:f8:0b:67:16:16:c6:82:b8:32:
+ 19:f9:f9:b9:79:dc:1f:cd:eb:af:ab:0e:dd:1b:db:45:e4:7a:
+ e7:02:e2:95:5d:fc:69:f0:53:69:61:95:75:79:0b:5e:55:e6:
+ 38:1c:94:a9:59:33:9e:c8:71:74:79:7f:51:89:b6:c8:6a:b8:
+ 30:c8:6a:38:c3:6e:9e:e1:37:16:ea:05:62:4c:5b:12:47:ed:
+ a7:b4:b3:58:56:c7:49:f3:7f:12:68:09:31:71:f0:6d:f8:4e:
+ 47:fb:d6:85:ee:c5:58:40:19:a4:1d:a7:f9:4b:43:37:dc:68:
+ 5a:4f:cf:eb:c2:64:74:de:b4:15:d9:f4:54:54:1a:2f:1c:d7:
+ 97:71:54:90:8e:d9:20:9d:53:2b:7f:ab:8f:e2:ea:30:bc:50:
+ 37:ef:f1:47:b5:7d:7c:2c:04:ec:68:9d:b4:49:44:10:f4:72:
+ 4b:1c:64:e7:fc:e6:6b:90:dd:69:7d:69:fd:00:56:a5:b7:ac:
+ b6:ad:b7:ca:3e:01:ef:9c
+SHA1 Fingerprint=BA:29:41:60:77:98:3F:F4:F3:EF:F2:31:05:3B:2E:EA:6D:4D:45:FD
diff --git a/apex/ca-certificates/files/4c3982f2.0 b/apex/ca-certificates/files/4c3982f2.0
new file mode 100644
index 0000000..b162f02
--- /dev/null
+++ b/apex/ca-certificates/files/4c3982f2.0
@@ -0,0 +1,55 @@
+-----BEGIN CERTIFICATE-----
+MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw
+CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh
+cmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9v
+dCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoXDTQ1MDIxMzExMDEwOVowbDELMAkG
+A1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj
+aCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJvb3Qg
+Q0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7
+KKrxcm1lAEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9Y
+STHMmE5gEYd103KUkE+bECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQD
+AgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAircJRQO9gcS3ujwLEXQNw
+SaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/QwCZ61IygN
+nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 67:74:9d:8d:77:d8:3b:6a:db:22:f4:ff:59:e2:bf:ce
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=GR, O=Hellenic Academic and Research Institutions CA, CN=HARICA TLS ECC Root CA 2021
+ Validity
+ Not Before: Feb 19 11:01:10 2021 GMT
+ Not After : Feb 13 11:01:09 2045 GMT
+ Subject: C=GR, O=Hellenic Academic and Research Institutions CA, CN=HARICA TLS ECC Root CA 2021
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:38:08:fe:b1:a0:96:d2:7a:ac:af:49:3a:d0:c0:
+ e0:c3:3b:28:aa:f1:72:6d:65:00:47:88:84:fc:9a:
+ 26:6b:aa:4b:ba:6c:04:0a:88:5e:17:f2:55:87:fc:
+ 30:b0:34:e2:34:58:57:1a:84:53:e9:30:d9:a9:f2:
+ 96:74:c3:51:1f:58:49:31:cc:98:4e:60:11:87:75:
+ d3:72:94:90:4f:9b:10:25:2a:a8:78:2d:be:90:41:
+ 58:90:15:72:a7:a1:b7
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ C9:1B:53:81:12:FE:04:D5:16:D1:AA:BC:9A:6F:B7:A0:95:19:6E:CA
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:64:02:30:11:de:ae:f8:dc:4e:88:b0:a9:f0:22:ad:c2:51:
+ 40:ef:60:71:2d:ee:8f:02:c4:5d:03:70:49:a4:92:ea:c5:14:
+ 88:70:a6:d3:0d:b0:aa:ca:2c:40:9c:fb:e9:82:6e:9a:02:30:
+ 2b:47:9a:07:c6:d1:c2:81:7c:ca:0b:96:18:41:1b:a3:f4:30:
+ 09:9e:b5:23:28:0d:9f:14:b6:3c:53:a2:4c:06:69:7d:fa:6c:
+ 91:c6:2a:49:45:e6:ec:b7:13:e1:3a:6c
+SHA1 Fingerprint=BC:B0:C1:9D:E9:98:92:70:19:38:57:E9:8D:A7:B4:5D:6E:EE:01:48
diff --git a/apex/ca-certificates/files/5046c355.0 b/apex/ca-certificates/files/5046c355.0
new file mode 100644
index 0000000..73fd8d6
--- /dev/null
+++ b/apex/ca-certificates/files/5046c355.0
@@ -0,0 +1,127 @@
+-----BEGIN CERTIFICATE-----
+MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE
+BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu
+IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow
+RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY
+U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv
+Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br
+YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF
+nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH
+6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt
+eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/
+c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ
+MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH
+HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf
+jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6
+5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB
+rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
+F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c
+wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0
+cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB
+AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp
+WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9
+xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ
+2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ
+IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8
+aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X
+em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR
+dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/
+OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+
+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy
+tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 5700383053117599563 (0x4f1bd42f54bb2f4b)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=CH, O=SwissSign AG, CN=SwissSign Silver CA - G2
+ Validity
+ Not Before: Oct 25 08:32:46 2006 GMT
+ Not After : Oct 25 08:32:46 2036 GMT
+ Subject: C=CH, O=SwissSign AG, CN=SwissSign Silver CA - G2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:c4:f1:87:7f:d3:78:31:f7:38:c9:f8:c3:99:43:
+ bc:c7:f7:bc:37:e7:4e:71:ba:4b:8f:a5:73:1d:5c:
+ 6e:98:ae:03:57:ae:38:37:43:2f:17:3d:1f:c8:ce:
+ 68:10:c1:78:ae:19:03:2b:10:fa:2c:79:83:f6:e8:
+ b9:68:b9:55:f2:04:44:a7:39:f9:fc:04:8b:1e:f1:
+ a2:4d:27:f9:61:7b:ba:b7:e5:a2:13:b6:eb:61:3e:
+ d0:6c:d1:e6:fb:fa:5e:ed:1d:b4:9e:a0:35:5b:a1:
+ 92:cb:f0:49:92:fe:85:0a:05:3e:e6:d9:0b:e2:4f:
+ bb:dc:95:37:fc:91:e9:32:35:22:d1:1f:3a:4e:27:
+ 85:9d:b0:15:94:32:da:61:0d:47:4d:60:42:ae:92:
+ 47:e8:83:5a:50:58:e9:8a:8b:b9:5d:a1:dc:dd:99:
+ 4a:1f:36:67:bb:48:e4:83:b6:37:eb:48:3a:af:0f:
+ 67:8f:17:07:e8:04:ca:ef:6a:31:87:d4:c0:b6:f9:
+ 94:71:7b:67:64:b8:b6:91:4a:42:7b:65:2e:30:6a:
+ 0c:f5:90:ee:95:e6:f2:cd:82:ec:d9:a1:4a:ec:f6:
+ b2:4b:e5:45:85:e6:6d:78:93:04:2e:9c:82:6d:36:
+ a9:c4:31:64:1f:86:83:0b:2a:f4:35:0a:78:c9:55:
+ cf:41:b0:47:e9:30:9f:99:be:61:a8:06:84:b9:28:
+ 7a:5f:38:d9:1b:a9:38:b0:83:7f:73:c1:c3:3b:48:
+ 2a:82:0f:21:9b:b8:cc:a8:35:c3:84:1b:83:b3:3e:
+ be:a4:95:69:01:3a:89:00:78:04:d9:c9:f4:99:19:
+ ab:56:7e:5b:8b:86:39:15:91:a4:10:2c:09:32:80:
+ 60:b3:93:c0:2a:b6:18:0b:9d:7e:8d:49:f2:10:4a:
+ 7f:f9:d5:46:2f:19:92:a3:99:a7:26:ac:bb:8c:3c:
+ e6:0e:bc:47:07:dc:73:51:f1:70:64:2f:08:f9:b4:
+ 47:1d:30:6c:44:ea:29:37:85:92:68:66:bc:83:38:
+ fe:7b:39:2e:d3:50:f0:1f:fb:5e:60:b6:a9:a6:fa:
+ 27:41:f1:9b:18:72:f2:f5:84:74:4a:c9:67:c4:54:
+ ae:48:64:df:8c:d1:6e:b0:1d:e1:07:8f:08:1e:99:
+ 9c:71:e9:4c:d8:a5:f7:47:12:1f:74:d1:51:9e:86:
+ f3:c2:a2:23:40:0b:73:db:4b:a6:e7:73:06:8c:c1:
+ a0:e9:c1:59:ac:46:fa:e6:2f:f8:cf:71:9c:46:6d:
+ b9:c4:15:8d:38:79:03:45:48:ef:c4:5d:d7:08:ee:
+ 87:39:22:86:b2:0d:0f:58:43:f7:71:a9:48:2e:fd:
+ ea:d6:1f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 17:A0:CD:C1:E4:41:B6:3A:5B:3B:CB:45:9D:BD:1C:C2:98:FA:86:58
+ X509v3 Authority Key Identifier:
+ 17:A0:CD:C1:E4:41:B6:3A:5B:3B:CB:45:9D:BD:1C:C2:98:FA:86:58
+ X509v3 Certificate Policies:
+ Policy: 2.16.756.1.89.1.3.1.1
+ CPS: http://repository.swisssign.com/
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 73:c6:81:e0:27:d2:2d:0f:e0:95:30:e2:9a:41:7f:50:2c:5f:
+ 5f:62:61:a9:86:6a:69:18:0c:74:49:d6:5d:84:ea:41:52:18:
+ 6f:58:ad:50:56:20:6a:c6:bd:28:69:58:91:dc:91:11:35:a9:
+ 3a:1d:bc:1a:a5:60:9e:d8:1f:7f:45:91:69:d9:7e:bb:78:72:
+ c1:06:0f:2a:ce:8f:85:70:61:ac:a0:cd:0b:b8:39:29:56:84:
+ 32:4e:86:bb:3d:c4:2a:d9:d7:1f:72:ee:fe:51:a1:22:41:b1:
+ 71:02:63:1a:82:b0:62:ab:5e:57:12:1f:df:cb:dd:75:a0:c0:
+ 5d:79:90:8c:1b:e0:50:e6:de:31:fe:98:7b:70:5f:a5:90:d8:
+ ad:f8:02:b6:6f:d3:60:dd:40:4b:22:c5:3d:ad:3a:7a:9f:1a:
+ 1a:47:91:79:33:ba:82:dc:32:69:03:96:6e:1f:4b:f0:71:fe:
+ e3:67:72:a0:b1:bf:5c:8b:e4:fa:99:22:c7:84:b9:1b:8d:23:
+ 97:3f:ed:25:e0:cf:65:bb:f5:61:04:ef:dd:1e:b2:5a:41:22:
+ 5a:a1:9f:5d:2c:e8:5b:c9:6d:a9:0c:0c:78:aa:60:c6:56:8f:
+ 01:5a:0c:68:bc:69:19:79:c4:1f:7e:97:05:bf:c5:e9:24:51:
+ 5e:d4:d5:4b:53:ed:d9:23:5a:36:03:65:a3:c1:03:ad:41:30:
+ f3:46:1b:85:90:af:65:b5:d5:b1:e4:16:5b:78:75:1d:97:7a:
+ 6d:59:a9:2a:8f:7b:de:c3:87:89:10:99:49:73:78:c8:3d:bd:
+ 51:35:74:2a:d5:f1:7e:69:1b:2a:bb:3b:bd:25:b8:9a:5a:3d:
+ 72:61:90:66:87:ee:0c:d6:4d:d4:11:74:0b:6a:fe:0b:03:fc:
+ a3:55:57:89:fe:4a:cb:ae:5b:17:05:c8:f2:8d:23:31:53:38:
+ d2:2d:6a:3f:82:b9:8d:08:6a:f7:5e:41:74:6e:c3:11:7e:07:
+ ac:29:60:91:3f:38:ca:57:10:0d:bd:30:2f:c7:a5:e6:41:a0:
+ da:ae:05:87:9a:a0:a4:65:6c:4c:09:0c:89:ba:b8:d3:b9:c0:
+ 93:8a:30:fa:8d:e5:9a:6b:15:01:4e:67:aa:da:62:56:3e:84:
+ 08:66:d2:c4:36:7d:a7:3e:10:fc:88:e0:d4:80:e5:00:bd:aa:
+ f3:4e:06:a3:7a:6a:f9:62:72:e3:09:4f:eb:9b:0e:01:23:f1:
+ 9f:bb:7c:dc:dc:6c:11:97:25:b2:f2:b4:63:14:d2:06:2a:67:
+ 8c:83:f5:ce:ea:07:d8:9a:6a:1e:ec:e4:0a:bb:2a:4c:eb:09:
+ 60:39:ce:ca:62:d8:2e:6e
+SHA1 Fingerprint=9B:AA:E5:9F:56:EE:21:CB:43:5A:BE:25:93:DF:A7:F0:40:D1:1D:CB
diff --git a/apex/ca-certificates/files/52b525c7.0 b/apex/ca-certificates/files/52b525c7.0
new file mode 100644
index 0000000..391f6a3
--- /dev/null
+++ b/apex/ca-certificates/files/52b525c7.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL
+BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc
+BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00
+MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
+aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG
+SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV
+wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe
+rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341
+68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh
+4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp
+UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o
+abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc
+3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G
+KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt
+hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO
+Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt
+zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
+BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD
+ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC
+MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2
+cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN
+qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5
+YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv
+b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2
+8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k
+NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj
+ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp
+q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt
+nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 78:58:5f:2e:ad:2c:19:4b:e3:37:07:35:34:13:28:b5:96:d4:65:93
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 1 G3
+ Validity
+ Not Before: Jan 12 17:27:44 2012 GMT
+ Not After : Jan 12 17:27:44 2042 GMT
+ Subject: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 1 G3
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:a0:be:50:10:8e:e9:f2:6c:40:b4:04:9c:85:b9:
+ 31:ca:dc:2d:e4:11:a9:04:3c:1b:55:c1:e7:58:30:
+ 1d:24:b4:c3:ef:85:de:8c:2c:e1:c1:3d:df:82:e6:
+ 4f:ad:47:87:6c:ec:5b:49:c1:4a:d5:bb:8f:ec:87:
+ ac:7f:82:9a:86:ec:3d:03:99:52:01:d2:35:9e:ac:
+ da:f0:53:c9:66:3c:d4:ac:02:01:da:24:d3:3b:a8:
+ 02:46:af:a4:1c:e3:f8:73:58:76:b7:f6:0e:90:0d:
+ b5:f0:cf:cc:fa:f9:c6:4c:e5:c3:86:30:0a:8d:17:
+ 7e:35:eb:c5:df:bb:0e:9c:c0:8d:87:e3:88:38:85:
+ 67:fa:3e:c7:ab:e0:13:9c:05:18:98:cf:93:f5:b1:
+ 92:b4:fc:23:d3:cf:d5:c4:27:49:e0:9e:3c:9b:08:
+ a3:8b:5d:2a:21:e0:fc:39:aa:53:da:7d:7e:cf:1a:
+ 09:53:bc:5d:05:04:cf:a1:4a:8f:8b:76:82:0d:a1:
+ f8:d2:c7:14:77:5b:90:36:07:81:9b:3e:06:fa:52:
+ 5e:63:c5:a6:00:fe:a5:e9:52:1b:52:b5:92:39:72:
+ 03:09:62:bd:b0:60:16:6e:a6:dd:25:c2:03:66:dd:
+ f3:04:d1:40:e2:4e:8b:86:f4:6f:e5:83:a0:27:84:
+ 5e:04:c1:f5:90:bd:30:3d:c4:ef:a8:69:bc:38:9b:
+ a4:a4:96:d1:62:da:69:c0:01:96:ae:cb:c4:51:34:
+ ea:0c:aa:ff:21:8e:59:8f:4a:5c:e4:61:9a:a7:d2:
+ e9:2a:78:8d:51:3d:3a:15:ee:a2:59:8e:a9:5c:de:
+ c5:f9:90:22:e5:88:45:71:dd:91:99:6c:7a:9f:3d:
+ 3d:98:7c:5e:f6:be:16:68:a0:5e:ae:0b:23:fc:5a:
+ 0f:aa:22:76:2d:c9:a1:10:1d:e4:d3:44:23:90:88:
+ 9f:c6:2a:e6:d7:f5:9a:b3:58:1e:2f:30:89:08:1b:
+ 54:a2:b5:98:23:ec:08:77:1c:95:5d:61:d1:cb:89:
+ 9c:5f:a2:4a:91:9a:ef:21:aa:49:16:08:a8:bd:61:
+ 28:31:c9:74:ad:85:f6:d9:c5:b1:8b:d1:e5:10:32:
+ 4d:5f:8b:20:3a:3c:49:1f:33:85:59:0d:db:cb:09:
+ 75:43:69:73:fb:6b:71:7d:f0:df:c4:4c:7d:c6:a3:
+ 2e:c8:95:79:cb:73:a2:8e:4e:4d:24:fb:5e:e4:04:
+ be:72:1b:a6:27:2d:49:5a:99:7a:d7:5c:09:20:b7:
+ 7f:94:b9:4f:f1:0d:1c:5e:88:42:1b:11:b7:e7:91:
+ db:9e:6c:f4:6a:df:8c:06:98:03:ad:cc:28:ef:a5:
+ 47:f3:53
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ A3:97:D6:F3:5E:A2:10:E1:AB:45:9F:3C:17:64:3C:EE:01:70:9C:CC
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 18:fa:5b:75:fc:3e:7a:c7:5f:77:c7:ca:df:cf:5f:c3:12:c4:
+ 40:5d:d4:32:aa:b8:6a:d7:d5:15:15:46:98:23:a5:e6:90:5b:
+ 18:99:4c:e3:ad:42:a3:82:31:36:88:cd:e9:fb:c4:04:96:48:
+ 8b:01:c7:8d:01:cf:5b:33:06:96:46:66:74:1d:4f:ed:c1:b6:
+ b9:b4:0d:61:cc:63:7e:d7:2e:77:8c:96:1c:2a:23:68:6b:85:
+ 57:76:70:33:13:fe:e1:4f:a6:23:77:18:fa:1a:8c:e8:bd:65:
+ c9:cf:3f:f4:c9:17:dc:eb:c7:bc:c0:04:2e:2d:46:2f:69:66:
+ c3:1b:8f:fe:ec:3e:d3:ca:94:bf:76:0a:25:0d:a9:7b:02:1c:
+ a9:d0:3b:5f:0b:c0:81:3a:3d:64:e1:bf:a7:2d:4e:bd:4d:c4:
+ d8:29:c6:22:18:d0:c5:ac:72:02:82:3f:aa:3a:a2:3a:22:97:
+ 31:dd:08:63:c3:75:14:b9:60:28:2d:5b:68:e0:16:a9:66:82:
+ 23:51:f5:eb:53:d8:31:9b:7b:e9:b7:9d:4b:eb:88:16:cf:f9:
+ 5d:38:8a:49:30:8f:ed:f1:eb:19:f4:77:1a:31:18:4d:67:54:
+ 6c:2f:6f:65:f9:db:3d:ec:21:ec:5e:f4:f4:8b:ca:60:65:54:
+ d1:71:64:f4:f9:a6:a3:81:33:36:33:71:f0:a4:78:5f:4e:ad:
+ 83:21:de:34:49:8d:e8:59:ac:9d:f2:76:5a:36:f2:13:f4:af:
+ e0:09:c7:61:2a:6c:f7:e0:9d:ae:bb:86:4a:28:6f:2e:ee:b4:
+ 79:cd:90:33:c3:b3:76:fa:f5:f0:6c:9d:01:90:fa:9e:90:f6:
+ 9c:72:cf:47:da:c3:1f:e4:35:20:53:f2:54:d1:df:61:83:a6:
+ 02:e2:25:38:de:85:32:2d:5e:73:90:52:5d:42:c4:ce:3d:4b:
+ e1:f9:19:84:1d:d5:a2:50:cc:41:fb:41:14:c3:bd:d6:c9:5a:
+ a3:63:66:02:80:bd:05:3a:3b:47:9c:ec:00:26:4c:f5:88:51:
+ bf:a8:23:7f:18:07:b0:0b:ed:8b:26:a1:64:d3:61:4a:eb:5c:
+ 9f:de:b3:af:67:03:b3:1f:dd:6d:5d:69:68:69:ab:5e:3a:ec:
+ 7c:69:bc:c7:3b:85:4e:9e:15:b9:b4:15:4f:c3:95:7a:58:d7:
+ c9:6c:e9:6c:b9:f3:29:63:5e:b4:2c:f0:2d:3d:ed:5a:65:e0:
+ a9:5b:40:c2:48:99:81:6d:9e:1f:06:2a:3c:12:b4:8b:0f:9b:
+ a2:24:f0:a6:8d:d6:7a:e0:4b:b6:64:96:63:95:84:c2:4a:cd:
+ 1c:2e:24:87:33:60:e5:c3
+SHA1 Fingerprint=1B:8E:EA:57:96:29:1A:C9:39:EA:B8:0A:81:1A:73:73:C0:93:79:67
diff --git a/apex/ca-certificates/files/53a1b57a.0 b/apex/ca-certificates/files/53a1b57a.0
new file mode 100644
index 0000000..acf982e
--- /dev/null
+++ b/apex/ca-certificates/files/53a1b57a.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBP
+MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0
+ZC4xGzAZBgNVBAMMEkhpUEtJIFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRa
+Fw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3
+YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kgUm9vdCBDQSAtIEcx
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0o9Qw
+qNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twv
+Vcg3Px+kwJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6
+lZgRZq2XNdZ1AYDgr/SEYYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnz
+Qs7ZngyzsHeXZJzA9KMuH5UHsBffMNsAGJZMoYFL3QRtU6M9/Aes1MU3guvklQgZ
+KILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfdhSi8MEyr48KxRURHH+CK
+FgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj1jOXTyFj
+HluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDr
+y+K49a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ
+/W3c1pzAtH2lsN0/Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgM
+a/aOEmem8rJY5AIJEzypuxC00jBF8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6
+fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
+HQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQDAgGGMA0GCSqG
+SIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi
+7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqc
+SE5XCV0vrPSltJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6Fza
+ZsT0pPBWGTMpWmWSBUdGSquEwx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9Tc
+XzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07QJNBAsNB1CI69aO4I1258EHBGG3zg
+iLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv5wiZqAxeJoBF1Pho
+L5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+GpzjLrF
+Ne85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wr
+kkVbbiVghUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+
+vhV4nYWBSipX3tUZQ9rbyltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQU
+YDksswBVLuT1sw5XxJFBAJw/6KXf6vb/yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 2d:dd:ac:ce:62:97:94:a1:43:e8:b0:cd:76:6a:5e:60
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=TW, O=Chunghwa Telecom Co., Ltd., CN=HiPKI Root CA - G1
+ Validity
+ Not Before: Feb 22 09:46:04 2019 GMT
+ Not After : Dec 31 15:59:59 2037 GMT
+ Subject: C=TW, O=Chunghwa Telecom Co., Ltd., CN=HiPKI Root CA - G1
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:f4:1e:7f:52:73:32:0c:73:e4:bd:13:74:a3:d4:
+ 30:a8:d0:ae:4b:d8:b6:df:75:47:66:f4:7c:e7:39:
+ 04:1e:6a:70:20:d2:5a:47:72:67:55:f4:a5:e8:9d:
+ d5:1e:21:a1:f0:67:ba:cc:21:68:be:44:53:bf:8d:
+ f9:e2:dc:2f:55:c8:37:3f:1f:a4:c0:9c:b3:e4:77:
+ 5c:a0:46:fe:77:fa:1a:a0:38:ea:ed:9a:72:de:2b:
+ bd:94:57:3a:ba:ec:79:e7:5f:7d:42:64:39:7a:26:
+ 36:f7:24:f0:d5:2f:ba:95:98:11:66:ad:97:35:d6:
+ 75:01:80:e0:af:f4:84:61:8c:0d:1e:5f:7c:87:96:
+ 5e:41:af:eb:87:ea:f8:5d:f1:2e:88:05:3e:4c:22:
+ bb:da:1f:2a:dd:52:46:64:39:f3:42:ce:d9:9e:0c:
+ b3:b0:77:97:64:9c:c0:f4:a3:2e:1f:95:07:b0:17:
+ df:30:db:00:18:96:4c:a1:81:4b:dd:04:6d:53:a3:
+ 3d:fc:07:ac:d4:c5:37:82:eb:e4:95:08:19:28:82:
+ d2:42:3a:a3:d8:53:ec:79:89:60:48:60:c8:72:92:
+ 50:dc:03:8f:83:3f:b2:42:57:5a:db:6a:e9:11:97:
+ dd:85:28:bc:30:4c:ab:e3:c2:b1:45:44:47:1f:e0:
+ 8a:16:07:96:d2:21:0f:53:c0:ed:a9:7e:d4:4e:ec:
+ 9b:09:ec:af:42:ac:30:d6:bf:d1:10:45:e0:a6:16:
+ b2:a5:c5:d3:4f:73:94:33:71:02:a1:6a:a3:d6:33:
+ 97:4f:21:63:1e:5b:8f:d9:c1:5e:45:71:77:0f:81:
+ 5d:5f:21:9a:ad:83:cc:fa:5e:d6:8d:23:5f:1b:3d:
+ 41:af:20:75:66:5a:4a:f6:9f:fb:ab:18:f7:71:c0:
+ b6:1d:31:ec:3b:20:eb:cb:e2:b8:f5:ae:92:b2:f7:
+ e1:84:4b:f2:a2:f2:93:9a:22:9e:d3:14:6f:36:54:
+ bd:1f:5e:59:15:b9:73:a8:c1:7c:6f:7b:62:e9:16:
+ 6c:47:5a:65:f3:0e:11:9b:46:d9:fd:6d:dc:d6:9c:
+ c0:b4:7d:a5:b0:dd:3f:56:6f:a1:f9:f6:e4:12:48:
+ fd:06:7f:12:57:b6:a9:23:4f:5b:03:c3:e0:71:2a:
+ 23:b7:f7:b0:b1:3b:bc:98:bd:d6:98:a8:0c:6b:f6:
+ 8e:12:67:a6:f2:b2:58:e4:02:09:13:3c:a9:bb:10:
+ b4:d2:30:45:f1:ec:f7:00:11:df:65:f8:dc:2b:43:
+ 55:bf:16:97:c4:0f:d5:2c:61:84:aa:72:86:fe:e6:
+ 3a:7e:c2:3f:7d:ee:fc:2f:14:3e:e6:85:dd:50:6f:
+ b7:49:ed
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ F2:77:17:FA:5E:A8:FE:F6:3D:71:D5:68:BA:C9:46:0C:38:D8:AF:B0
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 50:51:f0:75:dc:70:04:e3:ff:aa:75:d4:71:a2:cb:9e:8f:a8:
+ a9:d3:af:75:c7:54:cf:3a:1c:04:99:22:ac:c4:11:e2:ef:33:
+ 4a:a6:23:1d:0e:0d:47:d8:37:c7:6f:af:34:7f:4f:81:6b:35:
+ 4f:e9:72:a5:31:e2:78:e7:f7:4e:94:18:5b:40:7d:cf:6b:21:
+ 54:86:e6:95:7a:fb:c6:ca:ea:9c:48:4e:57:09:5d:2f:ac:f4:
+ a5:b4:97:33:58:d5:ac:79:a9:cc:5f:f9:85:fa:52:c5:8d:f8:
+ 91:14:eb:3a:0d:17:d0:52:c2:7b:e3:c2:73:8e:46:78:06:38:
+ 2c:e8:5c:da:66:c4:f4:a4:f0:56:19:33:29:5a:65:92:05:47:
+ 46:4a:ab:84:c3:1e:27:a1:1f:11:92:99:27:75:93:0f:bc:36:
+ 3b:97:57:8f:26:5b:0c:bb:9c:0f:d4:6e:30:07:d4:dc:5f:36:
+ 68:66:39:83:96:27:26:8a:c8:c4:39:fe:9a:21:6f:d5:72:86:
+ e9:7f:62:e5:97:4e:d0:24:d0:40:b0:d0:75:08:8e:bd:68:ee:
+ 08:d7:6e:7c:10:70:46:1b:7c:e0:88:b2:9e:72:86:99:01:e3:
+ bf:9f:49:19:b4:25:be:56:65:ae:17:63:e5:1e:df:e8:ff:47:
+ a5:bf:e1:26:05:84:e4:b0:c0:af:e7:08:99:a8:0c:5e:26:80:
+ 45:d4:f8:68:2f:96:8f:ae:e2:4a:1c:9c:16:0c:13:6f:38:87:
+ f6:bb:c8:34:5f:92:03:51:79:70:a6:df:cb:f5:99:4d:79:cd:
+ 4e:bc:57:9f:43:4e:6b:2e:2b:18:f8:6a:73:8c:ba:c5:35:ef:
+ 39:6a:41:1e:cf:71:a8:a2:b2:86:07:5b:3a:c9:e1:ef:3f:65:
+ 04:80:47:32:44:70:95:4e:31:67:6a:74:5b:10:45:75:ea:b0:
+ 9f:d0:e6:35:fe:4e:9f:8b:cc:2b:92:45:5b:6e:25:60:85:46:
+ cd:d1:aa:b0:76:66:93:77:96:be:83:be:38:b6:24:4e:26:0b:
+ cc:ed:7a:56:1a:e0:e9:5a:c6:64:ad:4c:7a:00:48:44:2f:b9:
+ 40:bb:13:3e:be:15:78:9d:85:81:4a:2a:57:de:d5:19:43:da:
+ db:ca:5b:47:86:83:0b:3f:b6:0d:76:78:73:79:22:5e:b1:80:
+ 1f:cf:be:d1:3f:56:10:98:2b:95:87:a1:1f:9d:64:14:60:39:
+ 2c:b3:00:55:2e:e4:f5:b3:0e:57:c4:91:41:00:9c:3f:e8:a5:
+ df:ea:f6:ff:c8:f0:ad:6d:52:a8:17:ab:9b:61:fc:12:51:35:
+ e4:25:fd:af:aa:6a:86:39
+SHA1 Fingerprint=6A:92:E4:A8:EE:1B:EC:96:45:37:E3:29:57:49:CD:96:E3:E5:D2:60
diff --git a/apex/ca-certificates/files/583d0756.0 b/apex/ca-certificates/files/583d0756.0
new file mode 100644
index 0000000..7486f7b
--- /dev/null
+++ b/apex/ca-certificates/files/583d0756.0
@@ -0,0 +1,125 @@
+-----BEGIN CERTIFICATE-----
+MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV
+BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE
+CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy
+dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy
+MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G
+A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD
+DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq
+M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf
+OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa
+4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9
+HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR
+aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA
+b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ
+Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV
+PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO
+pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu
+UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY
+MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV
+HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4
+9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW
+s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5
+Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg
+cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM
+79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz
+/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt
+ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm
+Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK
+QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ
+w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi
+S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07
+mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 6248227494352943350 (0x56b629cd34bc78f6)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=Texas, L=Houston, O=SSL Corporation, CN=SSL.com EV Root Certification Authority RSA R2
+ Validity
+ Not Before: May 31 18:14:37 2017 GMT
+ Not After : May 30 18:14:37 2042 GMT
+ Subject: C=US, ST=Texas, L=Houston, O=SSL Corporation, CN=SSL.com EV Root Certification Authority RSA R2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:8f:36:65:40:e1:d6:4d:c0:d7:b4:e9:46:da:6b:
+ ea:33:47:cd:4c:f9:7d:7d:be:bd:2d:3d:f0:db:78:
+ e1:86:a5:d9:ba:09:57:68:ed:57:3e:a0:d0:08:41:
+ 83:e7:28:41:24:1f:e3:72:15:d0:01:1a:fb:5e:70:
+ 23:b2:cb:9f:39:e3:cf:c5:4e:c6:92:6d:26:c6:7b:
+ bb:b3:da:27:9d:0a:86:e9:81:37:05:fe:f0:71:71:
+ ec:c3:1c:e9:63:a2:17:14:9d:ef:1b:67:d3:85:55:
+ 02:02:d6:49:c9:cc:5a:e1:b1:f7:6f:32:9f:c9:d4:
+ 3b:88:41:a8:9c:bd:cb:ab:db:6d:7b:09:1f:a2:4c:
+ 72:90:da:2b:08:fc:cf:3c:54:ce:67:0f:a8:cf:5d:
+ 96:19:0b:c4:e3:72:eb:ad:d1:7d:1d:27:ef:92:eb:
+ 10:bf:5b:eb:3b:af:cf:80:dd:c1:d2:96:04:5b:7a:
+ 7e:a4:a9:3c:38:76:a4:62:8e:a0:39:5e:ea:77:cf:
+ 5d:00:59:8f:66:2c:3e:07:a2:a3:05:26:11:69:97:
+ ea:85:b7:0f:96:0b:4b:c8:40:e1:50:ba:2e:8a:cb:
+ f7:0f:9a:22:e7:7f:9a:37:13:cd:f2:4d:13:6b:21:
+ d1:c0:cc:22:f2:a1:46:f6:44:69:9c:ca:61:35:07:
+ 00:6f:d6:61:08:11:ea:ba:b8:f6:e9:b3:60:e5:4d:
+ b9:ec:9f:14:66:c9:57:58:db:cd:87:69:f8:8a:86:
+ 12:03:47:bf:66:13:76:ac:77:7d:34:24:85:83:cd:
+ d7:aa:9c:90:1a:9f:21:2c:7f:78:b7:64:b8:d8:e8:
+ a6:f4:78:b3:55:cb:84:d2:32:c4:78:ae:a3:8f:61:
+ dd:ce:08:53:ad:ec:88:fc:15:e4:9a:0d:e6:9f:1a:
+ 77:ce:4c:8f:b8:14:15:3d:62:9c:86:38:06:00:66:
+ 12:e4:59:76:5a:53:c0:02:98:a2:10:2b:68:44:7b:
+ 8e:79:ce:33:4a:76:aa:5b:81:16:1b:b5:8a:d8:d0:
+ 00:7b:5e:62:b4:09:d6:86:63:0e:a6:05:95:49:ba:
+ 28:8b:88:93:b2:34:1c:d8:a4:55:6e:b7:1c:d0:de:
+ 99:55:3b:23:f4:22:e0:f9:29:66:26:ec:20:50:77:
+ db:4a:0b:8f:be:e5:02:60:70:41:5e:d4:ae:50:39:
+ 22:14:26:cb:b2:3b:73:74:55:47:07:79:81:39:a8:
+ 30:13:44:e5:04:8a:ae:96:13:25:42:0f:b9:53:c4:
+ 9b:fc:cd:e4:1c:de:3c:fa:ab:d6:06:4a:1f:67:a6:
+ 98:30:1c:dd:2c:db:dc:18:95:57:66:c6:ff:5c:8b:
+ 56:f5:77
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Authority Key Identifier:
+ F9:60:BB:D4:E3:D5:34:F6:B8:F5:06:80:25:A7:73:DB:46:69:A8:9E
+ X509v3 Subject Key Identifier:
+ F9:60:BB:D4:E3:D5:34:F6:B8:F5:06:80:25:A7:73:DB:46:69:A8:9E
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 56:b3:8e:cb:0a:9d:49:8e:bf:a4:c4:91:bb:66:17:05:51:98:
+ 75:fb:e5:50:2c:7a:9e:f1:14:fa:ab:d3:8a:3e:ff:91:29:8f:
+ 63:8b:d8:b4:a9:54:01:0d:be:93:86:2f:f9:4a:6d:c7:5e:f5:
+ 57:f9:ca:55:1c:12:be:47:0f:36:c5:df:6a:b7:db:75:c2:47:
+ 25:7f:b9:f1:63:f8:68:2d:55:04:d1:f2:8d:b0:a4:cf:bc:3c:
+ 5e:1f:78:e7:a5:a0:20:70:b0:04:c5:b7:f7:72:a7:de:22:0d:
+ bd:33:25:46:8c:64:92:26:e3:3e:2e:63:96:da:9b:8c:3d:f8:
+ 18:09:d7:03:cc:7d:86:82:e0:ca:04:07:51:50:d7:ff:92:d5:
+ 0c:ef:da:86:9f:99:d7:eb:b7:af:68:e2:39:26:94:ba:68:b7:
+ bf:83:d3:ea:7a:67:3d:62:67:ae:25:e5:72:e8:e2:e4:ec:ae:
+ 12:f6:4b:2b:3c:9f:e9:b0:40:f3:38:54:b3:fd:b7:68:c8:da:
+ c6:8f:51:3c:b2:fb:91:dc:1c:e7:9b:9d:e1:b7:0d:72:8f:e2:
+ a4:c4:a9:78:f9:eb:14:ac:c6:43:05:c2:65:39:28:18:02:c3:
+ 82:b2:9d:05:be:65:ed:96:5f:65:74:3c:fb:09:35:2e:7b:9c:
+ 13:fd:1b:0f:5d:c7:6d:81:3a:56:0f:cc:3b:e1:af:02:2f:22:
+ ac:46:ca:46:3c:a0:1c:4c:d6:44:b4:5e:2e:5c:15:66:09:e1:
+ 26:29:fe:c6:52:61:ba:b1:73:ff:c3:0c:9c:e5:6c:6a:94:3f:
+ 14:ca:40:16:95:84:f3:59:a9:ac:5f:4c:61:93:6d:d1:3b:cc:
+ a2:95:0c:22:a6:67:67:44:2e:b9:d9:d2:8a:41:b3:66:0b:5a:
+ fb:7d:23:a5:f2:1a:b0:ff:de:9b:83:94:2e:d1:3f:df:92:b7:
+ 91:af:05:3b:65:c7:a0:6c:b1:cd:62:12:c3:90:1b:e3:25:ce:
+ 34:bc:6f:77:76:b1:10:c3:f7:05:1a:c0:d6:af:74:62:48:17:
+ 77:92:69:90:61:1c:de:95:80:74:54:8f:18:1c:c3:f3:03:d0:
+ bf:a4:43:75:86:53:18:7a:0a:2e:09:1c:36:9f:91:fd:82:8a:
+ 22:4b:d1:0e:50:25:dd:cb:03:0c:17:c9:83:00:08:4e:35:4d:
+ 8a:8b:ed:f0:02:94:66:2c:44:7f:cb:95:27:96:17:ad:09:30:
+ ac:b6:71:17:6e:8b:17:f6:1c:09:d4:2d:3b:98:a5:71:d3:54:
+ 13:d9:60:f3:f5:4b:66:4f:fa:f1:ee:20:12:8d:b4:ac:57:b1:
+ 45:63:a1:ac:76:a9:c2:fb
+SHA1 Fingerprint=74:3A:F0:52:9B:D0:32:A0:F4:4A:83:CD:D4:BA:A9:7B:7C:2E:C4:9A
diff --git a/apex/ca-certificates/files/5a3f0ff8.0 b/apex/ca-certificates/files/5a3f0ff8.0
new file mode 100644
index 0000000..59f0a07
--- /dev/null
+++ b/apex/ca-certificates/files/5a3f0ff8.0
@@ -0,0 +1,87 @@
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB
+gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
+BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw
+MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl
+YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P
+RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3
+UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI
+2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8
+Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp
++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+
+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O
+nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW
+/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g
+PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u
+QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY
+SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv
+IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
+RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4
+zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd
+BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB
+ZQ==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 4e:81:2d:8a:82:65:e0:0b:02:ee:3e:35:02:46:e5:3d
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO Certification Authority
+ Validity
+ Not Before: Dec 1 00:00:00 2006 GMT
+ Not After : Dec 31 23:59:59 2029 GMT
+ Subject: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO Certification Authority
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:d0:40:8b:8b:72:e3:91:1b:f7:51:c1:1b:54:04:
+ 98:d3:a9:bf:c1:e6:8a:5d:3b:87:fb:bb:88:ce:0d:
+ e3:2f:3f:06:96:f0:a2:29:50:99:ae:db:3b:a1:57:
+ b0:74:51:71:cd:ed:42:91:4d:41:fe:a9:c8:d8:6a:
+ 86:77:44:bb:59:66:97:50:5e:b4:d4:2c:70:44:cf:
+ da:37:95:42:69:3c:30:c4:71:b3:52:f0:21:4d:a1:
+ d8:ba:39:7c:1c:9e:a3:24:9d:f2:83:16:98:aa:16:
+ 7c:43:9b:15:5b:b7:ae:34:91:fe:d4:62:26:18:46:
+ 9a:3f:eb:c1:f9:f1:90:57:eb:ac:7a:0d:8b:db:72:
+ 30:6a:66:d5:e0:46:a3:70:dc:68:d9:ff:04:48:89:
+ 77:de:b5:e9:fb:67:6d:41:e9:bc:39:bd:32:d9:62:
+ 02:f1:b1:a8:3d:6e:37:9c:e2:2f:e2:d3:a2:26:8b:
+ c6:b8:55:43:88:e1:23:3e:a5:d2:24:39:6a:47:ab:
+ 00:d4:a1:b3:a9:25:fe:0d:3f:a7:1d:ba:d3:51:c1:
+ 0b:a4:da:ac:38:ef:55:50:24:05:65:46:93:34:4f:
+ 2d:8d:ad:c6:d4:21:19:d2:8e:ca:05:61:71:07:73:
+ 47:e5:8a:19:12:bd:04:4d:ce:4e:9c:a5:48:ac:bb:
+ 26:f7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 0B:58:E5:8B:C6:4C:15:37:A4:40:A9:30:A9:21:BE:47:36:5A:56:FF
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 CRL Distribution Points:
+ Full Name:
+ URI:http://crl.comodoca.com/COMODOCertificationAuthority.crl
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 3e:98:9e:9b:f6:1b:e9:d7:39:b7:78:ae:1d:72:18:49:d3:87:
+ e4:43:82:eb:3f:c9:aa:f5:a8:b5:ef:55:7c:21:52:65:f9:d5:
+ 0d:e1:6c:f4:3e:8c:93:73:91:2e:02:c4:4e:07:71:6f:c0:8f:
+ 38:61:08:a8:1e:81:0a:c0:2f:20:2f:41:8b:91:dc:48:45:bc:
+ f1:c6:de:ba:76:6b:33:c8:00:2d:31:46:4c:ed:e7:9d:cf:88:
+ 94:ff:33:c0:56:e8:24:86:26:b8:d8:38:38:df:2a:6b:dd:12:
+ cc:c7:3f:47:17:4c:a2:c2:06:96:09:d6:db:fe:3f:3c:46:41:
+ df:58:e2:56:0f:3c:3b:c1:1c:93:35:d9:38:52:ac:ee:c8:ec:
+ 2e:30:4e:94:35:b4:24:1f:4b:78:69:da:f2:02:38:cc:95:52:
+ 93:f0:70:25:59:9c:20:67:c4:ee:f9:8b:57:61:f4:92:76:7d:
+ 3f:84:8d:55:b7:e8:e5:ac:d5:f1:f5:19:56:a6:5a:fb:90:1c:
+ af:93:eb:e5:1c:d4:67:97:5d:04:0e:be:0b:83:a6:17:83:b9:
+ 30:12:a0:c5:33:15:05:b9:0d:fb:c7:05:76:e3:d8:4a:8d:fc:
+ 34:17:a3:c6:21:28:be:30:45:31:1e:c7:78:be:58:61:38:ac:
+ 3b:e2:01:65
+SHA1 Fingerprint=66:31:BF:9E:F7:4F:9E:B6:C9:D5:A6:0C:BA:6A:BE:D1:F7:BD:EF:7B
diff --git a/apex/ca-certificates/files/5acf816d.0 b/apex/ca-certificates/files/5acf816d.0
new file mode 100644
index 0000000..1da2c79
--- /dev/null
+++ b/apex/ca-certificates/files/5acf816d.0
@@ -0,0 +1,53 @@
+-----BEGIN CERTIFICATE-----
+MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD
+VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG
+A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw
+WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz
+IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi
+AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi
+QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR
+HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D
+9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8
+p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 02:03:e5:c0:68:ef:63:1a:9c:72:90:50:52
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R4
+ Validity
+ Not Before: Jun 22 00:00:00 2016 GMT
+ Not After : Jun 22 00:00:00 2036 GMT
+ Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R4
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:f3:74:73:a7:68:8b:60:ae:43:b8:35:c5:81:30:
+ 7b:4b:49:9d:fb:c1:61:ce:e6:de:46:bd:6b:d5:61:
+ 18:35:ae:40:dd:73:f7:89:91:30:5a:eb:3c:ee:85:
+ 7c:a2:40:76:3b:a9:c6:b8:47:d8:2a:e7:92:91:6a:
+ 73:e9:b1:72:39:9f:29:9f:a2:98:d3:5f:5e:58:86:
+ 65:0f:a1:84:65:06:d1:dc:8b:c9:c7:73:c8:8c:6a:
+ 2f:e5:c4:ab:d1:1d:8a
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 80:4C:D6:EB:74:FF:49:36:A3:D5:D8:FC:B5:3E:C5:6A:F0:94:1D:8C
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:66:02:31:00:e8:40:ff:83:de:03:f4:9f:ae:1d:7a:a7:2e:
+ b9:af:4f:f6:83:1d:0e:2d:85:01:1d:d1:d9:6a:ec:0f:c2:af:
+ c7:5e:56:5e:5c:d5:1c:58:22:28:0b:f7:30:b6:2f:b1:7c:02:
+ 31:00:f0:61:3c:a7:f4:a0:82:e3:21:d5:84:1d:73:86:9c:2d:
+ af:ca:34:9b:f1:9f:b9:23:36:e2:bc:60:03:9d:80:b3:9a:56:
+ c8:e1:e2:bb:14:79:ca:cd:21:d4:94:b5:49:43
+SHA1 Fingerprint=77:D3:03:67:B5:E0:0C:15:F6:0C:38:61:DF:7C:E1:3B:92:46:4D:47
diff --git a/apex/ca-certificates/files/5f47b495.0 b/apex/ca-certificates/files/5f47b495.0
new file mode 100644
index 0000000..052b8c0
--- /dev/null
+++ b/apex/ca-certificates/files/5f47b495.0
@@ -0,0 +1,124 @@
+-----BEGIN CERTIFICATE-----
+MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE
+BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w
+MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
+IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC
+SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1
+ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv
+UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX
+4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9
+KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/
+gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb
+rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ
+51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F
+be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe
+KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F
+v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn
+fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7
+jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz
+ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt
+ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL
+e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70
+jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz
+WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V
+SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j
+pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX
+X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok
+fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R
+K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU
+ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU
+LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT
+LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 6271844772424770508 (0x570a119742c4e3cc)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=IT, L=Milan, O=Actalis S.p.A.\/03358520967, CN=Actalis Authentication Root CA
+ Validity
+ Not Before: Sep 22 11:22:02 2011 GMT
+ Not After : Sep 22 11:22:02 2030 GMT
+ Subject: C=IT, L=Milan, O=Actalis S.p.A.\/03358520967, CN=Actalis Authentication Root CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:a7:c6:c4:a5:29:a4:2c:ef:e5:18:c5:b0:50:a3:
+ 6f:51:3b:9f:0a:5a:c9:c2:48:38:0a:c2:1c:a0:18:
+ 7f:91:b5:87:b9:40:3f:dd:1d:68:1f:08:83:d5:2d:
+ 1e:88:a0:f8:8f:56:8f:6d:99:02:92:90:16:d5:5f:
+ 08:6c:89:d7:e1:ac:bc:20:c2:b1:e0:83:51:8a:69:
+ 4d:00:96:5a:6f:2f:c0:44:7e:a3:0e:e4:91:cd:58:
+ ee:dc:fb:c7:1e:45:47:dd:27:b9:08:01:9f:a6:21:
+ 1d:f5:41:2d:2f:4c:fd:28:ad:e0:8a:ad:22:b4:56:
+ 65:8e:86:54:8f:93:43:29:de:39:46:78:a3:30:23:
+ ba:cd:f0:7d:13:57:c0:5d:d2:83:6b:48:4c:c4:ab:
+ 9f:80:5a:5b:3a:bd:c9:a7:22:3f:80:27:33:5b:0e:
+ b7:8a:0c:5d:07:37:08:cb:6c:d2:7a:47:22:44:35:
+ c5:cc:cc:2e:8e:dd:2a:ed:b7:7d:66:0d:5f:61:51:
+ 22:55:1b:e3:46:e3:e3:3d:d0:35:62:9a:db:af:14:
+ c8:5b:a1:cc:89:1b:e1:30:26:fc:a0:9b:1f:81:a7:
+ 47:1f:04:eb:a3:39:92:06:9f:99:d3:bf:d3:ea:4f:
+ 50:9c:19:fe:96:87:1e:3c:65:f6:a3:18:24:83:86:
+ 10:e7:54:3e:a8:3a:76:24:4f:81:21:c5:e3:0f:02:
+ f8:93:94:47:20:bb:fe:d4:0e:d3:68:b9:dd:c4:7a:
+ 84:82:e3:53:54:79:dd:db:9c:d2:f2:07:9b:2e:b6:
+ bc:3e:ed:85:6d:ef:25:11:f2:97:1a:42:61:f7:4a:
+ 97:e8:8b:b1:10:07:fa:65:81:b2:a2:39:cf:f7:3c:
+ ff:18:fb:c6:f1:5a:8b:59:e2:02:ac:7b:92:d0:4e:
+ 14:4f:59:45:f6:0c:5e:28:5f:b0:e8:3f:45:cf:cf:
+ af:9b:6f:fb:84:d3:77:5a:95:6f:ac:94:84:9e:ee:
+ bc:c0:4a:8f:4a:93:f8:44:21:e2:31:45:61:50:4e:
+ 10:d8:e3:35:7c:4c:19:b4:de:05:bf:a3:06:9f:c8:
+ b5:cd:e4:1f:d7:17:06:0d:7a:95:74:55:0d:68:1a:
+ fc:10:1b:62:64:9d:6d:e0:95:a0:c3:94:07:57:0d:
+ 14:e6:bd:05:fb:b8:9f:e6:df:8b:e2:c6:e7:7e:96:
+ f6:53:c5:80:34:50:28:58:f0:12:50:71:17:30:ba:
+ e6:78:63:bc:f4:b2:ad:9b:2b:b2:fe:e1:39:8c:5e:
+ ba:0b:20:94:de:7b:83:b8:ff:e3:56:8d:b7:11:e9:
+ 3b:8c:f2:b1:c1:5d:9d:a4:0b:4c:2b:d9:b2:18:f5:
+ b5:9f:4b
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 52:D8:88:3A:C8:9F:78:66:ED:89:F3:7B:38:70:94:C9:02:02:36:D0
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Authority Key Identifier:
+ 52:D8:88:3A:C8:9F:78:66:ED:89:F3:7B:38:70:94:C9:02:02:36:D0
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 0b:7b:72:87:c0:60:a6:49:4c:88:58:e6:1d:88:f7:14:64:48:
+ a6:d8:58:0a:0e:4f:13:35:df:35:1d:d4:ed:06:31:c8:81:3e:
+ 6a:d5:dd:3b:1a:32:ee:90:3d:11:d2:2e:f4:8e:c3:63:2e:23:
+ 66:b0:67:be:6f:b6:c0:13:39:60:aa:a2:34:25:93:75:52:de:
+ a7:9d:ad:0e:87:89:52:71:6a:16:3c:19:1d:83:f8:9a:29:65:
+ be:f4:3f:9a:d9:f0:f3:5a:87:21:71:80:4d:cb:e0:38:9b:3f:
+ bb:fa:e0:30:4d:cf:86:d3:65:10:19:18:d1:97:02:b1:2b:72:
+ 42:68:ac:a0:bd:4e:5a:da:18:bf:6b:98:81:d0:fd:9a:be:5e:
+ 15:48:cd:11:15:b9:c0:29:5c:b4:e8:88:f7:3e:36:ae:b7:62:
+ fd:1e:62:de:70:78:10:1c:48:5b:da:bc:a4:38:ba:67:ed:55:
+ 3e:5e:57:df:d4:03:40:4c:81:a4:d2:4f:63:a7:09:42:09:14:
+ fc:00:a9:c2:80:73:4f:2e:c0:40:d9:11:7b:48:ea:7a:02:c0:
+ d3:eb:28:01:26:58:74:c1:c0:73:22:6d:93:95:fd:39:7d:bb:
+ 2a:e3:f6:82:e3:2c:97:5f:4e:1f:91:94:fa:fe:2c:a3:d8:76:
+ 1a:b8:4d:b2:38:4f:9b:fa:1d:48:60:79:26:e2:f3:fd:a9:d0:
+ 9a:e8:70:8f:49:7a:d6:e5:bd:0a:0e:db:2d:f3:8d:bf:eb:e3:
+ a4:7d:cb:c7:95:71:e8:da:a3:7c:c5:c2:f8:74:92:04:1b:86:
+ ac:a4:22:53:40:b6:ac:fe:4c:76:cf:fb:94:32:c0:35:9f:76:
+ 3f:6e:e5:90:6e:a0:a6:26:a2:b8:2c:be:d1:2b:85:fd:a7:68:
+ c8:ba:01:2b:b1:6c:74:1d:b8:73:95:e7:ee:b7:c7:25:f0:00:
+ 4c:00:b2:7e:b6:0b:8b:1c:f3:c0:50:9e:25:b9:e0:08:de:36:
+ 66:ff:37:a5:d1:bb:54:64:2c:c9:27:b5:4b:92:7e:65:ff:d3:
+ 2d:e1:b9:4e:bc:7f:a4:41:21:90:41:77:a6:39:1f:ea:9e:e3:
+ 9f:d0:66:6f:05:ec:aa:76:7e:bf:6b:16:a0:eb:b5:c7:fc:92:
+ 54:2f:2b:11:27:25:37:78:4c:51:6a:b0:f3:cc:58:5d:14:f1:
+ 6a:48:15:ff:c2:07:b6:b1:8d:0f:8e:5c:50:46:b3:3d:bf:01:
+ 98:4f:b2:59:54:47:3e:34:7b:78:6d:56:93:2e:73:ea:66:28:
+ 78:cd:1d:14:bf:a0:8f:2f:2e:b8:2e:8e:f2:14:8a:cc:e9:b5:
+ 7c:fb:6c:9d:0c:a5:e1:96
+SHA1 Fingerprint=F3:73:B3:87:06:5A:28:84:8A:F2:F3:4A:CE:19:2B:DD:C7:8E:9C:AC
diff --git a/apex/ca-certificates/files/5f9a69fa.0 b/apex/ca-certificates/files/5f9a69fa.0
new file mode 100644
index 0000000..dca933e
--- /dev/null
+++ b/apex/ca-certificates/files/5f9a69fa.0
@@ -0,0 +1,56 @@
+-----BEGIN CERTIFICATE-----
+MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw
+CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw
+FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S
+Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5
+MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL
+DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS
+QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB
+BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH
+sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK
+Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu
+SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC
+MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy
+v+c=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 62:f6:32:6c:e5:c4:e3:68:5c:1b:62:dd:9c:2e:9d:95
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=ES, O=FNMT-RCM, OU=Ceres/organizationIdentifier=VATES-Q2826004J, CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS
+ Validity
+ Not Before: Dec 20 09:37:33 2018 GMT
+ Not After : Dec 20 09:37:33 2043 GMT
+ Subject: C=ES, O=FNMT-RCM, OU=Ceres/organizationIdentifier=VATES-Q2826004J, CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:f6:ba:57:53:c8:ca:ab:df:36:4a:52:21:e4:97:
+ d2:83:67:9e:f0:65:51:d0:5e:87:c7:47:b1:59:f2:
+ 57:47:9b:00:02:93:44:17:69:db:42:c7:b1:b2:3a:
+ 18:0e:b4:5d:8c:b3:66:5d:a1:34:f9:36:2c:49:db:
+ f3:46:fc:b3:44:69:44:13:66:fd:d7:c5:fd:af:36:
+ 4d:ce:03:4d:07:71:cf:af:6a:05:d2:a2:43:5a:0a:
+ 52:6f:01:03:4e:8e:8b
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 01:B9:2F:EF:BF:11:86:60:F2:4F:D0:41:6E:AB:73:1F:E7:D2:6E:49
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:66:02:31:00:ae:4a:e3:2b:40:c3:74:11:f2:95:ad:16:23:
+ de:4e:0c:1a:e6:5d:a5:24:5e:6b:44:7b:fc:38:e2:4f:cb:9c:
+ 45:17:11:4c:14:27:26:55:39:75:4a:03:cc:13:90:9f:92:02:
+ 31:00:fa:4a:6c:60:88:73:f3:ee:b8:98:62:a9:ce:2b:c2:d9:
+ 8a:a6:70:31:1d:af:b0:94:4c:eb:4f:c6:e3:d1:f3:62:a7:3c:
+ ff:93:2e:07:5c:49:01:67:69:12:02:72:bf:e7
+SHA1 Fingerprint=62:FF:D9:9E:C0:65:0D:03:CE:75:93:D2:ED:3F:2D:32:C9:E3:E5:4A
diff --git a/apex/ca-certificates/files/5fdd185d.0 b/apex/ca-certificates/files/5fdd185d.0
new file mode 100644
index 0000000..2b34c68
--- /dev/null
+++ b/apex/ca-certificates/files/5fdd185d.0
@@ -0,0 +1,53 @@
+-----BEGIN CERTIFICATE-----
+MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQsw
+CQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlu
+bHkgUm9vdCBFMTAeFw0yMTA0MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJ
+BgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlubHkxGjAYBgNVBAMTEUNlcnRhaW5s
+eSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4fxzf7flHh4axpMCK
++IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9YBk2
+QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4
+hevIIgcwCgYIKoZIzj0EAwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozm
+ut6Dacpps6kFtZaSF4fC0urQe87YQVt8rgIwRt7qy12a7DLCZRawTDBcMPPaTnOG
+BtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 06:25:33:b1:47:03:33:27:5c:f9:8d:9a:b9:bf:cc:f8
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=US, O=Certainly, CN=Certainly Root E1
+ Validity
+ Not Before: Apr 1 00:00:00 2021 GMT
+ Not After : Apr 1 00:00:00 2046 GMT
+ Subject: C=US, O=Certainly, CN=Certainly Root E1
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:de:6f:f8:7f:1c:df:ed:f9:47:87:86:b1:a4:c0:
+ 8a:f8:82:97:80:ea:8f:c8:4a:5e:2a:7d:88:68:a7:
+ 01:62:14:91:24:7a:5c:9e:a3:17:7d:8a:86:21:34:
+ 18:50:1b:10:de:d0:37:4b:26:c7:19:60:80:e9:34:
+ bd:60:19:36:40:d6:29:87:09:3c:91:7a:f6:bc:13:
+ 23:dd:59:4e:04:5e:cf:c8:02:1c:18:53:c1:31:d8:
+ da:20:e9:44:8d:e4:76
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ F3:28:18:CB:64:75:EE:29:2A:EB:ED:AE:23:58:38:85:EB:C8:22:07
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:65:02:31:00:b1:8e:5a:20:c3:b2:19:62:4d:de:b0:4f:df:
+ 6e:d2:70:8a:f1:9f:7e:6a:8c:e6:ba:de:83:69:ca:69:b3:a9:
+ 05:b5:96:92:17:87:c2:d2:ea:d0:7b:ce:d8:41:5b:7c:ae:02:
+ 30:46:de:ea:cb:5d:9a:ec:32:c2:65:16:b0:4c:30:5c:30:f3:
+ da:4e:73:86:06:d8:ce:89:04:48:37:37:f8:dd:33:51:9d:70:
+ af:7b:55:d8:01:2e:7d:05:64:0e:86:b8:91
+SHA1 Fingerprint=F9:E1:6D:DC:01:89:CF:D5:82:45:63:3E:C5:37:7D:C2:EB:93:6F:2B
diff --git a/apex/ca-certificates/files/60afe812.0 b/apex/ca-certificates/files/60afe812.0
new file mode 100644
index 0000000..1f49382
--- /dev/null
+++ b/apex/ca-certificates/files/60afe812.0
@@ -0,0 +1,82 @@
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG
+EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3
+MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl
+cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR
+dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB
+pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM
+b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm
+aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz
+IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT
+lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz
+AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5
+VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG
+ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2
+BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG
+AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M
+U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh
+bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C
++C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC
+bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F
+uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2
+XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 80544274841616 (0x49412ce40010)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=HU, L=Budapest, O=NetLock Kft., OU=Tan\xC3\xBAs\xC3\xADtv\xC3\xA1nykiad\xC3\xB3k (Certification Services), CN=NetLock Arany (Class Gold) F\xC5\x91tan\xC3\xBAs\xC3\xADtv\xC3\xA1ny
+ Validity
+ Not Before: Dec 11 15:08:21 2008 GMT
+ Not After : Dec 6 15:08:21 2028 GMT
+ Subject: C=HU, L=Budapest, O=NetLock Kft., OU=Tan\xC3\xBAs\xC3\xADtv\xC3\xA1nykiad\xC3\xB3k (Certification Services), CN=NetLock Arany (Class Gold) F\xC5\x91tan\xC3\xBAs\xC3\xADtv\xC3\xA1ny
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c4:24:5e:73:be:4b:6d:14:c3:a1:f4:e3:97:90:
+ 6e:d2:30:45:1e:3c:ee:67:d9:64:e0:1a:8a:7f:ca:
+ 30:ca:83:e3:20:c1:e3:f4:3a:d3:94:5f:1a:7c:5b:
+ 6d:bf:30:4f:84:27:f6:9f:1f:49:bc:c6:99:0a:90:
+ f2:0f:f5:7f:43:84:37:63:51:8b:7a:a5:70:fc:7a:
+ 58:cd:8e:9b:ed:c3:46:6c:84:70:5d:da:f3:01:90:
+ 23:fc:4e:30:a9:7e:e1:27:63:e7:ed:64:3c:a0:b8:
+ c9:33:63:fe:16:90:ff:b0:b8:fd:d7:a8:c0:c0:94:
+ 43:0b:b6:d5:59:a6:9e:56:d0:24:1f:70:79:af:db:
+ 39:54:0d:65:75:d9:15:41:94:01:af:5e:ec:f6:8d:
+ f1:ff:ad:64:fe:20:9a:d7:5c:eb:fe:a6:1f:08:64:
+ a3:8b:76:55:ad:1e:3b:28:60:2e:87:25:e8:aa:af:
+ 1f:c6:64:46:20:b7:70:7f:3c:de:48:db:96:53:b7:
+ 39:77:e4:1a:e2:c7:16:84:76:97:5b:2f:bb:19:15:
+ 85:f8:69:85:f5:99:a7:a9:f2:34:a7:a9:b6:a6:03:
+ fc:6f:86:3d:54:7c:76:04:9b:6b:f9:40:5d:00:34:
+ c7:2e:99:75:9d:e5:88:03:aa:4d:f8:03:d2:42:76:
+ c0:1b
+ Exponent: 43147 (0xa88b)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE, pathlen:4
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ CC:FA:67:93:F0:B6:B8:D0:A5:C0:1E:F3:53:FD:8C:53:DF:83:D7:96
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ ab:7f:ee:1c:16:a9:9c:3c:51:00:a0:c0:11:08:05:a7:99:e6:
+ 6f:01:88:54:61:6e:f1:b9:18:ad:4a:ad:fe:81:40:23:94:2f:
+ fb:75:7c:2f:28:4b:62:24:81:82:0b:f5:61:f1:1c:6e:b8:61:
+ 38:eb:81:fa:62:a1:3b:5a:62:d3:94:65:c4:e1:e6:6d:82:f8:
+ 2f:25:70:b2:21:26:c1:72:51:1f:8c:2c:c3:84:90:c3:5a:8f:
+ ba:cf:f4:a7:65:a5:eb:98:d1:fb:05:b2:46:75:15:23:6a:6f:
+ 85:63:30:80:f0:d5:9e:1f:29:1c:c2:6c:b0:50:59:5d:90:5b:
+ 3b:a8:0d:30:cf:bf:7d:7f:ce:f1:9d:83:bd:c9:46:6e:20:a6:
+ f9:61:51:ba:21:2f:7b:be:a5:15:63:a1:d4:95:87:f1:9e:b9:
+ f3:89:f3:3d:85:b8:b8:db:be:b5:b9:29:f9:da:37:05:00:49:
+ 94:03:84:44:e7:bf:43:31:cf:75:8b:25:d1:f4:a6:64:f5:92:
+ f6:ab:05:eb:3d:e9:a5:0b:36:62:da:cc:06:5f:36:8b:b6:5e:
+ 31:b8:2a:fb:5e:f6:71:df:44:26:9e:c4:e6:0d:91:b4:2e:75:
+ 95:80:51:6a:4b:30:a6:b0:62:a1:93:f1:9b:d8:ce:c4:63:75:
+ 3f:59:47:b1
+SHA1 Fingerprint=06:08:3F:59:3F:15:A1:04:A0:69:A4:6B:A9:03:D0:06:B7:97:09:91
diff --git a/apex/ca-certificates/files/6187b673.0 b/apex/ca-certificates/files/6187b673.0
new file mode 100644
index 0000000..230a237
--- /dev/null
+++ b/apex/ca-certificates/files/6187b673.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
+TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
+cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
+WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
+ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
+MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
+h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
+0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
+A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
+T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
+B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
+B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
+KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
+OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
+jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
+qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
+rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
+hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
+ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
+3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
+NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
+ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
+TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
+jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
+oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
+4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
+mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
+emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 82:10:cf:b0:d2:40:e3:59:44:63:e0:bb:63:82:8b:00
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X1
+ Validity
+ Not Before: Jun 4 11:04:38 2015 GMT
+ Not After : Jun 4 11:04:38 2035 GMT
+ Subject: C=US, O=Internet Security Research Group, CN=ISRG Root X1
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:ad:e8:24:73:f4:14:37:f3:9b:9e:2b:57:28:1c:
+ 87:be:dc:b7:df:38:90:8c:6e:3c:e6:57:a0:78:f7:
+ 75:c2:a2:fe:f5:6a:6e:f6:00:4f:28:db:de:68:86:
+ 6c:44:93:b6:b1:63:fd:14:12:6b:bf:1f:d2:ea:31:
+ 9b:21:7e:d1:33:3c:ba:48:f5:dd:79:df:b3:b8:ff:
+ 12:f1:21:9a:4b:c1:8a:86:71:69:4a:66:66:6c:8f:
+ 7e:3c:70:bf:ad:29:22:06:f3:e4:c0:e6:80:ae:e2:
+ 4b:8f:b7:99:7e:94:03:9f:d3:47:97:7c:99:48:23:
+ 53:e8:38:ae:4f:0a:6f:83:2e:d1:49:57:8c:80:74:
+ b6:da:2f:d0:38:8d:7b:03:70:21:1b:75:f2:30:3c:
+ fa:8f:ae:dd:da:63:ab:eb:16:4f:c2:8e:11:4b:7e:
+ cf:0b:e8:ff:b5:77:2e:f4:b2:7b:4a:e0:4c:12:25:
+ 0c:70:8d:03:29:a0:e1:53:24:ec:13:d9:ee:19:bf:
+ 10:b3:4a:8c:3f:89:a3:61:51:de:ac:87:07:94:f4:
+ 63:71:ec:2e:e2:6f:5b:98:81:e1:89:5c:34:79:6c:
+ 76:ef:3b:90:62:79:e6:db:a4:9a:2f:26:c5:d0:10:
+ e1:0e:de:d9:10:8e:16:fb:b7:f7:a8:f7:c7:e5:02:
+ 07:98:8f:36:08:95:e7:e2:37:96:0d:36:75:9e:fb:
+ 0e:72:b1:1d:9b:bc:03:f9:49:05:d8:81:dd:05:b4:
+ 2a:d6:41:e9:ac:01:76:95:0a:0f:d8:df:d5:bd:12:
+ 1f:35:2f:28:17:6c:d2:98:c1:a8:09:64:77:6e:47:
+ 37:ba:ce:ac:59:5e:68:9d:7f:72:d6:89:c5:06:41:
+ 29:3e:59:3e:dd:26:f5:24:c9:11:a7:5a:a3:4c:40:
+ 1f:46:a1:99:b5:a7:3a:51:6e:86:3b:9e:7d:72:a7:
+ 12:05:78:59:ed:3e:51:78:15:0b:03:8f:8d:d0:2f:
+ 05:b2:3e:7b:4a:1c:4b:73:05:12:fc:c6:ea:e0:50:
+ 13:7c:43:93:74:b3:ca:74:e7:8e:1f:01:08:d0:30:
+ d4:5b:71:36:b4:07:ba:c1:30:30:5c:48:b7:82:3b:
+ 98:a6:7d:60:8a:a2:a3:29:82:cc:ba:bd:83:04:1b:
+ a2:83:03:41:a1:d6:05:f1:1b:c2:b6:f0:a8:7c:86:
+ 3b:46:a8:48:2a:88:dc:76:9a:76:bf:1f:6a:a5:3d:
+ 19:8f:eb:38:f3:64:de:c8:2b:0d:0a:28:ff:f7:db:
+ e2:15:42:d4:22:d0:27:5d:e1:79:fe:18:e7:70:88:
+ ad:4e:e6:d9:8b:3a:c6:dd:27:51:6e:ff:bc:64:f5:
+ 33:43:4f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 55:1f:58:a9:bc:b2:a8:50:d0:0c:b1:d8:1a:69:20:27:29:08:
+ ac:61:75:5c:8a:6e:f8:82:e5:69:2f:d5:f6:56:4b:b9:b8:73:
+ 10:59:d3:21:97:7e:e7:4c:71:fb:b2:d2:60:ad:39:a8:0b:ea:
+ 17:21:56:85:f1:50:0e:59:eb:ce:e0:59:e9:ba:c9:15:ef:86:
+ 9d:8f:84:80:f6:e4:e9:91:90:dc:17:9b:62:1b:45:f0:66:95:
+ d2:7c:6f:c2:ea:3b:ef:1f:cf:cb:d6:ae:27:f1:a9:b0:c8:ae:
+ fd:7d:7e:9a:fa:22:04:eb:ff:d9:7f:ea:91:2b:22:b1:17:0e:
+ 8f:f2:8a:34:5b:58:d8:fc:01:c9:54:b9:b8:26:cc:8a:88:33:
+ 89:4c:2d:84:3c:82:df:ee:96:57:05:ba:2c:bb:f7:c4:b7:c7:
+ 4e:3b:82:be:31:c8:22:73:73:92:d1:c2:80:a4:39:39:10:33:
+ 23:82:4c:3c:9f:86:b2:55:98:1d:be:29:86:8c:22:9b:9e:e2:
+ 6b:3b:57:3a:82:70:4d:dc:09:c7:89:cb:0a:07:4d:6c:e8:5d:
+ 8e:c9:ef:ce:ab:c7:bb:b5:2b:4e:45:d6:4a:d0:26:cc:e5:72:
+ ca:08:6a:a5:95:e3:15:a1:f7:a4:ed:c9:2c:5f:a5:fb:ff:ac:
+ 28:02:2e:be:d7:7b:bb:e3:71:7b:90:16:d3:07:5e:46:53:7c:
+ 37:07:42:8c:d3:c4:96:9c:d5:99:b5:2a:e0:95:1a:80:48:ae:
+ 4c:39:07:ce:cc:47:a4:52:95:2b:ba:b8:fb:ad:d2:33:53:7d:
+ e5:1d:4d:6d:d5:a1:b1:c7:42:6f:e6:40:27:35:5c:a3:28:b7:
+ 07:8d:e7:8d:33:90:e7:23:9f:fb:50:9c:79:6c:46:d5:b4:15:
+ b3:96:6e:7e:9b:0c:96:3a:b8:52:2d:3f:d6:5b:e1:fb:08:c2:
+ 84:fe:24:a8:a3:89:da:ac:6a:e1:18:2a:b1:a8:43:61:5b:d3:
+ 1f:dc:3b:8d:76:f2:2d:e8:8d:75:df:17:33:6c:3d:53:fb:7b:
+ cb:41:5f:ff:dc:a2:d0:61:38:e1:96:b8:ac:5d:8b:37:d7:75:
+ d5:33:c0:99:11:ae:9d:41:c1:72:75:84:be:02:41:42:5f:67:
+ 24:48:94:d1:9b:27:be:07:3f:b9:b8:4f:81:74:51:e1:7a:b7:
+ ed:9d:23:e2:be:e0:d5:28:04:13:3c:31:03:9e:dd:7a:6c:8f:
+ c6:07:18:c6:7f:de:47:8e:3f:28:9e:04:06:cf:a5:54:34:77:
+ bd:ec:89:9b:e9:17:43:df:5b:db:5f:fe:8e:1e:57:a2:cd:40:
+ 9d:7e:62:22:da:de:18:27
+SHA1 Fingerprint=CA:BD:2A:79:A1:07:6A:31:F2:1D:25:36:35:CB:03:9D:43:29:A5:E8
diff --git a/apex/ca-certificates/files/63a2c897.0 b/apex/ca-certificates/files/63a2c897.0
new file mode 100644
index 0000000..9748d9a
--- /dev/null
+++ b/apex/ca-certificates/files/63a2c897.0
@@ -0,0 +1,120 @@
+-----BEGIN CERTIFICATE-----
+MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw
+NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv
+b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD
+VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2
+MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F
+VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1
+7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X
+Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+
+/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs
+81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm
+dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe
+Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu
+sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4
+pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs
+slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ
+arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD
+VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG
+9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl
+dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx
+0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj
+TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed
+Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7
+Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI
+OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7
+vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW
+t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn
+HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx
+SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 95:be:16:a0:f7:2e:46:f1:7b:39:82:72:fa:8b:cd:96
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: O=TeliaSonera, CN=TeliaSonera Root CA v1
+ Validity
+ Not Before: Oct 18 12:00:50 2007 GMT
+ Not After : Oct 18 12:00:50 2032 GMT
+ Subject: O=TeliaSonera, CN=TeliaSonera Root CA v1
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:c2:be:eb:27:f0:21:a3:f3:69:26:55:7e:9d:c5:
+ 55:16:91:5c:fd:ef:21:bf:53:80:7a:2d:d2:91:8c:
+ 63:31:f0:ec:24:f0:c3:a5:d2:72:7c:10:6d:f4:37:
+ b7:e5:e6:7c:79:ea:8c:b5:82:8b:ae:48:b6:ac:00:
+ dc:65:75:ec:2a:4d:5f:c1:87:f5:20:65:2b:81:a8:
+ 47:3e:89:23:95:30:16:90:7f:e8:57:07:48:e7:19:
+ ae:bf:45:67:b1:37:1b:06:2a:fe:de:f9:ac:7d:83:
+ fb:5e:ba:e4:8f:97:67:be:4b:8e:8d:64:07:57:38:
+ 55:69:34:36:3d:13:48:ef:4f:e2:d3:66:1e:a4:cf:
+ 1a:b7:5e:36:33:d4:b4:06:bd:18:01:fd:77:84:50:
+ 00:45:f5:8c:5d:e8:23:bc:7e:fe:35:e1:ed:50:7b:
+ a9:30:8d:19:d3:09:8e:68:67:5d:bf:3c:97:18:53:
+ bb:29:62:c5:ca:5e:72:c1:c7:96:d4:db:2d:a0:b4:
+ 1f:69:03:ec:ea:e2:50:f1:0c:3c:f0:ac:f3:53:2d:
+ f0:1c:f5:ed:6c:39:39:73:80:16:c8:52:b0:23:cd:
+ e0:3e:dc:dd:3c:47:a0:bb:35:8a:e2:98:68:8b:be:
+ e5:bf:72:ee:d2:fa:a5:ed:12:ed:fc:98:18:a9:26:
+ 76:dc:28:4b:10:20:1c:d3:7f:16:77:2d:ed:6f:80:
+ f7:49:bb:53:05:bb:5d:68:c7:d4:c8:75:16:3f:89:
+ 5a:8b:f7:17:47:d4:4c:f1:d2:89:79:3e:4d:3d:98:
+ a8:61:de:3a:1e:d2:f8:5e:03:e0:c1:c9:1c:8c:d3:
+ 8d:4d:d3:95:36:b3:37:5f:63:63:9b:33:14:f0:2d:
+ 26:6b:53:7c:89:8c:32:c2:6e:ec:3d:21:00:39:c9:
+ a1:68:e2:50:83:2e:b0:3a:2b:f3:36:a0:ac:2f:e4:
+ 6f:61:c2:51:09:39:3e:8b:53:b9:bb:67:da:dc:53:
+ b9:76:59:36:9d:43:e5:20:e0:3d:32:60:85:22:51:
+ b7:c7:33:bb:dd:15:2f:a4:78:a6:07:7b:81:46:36:
+ 04:86:dd:79:35:c7:95:2c:3b:b0:a3:17:35:e5:73:
+ 1f:b4:5c:59:ef:da:ea:10:65:7b:7a:d0:7f:9f:b3:
+ b4:2a:37:3b:70:8b:9b:5b:b9:2b:b7:ec:b2:51:12:
+ 97:53:29:5a:d4:f0:12:10:dc:4f:02:bb:12:92:2f:
+ 62:d4:3f:69:43:7c:0d:d6:fc:58:75:01:88:9d:58:
+ 16:4b:de:ba:90:ff:47:01:89:06:6a:f6:5f:b2:90:
+ 6a:b3:02:a6:02:88:bf:b3:47:7e:2a:d9:d5:fa:68:
+ 78:35:4d
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage:
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ F0:8F:59:38:00:B3:F5:8F:9A:96:0C:D5:EB:FA:7B:AA:17:E8:13:12
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ be:e4:5c:62:4e:24:f4:0c:08:ff:f0:d3:0c:68:e4:93:49:22:
+ 3f:44:27:6f:bb:6d:de:83:66:ce:a8:cc:0d:fc:f5:9a:06:e5:
+ 77:14:91:eb:9d:41:7b:99:2a:84:e5:ff:fc:21:c1:5d:f0:e4:
+ 1f:57:b7:75:a9:a1:5f:02:26:ff:d7:c7:f7:4e:de:4f:f8:f7:
+ 1c:46:c0:7a:4f:40:2c:22:35:f0:19:b1:d0:6b:67:2c:b0:a8:
+ e0:c0:40:37:35:f6:84:5c:5c:e3:af:42:78:fe:a7:c9:0d:50:
+ ea:0d:84:76:f6:51:ef:83:53:c6:7a:ff:0e:56:49:2e:8f:7a:
+ d6:0c:e6:27:54:e3:4d:0a:60:72:62:cd:91:07:d6:a5:bf:c8:
+ 99:6b:ed:c4:19:e6:ab:4c:11:38:c5:6f:31:e2:6e:49:c8:3f:
+ 76:80:26:03:26:29:e0:36:f6:f6:20:53:e3:17:70:34:17:9d:
+ 63:68:1e:6b:ec:c3:4d:86:b8:13:30:2f:5d:46:0d:47:43:d5:
+ 1b:aa:59:0e:b9:5c:8d:06:48:ad:74:87:5f:c7:fc:31:54:41:
+ 13:e2:c7:21:0e:9e:e0:1e:0d:e1:c0:7b:43:85:90:c5:8a:58:
+ c6:65:0a:78:57:f2:c6:23:0f:01:d9:20:4b:de:0f:fb:92:85:
+ 75:2a:5c:73:8d:6d:7b:25:91:ca:ee:45:ae:06:4b:00:cc:d3:
+ b1:59:50:da:3a:88:3b:29:43:46:5e:97:2b:54:ce:53:6f:8d:
+ 4a:e7:96:fa:bf:71:0e:42:8b:7c:fd:28:a0:d0:48:ca:da:c4:
+ 81:4c:bb:a2:73:93:26:c8:eb:0c:d6:26:88:b6:c0:24:cf:bb:
+ bd:5b:eb:75:7d:e9:08:8e:86:33:2c:79:77:09:69:a5:89:fc:
+ b3:70:90:87:76:8f:d3:22:bb:42:ce:bd:73:0b:20:26:2a:d0:
+ 9b:3d:70:1e:24:6c:cd:87:76:a9:17:96:b7:cf:0d:92:fb:8e:
+ 18:a9:98:49:d1:9e:fe:60:44:72:21:b9:19:ed:c2:f5:31:f1:
+ 39:48:88:90:24:75:54:16:ad:ce:f4:f8:69:14:64:39:fb:a3:
+ b8:ba:70:40:c7:27:1c:bf:c4:56:53:fa:63:65:d0:f3:1c:0e:
+ 16:f5:6b:86:58:4d:18:d4:e4:0d:8e:a5:9d:5b:91:dc:76:24:
+ 50:3f:c6:2a:fb:d9:b7:9c:b5:d6:e6:d0:d9:e8:19:8b:15:71:
+ 48:ad:b7:ea:d8:59:88:d4:90:bf:16:b3:d9:e9:ac:59:61:54:
+ c8:1c:ba:ca:c1:ca:e1:b9:20:4c:8f:3a:93:89:a5:a0:cc:bf:
+ d3:f6:75:a4:75:96:6d:56
+SHA1 Fingerprint=43:13:BB:96:F1:D5:86:9B:C1:4E:6A:92:F6:CF:F6:34:69:87:82:37
diff --git a/apex/ca-certificates/files/69105f4f.0 b/apex/ca-certificates/files/69105f4f.0
new file mode 100644
index 0000000..65391c0
--- /dev/null
+++ b/apex/ca-certificates/files/69105f4f.0
@@ -0,0 +1,83 @@
+-----BEGIN CERTIFICATE-----
+MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
+b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
+cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c
+JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP
+mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+
+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4
+VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/
+AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB
+AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun
+pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC
+dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf
+fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm
+NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx
+H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 0c:e7:e0:e5:17:d8:46:fe:8f:e5:60:fc:1b:f0:30:39
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Assured ID Root CA
+ Validity
+ Not Before: Nov 10 00:00:00 2006 GMT
+ Not After : Nov 10 00:00:00 2031 GMT
+ Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Assured ID Root CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:ad:0e:15:ce:e4:43:80:5c:b1:87:f3:b7:60:f9:
+ 71:12:a5:ae:dc:26:94:88:aa:f4:ce:f5:20:39:28:
+ 58:60:0c:f8:80:da:a9:15:95:32:61:3c:b5:b1:28:
+ 84:8a:8a:dc:9f:0a:0c:83:17:7a:8f:90:ac:8a:e7:
+ 79:53:5c:31:84:2a:f6:0f:98:32:36:76:cc:de:dd:
+ 3c:a8:a2:ef:6a:fb:21:f2:52:61:df:9f:20:d7:1f:
+ e2:b1:d9:fe:18:64:d2:12:5b:5f:f9:58:18:35:bc:
+ 47:cd:a1:36:f9:6b:7f:d4:b0:38:3e:c1:1b:c3:8c:
+ 33:d9:d8:2f:18:fe:28:0f:b3:a7:83:d6:c3:6e:44:
+ c0:61:35:96:16:fe:59:9c:8b:76:6d:d7:f1:a2:4b:
+ 0d:2b:ff:0b:72:da:9e:60:d0:8e:90:35:c6:78:55:
+ 87:20:a1:cf:e5:6d:0a:c8:49:7c:31:98:33:6c:22:
+ e9:87:d0:32:5a:a2:ba:13:82:11:ed:39:17:9d:99:
+ 3a:72:a1:e6:fa:a4:d9:d5:17:31:75:ae:85:7d:22:
+ ae:3f:01:46:86:f6:28:79:c8:b1:da:e4:57:17:c4:
+ 7e:1c:0e:b0:b4:92:a6:56:b3:bd:b2:97:ed:aa:a7:
+ f0:b7:c5:a8:3f:95:16:d0:ff:a1:96:eb:08:5f:18:
+ 77:4f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 45:EB:A2:AF:F4:92:CB:82:31:2D:51:8B:A7:A7:21:9D:F3:6D:C8:0F
+ X509v3 Authority Key Identifier:
+ 45:EB:A2:AF:F4:92:CB:82:31:2D:51:8B:A7:A7:21:9D:F3:6D:C8:0F
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ a2:0e:bc:df:e2:ed:f0:e3:72:73:7a:64:94:bf:f7:72:66:d8:
+ 32:e4:42:75:62:ae:87:eb:f2:d5:d9:de:56:b3:9f:cc:ce:14:
+ 28:b9:0d:97:60:5c:12:4c:58:e4:d3:3d:83:49:45:58:97:35:
+ 69:1a:a8:47:ea:56:c6:79:ab:12:d8:67:81:84:df:7f:09:3c:
+ 94:e6:b8:26:2c:20:bd:3d:b3:28:89:f7:5f:ff:22:e2:97:84:
+ 1f:e9:65:ef:87:e0:df:c1:67:49:b3:5d:eb:b2:09:2a:eb:26:
+ ed:78:be:7d:3f:2b:f3:b7:26:35:6d:5f:89:01:b6:49:5b:9f:
+ 01:05:9b:ab:3d:25:c1:cc:b6:7f:c2:f1:6f:86:c6:fa:64:68:
+ eb:81:2d:94:eb:42:b7:fa:8c:1e:dd:62:f1:be:50:67:b7:6c:
+ bd:f3:f1:1f:6b:0c:36:07:16:7f:37:7c:a9:5b:6d:7a:f1:12:
+ 46:60:83:d7:27:04:be:4b:ce:97:be:c3:67:2a:68:11:df:80:
+ e7:0c:33:66:bf:13:0d:14:6e:f3:7f:1f:63:10:1e:fa:8d:1b:
+ 25:6d:6c:8f:a5:b7:61:01:b1:d2:a3:26:a1:10:71:9d:ad:e2:
+ c3:f9:c3:99:51:b7:2b:07:08:ce:2e:e6:50:b2:a7:fa:0a:45:
+ 2f:a2:f0:f2
+SHA1 Fingerprint=05:63:B8:63:0D:62:D7:5A:BB:C8:AB:1E:4B:DF:B5:A8:99:B2:4D:43
diff --git a/apex/ca-certificates/files/6b03dec0.0 b/apex/ca-certificates/files/6b03dec0.0
new file mode 100644
index 0000000..2157a4e
--- /dev/null
+++ b/apex/ca-certificates/files/6b03dec0.0
@@ -0,0 +1,53 @@
+-----BEGIN CERTIFICATE-----
+MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD
+VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG
+A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw
+WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz
+IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNi
+AAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout736G
+jOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL2
+4CejQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7
+VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azTL818+FsuVbu/3ZL3pAzcMeGiAjEA/Jdm
+ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 02:03:e5:b8:82:eb:20:f8:25:27:6d:3d:66
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R3
+ Validity
+ Not Before: Jun 22 00:00:00 2016 GMT
+ Not After : Jun 22 00:00:00 2036 GMT
+ Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R3
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:1f:4f:33:87:33:29:8a:a1:84:de:cb:c7:21:58:
+ 41:89:ea:56:9d:2b:4b:85:c6:1d:4c:27:bc:7f:26:
+ 51:72:6f:e2:9f:d6:a3:ca:cc:45:14:46:8b:ad:ef:
+ 7e:86:8c:ec:b1:7e:2f:ff:a9:71:9d:18:84:45:04:
+ 41:55:6e:2b:ea:26:7f:bb:90:01:e3:4b:19:ba:e4:
+ 54:96:45:09:b1:d5:6c:91:44:ad:84:13:8e:9a:8c:
+ 0d:80:0c:32:f6:e0:27
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ C1:F1:26:BA:A0:2D:AE:85:81:CF:D3:F1:2A:12:BD:B8:0A:67:FD:BC
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:66:02:31:00:f6:e1:20:95:14:7b:54:a3:90:16:11:bf:84:
+ c8:ea:6f:6b:17:9e:1e:46:98:20:9b:9f:d3:0d:d9:ac:d3:2f:
+ cd:7c:f8:5b:2e:55:bb:bf:dd:92:f7:a4:0c:dc:31:e1:a2:02:
+ 31:00:fc:97:66:66:e5:43:16:13:83:dd:c7:df:2f:be:14:38:
+ ed:01:ce:b1:17:1a:11:75:e9:bd:03:8f:26:7e:84:e5:c9:60:
+ a6:95:d7:54:59:b7:e7:11:2c:89:d4:b9:ee:17
+SHA1 Fingerprint=ED:E5:71:80:2B:C8:92:B9:5B:83:3C:D2:32:68:3F:09:CD:A0:1E:46
diff --git a/apex/ca-certificates/files/6f7454b3.0 b/apex/ca-certificates/files/6f7454b3.0
new file mode 100644
index 0000000..45c0559
--- /dev/null
+++ b/apex/ca-certificates/files/6f7454b3.0
@@ -0,0 +1,122 @@
+-----BEGIN CERTIFICATE-----
+MIIFfzCCA2egAwIBAgIJAOF8N0D9G/5nMA0GCSqGSIb3DQEBDAUAMF0xCzAJBgNV
+BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw
+JQYDVQQDEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTMwHhcNMTYwNjE2
+MDYxNzE2WhcNMzgwMTE4MDYxNzE2WjBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
+U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UEAxMeU2VjdXJpdHkg
+Q29tbXVuaWNhdGlvbiBSb290Q0EzMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+CgKCAgEA48lySfcw3gl8qUCBWNO0Ot26YQ+TUG5pPDXC7ltzkBtnTCHsXzW7OT4r
+CmDvu20rhvtxosis5FaU+cmvsXLUIKx00rgVrVH+hXShuRD+BYD5UpOzQD11EKzA
+lrenfna84xtSGc4RHwsENPXY9Wk8d/Nk9A2qhd7gCVAEF5aEt8iKvE1y/By7z/MG
+TfmfZPd+pmaGNXHIEYBMwXFAWB6+oHP2/D5Q4eAvJj1+XCO1eXDe+uDRpdYMQXF7
+9+qMHIjH7Iv10S9VlkZ8WjtYO/u62C21Jdp6Ts9EriGmnpjKIG58u4iFW/vAEGK7
+8vknR+/RiTlDxN/e4UG/VHMgly1s2vPUB6PmudhvrvyMGS7TZ2crldtYXLVqAvO4
+g160a75BflcJdURQVc1aEWEhCmHCqYj9E7wtiS/NYeCVvsq1e+F7NGcLH7YMx3we
+GVPKp7FKFSBWFHA9K4IsD50VHUeAR/94mQ4xr28+j+2GaR57GIgUssL8gjMunEst
++3A7caoreyYn8xrC3PsXuKHqy6C0rtOUfnrQq8PsOC0RLoi/1D+tEjtCrI8Cbn3M
+0V9hvqG8OmpI6iZVIhZdXw3/JzOfGAN0iltSIEdrRU0id4xVJ/CvHozJgyJUt5rQ
+T9nO/NkuHJYosQLTA70lUhw0Zk8jq/R3gpYd0VcwCBEF/VfR2ccCAwEAAaNCMEAw
+HQYDVR0OBBYEFGQUfPxYchamCik0FW8qy7z8r6irMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDAUAA4ICAQDcAiMI4u8hOscNtybS
+YpOnpSNyByCCYN8Y11StaSWSntkUz5m5UoHPrmyKO1o5yGwBQ8IibQLwYs1OY0PA
+FNr0Y/Dq9HHuTofjcan0yVflLl8cebsjqodEV+m9NU1Bu0soo5iyG9kLFwfl9+qd
+9XbXv8S2gVj/yP9kaWJ5rW4OH3/uHWnlt3Jxs/6lATWUVCvAUm2PVcTJ0rjLyjQI
+UYWg9by0F1jqClx6vWPGOi//lkkZhOpn2ASxYfQAW0q3nHE3GYV5v4GwxxMOdnE+
+OoAGrgYWp421wsTL/0ClXI2lyTrtcoHKXJg80jQDdwj98ClZXSEIx2C/pHF7uNke
+gr4Jr2VvKKu/S7XuPghHJ6APbw+LP6yVGPO5DtxnVW5inkYO0QR4ynKudtml+LLf
+iAlhi+8kTtFZP1rUPcmTPCtk9YENFpb3ksP+MW/oKjJ0DvRMmEoYDjBU1cXrvMUV
+nuiZIesnKwkK2/HmcBhWuwzkvvnoEKQTkrgc4NtnHVMDpCKn3F2SEDzq//wbEBrD
+2NCcnWXL0CsnMQMeNuE9dnUM/0Umud1RvCPHX9jYhxBAEg09ODfnRDwYwFMJZI//
+1ZqmfHAuc1Uh6N//g7kdPjIe1qZ9LPFm6Vwdp6POXiUyK+OVrCoHzrQoeIY8Laad
+TdJ0MN1kURXbg4NR16/9M51NZg==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ e1:7c:37:40:fd:1b:fe:67
+ Signature Algorithm: sha384WithRSAEncryption
+ Issuer: C=JP, O=SECOM Trust Systems CO.,LTD., CN=Security Communication RootCA3
+ Validity
+ Not Before: Jun 16 06:17:16 2016 GMT
+ Not After : Jan 18 06:17:16 2038 GMT
+ Subject: C=JP, O=SECOM Trust Systems CO.,LTD., CN=Security Communication RootCA3
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:e3:c9:72:49:f7:30:de:09:7c:a9:40:81:58:d3:
+ b4:3a:dd:ba:61:0f:93:50:6e:69:3c:35:c2:ee:5b:
+ 73:90:1b:67:4c:21:ec:5f:35:bb:39:3e:2b:0a:60:
+ ef:bb:6d:2b:86:fb:71:a2:c8:ac:e4:56:94:f9:c9:
+ af:b1:72:d4:20:ac:74:d2:b8:15:ad:51:fe:85:74:
+ a1:b9:10:fe:05:80:f9:52:93:b3:40:3d:75:10:ac:
+ c0:96:b7:a7:7e:76:bc:e3:1b:52:19:ce:11:1f:0b:
+ 04:34:f5:d8:f5:69:3c:77:f3:64:f4:0d:aa:85:de:
+ e0:09:50:04:17:96:84:b7:c8:8a:bc:4d:72:fc:1c:
+ bb:cf:f3:06:4d:f9:9f:64:f7:7e:a6:66:86:35:71:
+ c8:11:80:4c:c1:71:40:58:1e:be:a0:73:f6:fc:3e:
+ 50:e1:e0:2f:26:3d:7e:5c:23:b5:79:70:de:fa:e0:
+ d1:a5:d6:0c:41:71:7b:f7:ea:8c:1c:88:c7:ec:8b:
+ f5:d1:2f:55:96:46:7c:5a:3b:58:3b:fb:ba:d8:2d:
+ b5:25:da:7a:4e:cf:44:ae:21:a6:9e:98:ca:20:6e:
+ 7c:bb:88:85:5b:fb:c0:10:62:bb:f2:f9:27:47:ef:
+ d1:89:39:43:c4:df:de:e1:41:bf:54:73:20:97:2d:
+ 6c:da:f3:d4:07:a3:e6:b9:d8:6f:ae:fc:8c:19:2e:
+ d3:67:67:2b:95:db:58:5c:b5:6a:02:f3:b8:83:5e:
+ b4:6b:be:41:7e:57:09:75:44:50:55:cd:5a:11:61:
+ 21:0a:61:c2:a9:88:fd:13:bc:2d:89:2f:cd:61:e0:
+ 95:be:ca:b5:7b:e1:7b:34:67:0b:1f:b6:0c:c7:7c:
+ 1e:19:53:ca:a7:b1:4a:15:20:56:14:70:3d:2b:82:
+ 2c:0f:9d:15:1d:47:80:47:ff:78:99:0e:31:af:6f:
+ 3e:8f:ed:86:69:1e:7b:18:88:14:b2:c2:fc:82:33:
+ 2e:9c:4b:2d:fb:70:3b:71:aa:2b:7b:26:27:f3:1a:
+ c2:dc:fb:17:b8:a1:ea:cb:a0:b4:ae:d3:94:7e:7a:
+ d0:ab:c3:ec:38:2d:11:2e:88:bf:d4:3f:ad:12:3b:
+ 42:ac:8f:02:6e:7d:cc:d1:5f:61:be:a1:bc:3a:6a:
+ 48:ea:26:55:22:16:5d:5f:0d:ff:27:33:9f:18:03:
+ 74:8a:5b:52:20:47:6b:45:4d:22:77:8c:55:27:f0:
+ af:1e:8c:c9:83:22:54:b7:9a:d0:4f:d9:ce:fc:d9:
+ 2e:1c:96:28:b1:02:d3:03:bd:25:52:1c:34:66:4f:
+ 23:ab:f4:77:82:96:1d:d1:57:30:08:11:05:fd:57:
+ d1:d9:c7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 64:14:7C:FC:58:72:16:A6:0A:29:34:15:6F:2A:CB:BC:FC:AF:A8:AB
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha384WithRSAEncryption
+ Signature Value:
+ dc:02:23:08:e2:ef:21:3a:c7:0d:b7:26:d2:62:93:a7:a5:23:
+ 72:07:20:82:60:df:18:d7:54:ad:69:25:92:9e:d9:14:cf:99:
+ b9:52:81:cf:ae:6c:8a:3b:5a:39:c8:6c:01:43:c2:22:6d:02:
+ f0:62:cd:4e:63:43:c0:14:da:f4:63:f0:ea:f4:71:ee:4e:87:
+ e3:71:a9:f4:c9:57:e5:2e:5f:1c:79:bb:23:aa:87:44:57:e9:
+ bd:35:4d:41:bb:4b:28:a3:98:b2:1b:d9:0b:17:07:e5:f7:ea:
+ 9d:f5:76:d7:bf:c4:b6:81:58:ff:c8:ff:64:69:62:79:ad:6e:
+ 0e:1f:7f:ee:1d:69:e5:b7:72:71:b3:fe:a5:01:35:94:54:2b:
+ c0:52:6d:8f:55:c4:c9:d2:b8:cb:ca:34:08:51:85:a0:f5:bc:
+ b4:17:58:ea:0a:5c:7a:bd:63:c6:3a:2f:ff:96:49:19:84:ea:
+ 67:d8:04:b1:61:f4:00:5b:4a:b7:9c:71:37:19:85:79:bf:81:
+ b0:c7:13:0e:76:71:3e:3a:80:06:ae:06:16:a7:8d:b5:c2:c4:
+ cb:ff:40:a5:5c:8d:a5:c9:3a:ed:72:81:ca:5c:98:3c:d2:34:
+ 03:77:08:fd:f0:29:59:5d:21:08:c7:60:bf:a4:71:7b:b8:d9:
+ 1e:82:be:09:af:65:6f:28:ab:bf:4b:b5:ee:3e:08:47:27:a0:
+ 0f:6f:0f:8b:3f:ac:95:18:f3:b9:0e:dc:67:55:6e:62:9e:46:
+ 0e:d1:04:78:ca:72:ae:76:d9:a5:f8:b2:df:88:09:61:8b:ef:
+ 24:4e:d1:59:3f:5a:d4:3d:c9:93:3c:2b:64:f5:81:0d:16:96:
+ f7:92:c3:fe:31:6f:e8:2a:32:74:0e:f4:4c:98:4a:18:0e:30:
+ 54:d5:c5:eb:bc:c5:15:9e:e8:99:21:eb:27:2b:09:0a:db:f1:
+ e6:70:18:56:bb:0c:e4:be:f9:e8:10:a4:13:92:b8:1c:e0:db:
+ 67:1d:53:03:a4:22:a7:dc:5d:92:10:3c:ea:ff:fc:1b:10:1a:
+ c3:d8:d0:9c:9d:65:cb:d0:2b:27:31:03:1e:36:e1:3d:76:75:
+ 0c:ff:45:26:b9:dd:51:bc:23:c7:5f:d8:d8:87:10:40:12:0d:
+ 3d:38:37:e7:44:3c:18:c0:53:09:64:8f:ff:d5:9a:a6:7c:70:
+ 2e:73:55:21:e8:df:ff:83:b9:1d:3e:32:1e:d6:a6:7d:2c:f1:
+ 66:e9:5c:1d:a7:a3:ce:5e:25:32:2b:e3:95:ac:2a:07:ce:b4:
+ 28:78:86:3c:2d:a6:9d:4d:d2:74:30:dd:64:51:15:db:83:83:
+ 51:d7:af:fd:33:9d:4d:66
+SHA1 Fingerprint=C3:03:C8:22:74:92:E5:61:A2:9C:5F:79:91:2B:1E:44:13:91:30:3A
diff --git a/apex/ca-certificates/files/75680d2e.0 b/apex/ca-certificates/files/75680d2e.0
new file mode 100644
index 0000000..d3e1b4c
--- /dev/null
+++ b/apex/ca-certificates/files/75680d2e.0
@@ -0,0 +1,88 @@
+-----BEGIN CERTIFICATE-----
+MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
+YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
+MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
+BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
+GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
+BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
+3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
+YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
+rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
+ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
+oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
+MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
+QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
+b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
+AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
+GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
+Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
+G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
+l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
+smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=GB, ST=Greater Manchester, L=Salford, O=Comodo CA Limited, CN=AAA Certificate Services
+ Validity
+ Not Before: Jan 1 00:00:00 2004 GMT
+ Not After : Dec 31 23:59:59 2028 GMT
+ Subject: C=GB, ST=Greater Manchester, L=Salford, O=Comodo CA Limited, CN=AAA Certificate Services
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:be:40:9d:f4:6e:e1:ea:76:87:1c:4d:45:44:8e:
+ be:46:c8:83:06:9d:c1:2a:fe:18:1f:8e:e4:02:fa:
+ f3:ab:5d:50:8a:16:31:0b:9a:06:d0:c5:70:22:cd:
+ 49:2d:54:63:cc:b6:6e:68:46:0b:53:ea:cb:4c:24:
+ c0:bc:72:4e:ea:f1:15:ae:f4:54:9a:12:0a:c3:7a:
+ b2:33:60:e2:da:89:55:f3:22:58:f3:de:dc:cf:ef:
+ 83:86:a2:8c:94:4f:9f:68:f2:98:90:46:84:27:c7:
+ 76:bf:e3:cc:35:2c:8b:5e:07:64:65:82:c0:48:b0:
+ a8:91:f9:61:9f:76:20:50:a8:91:c7:66:b5:eb:78:
+ 62:03:56:f0:8a:1a:13:ea:31:a3:1e:a0:99:fd:38:
+ f6:f6:27:32:58:6f:07:f5:6b:b8:fb:14:2b:af:b7:
+ aa:cc:d6:63:5f:73:8c:da:05:99:a8:38:a8:cb:17:
+ 78:36:51:ac:e9:9e:f4:78:3a:8d:cf:0f:d9:42:e2:
+ 98:0c:ab:2f:9f:0e:01:de:ef:9f:99:49:f1:2d:df:
+ ac:74:4d:1b:98:b5:47:c5:e5:29:d1:f9:90:18:c7:
+ 62:9c:be:83:c7:26:7b:3e:8a:25:c7:c0:dd:9d:e6:
+ 35:68:10:20:9d:8f:d8:de:d2:c3:84:9c:0d:5e:e8:
+ 2f:c9
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ A0:11:0A:23:3E:96:F1:07:EC:E2:AF:29:EF:82:A5:7F:D0:30:A4:B4
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 CRL Distribution Points:
+ Full Name:
+ URI:http://crl.comodoca.com/AAACertificateServices.crl
+ Full Name:
+ URI:http://crl.comodo.net/AAACertificateServices.crl
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 08:56:fc:02:f0:9b:e8:ff:a4:fa:d6:7b:c6:44:80:ce:4f:c4:
+ c5:f6:00:58:cc:a6:b6:bc:14:49:68:04:76:e8:e6:ee:5d:ec:
+ 02:0f:60:d6:8d:50:18:4f:26:4e:01:e3:e6:b0:a5:ee:bf:bc:
+ 74:54:41:bf:fd:fc:12:b8:c7:4f:5a:f4:89:60:05:7f:60:b7:
+ 05:4a:f3:f6:f1:c2:bf:c4:b9:74:86:b6:2d:7d:6b:cc:d2:f3:
+ 46:dd:2f:c6:e0:6a:c3:c3:34:03:2c:7d:96:dd:5a:c2:0e:a7:
+ 0a:99:c1:05:8b:ab:0c:2f:f3:5c:3a:cf:6c:37:55:09:87:de:
+ 53:40:6c:58:ef:fc:b6:ab:65:6e:04:f6:1b:dc:3c:e0:5a:15:
+ c6:9e:d9:f1:59:48:30:21:65:03:6c:ec:e9:21:73:ec:9b:03:
+ a1:e0:37:ad:a0:15:18:8f:fa:ba:02:ce:a7:2c:a9:10:13:2c:
+ d4:e5:08:26:ab:22:97:60:f8:90:5e:74:d4:a2:9a:53:bd:f2:
+ a9:68:e0:a2:6e:c2:d7:6c:b1:a3:0f:9e:bf:eb:68:e7:56:f2:
+ ae:f2:e3:2b:38:3a:09:81:b5:6b:85:d7:be:2d:ed:3f:1a:b7:
+ b2:63:e2:f5:62:2c:82:d4:6a:00:41:50:f1:39:83:9f:95:e9:
+ 36:96:98:6e
+SHA1 Fingerprint=D1:EB:23:A4:6D:17:D6:8F:D9:25:64:C2:F1:F1:60:17:64:D8:E3:49
diff --git a/apex/ca-certificates/files/76579174.0 b/apex/ca-certificates/files/76579174.0
new file mode 100644
index 0000000..6ab47d6
--- /dev/null
+++ b/apex/ca-certificates/files/76579174.0
@@ -0,0 +1,91 @@
+-----BEGIN CERTIFICATE-----
+MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB
+gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk
+MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY
+UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx
+NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3
+dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy
+dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6
+38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP
+KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q
+DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4
+qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa
+JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi
+PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P
+BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs
+jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0
+eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD
+ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR
+vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
+qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa
+IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy
+i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ
+O+7ETPTsJ3xCwnR8gooJybQDJbw=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 50:94:6c:ec:18:ea:d5:9c:4d:d5:97:ef:75:8f:a0:ad
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=US, OU=www.xrampsecurity.com, O=XRamp Security Services Inc, CN=XRamp Global Certification Authority
+ Validity
+ Not Before: Nov 1 17:14:04 2004 GMT
+ Not After : Jan 1 05:37:19 2035 GMT
+ Subject: C=US, OU=www.xrampsecurity.com, O=XRamp Security Services Inc, CN=XRamp Global Certification Authority
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:98:24:1e:bd:15:b4:ba:df:c7:8c:a5:27:b6:38:
+ 0b:69:f3:b6:4e:a8:2c:2e:21:1d:5c:44:df:21:5d:
+ 7e:23:74:fe:5e:7e:b4:4a:b7:a6:ad:1f:ae:e0:06:
+ 16:e2:9b:5b:d9:67:74:6b:5d:80:8f:29:9d:86:1b:
+ d9:9c:0d:98:6d:76:10:28:58:e4:65:b0:7f:4a:98:
+ 79:9f:e0:c3:31:7e:80:2b:b5:8c:c0:40:3b:11:86:
+ d0:cb:a2:86:36:60:a4:d5:30:82:6d:d9:6e:d0:0f:
+ 12:04:33:97:5f:4f:61:5a:f0:e4:f9:91:ab:e7:1d:
+ 3b:bc:e8:cf:f4:6b:2d:34:7c:e2:48:61:1c:8e:f3:
+ 61:44:cc:6f:a0:4a:a9:94:b0:4d:da:e7:a9:34:7a:
+ 72:38:a8:41:cc:3c:94:11:7d:eb:c8:a6:8c:b7:86:
+ cb:ca:33:3b:d9:3d:37:8b:fb:7a:3e:86:2c:e7:73:
+ d7:0a:57:ac:64:9b:19:eb:f4:0f:04:08:8a:ac:03:
+ 17:19:64:f4:5a:25:22:8d:34:2c:b2:f6:68:1d:12:
+ 6d:d3:8a:1e:14:da:c4:8f:a6:e2:23:85:d5:7a:0d:
+ bd:6a:e0:e9:ec:ec:17:bb:42:1b:67:aa:25:ed:45:
+ 83:21:fc:c1:c9:7c:d5:62:3e:fa:f2:c5:2d:d3:fd:
+ d4:65
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ 1.3.6.1.4.1.311.20.2:
+ ...C.A
+ X509v3 Key Usage:
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ C6:4F:A2:3D:06:63:84:09:9C:CE:62:E4:04:AC:8D:5C:B5:E9:B6:1B
+ X509v3 CRL Distribution Points:
+ Full Name:
+ URI:http://crl.xrampsecurity.com/XGCA.crl
+ 1.3.6.1.4.1.311.21.1:
+ ...
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 91:15:39:03:01:1b:67:fb:4a:1c:f9:0a:60:5b:a1:da:4d:97:
+ 62:f9:24:53:27:d7:82:64:4e:90:2e:c3:49:1b:2b:9a:dc:fc:
+ a8:78:67:35:f1:1d:f0:11:bd:b7:48:e3:10:f6:0d:df:3f:d2:
+ c9:b6:aa:55:a4:48:ba:02:db:de:59:2e:15:5b:3b:9d:16:7d:
+ 47:d7:37:ea:5f:4d:76:12:36:bb:1f:d7:a1:81:04:46:20:a3:
+ 2c:6d:a9:9e:01:7e:3f:29:ce:00:93:df:fd:c9:92:73:89:89:
+ 64:9e:e7:2b:e4:1c:91:2c:d2:b9:ce:7d:ce:6f:31:99:d3:e6:
+ be:d2:1e:90:f0:09:14:79:5c:23:ab:4d:d2:da:21:1f:4d:99:
+ 79:9d:e1:cf:27:9f:10:9b:1c:88:0d:b0:8a:64:41:31:b8:0e:
+ 6c:90:24:a4:9b:5c:71:8f:ba:bb:7e:1c:1b:db:6a:80:0f:21:
+ bc:e9:db:a6:b7:40:f4:b2:8b:a9:b1:e4:ef:9a:1a:d0:3d:69:
+ 99:ee:a8:28:a3:e1:3c:b3:f0:b2:11:9c:cf:7c:40:e6:dd:e7:
+ 43:7d:a2:d8:3a:b5:a9:8d:f2:34:99:c4:d4:10:e1:06:fd:09:
+ 84:10:3b:ee:c4:4c:f4:ec:27:7c:42:c2:74:7c:82:8a:09:c9:
+ b4:03:25:bc
+SHA1 Fingerprint=B8:01:86:D1:EB:9C:86:A5:41:04:CF:30:54:F3:4C:52:B7:E5:58:C6
diff --git a/apex/ca-certificates/files/7892ad52.0 b/apex/ca-certificates/files/7892ad52.0
new file mode 100644
index 0000000..3d6eb4f
--- /dev/null
+++ b/apex/ca-certificates/files/7892ad52.0
@@ -0,0 +1,57 @@
+-----BEGIN CERTIFICATE-----
+MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC
+VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T
+U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx
+NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv
+dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv
+bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49
+AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA
+VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku
+WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP
+MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX
+5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ
+ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg
+h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 3182246526754555285 (0x2c299c5b16ed0595)
+ Signature Algorithm: ecdsa-with-SHA256
+ Issuer: C=US, ST=Texas, L=Houston, O=SSL Corporation, CN=SSL.com EV Root Certification Authority ECC
+ Validity
+ Not Before: Feb 12 18:15:23 2016 GMT
+ Not After : Feb 12 18:15:23 2041 GMT
+ Subject: C=US, ST=Texas, L=Houston, O=SSL Corporation, CN=SSL.com EV Root Certification Authority ECC
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:aa:12:47:90:98:1b:fb:ef:c3:40:07:83:20:4e:
+ f1:30:82:a2:06:d1:f2:92:86:61:f2:f6:21:68:ca:
+ 00:c4:c7:ea:43:00:54:86:dc:fd:1f:df:00:b8:41:
+ 62:5c:dc:70:16:32:de:1f:99:d4:cc:c5:07:c8:08:
+ 1f:61:16:07:51:3d:7d:5c:07:53:e3:35:38:8c:df:
+ cd:9f:d9:2e:0d:4a:b6:19:2e:5a:70:5a:06:ed:be:
+ f0:a1:b0:ca:d0:09:29
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 5B:CA:5E:E5:DE:D2:81:AA:CD:A8:2D:64:51:B6:D9:72:9B:97:E6:4F
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Authority Key Identifier:
+ 5B:CA:5E:E5:DE:D2:81:AA:CD:A8:2D:64:51:B6:D9:72:9B:97:E6:4F
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ Signature Algorithm: ecdsa-with-SHA256
+ Signature Value:
+ 30:65:02:31:00:8a:e6:40:89:37:eb:e9:d5:13:d9:ca:d4:6b:
+ 24:f3:b0:3d:87:46:58:1a:ec:b1:df:6f:fb:56:ba:70:6b:c7:
+ 38:cc:e8:b1:8c:4f:0f:f7:f1:67:76:0e:83:d0:1e:51:8f:02:
+ 30:3d:f6:23:28:26:4c:c6:60:87:93:26:9b:b2:35:1e:ba:d6:
+ f7:3c:d1:1c:ce:fa:25:3c:a6:1a:81:15:5b:f3:12:0f:6c:ee:
+ 65:8a:c9:87:a8:f9:07:e0:62:9a:8c:5c:4a
+SHA1 Fingerprint=4C:DD:51:A3:D1:F5:20:32:14:B0:C6:C5:32:23:03:91:C7:46:42:6D
diff --git a/apex/ca-certificates/files/7a7c655d.0 b/apex/ca-certificates/files/7a7c655d.0
new file mode 100644
index 0000000..b671122
--- /dev/null
+++ b/apex/ca-certificates/files/7a7c655d.0
@@ -0,0 +1,48 @@
+-----BEGIN CERTIFICATE-----
+MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5
+MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
+Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
+A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
+Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl
+ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j
+QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr
+ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr
+BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM
+YyRIHN8wfdVoOw==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 06:6c:9f:d5:74:97:36:66:3f:3b:0b:9a:d9:e8:9e:76:03:f2:4a
+ Signature Algorithm: ecdsa-with-SHA256
+ Issuer: C=US, O=Amazon, CN=Amazon Root CA 3
+ Validity
+ Not Before: May 26 00:00:00 2015 GMT
+ Not After : May 26 00:00:00 2040 GMT
+ Subject: C=US, O=Amazon, CN=Amazon Root CA 3
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (256 bit)
+ pub:
+ 04:29:97:a7:c6:41:7f:c0:0d:9b:e8:01:1b:56:c6:
+ f2:52:a5:ba:2d:b2:12:e8:d2:2e:d7:fa:c9:c5:d8:
+ aa:6d:1f:73:81:3b:3b:98:6b:39:7c:33:a5:c5:4e:
+ 86:8e:80:17:68:62:45:57:7d:44:58:1d:b3:37:e5:
+ 67:08:eb:66:de
+ ASN1 OID: prime256v1
+ NIST CURVE: P-256
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ AB:B6:DB:D7:06:9E:37:AC:30:86:07:91:70:C7:9C:C4:19:B1:78:C0
+ Signature Algorithm: ecdsa-with-SHA256
+ Signature Value:
+ 30:46:02:21:00:e0:85:92:a3:17:b7:8d:f9:2b:06:a5:93:ac:
+ 1a:98:68:61:72:fa:e1:a1:d0:fb:1c:78:60:a6:43:99:c5:b8:
+ c4:02:21:00:9c:02:ef:f1:94:9c:b3:96:f9:eb:c6:2a:f8:b6:
+ 2c:fe:3a:90:14:16:d7:8c:63:24:48:1c:df:30:7d:d5:68:3b
+SHA1 Fingerprint=0D:44:DD:8C:3C:8C:1A:1A:58:75:64:81:E9:0F:2E:2A:FF:B3:D2:6E
diff --git a/apex/ca-certificates/files/7a819ef2.0 b/apex/ca-certificates/files/7a819ef2.0
new file mode 100644
index 0000000..da677d1
--- /dev/null
+++ b/apex/ca-certificates/files/7a819ef2.0
@@ -0,0 +1,126 @@
+-----BEGIN CERTIFICATE-----
+MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
+GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
+b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV
+BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W
+YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa
+GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg
+Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J
+WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB
+rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp
++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1
+ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i
+Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz
+PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og
+/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH
+oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI
+yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud
+EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2
+A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL
+MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT
+ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f
+BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn
+g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl
+fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K
+WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha
+B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc
+hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR
+TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD
+mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z
+ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y
+4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza
+8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1289 (0x509)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 2
+ Validity
+ Not Before: Nov 24 18:27:00 2006 GMT
+ Not After : Nov 24 18:23:33 2031 GMT
+ Subject: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:9a:18:ca:4b:94:0d:00:2d:af:03:29:8a:f0:0f:
+ 81:c8:ae:4c:19:85:1d:08:9f:ab:29:44:85:f3:2f:
+ 81:ad:32:1e:90:46:bf:a3:86:26:1a:1e:fe:7e:1c:
+ 18:3a:5c:9c:60:17:2a:3a:74:83:33:30:7d:61:54:
+ 11:cb:ed:ab:e0:e6:d2:a2:7e:f5:6b:6f:18:b7:0a:
+ 0b:2d:fd:e9:3e:ef:0a:c6:b3:10:e9:dc:c2:46:17:
+ f8:5d:fd:a4:da:ff:9e:49:5a:9c:e6:33:e6:24:96:
+ f7:3f:ba:5b:2b:1c:7a:35:c2:d6:67:fe:ab:66:50:
+ 8b:6d:28:60:2b:ef:d7:60:c3:c7:93:bc:8d:36:91:
+ f3:7f:f8:db:11:13:c4:9c:77:76:c1:ae:b7:02:6a:
+ 81:7a:a9:45:83:e2:05:e6:b9:56:c1:94:37:8f:48:
+ 71:63:22:ec:17:65:07:95:8a:4b:df:8f:c6:5a:0a:
+ e5:b0:e3:5f:5e:6b:11:ab:0c:f9:85:eb:44:e9:f8:
+ 04:73:f2:e9:fe:5c:98:8c:f5:73:af:6b:b4:7e:cd:
+ d4:5c:02:2b:4c:39:e1:b2:95:95:2d:42:87:d7:d5:
+ b3:90:43:b7:6c:13:f1:de:dd:f6:c4:f8:89:3f:d1:
+ 75:f5:92:c3:91:d5:8a:88:d0:90:ec:dc:6d:de:89:
+ c2:65:71:96:8b:0d:03:fd:9c:bf:5b:16:ac:92:db:
+ ea:fe:79:7c:ad:eb:af:f7:16:cb:db:cd:25:2b:e5:
+ 1f:fb:9a:9f:e2:51:cc:3a:53:0c:48:e6:0e:bd:c9:
+ b4:76:06:52:e6:11:13:85:72:63:03:04:e0:04:36:
+ 2b:20:19:02:e8:74:a7:1f:b6:c9:56:66:f0:75:25:
+ dc:67:c1:0e:61:60:88:b3:3e:d1:a8:fc:a3:da:1d:
+ b0:d1:b1:23:54:df:44:76:6d:ed:41:d8:c1:b2:22:
+ b6:53:1c:df:35:1d:dc:a1:77:2a:31:e4:2d:f5:e5:
+ e5:db:c8:e0:ff:e5:80:d7:0b:63:a0:ff:33:a1:0f:
+ ba:2c:15:15:ea:97:b3:d2:a2:b5:be:f2:8c:96:1e:
+ 1a:8f:1d:6c:a4:61:37:b9:86:73:33:d7:97:96:9e:
+ 23:7d:82:a4:4c:81:e2:a1:d1:ba:67:5f:95:07:a3:
+ 27:11:ee:16:10:7b:bc:45:4a:4c:b2:04:d2:ab:ef:
+ d5:fd:0c:51:ce:50:6a:08:31:f9:91:da:0c:8f:64:
+ 5c:03:c3:3a:8b:20:3f:6e:8d:67:3d:3a:d6:fe:7d:
+ 5b:88:c9:5e:fb:cc:61:dc:8b:33:77:d3:44:32:35:
+ 09:62:04:92:16:10:d8:9e:27:47:fb:3b:21:e3:f8:
+ eb:1d:5b
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage:
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 1A:84:62:BC:48:4C:33:25:04:D4:EE:D0:F6:03:C4:19:46:D1:94:6B
+ X509v3 Authority Key Identifier:
+ keyid:1A:84:62:BC:48:4C:33:25:04:D4:EE:D0:F6:03:C4:19:46:D1:94:6B
+ DirName:/C=BM/O=QuoVadis Limited/CN=QuoVadis Root CA 2
+ serial:05:09
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 3e:0a:16:4d:9f:06:5b:a8:ae:71:5d:2f:05:2f:67:e6:13:45:
+ 83:c4:36:f6:f3:c0:26:0c:0d:b5:47:64:5d:f8:b4:72:c9:46:
+ a5:03:18:27:55:89:78:7d:76:ea:96:34:80:17:20:dc:e7:83:
+ f8:8d:fc:07:b8:da:5f:4d:2e:67:b2:84:fd:d9:44:fc:77:50:
+ 81:e6:7c:b4:c9:0d:0b:72:53:f8:76:07:07:41:47:96:0c:fb:
+ e0:82:26:93:55:8c:fe:22:1f:60:65:7c:5f:e7:26:b3:f7:32:
+ 90:98:50:d4:37:71:55:f6:92:21:78:f7:95:79:fa:f8:2d:26:
+ 87:66:56:30:77:a6:37:78:33:52:10:58:ae:3f:61:8e:f2:6a:
+ b1:ef:18:7e:4a:59:63:ca:8d:a2:56:d5:a7:2f:bc:56:1f:cf:
+ 39:c1:e2:fb:0a:a8:15:2c:7d:4d:7a:63:c6:6c:97:44:3c:d2:
+ 6f:c3:4a:17:0a:f8:90:d2:57:a2:19:51:a5:2d:97:41:da:07:
+ 4f:a9:50:da:90:8d:94:46:e1:3e:f0:94:fd:10:00:38:f5:3b:
+ e8:40:e1:b4:6e:56:1a:20:cc:6f:58:8d:ed:2e:45:8f:d6:e9:
+ 93:3f:e7:b1:2c:df:3a:d6:22:8c:dc:84:bb:22:6f:d0:f8:e4:
+ c6:39:e9:04:88:3c:c3:ba:eb:55:7a:6d:80:99:24:f5:6c:01:
+ fb:f8:97:b0:94:5b:eb:fd:d2:6f:f1:77:68:0d:35:64:23:ac:
+ b8:55:a1:03:d1:4d:42:19:dc:f8:75:59:56:a3:f9:a8:49:79:
+ f8:af:0e:b9:11:a0:7c:b7:6a:ed:34:d0:b6:26:62:38:1a:87:
+ 0c:f8:e8:fd:2e:d3:90:7f:07:91:2a:1d:d6:7e:5c:85:83:99:
+ b0:38:08:3f:e9:5e:f9:35:07:e4:c9:62:6e:57:7f:a7:50:95:
+ f7:ba:c8:9b:e6:8e:a2:01:c5:d6:66:bf:79:61:f3:3c:1c:e1:
+ b9:82:5c:5d:a0:c3:e9:d8:48:bd:19:a2:11:14:19:6e:b2:86:
+ 1b:68:3e:48:37:1a:88:b7:5d:96:5e:9c:c7:ef:27:62:08:e2:
+ 91:19:5c:d2:f1:21:dd:ba:17:42:82:97:71:81:53:31:a9:9f:
+ f6:7d:62:bf:72:e1:a3:93:1d:cc:8a:26:5a:09:38:d0:ce:d7:
+ 0d:80:16:b4:78:a5:3a:87:4c:8d:8a:a5:d5:46:97:f2:2c:10:
+ b9:bc:54:22:c0:01:50:69:43:9e:f4:b2:ef:6d:f8:ec:da:f1:
+ e3:b1:ef:df:91:8f:54:2a:0b:25:c1:26:19:c4:52:10:05:65:
+ d5:82:10:ea:c2:31:cd:2e
+SHA1 Fingerprint=CA:3A:FB:CF:12:40:36:4B:44:B2:16:20:88:80:48:39:19:93:7C:F7
diff --git a/apex/ca-certificates/files/81b9768f.0 b/apex/ca-certificates/files/81b9768f.0
new file mode 100644
index 0000000..53f0bce
--- /dev/null
+++ b/apex/ca-certificates/files/81b9768f.0
@@ -0,0 +1,84 @@
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
+ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
+MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
+LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
+RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
+PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
+xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
+Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
+hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
+EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
+FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
+nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
+eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
+hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
+Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
+vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
++OkuE6N36B9K
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 02:ac:5c:26:6a:0b:40:9b:8f:0b:79:f2:ae:46:25:77
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA
+ Validity
+ Not Before: Nov 10 00:00:00 2006 GMT
+ Not After : Nov 10 00:00:00 2031 GMT
+ Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c6:cc:e5:73:e6:fb:d4:bb:e5:2d:2d:32:a6:df:
+ e5:81:3f:c9:cd:25:49:b6:71:2a:c3:d5:94:34:67:
+ a2:0a:1c:b0:5f:69:a6:40:b1:c4:b7:b2:8f:d0:98:
+ a4:a9:41:59:3a:d3:dc:94:d6:3c:db:74:38:a4:4a:
+ cc:4d:25:82:f7:4a:a5:53:12:38:ee:f3:49:6d:71:
+ 91:7e:63:b6:ab:a6:5f:c3:a4:84:f8:4f:62:51:be:
+ f8:c5:ec:db:38:92:e3:06:e5:08:91:0c:c4:28:41:
+ 55:fb:cb:5a:89:15:7e:71:e8:35:bf:4d:72:09:3d:
+ be:3a:38:50:5b:77:31:1b:8d:b3:c7:24:45:9a:a7:
+ ac:6d:00:14:5a:04:b7:ba:13:eb:51:0a:98:41:41:
+ 22:4e:65:61:87:81:41:50:a6:79:5c:89:de:19:4a:
+ 57:d5:2e:e6:5d:1c:53:2c:7e:98:cd:1a:06:16:a4:
+ 68:73:d0:34:04:13:5c:a1:71:d3:5a:7c:55:db:5e:
+ 64:e1:37:87:30:56:04:e5:11:b4:29:80:12:f1:79:
+ 39:88:a2:02:11:7c:27:66:b7:88:b7:78:f2:ca:0a:
+ a8:38:ab:0a:64:c2:bf:66:5d:95:84:c1:a1:25:1e:
+ 87:5d:1a:50:0b:20:12:cc:41:bb:6e:0b:51:38:b8:
+ 4b:cb
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3
+ X509v3 Authority Key Identifier:
+ B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 1c:1a:06:97:dc:d7:9c:9f:3c:88:66:06:08:57:21:db:21:47:
+ f8:2a:67:aa:bf:18:32:76:40:10:57:c1:8a:f3:7a:d9:11:65:
+ 8e:35:fa:9e:fc:45:b5:9e:d9:4c:31:4b:b8:91:e8:43:2c:8e:
+ b3:78:ce:db:e3:53:79:71:d6:e5:21:94:01:da:55:87:9a:24:
+ 64:f6:8a:66:cc:de:9c:37:cd:a8:34:b1:69:9b:23:c8:9e:78:
+ 22:2b:70:43:e3:55:47:31:61:19:ef:58:c5:85:2f:4e:30:f6:
+ a0:31:16:23:c8:e7:e2:65:16:33:cb:bf:1a:1b:a0:3d:f8:ca:
+ 5e:8b:31:8b:60:08:89:2d:0c:06:5c:52:b7:c4:f9:0a:98:d1:
+ 15:5f:9f:12:be:7c:36:63:38:bd:44:a4:7f:e4:26:2b:0a:c4:
+ 97:69:0d:e9:8c:e2:c0:10:57:b8:c8:76:12:91:55:f2:48:69:
+ d8:bc:2a:02:5b:0f:44:d4:20:31:db:f4:ba:70:26:5d:90:60:
+ 9e:bc:4b:17:09:2f:b4:cb:1e:43:68:c9:07:27:c1:d2:5c:f7:
+ ea:21:b9:68:12:9c:3c:9c:bf:9e:fc:80:5c:9b:63:cd:ec:47:
+ aa:25:27:67:a0:37:f3:00:82:7d:54:d7:a9:f8:e9:2e:13:a3:
+ 77:e8:1f:4a
+SHA1 Fingerprint=5F:B7:EE:06:33:E2:59:DB:AD:0C:4C:9A:E6:D3:8F:1A:61:C7:DC:25
diff --git a/apex/ca-certificates/files/82223c44.0 b/apex/ca-certificates/files/82223c44.0
new file mode 100644
index 0000000..90d5339
--- /dev/null
+++ b/apex/ca-certificates/files/82223c44.0
@@ -0,0 +1,120 @@
+-----BEGIN CERTIFICATE-----
+MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd
+MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg
+Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow
+TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw
+HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB
+BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr
+6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV
+L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91
+1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx
+MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ
+QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB
+arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr
+Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi
+FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS
+P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN
+9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP
+AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz
+uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h
+9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s
+A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t
+OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo
++fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7
+KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2
+DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us
+H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ
+I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7
+5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h
+3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz
+Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=NO, O=Buypass AS-983163327, CN=Buypass Class 2 Root CA
+ Validity
+ Not Before: Oct 26 08:38:03 2010 GMT
+ Not After : Oct 26 08:38:03 2040 GMT
+ Subject: C=NO, O=Buypass AS-983163327, CN=Buypass Class 2 Root CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:d7:c7:5e:f7:c1:07:d4:77:fb:43:21:f4:f4:f5:
+ 69:e4:ee:32:01:db:a3:86:1f:e4:59:0d:ba:e7:75:
+ 83:52:eb:ea:1c:61:15:48:bb:1d:07:ca:8c:ae:b0:
+ dc:96:9d:ea:c3:60:92:86:82:28:73:9c:56:06:ff:
+ 4b:64:f0:0c:2a:37:49:b5:e5:cf:0c:7c:ee:f1:4a:
+ bb:73:30:65:f3:d5:2f:83:b6:7e:e3:e7:f5:9e:ab:
+ 60:f9:d3:f1:9d:92:74:8a:e4:1c:96:ac:5b:80:e9:
+ b5:f4:31:87:a3:51:fc:c7:7e:a1:6f:8e:53:77:d4:
+ 97:c1:55:33:92:3e:18:2f:75:d4:ad:86:49:cb:95:
+ af:54:06:6c:d8:06:13:8d:5b:ff:e1:26:19:59:c0:
+ 24:ba:81:71:79:90:44:50:68:24:94:5f:b8:b3:11:
+ f1:29:41:61:a3:41:cb:23:36:d5:c1:f1:32:50:10:
+ 4e:7f:f4:86:93:ec:84:d3:8e:bc:4b:bf:5c:01:4e:
+ 07:3d:dc:14:8a:94:0a:a4:ea:73:fb:0b:51:e8:13:
+ 07:18:fa:0e:f1:2b:d1:54:15:7d:3c:e1:f7:b4:19:
+ 42:67:62:5e:77:e0:a2:55:ec:b6:d9:69:17:d5:3a:
+ af:44:ed:4a:c5:9e:e4:7a:27:7c:e5:75:d7:aa:cb:
+ 25:e7:df:6b:0a:db:0f:4d:93:4e:a8:a0:cd:7b:2e:
+ f2:59:01:6a:b7:0d:b8:07:81:7e:8b:38:1b:38:e6:
+ 0a:57:99:3d:ee:21:e8:a3:f5:0c:16:dd:8b:ec:34:
+ 8e:9c:2a:1c:00:15:17:8d:68:83:d2:70:9f:18:08:
+ cd:11:68:d5:c9:6b:52:cd:c4:46:8f:dc:b5:f3:d8:
+ 57:73:1e:e9:94:39:04:bf:d3:de:38:de:b4:53:ec:
+ 69:1c:a2:7e:c4:8f:e4:1b:70:ad:f2:a2:f9:fb:f7:
+ 16:64:66:69:9f:49:51:a2:e2:15:18:67:06:4a:7f:
+ d5:6c:b5:4d:b3:33:e0:61:eb:5d:be:e9:98:0f:32:
+ d7:1d:4b:3c:2e:5a:01:52:91:09:f2:df:ea:8d:d8:
+ 06:40:63:aa:11:e4:fe:c3:37:9e:14:52:3f:f4:e2:
+ cc:f2:61:93:d1:fd:67:6b:d7:52:ae:bf:68:ab:40:
+ 43:a0:57:35:53:78:f0:53:f8:61:42:07:64:c6:d7:
+ 6f:9b:4c:38:0d:63:ac:62:af:36:8b:a2:73:0a:0d:
+ f5:21:bd:74:aa:4d:ea:72:03:49:db:c7:5f:1d:62:
+ 63:c7:fd:dd:91:ec:33:ee:f5:6d:b4:6e:30:68:de:
+ c8:d6:26:b0:75:5e:7b:b4:07:20:98:a1:76:32:b8:
+ 4d:6c:4f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ C9:80:77:E0:62:92:82:F5:46:9C:F3:BA:F7:4C:C3:DE:B8:A3:AD:39
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 53:5f:21:f5:ba:b0:3a:52:39:2c:92:b0:6c:00:c9:ef:ce:20:
+ ef:06:f2:96:9e:e9:a4:74:7f:7a:16:fc:b7:f5:b6:fb:15:1b:
+ 3f:ab:a6:c0:72:5d:10:b1:71:ee:bc:4f:e3:ad:ac:03:6d:2e:
+ 71:2e:af:c4:e3:ad:a3:bd:0c:11:a7:b4:ff:4a:b2:7b:10:10:
+ 1f:a7:57:41:b2:c0:ae:f4:2c:59:d6:47:10:88:f3:21:51:29:
+ 30:ca:60:86:af:46:ab:1d:ed:3a:5b:b0:94:de:44:e3:41:08:
+ a2:c1:ec:1d:d6:fd:4f:b6:d6:47:d0:14:0b:ca:e6:ca:b5:7b:
+ 77:7e:41:1f:5e:83:c7:b6:8c:39:96:b0:3f:96:81:41:6f:60:
+ 90:e2:e8:f9:fb:22:71:d9:7d:b3:3d:46:bf:b4:84:af:90:1c:
+ 0f:8f:12:6a:af:ef:ee:1e:7a:ae:02:4a:8a:17:2b:76:fe:ac:
+ 54:89:24:2c:4f:3f:b6:b2:a7:4e:8c:a8:91:97:fb:29:c6:7b:
+ 5c:2d:b9:cb:66:b6:b7:a8:5b:12:51:85:b5:09:7e:62:78:70:
+ fe:a9:6a:60:b6:1d:0e:79:0c:fd:ca:ea:24:80:72:c3:97:3f:
+ f2:77:ab:43:22:0a:c7:eb:b6:0c:84:82:2c:80:6b:41:8a:08:
+ c0:eb:a5:6b:df:99:12:cb:8a:d5:5e:80:0c:91:e0:26:08:36:
+ 48:c5:fa:38:11:35:ff:25:83:2d:f2:7a:bf:da:fd:8e:fe:a5:
+ cb:45:2c:1f:c4:88:53:ae:77:0e:d9:9a:76:c5:8e:2c:1d:a3:
+ ba:d5:ec:32:ae:c0:aa:ac:f7:d1:7a:4d:eb:d4:07:e2:48:f7:
+ 22:8e:b0:a4:9f:6a:ce:8e:b2:b2:60:f4:a3:22:d0:23:eb:94:
+ 5a:7a:69:dd:0f:bf:40:57:ac:6b:59:50:d9:a3:99:e1:6e:fe:
+ 8d:01:79:27:23:15:de:92:9d:7b:09:4d:5a:e7:4b:48:30:5a:
+ 18:e6:0a:6d:e6:8f:e0:d2:bb:e6:df:7c:6e:21:82:c1:68:39:
+ 4d:b4:98:58:66:62:cc:4a:90:5e:c3:fa:27:04:b1:79:15:74:
+ 99:cc:be:ad:20:de:26:60:1c:eb:56:51:a6:a3:ea:e4:a3:3f:
+ a7:ff:61:dc:f1:5a:4d:6c:32:23:43:ee:ac:a8:ee:ee:4a:12:
+ 09:3c:5d:71:c2:be:79:fa:c2:87:68:1d:0b:fd:5c:69:cc:06:
+ d0:9a:7d:54:99:2a:c9:39:1a:19:af:4b:2a:43:f3:63:5d:5a:
+ 58:e2:2f:e3:1d:e4:a9:d6:d0:0a:d0:9e:bf:d7:81:09:f1:c9:
+ c7:26:0d:ac:98:16:56:a0
+SHA1 Fingerprint=49:0A:75:74:DE:87:0A:47:FE:58:EE:F6:C7:6B:EB:C6:0B:12:40:99
diff --git a/apex/ca-certificates/files/83e9984f.0 b/apex/ca-certificates/files/83e9984f.0
new file mode 100644
index 0000000..95a4c43
--- /dev/null
+++ b/apex/ca-certificates/files/83e9984f.0
@@ -0,0 +1,53 @@
+-----BEGIN CERTIFICATE-----
+MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV
+BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk
+LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv
+b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ
+BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg
+THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v
+IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv
+xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H
+Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
+A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB
+eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo
+jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ
++efcMQ==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 01:54:48:ef:21:fd:97:59:0d:f5:04:0a
+ Signature Algorithm: ecdsa-with-SHA256
+ Issuer: C=HU, L=Budapest, O=Microsec Ltd./organizationIdentifier=VATHU-23584497, CN=e-Szigno Root CA 2017
+ Validity
+ Not Before: Aug 22 12:07:06 2017 GMT
+ Not After : Aug 22 12:07:06 2042 GMT
+ Subject: C=HU, L=Budapest, O=Microsec Ltd./organizationIdentifier=VATHU-23584497, CN=e-Szigno Root CA 2017
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (256 bit)
+ pub:
+ 04:96:dc:3d:8a:d8:b0:7b:6f:c6:27:be:44:90:b1:
+ b3:56:15:7b:8e:43:24:7d:1a:84:59:ee:63:68:b2:
+ c6:5e:87:d0:15:48:1e:a8:90:ad:bd:53:a2:da:de:
+ 3a:90:a6:60:5f:68:32:b5:86:41:df:87:5b:2c:7b:
+ c5:fe:7c:7a:da
+ ASN1 OID: prime256v1
+ NIST CURVE: P-256
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 87:11:15:08:D1:AA:C1:78:0C:B1:AF:CE:C6:C9:90:EF:BF:30:04:C0
+ X509v3 Authority Key Identifier:
+ 87:11:15:08:D1:AA:C1:78:0C:B1:AF:CE:C6:C9:90:EF:BF:30:04:C0
+ Signature Algorithm: ecdsa-with-SHA256
+ Signature Value:
+ 30:46:02:21:00:b5:57:dd:d7:8a:55:0b:36:e1:86:44:fa:d4:
+ d9:68:8d:b8:dc:23:8a:8a:0d:d4:2f:7d:ea:73:ec:bf:4d:6c:
+ a8:02:21:00:cb:a5:b4:12:fa:e7:b5:e8:cf:7e:93:fc:f3:35:
+ 8f:6f:4e:5a:7c:b4:bc:4e:b2:fc:72:aa:5b:59:f9:e7:dc:31
+SHA1 Fingerprint=89:D4:83:03:4F:9E:9A:48:80:5F:72:37:D4:A9:A6:EF:CB:7C:1F:D1
diff --git a/apex/ca-certificates/files/85cde254.0 b/apex/ca-certificates/files/85cde254.0
new file mode 100644
index 0000000..947817e
--- /dev/null
+++ b/apex/ca-certificates/files/85cde254.0
@@ -0,0 +1,81 @@
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
+HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs
+ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw
+MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
+b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj
+aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp
+Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg
+nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1
+HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N
+Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN
+dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0
+HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
+BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G
+CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU
+sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3
+4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg
+8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
+pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1
+mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 0 (0x0)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2
+ Validity
+ Not Before: Sep 1 00:00:00 2009 GMT
+ Not After : Dec 31 23:59:59 2037 GMT
+ Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:bd:ed:c1:03:fc:f6:8f:fc:02:b1:6f:5b:9f:48:
+ d9:9d:79:e2:a2:b7:03:61:56:18:c3:47:b6:d7:ca:
+ 3d:35:2e:89:43:f7:a1:69:9b:de:8a:1a:fd:13:20:
+ 9c:b4:49:77:32:29:56:fd:b9:ec:8c:dd:22:fa:72:
+ dc:27:61:97:ee:f6:5a:84:ec:6e:19:b9:89:2c:dc:
+ 84:5b:d5:74:fb:6b:5f:c5:89:a5:10:52:89:46:55:
+ f4:b8:75:1c:e6:7f:e4:54:ae:4b:f8:55:72:57:02:
+ 19:f8:17:71:59:eb:1e:28:07:74:c5:9d:48:be:6c:
+ b4:f4:a4:b0:f3:64:37:79:92:c0:ec:46:5e:7f:e1:
+ 6d:53:4c:62:af:cd:1f:0b:63:bb:3a:9d:fb:fc:79:
+ 00:98:61:74:cf:26:82:40:63:f3:b2:72:6a:19:0d:
+ 99:ca:d4:0e:75:cc:37:fb:8b:89:c1:59:f1:62:7f:
+ 5f:b3:5f:65:30:f8:a7:b7:4d:76:5a:1e:76:5e:34:
+ c0:e8:96:56:99:8a:b3:f0:7f:a4:cd:bd:dc:32:31:
+ 7c:91:cf:e0:5f:11:f8:6b:aa:49:5c:d1:99:94:d1:
+ a2:e3:63:5b:09:76:b5:56:62:e1:4b:74:1d:96:d4:
+ 26:d4:08:04:59:d0:98:0e:0e:e6:de:fc:c3:ec:1f:
+ 90:f1
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 7C:0C:32:1F:A7:D9:30:7F:C4:7D:68:A3:62:A8:A1:CE:AB:07:5B:27
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 11:59:fa:25:4f:03:6f:94:99:3b:9a:1f:82:85:39:d4:76:05:
+ 94:5e:e1:28:93:6d:62:5d:09:c2:a0:a8:d4:b0:75:38:f1:34:
+ 6a:9d:e4:9f:8a:86:26:51:e6:2c:d1:c6:2d:6e:95:20:4a:92:
+ 01:ec:b8:8a:67:7b:31:e2:67:2e:8c:95:03:26:2e:43:9d:4a:
+ 31:f6:0e:b5:0c:bb:b7:e2:37:7f:22:ba:00:a3:0e:7b:52:fb:
+ 6b:bb:3b:c4:d3:79:51:4e:cd:90:f4:67:07:19:c8:3c:46:7a:
+ 0d:01:7d:c5:58:e7:6d:e6:85:30:17:9a:24:c4:10:e0:04:f7:
+ e0:f2:7f:d4:aa:0a:ff:42:1d:37:ed:94:e5:64:59:12:20:77:
+ 38:d3:32:3e:38:81:75:96:73:fa:68:8f:b1:cb:ce:1f:c5:ec:
+ fa:9c:7e:cf:7e:b1:f1:07:2d:b6:fc:bf:ca:a4:bf:d0:97:05:
+ 4a:bc:ea:18:28:02:90:bd:54:78:09:21:71:d3:d1:7d:1d:d9:
+ 16:b0:a9:61:3d:d0:0a:00:22:fc:c7:7b:cb:09:64:45:0b:3b:
+ 40:81:f7:7d:7c:32:f5:98:ca:58:8e:7d:2a:ee:90:59:73:64:
+ f9:36:74:5e:25:a1:f5:66:05:2e:7f:39:15:a9:2a:fb:50:8b:
+ 8e:85:69:f4
+SHA1 Fingerprint=B5:1C:06:7C:EE:2B:0C:3D:F8:55:AB:2D:92:F4:FE:39:D4:E7:0F:0E
diff --git a/apex/ca-certificates/files/86212b19.0 b/apex/ca-certificates/files/86212b19.0
new file mode 100644
index 0000000..c383ab9
--- /dev/null
+++ b/apex/ca-certificates/files/86212b19.0
@@ -0,0 +1,78 @@
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE
+BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
+dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL
+MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp
+cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y
+YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua
+kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL
+QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp
+6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG
+yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i
+QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ
+KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO
+tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu
+QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ
+Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u
+olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48
+x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 8957382827206547757 (0x7c4f04391cd4992d)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=US, O=AffirmTrust, CN=AffirmTrust Networking
+ Validity
+ Not Before: Jan 29 14:08:24 2010 GMT
+ Not After : Dec 31 14:08:24 2030 GMT
+ Subject: C=US, O=AffirmTrust, CN=AffirmTrust Networking
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b4:84:cc:33:17:2e:6b:94:6c:6b:61:52:a0:eb:
+ a3:cf:79:94:4c:e5:94:80:99:cb:55:64:44:65:8f:
+ 67:64:e2:06:e3:5c:37:49:f6:2f:9b:84:84:1e:2d:
+ f2:60:9d:30:4e:cc:84:85:e2:2c:cf:1e:9e:fe:36:
+ ab:33:77:35:44:d8:35:96:1a:3d:36:e8:7a:0e:d8:
+ d5:47:a1:6a:69:8b:d9:fc:bb:3a:ae:79:5a:d5:f4:
+ d6:71:bb:9a:90:23:6b:9a:b7:88:74:87:0c:1e:5f:
+ b9:9e:2d:fa:ab:53:2b:dc:bb:76:3e:93:4c:08:08:
+ 8c:1e:a2:23:1c:d4:6a:ad:22:ba:99:01:2e:6d:65:
+ cb:be:24:66:55:24:4b:40:44:b1:1b:d7:e1:c2:85:
+ c0:de:10:3f:3d:ed:b8:fc:f1:f1:23:53:dc:bf:65:
+ 97:6f:d9:f9:40:71:8d:7d:bd:95:d4:ce:be:a0:5e:
+ 27:23:de:fd:a6:d0:26:0e:00:29:eb:3c:46:f0:3d:
+ 60:bf:3f:50:d2:dc:26:41:51:9e:14:37:42:04:a3:
+ 70:57:a8:1b:87:ed:2d:fa:7b:ee:8c:0a:e3:a9:66:
+ 89:19:cb:41:f9:dd:44:36:61:cf:e2:77:46:c8:7d:
+ f6:f4:92:81:36:fd:db:34:f1:72:7e:f3:0c:16:bd:
+ b4:15
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 07:1F:D2:E7:9C:DA:C2:6E:A2:40:B4:B0:7A:50:10:50:74:C4:C8:BD
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 89:57:b2:16:7a:a8:c2:fd:d6:d9:9b:9b:34:c2:9c:b4:32:14:
+ 4d:a7:a4:df:ec:be:a7:be:f8:43:db:91:37:ce:b4:32:2e:50:
+ 55:1a:35:4e:76:43:71:20:ef:93:77:4e:15:70:2e:87:c3:c1:
+ 1d:6d:dc:cb:b5:27:d4:2c:56:d1:52:53:3a:44:d2:73:c8:c4:
+ 1b:05:65:5a:62:92:9c:ee:41:8d:31:db:e7:34:ea:59:21:d5:
+ 01:7a:d7:64:b8:64:39:cd:c9:ed:af:ed:4b:03:48:a7:a0:99:
+ 01:80:dc:65:a3:36:ae:65:59:48:4f:82:4b:c8:65:f1:57:1d:
+ e5:59:2e:0a:3f:6c:d8:d1:f5:e5:09:b4:6c:54:00:0a:e0:15:
+ 4d:87:75:6d:b7:58:96:5a:dd:6d:d2:00:a0:f4:9b:48:be:c3:
+ 37:a4:ba:36:e0:7c:87:85:97:1a:15:a2:de:2e:a2:5b:bd:af:
+ 18:f9:90:50:cd:70:59:f8:27:67:47:cb:c7:a0:07:3a:7d:d1:
+ 2c:5d:6c:19:3a:66:b5:7d:fd:91:6f:82:b1:be:08:93:db:14:
+ 47:f1:a2:37:c7:45:9e:3c:c7:77:af:64:a8:93:df:f6:69:83:
+ 82:60:f2:49:42:34:ed:5a:00:54:85:1c:16:36:92:0c:5c:fa:
+ a6:ad:bf:db
+SHA1 Fingerprint=29:36:21:02:8B:20:ED:02:F5:66:C5:32:D1:D6:ED:90:9F:45:00:2F
diff --git a/apex/ca-certificates/files/869fbf79.0 b/apex/ca-certificates/files/869fbf79.0
new file mode 100644
index 0000000..504fc04
--- /dev/null
+++ b/apex/ca-certificates/files/869fbf79.0
@@ -0,0 +1,54 @@
+-----BEGIN CERTIFICATE-----
+MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG
+EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx
+IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw
+MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln
+biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND
+IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci
+MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti
+sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O
+BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB
+Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c
+3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J
+0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 7b:71:b6:82:56:b8:12:7c:9c:a8
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=US, OU=emSign PKI, O=eMudhra Inc, CN=emSign ECC Root CA - C3
+ Validity
+ Not Before: Feb 18 18:30:00 2018 GMT
+ Not After : Feb 18 18:30:00 2043 GMT
+ Subject: C=US, OU=emSign PKI, O=eMudhra Inc, CN=emSign ECC Root CA - C3
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:fd:a5:61:ae:7b:26:10:1d:e9:b7:22:30:ae:06:
+ f4:81:b3:b1:42:71:95:39:bc:d3:52:e3:af:af:f9:
+ f2:97:35:92:36:46:0e:87:95:8d:b9:39:5a:e9:bb:
+ df:d0:fe:c8:07:41:3c:bb:55:6f:83:a3:6a:fb:62:
+ b0:81:89:02:70:7d:48:c5:4a:e3:e9:22:54:22:4d:
+ 93:bb:42:0c:af:77:9c:23:a6:7d:d7:61:11:ce:65:
+ c7:f8:7f:fe:f5:f2:a9
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ FB:5A:48:D0:80:20:40:F2:A8:E9:00:07:69:19:77:A7:E6:C3:F4:CF
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:65:02:31:00:b4:d8:2f:02:89:fd:b6:4c:62:ba:43:4e:13:
+ 84:72:b5:ae:dd:1c:de:d6:b5:dc:56:8f:58:40:5a:2d:de:20:
+ 4c:22:83:ca:93:a8:7e:ee:12:40:c7:d6:87:4f:f8:df:85:02:
+ 30:1c:14:64:e4:7c:96:83:11:9c:b0:d1:5a:61:4b:a6:0f:49:
+ d3:00:fc:a1:fc:e4:a5:ff:7f:ad:d7:30:d0:c7:77:7f:be:81:
+ 07:55:30:50:20:14:f5:57:38:0a:a8:31:51
+SHA1 Fingerprint=B6:AF:43:C2:9B:81:53:7D:F6:EF:6B:C3:1F:1F:60:15:0C:EE:48:66
diff --git a/apex/ca-certificates/files/8794b4e3.0 b/apex/ca-certificates/files/8794b4e3.0
new file mode 100644
index 0000000..d5767e8
--- /dev/null
+++ b/apex/ca-certificates/files/8794b4e3.0
@@ -0,0 +1,54 @@
+-----BEGIN CERTIFICATE-----
+MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw
+CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg
+R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00
+MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT
+ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw
+EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW
++1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9
+ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T
+AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI
+zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW
+tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1
+/q4AaOeMSQ+2b1tbFfLn
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 41:d2:9d:d1:72:ea:ee:a7:80:c1:2c:6c:e9:2f:87:52
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X2
+ Validity
+ Not Before: Sep 4 00:00:00 2020 GMT
+ Not After : Sep 17 16:00:00 2040 GMT
+ Subject: C=US, O=Internet Security Research Group, CN=ISRG Root X2
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:cd:9b:d5:9f:80:83:0a:ec:09:4a:f3:16:4a:3e:
+ 5c:cf:77:ac:de:67:05:0d:1d:07:b6:dc:16:fb:5a:
+ 8b:14:db:e2:71:60:c4:ba:45:95:11:89:8e:ea:06:
+ df:f7:2a:16:1c:a4:b9:c5:c5:32:e0:03:e0:1e:82:
+ 18:38:8b:d7:45:d8:0a:6a:6e:e6:00:77:fb:02:51:
+ 7d:22:d8:0a:6e:9a:5b:77:df:f0:fa:41:ec:39:dc:
+ 75:ca:68:07:0c:1f:ea
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 7C:42:96:AE:DE:4B:48:3B:FA:92:F8:9E:8C:CF:6D:8B:A9:72:37:95
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:65:02:30:7b:79:4e:46:50:84:c2:44:87:46:1b:45:70:ff:
+ 58:99:de:f4:fd:a4:d2:55:a6:20:2d:74:d6:34:bc:41:a3:50:
+ 5f:01:27:56:b4:be:27:75:06:af:12:2e:75:98:8d:fc:02:31:
+ 00:8b:f5:77:6c:d4:c8:65:aa:e0:0b:2c:ee:14:9d:27:37:a4:
+ f9:53:a5:51:e4:29:83:d7:f8:90:31:5b:42:9f:0a:f5:fe:ae:
+ 00:68:e7:8c:49:0f:b6:6f:5b:5b:15:f2:e7
+SHA1 Fingerprint=BD:B1:B9:3C:D5:97:8D:45:C6:26:14:55:F8:DB:95:C7:5A:D1:53:AF
diff --git a/apex/ca-certificates/files/882de061.0 b/apex/ca-certificates/files/882de061.0
new file mode 100644
index 0000000..0ff6153
--- /dev/null
+++ b/apex/ca-certificates/files/882de061.0
@@ -0,0 +1,78 @@
+-----BEGIN CERTIFICATE-----
+MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT
+AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD
+QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP
+MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do
+0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ
+UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d
+RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ
+OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv
+JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C
+AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O
+BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ
+LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY
+MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ
+44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I
+Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw
+i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN
+9u6wWk5JRFRYX0KD
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 35210227249154 (0x200605167002)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=RO, O=certSIGN, OU=certSIGN ROOT CA
+ Validity
+ Not Before: Jul 4 17:20:04 2006 GMT
+ Not After : Jul 4 17:20:04 2031 GMT
+ Subject: C=RO, O=certSIGN, OU=certSIGN ROOT CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b7:33:b9:7e:c8:25:4a:8e:b5:db:b4:28:1b:aa:
+ 57:90:e8:d1:22:d3:64:ba:d3:93:e8:d4:ac:86:61:
+ 40:6a:60:57:68:54:84:4d:bc:6a:54:02:05:ff:df:
+ 9b:9a:2a:ae:5d:07:8f:4a:c3:28:7f:ef:fb:2b:fa:
+ 79:f1:c7:ad:f0:10:53:24:90:8b:66:c9:a8:88:ab:
+ af:5a:a3:00:e9:be:ba:46:ee:5b:73:7b:2c:17:82:
+ 81:5e:62:2c:a1:02:65:b3:bd:c5:2b:00:7e:c4:fc:
+ 03:33:57:0d:ed:e2:fa:ce:5d:45:d6:38:cd:35:b6:
+ b2:c1:d0:9c:81:4a:aa:e4:b2:01:5c:1d:8f:5f:99:
+ c4:b1:ad:db:88:21:eb:90:08:82:80:f3:30:a3:43:
+ e6:90:82:ae:55:28:49:ed:5b:d7:a9:10:38:0e:fe:
+ 8f:4c:5b:9b:46:ea:41:f5:b0:08:74:c3:d0:88:33:
+ b6:7c:d7:74:df:dc:84:d1:43:0e:75:39:a1:25:40:
+ 28:ea:78:cb:0e:2c:2e:39:9d:8c:8b:6e:16:1c:2f:
+ 26:82:10:e2:e3:65:94:0a:04:c0:5e:f7:5d:5b:f8:
+ 10:e2:d0:ba:7a:4b:fb:de:37:00:00:1a:5b:28:e3:
+ d2:9c:73:3e:32:87:98:a1:c9:51:2f:d7:de:ac:33:
+ b3:4f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Digital Signature, Non Repudiation, Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ E0:8C:9B:DB:25:49:B3:F1:7C:86:D6:B2:42:87:0B:D0:6B:A0:D9:E4
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 3e:d2:1c:89:2e:35:fc:f8:75:dd:e6:7f:65:88:f4:72:4c:c9:
+ 2c:d7:32:4e:f3:dd:19:79:47:bd:8e:3b:5b:93:0f:50:49:24:
+ 13:6b:14:06:72:ef:09:d3:a1:a1:e3:40:84:c9:e7:18:32:74:
+ 3c:48:6e:0f:9f:4b:d4:f7:1e:d3:93:86:64:54:97:63:72:50:
+ d5:55:cf:fa:20:93:02:a2:9b:c3:23:93:4e:16:55:76:a0:70:
+ 79:6d:cd:21:1f:cf:2f:2d:bc:19:e3:88:31:f8:59:1a:81:09:
+ c8:97:a6:74:c7:60:c4:5b:cc:57:8e:b2:75:fd:1b:02:09:db:
+ 59:6f:72:93:69:f7:31:41:d6:88:38:bf:87:b2:bd:16:79:f9:
+ aa:e4:be:88:25:dd:61:27:23:1c:b5:31:07:04:36:b4:1a:90:
+ bd:a0:74:71:50:89:6d:bc:14:e3:0f:86:ae:f1:ab:3e:c7:a0:
+ 09:cc:a3:48:d1:e0:db:64:e7:92:b5:cf:af:72:43:70:8b:f9:
+ c3:84:3c:13:aa:7e:92:9b:57:53:93:fa:70:c2:91:0e:31:f9:
+ 9b:67:5d:e9:96:38:5e:5f:b3:73:4e:88:15:67:de:9e:76:10:
+ 62:20:be:55:69:95:43:00:39:4d:f6:ee:b0:5a:4e:49:44:54:
+ 58:5f:42:83
+SHA1 Fingerprint=FA:B7:EE:36:97:26:62:FB:2D:B0:2A:F6:BF:03:FD:E8:7C:4B:2F:9B
diff --git a/apex/ca-certificates/files/88950faa.0 b/apex/ca-certificates/files/88950faa.0
new file mode 100644
index 0000000..5bdc5f1
--- /dev/null
+++ b/apex/ca-certificates/files/88950faa.0
@@ -0,0 +1,57 @@
+-----BEGIN CERTIFICATE-----
+MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC
+VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T
+U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0
+aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz
+WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0
+b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS
+b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB
+BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI
+7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg
+CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud
+EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD
+VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T
+kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+
+gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 8495723813297216424 (0x75e6dfcbc1685ba8)
+ Signature Algorithm: ecdsa-with-SHA256
+ Issuer: C=US, ST=Texas, L=Houston, O=SSL Corporation, CN=SSL.com Root Certification Authority ECC
+ Validity
+ Not Before: Feb 12 18:14:03 2016 GMT
+ Not After : Feb 12 18:14:03 2041 GMT
+ Subject: C=US, ST=Texas, L=Houston, O=SSL Corporation, CN=SSL.com Root Certification Authority ECC
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:45:6e:a9:50:c4:a6:23:36:9e:5f:28:8d:17:cb:
+ 96:22:64:3f:dc:7a:8e:1d:cc:08:b3:a2:71:24:ba:
+ 8e:49:b9:04:1b:47:96:58:ab:2d:95:c8:ed:9e:08:
+ 35:c8:27:eb:89:8c:53:58:eb:62:8a:fe:f0:5b:0f:
+ 6b:31:52:63:41:3b:89:cd:ec:ec:b6:8d:19:d3:34:
+ 07:dc:bb:c6:06:7f:c2:45:95:ec:cb:7f:a8:23:e0:
+ 09:e9:81:fa:f3:47:d3
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 82:D1:85:73:30:E7:35:04:D3:8E:02:92:FB:E5:A4:D1:C4:21:E8:CD
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Authority Key Identifier:
+ 82:D1:85:73:30:E7:35:04:D3:8E:02:92:FB:E5:A4:D1:C4:21:E8:CD
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ Signature Algorithm: ecdsa-with-SHA256
+ Signature Value:
+ 30:64:02:30:6f:e7:eb:59:11:a4:60:cf:61:b0:96:7b:ed:05:
+ f9:2f:13:91:dc:ed:e5:fc:50:6b:11:46:46:b3:1c:21:00:62:
+ bb:be:c3:e7:e8:cd:07:99:f9:0d:0b:5d:72:3e:c4:aa:02:30:
+ 1f:bc:ba:0b:e2:30:24:fb:7c:6d:80:55:0a:99:3e:80:0d:33:
+ e5:66:a3:b3:a3:bb:a5:d5:8b:8f:09:2c:a6:5d:7e:e2:f0:07:
+ 08:68:6d:d2:7c:69:6e:5f:df:e5:6a:65
+SHA1 Fingerprint=C3:19:7C:39:24:E6:54:AF:1B:C4:AB:20:95:7A:E2:C3:0E:13:02:6A
diff --git a/apex/ca-certificates/files/89c02a45.0 b/apex/ca-certificates/files/89c02a45.0
new file mode 100644
index 0000000..5a163b2
--- /dev/null
+++ b/apex/ca-certificates/files/89c02a45.0
@@ -0,0 +1,56 @@
+-----BEGIN CERTIFICATE-----
+MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL
+MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
+BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT
+IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw
+MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy
+ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N
+T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR
+FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J
+cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW
+BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
+BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm
+fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv
+GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 1f:47:af:aa:62:00:70:50:54:4c:01:9e:9b:63:99:2a
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO ECC Certification Authority
+ Validity
+ Not Before: Mar 6 00:00:00 2008 GMT
+ Not After : Jan 18 23:59:59 2038 GMT
+ Subject: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO ECC Certification Authority
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:03:47:7b:2f:75:c9:82:15:85:fb:75:e4:91:16:
+ d4:ab:62:99:f5:3e:52:0b:06:ce:41:00:7f:97:e1:
+ 0a:24:3c:1d:01:04:ee:3d:d2:8d:09:97:0c:e0:75:
+ e4:fa:fb:77:8a:2a:f5:03:60:4b:36:8b:16:23:16:
+ ad:09:71:f4:4a:f4:28:50:b4:fe:88:1c:6e:3f:6c:
+ 2f:2f:09:59:5b:a5:5b:0b:33:99:e2:c3:3d:89:f9:
+ 6a:2c:ef:b2:d3:06:e9
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 75:71:A7:19:48:19:BC:9D:9D:EA:41:47:DF:94:C4:48:77:99:D3:79
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:65:02:31:00:ef:03:5b:7a:ac:b7:78:0a:72:b7:88:df:ff:
+ b5:46:14:09:0a:fa:a0:e6:7d:08:c6:1a:87:bd:18:a8:73:bd:
+ 26:ca:60:0c:9d:ce:99:9f:cf:5c:0f:30:e1:be:14:31:ea:02:
+ 30:14:f4:93:3c:49:a7:33:7a:90:46:47:b3:63:7d:13:9b:4e:
+ b7:6f:18:37:80:53:fe:dd:20:e0:35:9a:36:d1:c7:01:b9:e6:
+ dc:dd:f3:ff:1d:2c:3a:16:57:d9:92:39:d6
+SHA1 Fingerprint=9F:74:4E:9F:2B:4D:BA:EC:0F:31:2C:50:B6:56:3B:8E:2D:93:C3:11
diff --git a/apex/ca-certificates/files/8d6437c3.0 b/apex/ca-certificates/files/8d6437c3.0
new file mode 100644
index 0000000..b47a3f5
--- /dev/null
+++ b/apex/ca-certificates/files/8d6437c3.0
@@ -0,0 +1,81 @@
+-----BEGIN CERTIFICATE-----
+MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
+b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
+cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA
+n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc
+biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp
+EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA
+bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu
+YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB
+AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW
+BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI
+QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I
+0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni
+lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9
+B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv
+ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo
+IhNzbM8m9Yop5w==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 0b:93:1c:3a:d6:39:67:ea:67:23:bf:c3:af:9a:f4:4b
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Assured ID Root G2
+ Validity
+ Not Before: Aug 1 12:00:00 2013 GMT
+ Not After : Jan 15 12:00:00 2038 GMT
+ Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Assured ID Root G2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:d9:e7:28:2f:52:3f:36:72:49:88:93:34:f3:f8:
+ 6a:1e:31:54:80:9f:ad:54:41:b5:47:df:96:a8:d4:
+ af:80:2d:b9:0a:cf:75:fd:89:a5:7d:24:fa:e3:22:
+ 0c:2b:bc:95:17:0b:33:bf:19:4d:41:06:90:00:bd:
+ 0c:4d:10:fe:07:b5:e7:1c:6e:22:55:31:65:97:bd:
+ d3:17:d2:1e:62:f3:db:ea:6c:50:8c:3f:84:0c:96:
+ cf:b7:cb:03:e0:ca:6d:a1:14:4c:1b:89:dd:ed:00:
+ b0:52:7c:af:91:6c:b1:38:13:d1:e9:12:08:c0:00:
+ b0:1c:2b:11:da:77:70:36:9b:ae:ce:79:87:dc:82:
+ 70:e6:09:74:70:55:69:af:a3:68:9f:bf:dd:b6:79:
+ b3:f2:9d:70:29:55:f4:ab:ff:95:61:f3:c9:40:6f:
+ 1d:d1:be:93:bb:d3:88:2a:bb:9d:bf:72:5a:56:71:
+ 3b:3f:d4:f3:d1:0a:fe:28:ef:a3:ee:d9:99:af:03:
+ d3:8f:60:b7:f2:92:a1:b1:bd:89:89:1f:30:cd:c3:
+ a6:2e:62:33:ae:16:02:77:44:5a:e7:81:0a:3c:a7:
+ 44:2e:79:b8:3f:04:bc:5c:a0:87:e1:1b:af:51:8e:
+ cd:ec:2c:fa:f8:fe:6d:f0:3a:7c:aa:8b:e4:67:95:
+ 31:8d
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ CE:C3:4A:B9:99:55:F2:B8:DB:60:BF:A9:7E:BD:56:B5:97:36:A7:D6
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ ca:a5:55:8c:e3:c8:41:6e:69:27:a7:75:11:ef:3c:86:36:6f:
+ d2:9d:c6:78:38:1d:69:96:a2:92:69:2e:38:6c:9b:7d:04:d4:
+ 89:a5:b1:31:37:8a:c9:21:cc:ab:6c:cd:8b:1c:9a:d6:bf:48:
+ d2:32:66:c1:8a:c0:f3:2f:3a:ef:c0:e3:d4:91:86:d1:50:e3:
+ 03:db:73:77:6f:4a:39:53:ed:de:26:c7:b5:7d:af:2b:42:d1:
+ 75:62:e3:4a:2b:02:c7:50:4b:e0:69:e2:96:6c:0e:44:66:10:
+ 44:8f:ad:05:eb:f8:79:ac:a6:1b:e8:37:34:9d:53:c9:61:aa:
+ a2:52:af:4a:70:16:86:c2:3a:c8:b1:13:70:36:d8:cf:ee:f4:
+ 0a:34:d5:5b:4c:fd:07:9c:a2:ba:d9:01:72:5c:f3:4d:c1:dd:
+ 0e:b1:1c:0d:c4:63:be:ad:f4:14:fb:89:ec:a2:41:0e:4c:cc:
+ c8:57:40:d0:6e:03:aa:cd:0c:8e:89:99:99:6c:f0:3c:30:af:
+ 38:df:6f:bc:a3:be:29:20:27:ab:74:ff:13:22:78:de:97:52:
+ 55:1e:83:b5:54:20:03:ee:ae:c0:4f:56:de:37:cc:c3:7f:aa:
+ 04:27:bb:d3:77:b8:62:db:17:7c:9c:28:22:13:73:6c:cf:26:
+ f5:8a:29:e7
+SHA1 Fingerprint=A1:4B:48:D9:43:EE:0A:0E:40:90:4F:3C:E0:A4:C0:91:93:51:5D:3F
diff --git a/apex/ca-certificates/files/9282e51c.0 b/apex/ca-certificates/files/9282e51c.0
new file mode 100644
index 0000000..b9f23da
--- /dev/null
+++ b/apex/ca-certificates/files/9282e51c.0
@@ -0,0 +1,123 @@
+-----BEGIN CERTIFICATE-----
+MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD
+TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y
+aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx
+MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j
+aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP
+T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03
+sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL
+TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5
+/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp
+7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz
+EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt
+hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP
+a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot
+aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg
+TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV
+PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv
+cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL
+tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd
+BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB
+ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT
+ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL
+jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS
+ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy
+P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19
+xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d
+Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN
+5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe
+/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z
+AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ
+5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 407555286 (0x184accd6)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=CN, O=China Financial Certification Authority, CN=CFCA EV ROOT
+ Validity
+ Not Before: Aug 8 03:07:01 2012 GMT
+ Not After : Dec 31 03:07:01 2029 GMT
+ Subject: C=CN, O=China Financial Certification Authority, CN=CFCA EV ROOT
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:d7:5d:6b:cd:10:3f:1f:05:59:d5:05:4d:37:b1:
+ 0e:ec:98:2b:8e:15:1d:fa:93:4b:17:82:21:71:10:
+ 52:d7:51:64:70:16:c2:55:69:4d:8e:15:6d:9f:bf:
+ 0c:1b:c2:e0:a3:67:d6:0c:ac:cf:22:ae:af:77:54:
+ 2a:4b:4c:8a:53:52:7a:c3:ee:2e:de:b3:71:25:c1:
+ e9:5d:3d:ee:a1:2f:a3:f7:2a:3c:c9:23:1d:6a:ab:
+ 1d:a1:a7:f1:f3:ec:a0:d5:44:cf:15:cf:72:2f:1d:
+ 63:97:e8:99:f9:fd:93:a4:54:80:4c:52:d4:52:ab:
+ 2e:49:df:90:cd:b8:5f:be:3f:de:a1:ca:4d:20:d4:
+ 25:e8:84:29:53:b7:b1:88:1f:ff:fa:da:90:9f:0a:
+ a9:2d:41:3f:b1:f1:18:29:ee:16:59:2c:34:49:1a:
+ a8:06:d7:a8:88:d2:03:72:7a:32:e2:ea:68:4d:6e:
+ 2c:96:65:7b:ca:59:fa:f2:e2:dd:ee:30:2c:fb:cc:
+ 46:ac:c4:63:eb:6f:7f:36:2b:34:73:12:94:7f:df:
+ cc:26:9e:f1:72:5d:50:65:59:8f:69:b3:87:5e:32:
+ 6f:c3:18:8a:b5:95:8f:b0:7a:37:de:5a:45:3b:c7:
+ 36:e1:ef:67:d1:39:d3:97:5b:73:62:19:48:2d:87:
+ 1c:06:fb:74:98:20:49:73:f0:05:d2:1b:b1:a0:a3:
+ b7:1b:70:d3:88:69:b9:5a:d6:38:f4:62:dc:25:8b:
+ 78:bf:f8:e8:7e:b8:5c:c9:95:4f:5f:a7:2d:b9:20:
+ 6b:cf:6b:dd:f5:0d:f4:82:b7:f4:b2:66:2e:10:28:
+ f6:97:5a:7b:96:16:8f:01:19:2d:6c:6e:7f:39:58:
+ 06:64:83:01:83:83:c3:4d:92:dd:32:c6:87:a4:37:
+ e9:16:ce:aa:2d:68:af:0a:81:65:3a:70:c1:9b:ad:
+ 4d:6d:54:ca:2a:2d:4b:85:1b:b3:80:e6:70:45:0d:
+ 6b:5e:35:f0:7f:3b:b8:9c:e4:04:70:89:12:25:93:
+ da:0a:99:22:60:6a:63:60:4e:76:06:98:4e:bd:83:
+ ad:1d:58:8a:25:85:d2:c7:65:1e:2d:8e:c6:df:b6:
+ c6:e1:7f:8a:04:21:15:29:74:f0:3e:9c:90:9d:0c:
+ 2e:f1:8a:3e:5a:aa:0c:09:1e:c7:d5:3c:a3:ed:97:
+ c3:1e:34:fa:38:f9:08:0e:e3:c0:5d:2b:83:d1:56:
+ 6a:c9:b6:a8:54:53:2e:78:32:67:3d:82:7f:74:d0:
+ fb:e1:b6:05:60:b9:70:db:8e:0b:f9:13:58:6f:71:
+ 60:10:52:10:b9:c1:41:09:ef:72:1f:67:31:78:ff:
+ 96:05:8d
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Authority Key Identifier:
+ E3:FE:2D:FD:28:D0:0B:B5:BA:B6:A2:C4:BF:06:AA:05:8C:93:FB:2F
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ E3:FE:2D:FD:28:D0:0B:B5:BA:B6:A2:C4:BF:06:AA:05:8C:93:FB:2F
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 25:c6:ba:6b:eb:87:cb:de:82:39:96:3d:f0:44:a7:6b:84:73:
+ 03:de:9d:2b:4f:ba:20:7f:bc:78:b2:cf:97:b0:1b:9c:f3:d7:
+ 79:2e:f5:48:b6:d2:fb:17:88:e6:d3:7a:3f:ed:53:13:d0:e2:
+ 2f:6a:79:cb:00:23:28:e6:1e:37:57:35:89:84:c2:76:4f:34:
+ 36:ad:67:c3:ce:41:06:88:c5:f7:ee:d8:1a:b8:d6:0b:7f:50:
+ ff:93:aa:17:4b:8c:ec:ed:52:60:b2:a4:06:ea:4e:eb:f4:6b:
+ 19:fd:eb:f5:1a:e0:25:2a:9a:dc:c7:41:36:f7:c8:74:05:84:
+ 39:95:39:d6:0b:3b:a4:27:fa:08:d8:5c:1e:f8:04:60:52:11:
+ 28:28:03:ff:ef:53:66:00:a5:4a:34:16:66:7c:fd:09:a4:ae:
+ 9e:67:1a:6f:41:0b:6b:06:13:9b:8f:86:71:05:b4:2f:8d:89:
+ 66:33:29:76:54:9a:11:f8:27:fa:b2:3f:91:e0:ce:0d:1b:f3:
+ 30:1a:ad:bf:22:5d:1b:d3:bf:25:05:4d:e1:92:1a:7f:99:9f:
+ 3c:44:93:ca:d4:40:49:6c:80:87:d7:04:3a:c3:32:52:35:0e:
+ 56:f8:a5:dd:7d:c4:8b:0d:11:1f:53:cb:1e:b2:17:b6:68:77:
+ 5a:e0:d4:cb:c8:07:ae:f5:3a:2e:8e:37:b7:d0:01:4b:43:29:
+ 77:8c:39:97:8f:82:5a:f8:51:e5:89:a0:18:e7:68:7f:5d:0a:
+ 2e:fb:a3:47:0e:3d:a6:23:7a:c6:01:c7:8f:c8:5e:bf:6d:80:
+ 56:be:8a:24:ba:33:ea:9f:e1:32:11:9e:f1:d2:4f:80:f6:1b:
+ 40:af:38:9e:11:50:79:73:12:12:cd:e6:6c:9d:2c:88:72:3c:
+ 30:81:06:91:22:ea:59:ad:da:19:2e:22:c2:8d:b9:8c:87:e0:
+ 66:bc:73:23:5f:21:64:63:80:48:f5:a0:3c:18:3d:94:c8:48:
+ 41:1d:40:ba:5e:fe:fe:56:39:a1:c8:cf:5e:9e:19:64:46:10:
+ da:17:91:b7:05:80:ac:8b:99:92:7d:e7:a2:d8:07:0b:36:27:
+ e7:48:79:60:8a:c3:d7:13:5c:f8:72:40:df:4a:cb:cf:99:00:
+ 0a:00:0b:11:95:da:56:45:03:88:0a:9f:67:d0:d5:79:b1:a8:
+ 8d:40:6d:0d:c2:7a:40:fa:f3:5f:64:47:92:cb:53:b9:bb:59:
+ ce:4f:fd:d0:15:53:01:d8:df:eb:d9:e6:76:ef:d0:23:bb:3b:
+ a9:79:b3:d5:02:29:cd:89:a3:96:0f:4a:35:e7:4e:42:c0:75:
+ cd:07:cf:e6:2c:eb:7b:2e
+SHA1 Fingerprint=E2:B8:29:4B:55:84:AB:6B:58:C2:90:46:6C:AC:3F:B8:39:8F:84:83
diff --git a/apex/ca-certificates/files/9339512a.0 b/apex/ca-certificates/files/9339512a.0
new file mode 100644
index 0000000..5254c67
--- /dev/null
+++ b/apex/ca-certificates/files/9339512a.0
@@ -0,0 +1,136 @@
+-----BEGIN CERTIFICATE-----
+MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
+GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
+b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV
+BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W
+YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM
+V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB
+4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr
+H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd
+8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv
+vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT
+mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe
+btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc
+T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt
+WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ
+c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A
+4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD
+VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG
+CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0
+aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0
+aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu
+dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw
+czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G
+A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC
+TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg
+Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0
+7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem
+d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd
++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B
+4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN
+t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x
+DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57
+k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s
+zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j
+Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT
+mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK
+4SVhM7JZG+Ju1zdXtg2pEto=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1478 (0x5c6)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 3
+ Validity
+ Not Before: Nov 24 19:11:23 2006 GMT
+ Not After : Nov 24 19:06:44 2031 GMT
+ Subject: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 3
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:cc:57:42:16:54:9c:e6:98:d3:d3:4d:ee:fe:ed:
+ c7:9f:43:39:4a:65:b3:e8:16:88:34:db:0d:59:91:
+ 74:cf:92:b8:04:40:ad:02:4b:31:ab:bc:8d:91:68:
+ d8:20:0e:1a:01:e2:1a:7b:4e:17:5d:e2:8a:b7:3f:
+ 99:1a:cd:eb:61:ab:c2:65:a6:1f:b7:b7:bd:b7:8f:
+ fc:fd:70:8f:0b:a0:67:be:01:a2:59:cf:71:e6:0f:
+ 29:76:ff:b1:56:79:45:2b:1f:9e:7a:54:e8:a3:29:
+ 35:68:a4:01:4f:0f:a4:2e:37:ef:1b:bf:e3:8f:10:
+ a8:72:ab:58:57:e7:54:86:c8:c9:f3:5b:da:2c:da:
+ 5d:8e:6e:3c:a3:3e:da:fb:82:e5:dd:f2:5c:b2:05:
+ 33:6f:8a:36:ce:d0:13:4e:ff:bf:4a:0c:34:4c:a6:
+ c3:21:bd:50:04:55:eb:b1:bb:9d:fb:45:1e:64:15:
+ de:55:01:8c:02:76:b5:cb:a1:3f:42:69:bc:2f:bd:
+ 68:43:16:56:89:2a:37:61:91:fd:a6:ae:4e:c0:cb:
+ 14:65:94:37:4b:92:06:ef:04:d0:c8:9c:88:db:0b:
+ 7b:81:af:b1:3d:2a:c4:65:3a:78:b6:ee:dc:80:b1:
+ d2:d3:99:9c:3a:ee:6b:5a:6b:b3:8d:b7:d5:ce:9c:
+ c2:be:a5:4b:2f:16:b1:9e:68:3b:06:6f:ae:7d:9f:
+ f8:de:ec:cc:29:a7:98:a3:25:43:2f:ef:f1:5f:26:
+ e1:88:4d:f8:5e:6e:d7:d9:14:6e:19:33:69:a7:3b:
+ 84:89:93:c4:53:55:13:a1:51:78:40:f8:b8:c9:a2:
+ ee:7b:ba:52:42:83:9e:14:ed:05:52:5a:59:56:a7:
+ 97:fc:9d:3f:0a:29:d8:dc:4f:91:0e:13:bc:de:95:
+ a4:df:8b:99:be:ac:9b:33:88:ef:b5:81:af:1b:c6:
+ 22:53:c8:f6:c7:ee:97:14:b0:c5:7c:78:52:c8:f0:
+ ce:6e:77:60:84:a6:e9:2a:76:20:ed:58:01:17:30:
+ 93:e9:1a:8b:e0:73:63:d9:6a:92:94:49:4e:b4:ad:
+ 4a:85:c4:a3:22:30:fc:09:ed:68:22:73:a6:88:0c:
+ 55:21:58:c5:e1:3a:9f:2a:dd:ca:e1:90:e0:d9:73:
+ ab:6c:80:b8:e8:0b:64:93:a0:9c:8c:19:ff:b3:d2:
+ 0c:ec:91:26:87:8a:b3:a2:e1:70:8f:2c:0a:e5:cd:
+ 6d:68:51:eb:da:3f:05:7f:8b:32:e6:13:5c:6b:fe:
+ 5f:40:e2:22:c8:b4:b4:64:4f:d6:ba:7d:48:3e:a8:
+ 69:0c:d7:bb:86:71:c9:73:b8:3f:3b:9d:25:4b:da:
+ ff:40:eb
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Certificate Policies:
+ Policy: 1.3.6.1.4.1.8024.0.3
+ User Notice:
+ Explicit Text: Any use of this Certificate constitutes acceptance of the QuoVadis Root CA 3 Certificate Policy / Certification Practice Statement.
+ CPS: http://www.quovadisglobal.com/cps
+ X509v3 Key Usage:
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ F2:C0:13:E0:82:43:3E:FB:EE:2F:67:32:96:35:5C:DB:B8:CB:02:D0
+ X509v3 Authority Key Identifier:
+ keyid:F2:C0:13:E0:82:43:3E:FB:EE:2F:67:32:96:35:5C:DB:B8:CB:02:D0
+ DirName:/C=BM/O=QuoVadis Limited/CN=QuoVadis Root CA 3
+ serial:05:C6
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 4f:ad:a0:2c:4c:fa:c0:f2:6f:f7:66:55:ab:23:34:ee:e7:29:
+ da:c3:5b:b6:b0:83:d9:d0:d0:e2:21:fb:f3:60:a7:3b:5d:60:
+ 53:27:a2:9b:f6:08:22:2a:e7:bf:a0:72:e5:9c:24:6a:31:b1:
+ 90:7a:27:db:84:11:89:27:a6:77:5a:38:d7:bf:ac:86:fc:ee:
+ 5d:83:bc:06:c6:d1:77:6b:0f:6d:24:2f:4b:7a:6c:a7:07:96:
+ ca:e3:84:9f:ad:88:8b:1d:ab:16:8d:5b:66:17:d9:16:f4:8b:
+ 80:d2:dd:f8:b2:76:c3:fc:38:13:aa:0c:de:42:69:2b:6e:f3:
+ 3c:eb:80:27:db:f5:a6:44:0d:9f:5a:55:59:0b:d5:0d:52:48:
+ c5:ae:9f:f2:2f:80:c5:ea:32:50:35:12:97:2e:c1:e1:ff:f1:
+ 23:88:51:38:9f:f2:66:56:76:e7:0f:51:97:a5:52:0c:4d:49:
+ 51:95:36:3d:bf:a2:4b:0c:10:1d:86:99:4c:aa:f3:72:11:93:
+ e4:ea:f6:9b:da:a8:5d:a7:4d:b7:9e:02:ae:73:00:c8:da:23:
+ 03:e8:f9:ea:19:74:62:00:94:cb:22:20:be:94:a7:59:b5:82:
+ 6a:be:99:79:7a:a9:f2:4a:24:52:f7:74:fd:ba:4e:e6:a8:1d:
+ 02:6e:b1:0d:80:44:c1:ae:d3:23:37:5f:bb:85:7c:2b:92:2e:
+ e8:7e:a5:8b:dd:99:e1:bf:27:6f:2d:5d:aa:7b:87:fe:0a:dd:
+ 4b:fc:8e:f5:26:e4:6e:70:42:6e:33:ec:31:9e:7b:93:c1:e4:
+ c9:69:1a:3d:c0:6b:4e:22:6d:ee:ab:58:4d:c6:d0:41:c1:2b:
+ ea:4f:12:87:5e:eb:45:d8:6c:f5:98:02:d3:a0:d8:55:8a:06:
+ 99:19:a2:a0:77:d1:30:9e:ac:cc:75:ee:83:f5:b0:62:39:cf:
+ 6c:57:e2:4c:d2:91:0b:0e:75:28:1b:9a:bf:fd:1a:43:f1:ca:
+ 77:fb:3b:8f:61:b8:69:28:16:42:04:5e:70:2a:1c:21:d8:8f:
+ e1:bd:23:5b:2d:74:40:92:d9:63:19:0d:73:dd:69:bc:62:47:
+ bc:e0:74:2b:b2:eb:7d:be:41:1b:b5:c0:46:c5:a1:22:cb:5f:
+ 4e:c1:28:92:de:18:ba:d5:2a:28:bb:11:8b:17:93:98:99:60:
+ 94:5c:23:cf:5a:27:97:5e:0b:05:06:93:37:1e:3b:69:36:eb:
+ a9:9e:61:1d:8f:32:da:8e:0c:d6:74:3e:7b:09:24:da:01:77:
+ 47:c4:3b:cd:34:8c:99:f5:ca:e1:25:61:33:b2:59:1b:e2:6e:
+ d7:37:57:b6:0d:a9:12:da
+SHA1 Fingerprint=1F:49:14:F7:D8:74:95:1D:DD:AE:02:C0:BE:FD:3A:2D:82:75:51:85
diff --git a/apex/ca-certificates/files/93851c9e.0 b/apex/ca-certificates/files/93851c9e.0
new file mode 100644
index 0000000..e123235
--- /dev/null
+++ b/apex/ca-certificates/files/93851c9e.0
@@ -0,0 +1,125 @@
+-----BEGIN CERTIFICATE-----
+MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNV
+BAUTCUc2MzI4NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlk
+YWQgZGUgQ2VydGlmaWNhY2lvbjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNV
+BAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3QgQ0EwHhcNMTkwOTA0MTAwMDM4WhcN
+MzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEwMQswCQYDVQQGEwJF
+UzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQwEgYD
+VQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9v
+dCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCj
+cqQZAZ2cC4Ffc0m6p6zzBE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9q
+yGFOtibBTI3/TO80sh9l2Ll49a2pcbnvT1gdpd50IJeh7WhM3pIXS7yr/2WanvtH
+2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcvB2VSAKduyK9o7PQUlrZX
+H1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXsezx76W0OL
+zc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyR
+p1RMVwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQz
+W7i1o0TJrH93PB0j7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/
+SiOL9V8BY9KHcyi1Swr1+KuCLH5zJTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJn
+LNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe8TZBAQIvfXOn3kLMTOmJDVb3
+n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVOHj1tyRRM4y5B
+u8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj
+o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAO
+BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
+AgEATh65isagmD9uw2nAalxJUqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L
+9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzxj6ptBZNscsdW699QIyjlRRA96Gej
+rw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDtdD+4E5UGUcjohybK
+pFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM5gf0
+vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjq
+OknkJjCb5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ
+/zo1PqVUSlJZS2Db7v54EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ9
+2zg/LFis6ELhDtjTO0wugumDLmsx2d1Hhk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI
++PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGyg77FGr8H6lnco4g175x2
+MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3r5+qPeoo
+tt7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 996390341000653745 (0xdd3e3bc6cf96bb1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: serialNumber=G63287510, C=ES, O=ANF Autoridad de Certificacion, OU=ANF CA Raiz, CN=ANF Secure Server Root CA
+ Validity
+ Not Before: Sep 4 10:00:38 2019 GMT
+ Not After : Aug 30 10:00:38 2039 GMT
+ Subject: serialNumber=G63287510, C=ES, O=ANF Autoridad de Certificacion, OU=ANF CA Raiz, CN=ANF Secure Server Root CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:db:eb:6b:2b:e6:64:54:95:82:90:a3:72:a4:19:
+ 01:9d:9c:0b:81:5f:73:49:ba:a7:ac:f3:04:4e:7b:
+ 96:0b:ec:11:e0:5b:a6:1c:ce:1b:d2:0d:83:1c:2b:
+ b8:9e:1d:7e:45:32:60:0f:07:e9:77:58:7e:9f:6a:
+ c8:61:4e:b6:26:c1:4c:8d:ff:4c:ef:34:b2:1f:65:
+ d8:b9:78:f5:ad:a9:71:b9:ef:4f:58:1d:a5:de:74:
+ 20:97:a1:ed:68:4c:de:92:17:4b:bc:ab:ff:65:9a:
+ 9e:fb:47:d9:57:72:f3:09:a1:ae:76:44:13:6e:9c:
+ 2d:44:39:bc:f9:c7:3b:a4:58:3d:41:bd:b4:c2:49:
+ a3:c8:0d:d2:97:2f:07:65:52:00:a7:6e:c8:af:68:
+ ec:f4:14:96:b6:57:1f:56:c3:39:9f:2b:6d:e4:f3:
+ 3e:f6:35:64:da:0c:1c:a1:84:4b:2f:4b:4b:e2:2c:
+ 24:9d:6d:93:40:eb:b5:23:8e:32:ca:6f:45:d3:a8:
+ 89:7b:1e:cf:1e:fa:5b:43:8b:cd:cd:a8:0f:6a:ca:
+ 0c:5e:b9:9e:47:8f:f0:d9:b6:0a:0b:58:65:17:33:
+ b9:23:e4:77:19:7d:cb:4a:2e:92:7b:4f:2f:10:77:
+ b1:8d:2f:68:9c:62:cc:e0:50:f8:ec:91:a7:54:4c:
+ 57:09:d5:76:63:c5:e8:65:1e:ee:6d:6a:cf:09:9d:
+ fa:7c:4f:ad:60:08:fd:56:99:0f:15:2c:7b:a9:80:
+ ab:8c:61:8f:4a:07:76:42:de:3d:f4:dd:b2:24:33:
+ 5b:b8:b5:a3:44:c9:ac:7f:77:3c:1d:23:ec:82:a9:
+ a6:e2:c8:06:4c:02:fe:ac:5c:99:99:0b:2f:10:8a:
+ a6:f4:7f:d5:87:74:0d:59:49:45:f6:f0:71:5c:39:
+ 29:d6:bf:4a:23:8b:f5:5f:01:63:d2:87:73:28:b5:
+ 4b:0a:f5:f8:ab:82:2c:7e:73:25:32:1d:0b:63:0a:
+ 17:81:00:ff:b6:76:5e:e7:b4:b1:40:ca:21:bb:d5:
+ 80:51:e5:48:52:67:2c:d2:61:89:07:0d:0f:ce:42:
+ 77:c0:44:73:9c:44:50:a0:db:10:0a:2d:95:1c:81:
+ af:e4:1c:e5:14:1e:f1:36:41:01:02:2f:7d:73:a7:
+ de:42:cc:4c:e9:89:0d:56:f7:9f:91:d4:03:c6:6c:
+ c9:8f:db:d8:1c:e0:40:98:5d:66:99:98:80:6e:2d:
+ ff:01:c5:ce:cb:46:1f:ac:02:c6:43:e6:ae:a2:84:
+ 3c:c5:4e:1e:3d:6d:c9:14:4c:e3:2e:41:bb:ca:39:
+ bf:36:3c:2a:19:aa:41:87:4e:a5:ce:4b:32:79:dd:
+ 90:49:7f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Authority Key Identifier:
+ 9C:5F:D0:6C:63:A3:5F:93:CA:93:98:08:AD:8C:87:A5:2C:5C:C1:37
+ X509v3 Subject Key Identifier:
+ 9C:5F:D0:6C:63:A3:5F:93:CA:93:98:08:AD:8C:87:A5:2C:5C:C1:37
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 4e:1e:b9:8a:c6:a0:98:3f:6e:c3:69:c0:6a:5c:49:52:ac:cb:
+ 2b:5d:78:38:c1:d5:54:84:9f:93:f0:87:19:3d:2c:66:89:eb:
+ 0d:42:fc:cc:f0:75:85:3f:8b:f4:80:5d:79:e5:17:67:bd:35:
+ 82:e2:f2:3c:8e:7d:5b:36:cb:5a:80:00:29:f2:ce:2b:2c:f1:
+ 8f:aa:6d:05:93:6c:72:c7:56:eb:df:50:23:28:e5:45:10:3d:
+ e8:67:a3:af:0e:55:0f:90:09:62:ef:4b:59:a2:f6:53:f1:c0:
+ 35:e4:2f:c1:24:bd:79:2f:4e:20:22:3b:fd:1a:20:b0:a4:0e:
+ 2c:70:ed:74:3f:b8:13:95:06:51:c8:e8:87:26:ca:a4:5b:6a:
+ 16:21:92:dd:73:60:9e:10:18:de:3c:81:ea:e8:18:c3:7c:89:
+ f2:8b:50:3e:bd:11:e2:15:03:a8:36:7d:33:01:6c:48:15:d7:
+ 88:90:99:04:c5:cc:e6:07:f4:bc:f4:90:ed:13:e2:ea:8b:c3:
+ 8f:a3:33:0f:c1:29:4c:13:4e:da:15:56:71:73:72:82:50:f6:
+ 9a:33:7c:a2:b1:a8:1a:34:74:65:5c:ce:d1:eb:ab:53:e0:1a:
+ 80:d8:ea:3a:49:e4:26:30:9b:e5:1c:8a:a8:a9:15:32:86:99:
+ 92:0a:10:23:56:12:e0:f6:ce:4c:e2:bb:be:db:8d:92:73:01:
+ 66:2f:62:3e:b2:72:27:45:36:ed:4d:56:e3:97:99:ff:3a:35:
+ 3e:a5:54:4a:52:59:4b:60:db:ee:fe:78:11:7f:4a:dc:14:79:
+ 60:b6:6b:64:03:db:15:83:e1:a2:be:f6:23:97:50:f0:09:33:
+ 36:a7:71:96:25:f3:b9:42:7d:db:38:3f:2c:58:ac:e8:42:e1:
+ 0e:d8:d3:3b:4c:2e:82:e9:83:2e:6b:31:d9:dd:47:86:4f:6d:
+ 97:91:2e:4f:e2:28:71:35:16:d1:f2:73:fe:25:2b:07:47:24:
+ 63:27:c8:f8:f6:d9:6b:fc:12:31:56:08:c0:53:42:af:9c:d0:
+ 33:7e:fc:06:f0:31:44:03:14:f1:58:ea:f2:6a:0d:a9:11:b2:
+ 83:be:c5:1a:bf:07:ea:59:dc:a3:88:35:ef:9c:76:32:3c:4d:
+ 06:22:ce:15:e5:dd:9e:d8:8f:da:de:d2:c4:39:e5:17:81:cf:
+ 38:47:eb:7f:88:6d:59:1b:df:9f:42:14:ae:7e:cf:a8:b0:66:
+ 65:da:37:af:9f:aa:3d:ea:28:b6:de:d5:31:58:16:82:5b:ea:
+ bb:19:75:02:73:1a:ca:48:1a:21:93:90:0a:8e:93:84:a7:7d:
+ 3b:23:18:92:89:a0:8d:ac
+SHA1 Fingerprint=5B:6E:68:D0:CC:15:B6:A0:5F:1E:C1:5F:AE:02:FC:6B:2F:5D:6F:74
diff --git a/apex/ca-certificates/files/9479c8c3.0 b/apex/ca-certificates/files/9479c8c3.0
new file mode 100644
index 0000000..87805bf
--- /dev/null
+++ b/apex/ca-certificates/files/9479c8c3.0
@@ -0,0 +1,56 @@
+-----BEGIN CERTIFICATE-----
+MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN
+BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl
+c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl
+bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv
+b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ
+BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj
+YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5
+MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0
+dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg
+QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa
+jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi
+C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep
+lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof
+TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 0 (0x0)
+ Signature Algorithm: ecdsa-with-SHA256
+ Issuer: C=GR, L=Athens, O=Hellenic Academic and Research Institutions Cert. Authority, CN=Hellenic Academic and Research Institutions ECC RootCA 2015
+ Validity
+ Not Before: Jul 7 10:37:12 2015 GMT
+ Not After : Jun 30 10:37:12 2040 GMT
+ Subject: C=GR, L=Athens, O=Hellenic Academic and Research Institutions Cert. Authority, CN=Hellenic Academic and Research Institutions ECC RootCA 2015
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:92:a0:41:e8:4b:82:84:5c:e2:f8:31:11:99:86:
+ 64:4e:09:25:2f:9d:41:2f:0a:ae:35:4f:74:95:b2:
+ 51:64:6b:8d:6b:e6:3f:70:95:f0:05:44:47:a6:72:
+ 38:50:76:95:02:5a:8e:ae:28:9e:f9:2d:4e:99:ef:
+ 2c:48:6f:4c:25:29:e8:d1:71:5b:df:1d:c1:75:37:
+ b4:d7:fa:7b:7a:42:9c:6a:0a:56:5a:7c:69:0b:aa:
+ 80:09:24:6c:7e:c1:46
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ B4:22:0B:82:99:24:01:0E:9C:BB:E4:0E:FD:BF:FB:97:20:93:99:2A
+ Signature Algorithm: ecdsa-with-SHA256
+ Signature Value:
+ 30:64:02:30:67:ce:16:62:38:a2:ac:62:45:a7:a9:95:24:c0:
+ 1a:27:9c:32:3b:c0:c0:d5:ba:a9:e7:f8:04:43:53:85:ee:52:
+ 21:de:9d:f5:25:83:3e:9e:58:4b:2f:d7:67:13:0e:21:02:30:
+ 05:e1:75:01:de:68:ed:2a:1f:4d:4c:09:08:0d:ec:4b:ad:64:
+ 17:28:e7:75:ce:45:65:72:21:17:cb:22:41:0e:8c:13:98:38:
+ 9a:54:6d:9b:ca:e2:7c:ea:02:58:22:91
+SHA1 Fingerprint=9F:F1:71:8D:92:D5:9A:F3:7D:74:97:B4:BC:6F:84:68:0B:BA:B6:66
diff --git a/apex/ca-certificates/files/9576d26b.0 b/apex/ca-certificates/files/9576d26b.0
new file mode 100644
index 0000000..b519b3c
--- /dev/null
+++ b/apex/ca-certificates/files/9576d26b.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV
+BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu
+MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy
+MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx
+EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw
+ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe
+NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH
+PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I
+x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe
+QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR
+yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO
+QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912
+H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ
+QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD
+i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs
+nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1
+rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud
+DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI
+hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM
+tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf
+GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb
+lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka
++elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal
+TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i
+nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3
+gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr
+G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os
+zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x
+L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 92:b8:88:db:b0:8a:c1:63
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=SK, L=Bratislava, O=Disig a.s., CN=CA Disig Root R2
+ Validity
+ Not Before: Jul 19 09:15:30 2012 GMT
+ Not After : Jul 19 09:15:30 2042 GMT
+ Subject: C=SK, L=Bratislava, O=Disig a.s., CN=CA Disig Root R2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:a2:a3:c4:00:09:d6:85:5d:2d:6d:14:f6:c2:c3:
+ 73:9e:35:c2:71:55:7e:81:fb:ab:46:50:e0:c1:7c:
+ 49:78:e6:ab:79:58:3c:da:ff:7c:1c:9f:d8:97:02:
+ 78:3e:6b:41:04:e9:41:bd:be:03:2c:45:f6:2f:64:
+ d4:ab:5d:a3:47:3d:64:9b:e9:68:9a:c6:cc:1b:3f:
+ ba:be:b2:8b:34:02:2e:98:55:19:fc:8c:6f:aa:5f:
+ da:4c:ce:4d:03:21:a3:d8:d2:34:93:56:96:cb:4c:
+ 0c:00:16:3c:5f:1a:cd:c8:c7:6c:a6:ad:d3:31:a7:
+ bc:e8:e5:e1:66:d6:d2:fb:03:b4:41:65:c9:10:ae:
+ 0e:05:63:c6:80:6a:69:30:fd:d2:ee:90:ef:0d:27:
+ df:9f:95:73:f4:e1:25:da:6c:16:de:41:38:34:ea:
+ 8b:fc:d1:e8:04:14:61:2d:41:7e:ac:c7:77:4e:cb:
+ 51:54:fb:5e:92:18:1b:04:5a:68:c6:c9:c4:fa:b7:
+ 13:a0:98:b7:11:2b:b7:d6:57:cc:7c:9e:17:d1:cb:
+ 25:fe:86:4e:24:2e:56:0c:78:4d:9e:01:12:a6:2b:
+ a7:01:65:6e:7c:62:1d:84:84:df:ea:c0:6b:b5:a5:
+ 2a:95:83:c3:53:11:0c:73:1d:0b:b2:46:90:d1:42:
+ 3a:ce:40:6e:95:ad:ff:c6:94:ad:6e:97:84:8e:7d:
+ 6f:9e:8a:80:0d:49:6d:73:e2:7b:92:1e:c3:f3:c1:
+ f3:eb:2e:05:6f:d9:1b:cf:37:76:04:c8:b4:5a:e4:
+ 17:a7:cb:dd:76:1f:d0:19:76:e8:2c:05:b3:d6:9c:
+ 34:d8:96:dc:61:87:91:05:e4:44:08:33:c1:da:b9:
+ 08:65:d4:ae:b2:36:0d:eb:ba:38:ba:0c:e5:9b:9e:
+ eb:8d:66:dd:99:cf:d6:89:41:f6:04:92:8a:29:29:
+ 6d:6b:3a:1c:e7:75:7d:02:71:0e:f3:c0:e7:bd:cb:
+ 19:dd:9d:60:b2:c2:66:60:b6:b1:04:ee:c9:e6:86:
+ b9:9a:66:40:a8:e7:11:ed:81:45:03:8b:f6:67:59:
+ e8:c1:06:11:bd:dd:cf:80:02:4f:65:40:78:5c:47:
+ 50:c8:9b:e6:1f:81:7b:e4:44:a8:5b:85:9a:e2:de:
+ 5a:d5:c7:f9:3a:44:66:4b:e4:32:54:7c:e4:6c:9c:
+ b3:0e:3d:17:a2:b2:34:12:d6:7e:b2:a8:49:bb:d1:
+ 7a:28:40:be:a2:16:1f:df:e4:37:1f:11:73:fb:90:
+ 0a:65:43:a2:0d:7c:f8:06:01:55:33:7d:b0:0d:b8:
+ f4:f5:ae:a5:42:57:7c:36:11:8c:7b:5e:c4:03:9d:
+ 8c:79:9d
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ B5:99:F8:AF:B0:94:F5:E3:20:D6:0A:AD:CE:4E:56:A4:2E:6E:42:ED
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 26:06:5e:70:e7:65:33:c8:82:6e:d9:9c:17:3a:1b:7a:66:b2:
+ 01:f6:78:3b:69:5e:2f:ea:ff:4e:f9:28:c3:98:2a:61:4c:b4:
+ 24:12:8a:7d:6d:11:14:f7:9c:b5:ca:e6:bc:9e:27:8e:4c:19:
+ c8:a9:bd:7a:c0:d7:36:0e:6d:85:72:6e:a8:c6:a2:6d:f6:fa:
+ 73:63:7f:bc:6e:79:08:1c:9d:8a:9f:1a:8a:53:a6:d8:bb:d9:
+ 35:55:b1:11:c5:a9:03:b3:56:3b:b9:84:93:22:5e:7e:c1:f6:
+ 12:52:8b:ea:2c:67:bc:fe:36:4c:f5:b8:cf:d1:b3:49:92:3b:
+ d3:29:0e:99:1b:96:f7:61:b8:3b:c4:2b:b6:78:6c:b4:23:6f:
+ f0:fd:d3:b2:5e:75:1f:99:95:a8:ac:f6:da:e1:c5:31:7b:fb:
+ d1:46:b3:d2:bc:67:b4:62:54:ba:09:f7:63:b0:93:a2:9a:f9:
+ e9:52:2e:8b:60:12:ab:fc:f5:60:56:ef:10:5c:8b:c4:1a:42:
+ dc:83:5b:64:0e:cb:b5:bc:d6:4f:c1:7c:3c:6e:8d:13:6d:fb:
+ 7b:eb:30:d0:dc:4d:af:c5:d5:b6:a5:4c:5b:71:c9:e8:31:be:
+ e8:38:06:48:a1:1a:e2:ea:d2:de:12:39:58:1a:ff:80:0e:82:
+ 75:e6:b7:c9:07:6c:0e:ef:ff:38:f1:98:71:c4:b7:7f:0e:15:
+ d0:25:69:bd:22:9d:2b:ed:05:f6:46:47:ac:ed:c0:f0:d4:3b:
+ e2:ec:ee:96:5b:90:13:4e:1e:56:3a:eb:b0:ef:96:bb:96:23:
+ 11:ba:f2:43:86:74:64:95:c8:28:75:df:1d:35:ba:d2:37:83:
+ 38:53:38:36:3b:cf:6c:e9:f9:6b:0e:d0:fb:04:e8:4f:77:d7:
+ 65:01:78:86:0c:7a:3e:21:62:f1:7f:63:71:0c:c9:9f:44:db:
+ a8:27:a2:75:be:6e:81:3e:d7:c0:eb:1b:98:0f:70:5c:34:b2:
+ 8a:cc:c0:85:18:eb:6e:7a:b3:f7:5a:a1:07:bf:a9:42:92:f3:
+ 60:22:97:e4:14:a1:07:9b:4e:76:c0:8e:7d:fd:a4:25:c7:47:
+ ed:ff:1f:73:ac:cc:c3:a5:e9:6f:0a:8e:9b:65:c2:50:85:b5:
+ a3:a0:53:12:cc:55:87:61:f3:81:ae:10:46:61:bd:44:21:b8:
+ c2:3d:74:cf:7e:24:35:fa:1c:07:0e:9b:3d:22:ca:ef:31:2f:
+ 8c:ac:12:bd:ef:40:28:fc:29:67:9f:b2:13:4f:66:24:c4:53:
+ 19:e9:1e:29:15:ef:e6:6d:b0:7f:2d:67:fd:f3:6c:1b:75:46:
+ a3:e5:4a:17:e9:a4:d7:0b
+SHA1 Fingerprint=B5:61:EB:EA:A4:DE:E4:25:4B:69:1A:98:A5:57:47:C2:34:C7:D9:71
diff --git a/apex/ca-certificates/files/9591a472.0 b/apex/ca-certificates/files/9591a472.0
new file mode 100644
index 0000000..9c4cc81
--- /dev/null
+++ b/apex/ca-certificates/files/9591a472.0
@@ -0,0 +1,125 @@
+-----BEGIN CERTIFICATE-----
+MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl
+MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw
+NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
+IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG
+EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N
+aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ
+Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0
+ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1
+HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm
+gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ
+jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc
+aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG
+YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6
+W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K
+UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH
++FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q
+W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/
+BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC
+NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC
+LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC
+gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6
+tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh
+SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2
+TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3
+pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR
+xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp
+GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9
+dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN
+AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB
+RA+GsCyRxj3qrg+E
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 1e:d3:97:09:5f:d8:b4:b3:47:70:1e:aa:be:7f:45:b3
+ Signature Algorithm: sha384WithRSAEncryption
+ Issuer: C=US, O=Microsoft Corporation, CN=Microsoft RSA Root Certificate Authority 2017
+ Validity
+ Not Before: Dec 18 22:51:22 2019 GMT
+ Not After : Jul 18 23:00:23 2042 GMT
+ Subject: C=US, O=Microsoft Corporation, CN=Microsoft RSA Root Certificate Authority 2017
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:ca:5b:be:94:33:8c:29:95:91:16:0a:95:bd:47:
+ 62:c1:89:f3:99:36:df:46:90:c9:a5:ed:78:6a:6f:
+ 47:91:68:f8:27:67:50:33:1d:a1:a6:fb:e0:e5:43:
+ a3:84:02:57:01:5d:9c:48:40:82:53:10:bc:bf:c7:
+ 3b:68:90:b6:82:2d:e5:f4:65:d0:cc:6d:19:cc:95:
+ f9:7b:ac:4a:94:ad:0e:de:4b:43:1d:87:07:92:13:
+ 90:80:83:64:35:39:04:fc:e5:e9:6c:b3:b6:1f:50:
+ 94:38:65:50:5c:17:46:b9:b6:85:b5:1c:b5:17:e8:
+ d6:45:9d:d8:b2:26:b0:ca:c4:70:4a:ae:60:a4:dd:
+ b3:d9:ec:fc:3b:d5:57:72:bc:3f:c8:c9:b2:de:4b:
+ 6b:f8:23:6c:03:c0:05:bd:95:c7:cd:73:3b:66:80:
+ 64:e3:1a:ac:2e:f9:47:05:f2:06:b6:9b:73:f5:78:
+ 33:5b:c7:a1:fb:27:2a:a1:b4:9a:91:8c:91:d3:3a:
+ 82:3e:76:40:b4:cd:52:61:51:70:28:3f:c5:c5:5a:
+ f2:c9:8c:49:bb:14:5b:4d:c8:ff:67:4d:4c:12:96:
+ ad:f5:fe:78:a8:97:87:d7:fd:5e:20:80:dc:a1:4b:
+ 22:fb:d4:89:ad:ba:ce:47:97:47:55:7b:8f:45:c8:
+ 67:28:84:95:1c:68:30:ef:ef:49:e0:35:7b:64:e7:
+ 98:b0:94:da:4d:85:3b:3e:55:c4:28:af:57:f3:9e:
+ 13:db:46:27:9f:1e:a2:5e:44:83:a4:a5:ca:d5:13:
+ b3:4b:3f:c4:e3:c2:e6:86:61:a4:52:30:b9:7a:20:
+ 4f:6f:0f:38:53:cb:33:0c:13:2b:8f:d6:9a:bd:2a:
+ c8:2d:b1:1c:7d:4b:51:ca:47:d1:48:27:72:5d:87:
+ eb:d5:45:e6:48:65:9d:af:52:90:ba:5b:a2:18:65:
+ 57:12:9f:68:b9:d4:15:6b:94:c4:69:22:98:f4:33:
+ e0:ed:f9:51:8e:41:50:c9:34:4f:76:90:ac:fc:38:
+ c1:d8:e1:7b:b9:e3:e3:94:e1:46:69:cb:0e:0a:50:
+ 6b:13:ba:ac:0f:37:5a:b7:12:b5:90:81:1e:56:ae:
+ 57:22:86:d9:c9:d2:d1:d7:51:e3:ab:3b:c6:55:fd:
+ 1e:0e:d3:74:0a:d1:da:aa:ea:69:b8:97:28:8f:48:
+ c4:07:f8:52:43:3a:f4:ca:55:35:2c:b0:a6:6a:c0:
+ 9c:f9:f2:81:e1:12:6a:c0:45:d9:67:b3:ce:ff:23:
+ a2:89:0a:54:d4:14:b9:2a:a8:d7:ec:f9:ab:cd:25:
+ 58:32:79:8f:90:5b:98:39:c4:08:06:c1:ac:7f:0e:
+ 3d:00:a5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 09:CB:59:7F:86:B2:70:8F:1A:C3:39:E3:C0:D9:E9:BF:BB:4D:B2:23
+ 1.3.6.1.4.1.311.21.1:
+ ...
+ Signature Algorithm: sha384WithRSAEncryption
+ Signature Value:
+ ac:af:3e:5d:c2:11:96:89:8e:a3:e7:92:d6:97:15:b8:13:a2:
+ a6:42:2e:02:cd:16:05:59:27:ca:20:e8:ba:b8:e8:1a:ec:4d:
+ a8:97:56:ae:65:43:b1:8f:00:9b:52:cd:55:cd:53:39:6d:62:
+ 4c:8b:0d:5b:7c:2e:44:bf:83:10:8f:f3:53:82:80:c3:4f:3a:
+ c7:6e:11:3f:e6:e3:16:91:84:fb:6d:84:7f:34:74:ad:89:a7:
+ ce:b9:d7:d7:9f:84:64:92:be:95:a1:ad:09:53:33:dd:ee:0a:
+ ea:4a:51:8e:6f:55:ab:ba:b5:94:46:ae:8c:7f:d8:a2:50:25:
+ 65:60:80:46:db:33:04:ae:6c:b5:98:74:54:25:dc:93:e4:f8:
+ e3:55:15:3d:b8:6d:c3:0a:a4:12:c1:69:85:6e:df:64:f1:53:
+ 99:e1:4a:75:20:9d:95:0f:e4:d6:dc:03:f1:59:18:e8:47:89:
+ b2:57:5a:94:b6:a9:d8:17:2b:17:49:e5:76:cb:c1:56:99:3a:
+ 37:b1:ff:69:2c:91:91:93:e1:df:4c:a3:37:76:4d:a1:9f:f8:
+ 6d:1e:1d:d3:fa:ec:fb:f4:45:1d:13:6d:cf:f7:59:e5:22:27:
+ 72:2b:86:f3:57:bb:30:ed:24:4d:dc:7d:56:bb:a3:b3:f8:34:
+ 79:89:c1:e0:f2:02:61:f7:a6:fc:0f:bb:1c:17:0b:ae:41:d9:
+ 7c:bd:27:a3:fd:2e:3a:d1:93:94:b1:73:1d:24:8b:af:5b:20:
+ 89:ad:b7:67:66:79:f5:3a:c6:a6:96:33:fe:53:92:c8:46:b1:
+ 11:91:c6:99:7f:8f:c9:d6:66:31:20:41:10:87:2d:0c:d6:c1:
+ af:34:98:ca:64:83:fb:13:57:d1:c1:f0:3c:7a:8c:a5:c1:fd:
+ 95:21:a0:71:c1:93:67:71:12:ea:8f:88:0a:69:19:64:99:23:
+ 56:fb:ac:2a:2e:70:be:66:c4:0c:84:ef:e5:8b:f3:93:01:f8:
+ 6a:90:93:67:4b:b2:68:a3:b5:62:8f:e9:3f:8c:7a:3b:5e:0f:
+ e7:8c:b8:c6:7c:ef:37:fd:74:e2:c8:4f:33:72:e1:94:39:6d:
+ bd:12:af:be:0c:4e:70:7c:1b:6f:8d:b3:32:93:73:44:16:6d:
+ e8:f4:f7:e0:95:80:8f:96:5d:38:a4:f4:ab:de:0a:30:87:93:
+ d8:4d:00:71:62:45:27:4b:3a:42:84:5b:7f:65:b7:67:34:52:
+ 2d:9c:16:6b:aa:a8:d8:7b:a3:42:4c:71:c7:0c:ca:3e:83:e4:
+ a6:ef:b7:01:30:5e:51:a3:79:f5:70:69:a6:41:44:0f:86:b0:
+ 2c:91:c6:3d:ea:ae:0f:84
+SHA1 Fingerprint=73:A5:E6:4A:3B:FF:83:16:FF:0E:DC:CC:61:8A:90:6E:4E:AE:4D:74
diff --git a/apex/ca-certificates/files/95aff9e3.0 b/apex/ca-certificates/files/95aff9e3.0
new file mode 100644
index 0000000..39cff63
--- /dev/null
+++ b/apex/ca-certificates/files/95aff9e3.0
@@ -0,0 +1,80 @@
+-----BEGIN CERTIFICATE-----
+MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM
+MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D
+ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU
+cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3
+WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg
+Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw
+IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH
+UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM
+TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU
+BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM
+kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x
+AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV
+HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y
+sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL
+I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8
+J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY
+VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
+03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 279744 (0x444c0)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=PL, O=Unizeto Technologies S.A., OU=Certum Certification Authority, CN=Certum Trusted Network CA
+ Validity
+ Not Before: Oct 22 12:07:37 2008 GMT
+ Not After : Dec 31 12:07:37 2029 GMT
+ Subject: C=PL, O=Unizeto Technologies S.A., OU=Certum Certification Authority, CN=Certum Trusted Network CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:e3:fb:7d:a3:72:ba:c2:f0:c9:14:87:f5:6b:01:
+ 4e:e1:6e:40:07:ba:6d:27:5d:7f:f7:5b:2d:b3:5a:
+ c7:51:5f:ab:a4:32:a6:61:87:b6:6e:0f:86:d2:30:
+ 02:97:f8:d7:69:57:a1:18:39:5d:6a:64:79:c6:01:
+ 59:ac:3c:31:4a:38:7c:d2:04:d2:4b:28:e8:20:5f:
+ 3b:07:a2:cc:4d:73:db:f3:ae:4f:c7:56:d5:5a:a7:
+ 96:89:fa:f3:ab:68:d4:23:86:59:27:cf:09:27:bc:
+ ac:6e:72:83:1c:30:72:df:e0:a2:e9:d2:e1:74:75:
+ 19:bd:2a:9e:7b:15:54:04:1b:d7:43:39:ad:55:28:
+ c5:e2:1a:bb:f4:c0:e4:ae:38:49:33:cc:76:85:9f:
+ 39:45:d2:a4:9e:f2:12:8c:51:f8:7c:e4:2d:7f:f5:
+ ac:5f:eb:16:9f:b1:2d:d1:ba:cc:91:42:77:4c:25:
+ c9:90:38:6f:db:f0:cc:fb:8e:1e:97:59:3e:d5:60:
+ 4e:e6:05:28:ed:49:79:13:4b:ba:48:db:2f:f9:72:
+ d3:39:ca:fe:1f:d8:34:72:f5:b4:40:cf:31:01:c3:
+ ec:de:11:2d:17:5d:1f:b8:50:d1:5e:19:a7:69:de:
+ 07:33:28:ca:50:95:f9:a7:54:cb:54:86:50:45:a9:
+ f9:49
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 08:76:CD:CB:07:FF:24:F6:C5:CD:ED:BB:90:BC:E2:84:37:46:75:F7
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ a6:a8:ad:22:ce:01:3d:a6:a3:ff:62:d0:48:9d:8b:5e:72:b0:
+ 78:44:e3:dc:1c:af:09:fd:23:48:fa:bd:2a:c4:b9:55:04:b5:
+ 10:a3:8d:27:de:0b:82:63:d0:ee:de:0c:37:79:41:5b:22:b2:
+ b0:9a:41:5c:a6:70:e0:d4:d0:77:cb:23:d3:00:e0:6c:56:2f:
+ e1:69:0d:0d:d9:aa:bf:21:81:50:d9:06:a5:a8:ff:95:37:d0:
+ aa:fe:e2:b3:f5:99:2d:45:84:8a:e5:42:09:d7:74:02:2f:f7:
+ 89:d8:99:e9:bc:27:d4:47:8d:ba:0d:46:1c:77:cf:14:a4:1c:
+ b9:a4:31:c4:9c:28:74:03:34:ff:33:19:26:a5:e9:0d:74:b7:
+ 3e:97:c6:76:e8:27:96:a3:66:dd:e1:ae:f2:41:5b:ca:98:56:
+ 83:73:70:e4:86:1a:d2:31:41:ba:2f:be:2d:13:5a:76:6f:4e:
+ e8:4e:81:0e:3f:5b:03:22:a0:12:be:66:58:11:4a:cb:03:c4:
+ b4:2a:2a:2d:96:17:e0:39:54:bc:48:d3:76:27:9d:9a:2d:06:
+ a6:c9:ec:39:d2:ab:db:9f:9a:0b:27:02:35:29:b1:40:95:e7:
+ f9:e8:9c:55:88:19:46:d6:b7:34:f5:7e:ce:39:9a:d9:38:f1:
+ 51:f7:4f:2c
+SHA1 Fingerprint=07:E0:32:E0:20:B7:2C:3F:19:2F:06:28:A2:59:3A:19:A7:0F:06:9E
diff --git a/apex/ca-certificates/files/9685a493.0 b/apex/ca-certificates/files/9685a493.0
new file mode 100644
index 0000000..8b9de91
--- /dev/null
+++ b/apex/ca-certificates/files/9685a493.0
@@ -0,0 +1,76 @@
+-----BEGIN CERTIFICATE-----
+MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx
+FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg
+Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG
+A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr
+b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ
+jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn
+PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh
+ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9
+nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h
+q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED
+MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC
+mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3
+7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB
+oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs
+EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO
+fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi
+AmvZWg==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1000 (0x3e8)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=HK, O=Hongkong Post, CN=Hongkong Post Root CA 1
+ Validity
+ Not Before: May 15 05:13:14 2003 GMT
+ Not After : May 15 04:52:29 2023 GMT
+ Subject: C=HK, O=Hongkong Post, CN=Hongkong Post Root CA 1
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:ac:ff:38:b6:e9:66:02:49:e3:a2:b4:e1:90:f9:
+ 40:8f:79:f9:e2:bd:79:fe:02:bd:ee:24:92:1d:22:
+ f6:da:85:72:69:fe:d7:3f:09:d4:dd:91:b5:02:9c:
+ d0:8d:5a:e1:55:c3:50:86:b9:29:26:c2:e3:d9:a0:
+ f1:69:03:28:20:80:45:22:2d:56:a7:3b:54:95:56:
+ 22:59:1f:28:df:1f:20:3d:6d:a2:36:be:23:a0:b1:
+ 6e:b5:b1:27:3f:39:53:09:ea:ab:6a:e8:74:b2:c2:
+ 65:5c:8e:bf:7c:c3:78:84:cd:9e:16:fc:f5:2e:4f:
+ 20:2a:08:9f:77:f3:c5:1e:c4:9a:52:66:1e:48:5e:
+ e3:10:06:8f:22:98:e1:65:8e:1b:5d:23:66:3b:b8:
+ a5:32:51:c8:86:aa:a1:a9:9e:7f:76:94:c2:a6:6c:
+ b7:41:f0:d5:c8:06:38:e6:d4:0c:e2:f3:3b:4c:6d:
+ 50:8c:c4:83:27:c1:13:84:59:3d:9e:75:74:b6:d8:
+ 02:5e:3a:90:7a:c0:42:36:72:ec:6a:4d:dc:ef:c4:
+ 00:df:13:18:57:5f:26:78:c8:d6:0a:79:77:bf:f7:
+ af:b7:76:b9:a5:0b:84:17:5d:10:ea:6f:e1:ab:95:
+ 11:5f:6d:3c:a3:5c:4d:83:5b:f2:b3:19:8a:80:8b:
+ 0b:87
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE, pathlen:3
+ X509v3 Key Usage: critical
+ Digital Signature, Non Repudiation, Certificate Sign, CRL Sign
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 0e:46:d5:3c:ae:e2:87:d9:5e:81:8b:02:98:41:08:8c:4c:bc:
+ da:db:ee:27:1b:82:e7:6a:45:ec:16:8b:4f:85:a0:f3:b2:70:
+ bd:5a:96:ba:ca:6e:6d:ee:46:8b:6e:e7:2a:2e:96:b3:19:33:
+ eb:b4:9f:a8:b2:37:ee:98:a8:97:b6:2e:b6:67:27:d4:a6:49:
+ fd:1c:93:65:76:9e:42:2f:dc:22:6c:9a:4f:f2:5a:15:39:b1:
+ 71:d7:2b:51:e8:6d:1c:98:c0:d9:2a:f4:a1:82:7b:d5:c9:41:
+ a2:23:01:74:38:55:8b:0f:b9:2e:67:a2:20:04:37:da:9c:0b:
+ d3:17:21:e0:8f:97:79:34:6f:84:48:02:20:33:1b:e6:34:44:
+ 9f:91:70:f4:80:5e:84:43:c2:29:d2:6c:12:14:e4:61:8d:ac:
+ 10:90:9e:84:50:bb:f0:96:6f:45:9f:8a:f3:ca:6c:4f:fa:11:
+ 3a:15:15:46:c3:cd:1f:83:5b:2d:41:12:ed:50:67:41:13:3d:
+ 21:ab:94:8a:aa:4e:7c:c1:b1:fb:a7:d6:b5:27:2f:97:ab:6e:
+ e0:1d:e2:d1:1c:2c:1f:44:e2:fc:be:91:a1:9c:fb:d6:29:53:
+ 73:86:9f:53:d8:43:0e:5d:d6:63:82:71:1d:80:74:ca:f6:e2:
+ 02:6b:d9:5a
+SHA1 Fingerprint=D6:DA:A8:20:8D:09:D2:15:4D:24:B5:2F:CB:34:6E:B2:58:B2:8A:58
diff --git a/apex/ca-certificates/files/985c1f52.0 b/apex/ca-certificates/files/985c1f52.0
new file mode 100644
index 0000000..9656b7e
--- /dev/null
+++ b/apex/ca-certificates/files/985c1f52.0
@@ -0,0 +1,124 @@
+-----BEGIN CERTIFICATE-----
+MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg
+MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh
+bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx
+MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET
+MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ
+KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI
+xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k
+ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD
+aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw
+LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw
+1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX
+k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2
+SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h
+bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n
+WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY
+rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce
+MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD
+AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu
+bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN
+nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt
+Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61
+55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj
+vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf
+cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz
+oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp
+nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs
+pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v
+JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R
+8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4
+5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 45:e6:bb:03:83:33:c3:85:65:48:e6:ff:45:51
+ Signature Algorithm: sha384WithRSAEncryption
+ Issuer: OU=GlobalSign Root CA - R6, O=GlobalSign, CN=GlobalSign
+ Validity
+ Not Before: Dec 10 00:00:00 2014 GMT
+ Not After : Dec 10 00:00:00 2034 GMT
+ Subject: OU=GlobalSign Root CA - R6, O=GlobalSign, CN=GlobalSign
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:95:07:e8:73:ca:66:f9:ec:14:ca:7b:3c:f7:0d:
+ 08:f1:b4:45:0b:2c:82:b4:48:c6:eb:5b:3c:ae:83:
+ b8:41:92:33:14:a4:6f:7f:e9:2a:cc:c6:b0:88:6b:
+ c5:b6:89:d1:c6:b2:ff:14:ce:51:14:21:ec:4a:dd:
+ 1b:5a:c6:d6:87:ee:4d:3a:15:06:ed:64:66:0b:92:
+ 80:ca:44:de:73:94:4e:f3:a7:89:7f:4f:78:63:08:
+ c8:12:50:6d:42:66:2f:4d:b9:79:28:4d:52:1a:8a:
+ 1a:80:b7:19:81:0e:7e:c4:8a:bc:64:4c:21:1c:43:
+ 68:d7:3d:3c:8a:c5:b2:66:d5:90:9a:b7:31:06:c5:
+ be:e2:6d:32:06:a6:1e:f9:b9:eb:aa:a3:b8:bf:be:
+ 82:63:50:d0:f0:18:89:df:e4:0f:79:f5:ea:a2:1f:
+ 2a:d2:70:2e:7b:e7:bc:93:bb:6d:53:e2:48:7c:8c:
+ 10:07:38:ff:66:b2:77:61:7e:e0:ea:8c:3c:aa:b4:
+ a4:f6:f3:95:4a:12:07:6d:fd:8c:b2:89:cf:d0:a0:
+ 61:77:c8:58:74:b0:d4:23:3a:f7:5d:3a:ca:a2:db:
+ 9d:09:de:5d:44:2d:90:f1:81:cd:57:92:fa:7e:bc:
+ 50:04:63:34:df:6b:93:18:be:6b:36:b2:39:e4:ac:
+ 24:36:b7:f0:ef:b6:1c:13:57:93:b6:de:b2:f8:e2:
+ 85:b7:73:a2:b8:35:aa:45:f2:e0:9d:36:a1:6f:54:
+ 8a:f1:72:56:6e:2e:88:c5:51:42:44:15:94:ee:a3:
+ c5:38:96:9b:4e:4e:5a:0b:47:f3:06:36:49:77:30:
+ bc:71:37:e5:a6:ec:21:08:75:fc:e6:61:16:3f:77:
+ d5:d9:91:97:84:0a:6c:d4:02:4d:74:c0:14:ed:fd:
+ 39:fb:83:f2:5e:14:a1:04:b0:0b:e9:fe:ee:8f:e1:
+ 6e:0b:b2:08:b3:61:66:09:6a:b1:06:3a:65:96:59:
+ c0:f0:35:fd:c9:da:28:8d:1a:11:87:70:81:0a:a8:
+ 9a:75:1d:9e:3a:86:05:00:9e:db:80:d6:25:f9:dc:
+ 05:9e:27:59:4c:76:39:5b:ea:f9:a5:a1:d8:83:0f:
+ d1:ff:df:30:11:f9:85:cf:33:48:f5:ca:6d:64:14:
+ 2c:7a:58:4f:d3:4b:08:49:c5:95:64:1a:63:0e:79:
+ 3d:f5:b3:8c:ca:58:ad:9c:42:45:79:6e:0e:87:19:
+ 5c:54:b1:65:b6:bf:8c:9b:dc:13:e9:0d:6f:b8:2e:
+ dc:67:6e:c9:8b:11:b5:84:14:8a:00:19:70:83:79:
+ 91:97:91:d4:1a:27:bf:37:1e:32:07:d8:14:63:3c:
+ 28:4c:af
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ AE:6C:05:A3:93:13:E2:A2:E7:E2:D7:1C:D6:C7:F0:7F:C8:67:53:A0
+ X509v3 Authority Key Identifier:
+ AE:6C:05:A3:93:13:E2:A2:E7:E2:D7:1C:D6:C7:F0:7F:C8:67:53:A0
+ Signature Algorithm: sha384WithRSAEncryption
+ Signature Value:
+ 83:25:ed:e8:d1:fd:95:52:cd:9e:c0:04:a0:91:69:e6:5c:d0:
+ 84:de:dc:ad:a2:4f:e8:47:78:d6:65:98:a9:5b:a8:3c:87:7c:
+ 02:8a:d1:6e:b7:16:73:e6:5f:c0:54:98:d5:74:be:c1:cd:e2:
+ 11:91:ad:23:18:3d:dd:e1:72:44:96:b4:95:5e:c0:7b:8e:99:
+ 78:16:43:13:56:57:b3:a2:b3:3b:b5:77:dc:40:72:ac:a3:eb:
+ 9b:35:3e:b1:08:21:a1:e7:c4:43:37:79:32:be:b5:e7:9c:2c:
+ 4c:bc:43:29:99:8e:30:d3:ac:21:e0:e3:1d:fa:d8:07:33:76:
+ 54:00:22:2a:b9:4d:20:2e:70:68:da:e5:53:fc:83:5c:d3:9d:
+ f2:ff:44:0c:44:66:f2:d2:e3:bd:46:00:1a:6d:02:ba:25:5d:
+ 8d:a1:31:51:dd:54:46:1c:4d:db:99:96:ef:1a:1c:04:5c:a6:
+ 15:ef:78:e0:79:fe:5d:db:3e:aa:4c:55:fd:9a:15:a9:6f:e1:
+ a6:fb:df:70:30:e9:c3:ee:42:46:ed:c2:93:05:89:fa:7d:63:
+ 7b:3f:d0:71:81:7c:00:e8:98:ae:0e:78:34:c3:25:fb:af:0a:
+ 9f:20:6b:dd:3b:13:8f:12:8c:e2:41:1a:48:7a:73:a0:77:69:
+ c7:b6:5c:7f:82:c8:1e:fe:58:1b:28:2b:a8:6c:ad:5e:6d:c0:
+ 05:d2:7b:b7:eb:80:fe:25:37:fe:02:9b:68:ac:42:5d:c3:ee:
+ f5:cc:dc:f0:50:75:d2:36:69:9c:e6:7b:04:df:6e:06:69:b6:
+ de:0a:09:48:59:87:eb:7b:14:60:7a:64:aa:69:43:ef:91:c7:
+ 4c:ec:18:dd:6c:ef:53:2d:8c:99:e1:5e:f2:72:3e:cf:54:c8:
+ bd:67:ec:a4:0f:4c:45:ff:d3:b9:30:23:07:4c:8f:10:bf:86:
+ 96:d9:99:5a:b4:99:57:1c:a4:cc:bb:15:89:53:ba:2c:05:0f:
+ e4:c4:9e:19:b1:18:34:d5:4c:9d:ba:ed:f7:1f:af:24:95:04:
+ 78:a8:03:bb:ee:81:e5:da:5f:7c:8b:4a:a1:90:74:25:a7:b3:
+ 3e:4b:c8:2c:56:bd:c7:c8:ef:38:e2:5c:92:f0:79:f7:9c:84:
+ ba:74:2d:61:01:20:7e:7e:d1:f2:4f:07:59:5f:8b:2d:43:52:
+ eb:46:0c:94:e1:f5:66:47:79:77:d5:54:5b:1f:ad:24:37:cb:
+ 45:5a:4e:a0:44:48:c8:d8:b0:99:c5:15:84:09:f6:d6:49:49:
+ c0:65:b8:e6:1a:71:6e:a0:a8:f1:82:e8:45:3e:6c:d6:02:d7:
+ 0a:67:83:05:5a:c9:a4:10
+SHA1 Fingerprint=80:94:64:0E:B5:A7:A1:CA:11:9C:1F:DD:D5:9F:81:02:63:A7:FB:D1
diff --git a/apex/ca-certificates/files/99e1b953.0 b/apex/ca-certificates/files/99e1b953.0
new file mode 100644
index 0000000..826d42c
--- /dev/null
+++ b/apex/ca-certificates/files/99e1b953.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQEL
+BQAwQzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4x
+FjAUBgNVBAMTDXZUcnVzIFJvb3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMx
+MDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoGA1UEChMTaVRydXNDaGluYSBDby4s
+THRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZotsSKYc
+IrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykU
+AyyNJJrIZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+
+GrPSbcKvdmaVayqwlHeFXgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z9
+8Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KAYPxMvDVTAWqXcoKv8R1w6Jz1717CbMdH
+flqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70kLJrxLT5ZOrpGgrIDajt
+J8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2AXPKBlim
+0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZN
+pGvu/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQ
+UqqzApVg+QxMaPnu1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHW
+OXSuTEGC2/KmSNGzm/MzqvOmwMVO9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMB
+AAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYgscasGrz2iTAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAKbqSSaet
+8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd
+nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1j
+bhd47F18iMjrjld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvM
+Kar5CKXiNxTKsbhm7xqC5PD48acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIiv
+TDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJnxDHO2zTlJQNgJXtxmOTAGytfdELS
+S8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554WgicEFOwE30z9J4nfr
+I8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4sEb9
+b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNB
+UvupLnKWnyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1P
+Ti07NEPhmg4NpGaXutIcSkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929ven
+sBxXVsFy6K2ir40zSbofitzmdHxghm+Hl3s=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 43:e3:71:13:d8:b3:59:14:5d:b7:ce:8c:fd:35:fd:6f:bc:05:8d:45
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=CN, O=iTrusChina Co.,Ltd., CN=vTrus Root CA
+ Validity
+ Not Before: Jul 31 07:24:05 2018 GMT
+ Not After : Jul 31 07:24:05 2043 GMT
+ Subject: C=CN, O=iTrusChina Co.,Ltd., CN=vTrus Root CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:bd:55:7c:61:d3:b8:1d:04:62:05:a0:ae:6c:b7:
+ 70:b4:41:ea:4b:03:5e:10:3f:90:5a:1c:8b:3b:b0:
+ 66:8b:6c:48:a6:1c:22:ba:d5:40:92:ee:33:b2:23:
+ 59:c9:8e:bc:58:da:8b:9e:d0:19:f2:2f:59:c6:8c:
+ 63:5a:ba:9f:a3:0b:b0:b3:9a:5c:ba:11:b8:12:e9:
+ 0c:bb:cf:6e:6c:80:87:29:14:03:2c:8d:24:9a:c8:
+ 64:83:b5:6a:ac:13:2c:33:f1:9f:dc:2c:61:3c:1a:
+ 3f:70:55:9b:ad:00:52:7f:cf:04:b9:fe:36:fa:9c:
+ c0:16:ae:62:fe:96:4c:43:7e:55:14:be:1a:b3:d2:
+ 6d:c2:af:76:66:95:6b:2a:b0:94:77:85:5e:04:0f:
+ 62:1d:63:75:f7:6b:e7:cb:5b:9a:70:ec:3e:67:05:
+ f0:fe:07:08:80:cf:28:db:05:c6:14:27:2f:86:7d:
+ f0:27:de:ff:e6:7e:33:48:e7:0b:1e:58:d1:27:2b:
+ 53:0e:57:4a:65:d7:fb:a2:80:60:fc:4c:bc:35:53:
+ 01:6a:97:72:82:af:f1:1d:70:e8:9c:f5:ef:5e:c2:
+ 6c:c7:47:7e:5a:94:85:26:4d:3b:ba:eb:4c:e8:b0:
+ 09:c2:65:c2:9d:9d:09:9b:4e:b5:97:05:ac:f5:06:
+ a0:f7:36:05:7e:f4:90:b2:6b:c4:b4:f9:64:ea:e9:
+ 1a:0a:c8:0d:a8:ed:27:c9:d4:e7:b3:b9:ab:82:22:
+ 90:27:3d:2a:e8:7c:90:ef:bc:4f:fd:e2:0a:24:a7:
+ de:65:24:a4:5d:ea:c0:76:30:d3:77:50:f8:0d:04:
+ 9b:94:36:01:73:ca:06:58:a6:d3:3b:dc:fa:04:46:
+ 13:55:8a:c9:44:47:b8:51:39:1a:2e:e8:34:e2:79:
+ cb:59:4a:0a:7f:bc:a6:ef:1f:03:67:6a:59:2b:25:
+ 62:93:d9:53:19:66:3c:27:62:29:86:4d:a4:6b:ee:
+ ff:d4:4e:ba:d5:b4:e2:8e:48:5a:00:19:09:f1:05:
+ d9:ce:91:b1:f7:eb:e9:39:4f:f6:6f:04:43:9a:55:
+ f5:3e:05:14:bd:bf:b3:59:b4:d8:8e:33:84:a3:90:
+ 52:aa:b3:02:95:60:f9:0c:4c:68:f9:ee:d5:17:0d:
+ f8:71:57:b5:25:e4:29:ee:65:5d:af:d1:ee:3c:17:
+ 0b:5a:43:c5:a5:86:ea:24:9e:e2:05:07:dc:34:42:
+ 12:91:d6:39:74:ae:4c:41:82:db:f2:a6:48:d1:b3:
+ 9b:f3:33:aa:f3:a6:c0:c5:4e:f5:f4:9d:76:63:e6:
+ 02:c6:22:4b:c1:95:3f:50:64:2c:54:e5:b6:f0:3c:
+ 29:cf:57
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 54:62:70:63:F1:75:84:43:58:8E:D1:16:20:B1:C6:AC:1A:BC:F6:89
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 29:ba:92:49:a7:ad:f0:f1:70:c3:e4:97:f0:9f:a9:25:d5:6b:
+ 9e:34:fe:e6:1a:64:f6:3a:6b:52:b2:10:78:1a:9f:4c:da:8a:
+ da:ec:1c:37:52:e0:42:4b:fb:6c:76:ca:24:0b:39:12:15:9d:
+ 9f:11:2d:fc:79:64:dc:e0:e0:f5:dd:e0:57:c9:a5:b2:76:70:
+ 50:a4:fe:b7:0a:70:d5:a0:34:f1:75:d7:4d:49:ba:11:d1:b3:
+ d8:ec:82:ff:eb:0e:c4:bf:64:2d:7d:63:6e:17:78:ec:5d:7c:
+ 88:c8:eb:8e:57:76:d9:59:04:fa:bc:52:1f:45:ac:f0:7a:80:
+ ec:ec:6f:76:ae:91:db:10:8e:04:dc:92:df:a0:f6:e6:ae:49:
+ d3:c1:6c:12:1b:cc:29:aa:f9:08:a5:e2:37:14:ca:b1:b8:66:
+ ef:1a:82:e4:f0:f8:f1:a7:16:69:b7:db:a9:61:3c:9f:f5:31:
+ cb:e4:00:46:c2:2f:74:b1:b1:d7:81:ee:a8:26:95:bc:88:af:
+ 4c:35:07:2a:02:ca:78:14:6d:47:2b:40:56:e9:cb:2a:60:a1:
+ 67:03:a0:ce:8c:bc:b0:72:67:c4:31:ce:db:34:e5:25:03:60:
+ 25:7b:71:98:e4:c0:1b:2b:5f:74:42:d2:4b:c5:59:08:07:87:
+ be:c5:c3:7f:e7:96:d9:e1:dc:28:97:d6:8f:05:e3:f5:9b:4e:
+ ca:1d:50:47:05:53:b0:ca:39:e7:85:a0:89:c1:05:3b:01:37:
+ d3:3f:49:e2:77:eb:23:c8:88:66:3b:3d:39:76:21:46:f1:ec:
+ 5f:23:b8:eb:a2:66:75:74:c1:40:f7:d8:68:9a:93:e2:2d:a9:
+ 2e:bd:1c:a3:1e:c8:74:c6:a4:2d:7a:20:ab:3b:b8:b0:46:fd:
+ 6f:dd:5f:52:55:75:62:f0:97:a0:7c:d7:38:fd:25:df:cd:a0:
+ 9b:10:cf:8b:b8:38:5e:5e:c5:b4:a6:02:36:a1:1e:5f:1c:cf:
+ e2:96:9d:29:aa:fd:98:ae:52:e1:f3:41:52:fb:a9:2e:72:96:
+ 9f:27:e3:aa:73:7d:f8:1a:23:66:7b:3b:ab:65:b0:32:01:4b:
+ 15:3e:3d:a2:4f:0c:2b:35:a2:c6:d9:67:12:35:30:cd:76:2e:
+ 16:b3:99:9e:4d:4f:4e:2d:3b:34:43:e1:9a:0e:0d:a4:66:97:
+ ba:d2:1c:4a:4c:2c:2a:8b:8b:81:4f:71:1a:a9:dd:5c:7b:7b:
+ 08:c5:00:0d:37:40:e3:7c:7b:54:5f:2f:85:5f:76:f6:f7:a7:
+ b0:1c:57:56:c1:72:e8:ad:a2:af:8d:33:49:ba:1f:8a:dc:e6:
+ 74:7c:60:86:6f:87:97:7b
+SHA1 Fingerprint=84:1A:69:FB:F5:CD:1A:25:34:13:3D:E3:F8:FC:B8:99:D0:C9:14:B7
diff --git a/apex/ca-certificates/files/9aef356c.0 b/apex/ca-certificates/files/9aef356c.0
new file mode 100644
index 0000000..dc3acda
--- /dev/null
+++ b/apex/ca-certificates/files/9aef356c.0
@@ -0,0 +1,57 @@
+-----BEGIN CERTIFICATE-----
+MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD
+VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf
+BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3
+YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x
+NzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYDVQQGEwJVUzERMA8G
+A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0
+d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF
+Q0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuB
+BAAiA2IABGvaDXU1CDFHBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJ
+j9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr/TklZvFe/oyujUF5nQlgziip04pt89ZF
+1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0G
+A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3
+AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC
+MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu
+Sw==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 08:bd:85:97:6c:99:27:a4:80:68:47:3b
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=US, ST=Illinois, L=Chicago, O=Trustwave Holdings, Inc., CN=Trustwave Global ECC P384 Certification Authority
+ Validity
+ Not Before: Aug 23 19:36:43 2017 GMT
+ Not After : Aug 23 19:36:43 2042 GMT
+ Subject: C=US, ST=Illinois, L=Chicago, O=Trustwave Holdings, Inc., CN=Trustwave Global ECC P384 Certification Authority
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:6b:da:0d:75:35:08:31:47:05:ae:45:99:55:f1:
+ 11:13:2e:4a:f8:10:31:23:a3:7e:83:d3:7f:28:08:
+ 3a:26:1a:3a:cf:97:82:1f:80:b7:27:09:8f:d1:8e:
+ 30:c4:0a:9b:0e:ac:58:04:ab:f7:36:7d:94:23:a4:
+ 9b:0a:8a:8b:ab:eb:fd:39:25:66:f1:5e:fe:8c:ae:
+ 8d:41:79:9d:09:60:ce:28:a9:d3:8a:6d:f3:d6:45:
+ d4:f2:98:84:38:65:a0
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 55:A9:84:89:D2:C1:32:BD:18:CB:6C:A6:07:4E:C8:E7:9D:BE:82:90
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:64:02:30:37:01:92:97:45:12:7e:a0:f3:3e:ad:19:3a:72:
+ dd:f4:50:93:03:12:be:44:d2:4f:41:a4:8c:9c:9d:1f:a3:f6:
+ c2:92:e7:48:14:fe:4e:9b:a5:91:57:ae:c6:37:72:bb:02:30:
+ 67:25:0a:b1:0c:5e:ee:a9:63:92:6f:e5:90:0b:fe:66:22:ca:
+ 47:fd:8a:31:f7:83:fe:7a:bf:10:be:18:2b:1e:8f:f6:29:1e:
+ 94:59:ef:8e:21:37:cb:51:98:a5:6e:4b
+SHA1 Fingerprint=E7:F3:A3:C8:CF:6F:C3:04:2E:6D:0E:67:32:C5:9E:68:95:0D:5E:D2
diff --git a/apex/ca-certificates/files/9d6523ce.0 b/apex/ca-certificates/files/9d6523ce.0
new file mode 100644
index 0000000..d3d4306
--- /dev/null
+++ b/apex/ca-certificates/files/9d6523ce.0
@@ -0,0 +1,124 @@
+-----BEGIN CERTIFICATE-----
+MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe
+MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0
+ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
+Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw
+IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL
+SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH
+SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh
+ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X
+DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1
+TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ
+fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA
+sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU
+WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS
+nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH
+dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip
+NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC
+AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF
+MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH
+ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB
+uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl
+PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP
+JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/
+gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2
+j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6
+5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB
+o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS
+/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z
+Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE
+W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D
+hNQ+IIX3Sj0rnP0qCglN6oH4EZw=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 15:c8:bd:65:47:5c:af:b8:97:00:5e:e4:06:d2:bc:9d
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=TW, O=Chunghwa Telecom Co., Ltd., OU=ePKI Root Certification Authority
+ Validity
+ Not Before: Dec 20 02:31:27 2004 GMT
+ Not After : Dec 20 02:31:27 2034 GMT
+ Subject: C=TW, O=Chunghwa Telecom Co., Ltd., OU=ePKI Root Certification Authority
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:e1:25:0f:ee:8d:db:88:33:75:67:cd:ad:1f:7d:
+ 3a:4e:6d:9d:d3:2f:14:f3:63:74:cb:01:21:6a:37:
+ ea:84:50:07:4b:26:5b:09:43:6c:21:9e:6a:c8:d5:
+ 03:f5:60:69:8f:cc:f0:22:e4:1f:e7:f7:6a:22:31:
+ b7:2c:15:f2:e0:fe:00:6a:43:ff:87:65:c6:b5:1a:
+ c1:a7:4c:6d:22:70:21:8a:31:f2:97:74:89:09:12:
+ 26:1c:9e:ca:d9:12:a2:95:3c:da:e9:67:bf:08:a0:
+ 64:e3:d6:42:b7:45:ef:97:f4:f6:f5:d7:b5:4a:15:
+ 02:58:7d:98:58:4b:60:bc:cd:d7:0d:9a:13:33:53:
+ d1:61:f9:7a:d5:d7:78:b3:9a:33:f7:00:86:ce:1d:
+ 4d:94:38:af:a8:ec:78:51:70:8a:5c:10:83:51:21:
+ f7:11:3d:34:86:5e:e5:48:cd:97:81:82:35:4c:19:
+ ec:65:f6:6b:c5:05:a1:ee:47:13:d6:b3:21:27:94:
+ 10:0a:d9:24:3b:ba:be:44:13:46:30:3f:97:3c:d8:
+ d7:d7:6a:ee:3b:38:e3:2b:d4:97:0e:b9:1b:e7:07:
+ 49:7f:37:2a:f9:77:78:cf:54:ed:5b:46:9d:a3:80:
+ 0e:91:43:c1:d6:5b:5f:14:ba:9f:a6:8d:24:47:40:
+ 59:bf:72:38:b2:36:6c:37:ff:99:d1:5d:0e:59:0a:
+ ab:69:f7:c0:b2:04:45:7a:54:00:ae:be:53:f6:b5:
+ e7:e1:f8:3c:a3:31:d2:a9:fe:21:52:64:c5:a6:67:
+ f0:75:07:06:94:14:81:55:c6:27:e4:01:8f:17:c1:
+ 6a:71:d7:be:4b:fb:94:58:7d:7e:11:33:b1:42:f7:
+ 62:6c:18:d6:cf:09:68:3e:7f:6c:f6:1e:8f:62:ad:
+ a5:63:db:09:a7:1f:22:42:41:1e:6f:99:8a:3e:d7:
+ f9:3f:40:7a:79:b0:a5:01:92:d2:9d:3d:08:15:a5:
+ 10:01:2d:b3:32:76:a8:95:0d:b3:7a:9a:fb:07:10:
+ 78:11:6f:e1:8f:c7:ba:0f:25:1a:74:2a:e5:1c:98:
+ 41:99:df:21:87:e8:95:06:6a:0a:b3:6a:47:76:65:
+ f6:3a:cf:8f:62:17:19:7b:0a:28:cd:1a:d2:83:1e:
+ 21:c7:2c:bf:be:ff:61:68:b7:67:1b:bb:78:4d:8d:
+ ce:67:e5:e4:c1:8e:b7:23:66:e2:9d:90:75:34:98:
+ a9:36:2b:8a:9a:94:b9:9d:ec:cc:8a:b1:f8:25:89:
+ 5c:5a:b6:2f:8c:1f:6d:79:24:a7:52:68:c3:84:35:
+ e2:66:8d:63:0e:25:4d:d5:19:b2:e6:79:37:a7:22:
+ 9d:54:31
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 1E:0C:F7:B6:67:F2:E1:92:26:09:45:C0:55:39:2E:77:3F:42:4A:A2
+ X509v3 Basic Constraints:
+ CA:TRUE
+ setCext-hashedRoot:
+ 0/0-...0...+......0...g*.....E...
+V|.[x....S.....
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 09:b3:83:53:59:01:3e:95:49:b9:f1:81:ba:f9:76:20:23:b5:
+ 27:60:74:d4:6a:99:34:5e:6c:00:53:d9:9f:f2:a6:b1:24:07:
+ 44:6a:2a:c6:a5:8e:78:12:e8:47:d9:58:1b:13:2a:5e:79:9b:
+ 9f:0a:2a:67:a6:25:3f:06:69:56:73:c3:8a:66:48:fb:29:81:
+ 57:74:06:ca:9c:ea:28:e8:38:67:26:2b:f1:d5:b5:3f:65:93:
+ f8:36:5d:8e:8d:8d:40:20:87:19:ea:ef:27:c0:3d:b4:39:0f:
+ 25:7b:68:50:74:55:9c:0c:59:7d:5a:3d:41:94:25:52:08:e0:
+ 47:2c:15:31:19:d5:bf:07:55:c6:bb:12:b5:97:f4:5f:83:85:
+ ba:71:c1:d9:6c:81:11:76:0a:0a:b0:bf:82:97:f7:ea:3d:fa:
+ fa:ec:2d:a9:28:94:3b:56:dd:d2:51:2e:ae:c0:bd:08:15:8c:
+ 77:52:34:96:d6:9b:ac:d3:1d:8e:61:0f:35:7b:9b:ae:39:69:
+ 0b:62:60:40:20:36:8f:af:fb:36:ee:2d:08:4a:1d:b8:bf:9b:
+ 5c:f8:ea:a5:1b:a0:73:a6:d8:f8:6e:e0:33:04:5f:68:aa:27:
+ 87:ed:d9:c1:90:9c:ed:bd:e3:6a:35:af:63:df:ab:18:d9:ba:
+ e6:e9:4a:ea:50:8a:0f:61:93:1e:e2:2d:19:e2:30:94:35:92:
+ 5d:0e:b6:07:af:19:80:8f:47:90:51:4b:2e:4d:dd:85:e2:d2:
+ 0a:52:0a:17:9a:fc:1a:b0:50:02:e5:01:a3:63:37:21:4c:44:
+ c4:9b:51:99:11:0e:73:9c:06:8f:54:2e:a7:28:5e:44:39:87:
+ 56:2d:37:bd:85:44:94:e1:0c:4b:2c:9c:c3:92:85:34:61:cb:
+ 0f:b8:9b:4a:43:52:fe:34:3a:7d:b8:e9:29:dc:76:a9:c8:30:
+ f8:14:71:80:c6:1e:36:48:74:22:41:5c:87:82:e8:18:71:8b:
+ 41:89:44:e7:7e:58:5b:a8:b8:8d:13:e9:a7:6c:c3:47:ed:b3:
+ 1a:9d:62:ae:8d:82:ea:94:9e:dd:59:10:c3:ad:dd:e2:4d:e3:
+ 31:d5:c7:ec:e8:f2:b0:fe:92:1e:16:0a:1a:fc:d9:f3:f8:27:
+ b6:c9:be:1d:b4:6c:64:90:7f:f4:e4:c4:5b:d7:37:ae:42:0e:
+ dd:a4:1a:6f:7c:88:54:c5:16:6e:e1:7a:68:2e:f8:3a:bf:0d:
+ a4:3c:89:3b:78:a7:4e:63:83:04:21:08:67:8d:f2:82:49:d0:
+ 5b:fd:b1:cd:0f:83:84:d4:3e:20:85:f7:4a:3d:2b:9c:fd:2a:
+ 0a:09:4d:ea:81:f8:11:9c
+SHA1 Fingerprint=67:65:0D:F1:7E:8E:7E:5B:82:40:A4:F4:56:4B:CF:E2:3D:69:C6:F0
diff --git a/apex/ca-certificates/files/a2c66da8.0 b/apex/ca-certificates/files/a2c66da8.0
new file mode 100644
index 0000000..8a5076f
--- /dev/null
+++ b/apex/ca-certificates/files/a2c66da8.0
@@ -0,0 +1,122 @@
+-----BEGIN CERTIFICATE-----
+MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg
+RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV
+UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu
+Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG
+SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y
+ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If
+xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV
+ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO
+DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ
+jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/
+CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi
+EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM
+fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY
+uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK
+chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t
+9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
+hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD
+ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2
+SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd
++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc
+fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa
+sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N
+cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N
+0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie
+4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI
+r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1
+/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm
+gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 05:9b:1b:57:9e:8e:21:32:e2:39:07:bd:a7:77:75:5c
+ Signature Algorithm: sha384WithRSAEncryption
+ Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Trusted Root G4
+ Validity
+ Not Before: Aug 1 12:00:00 2013 GMT
+ Not After : Jan 15 12:00:00 2038 GMT
+ Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Trusted Root G4
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:bf:e6:90:73:68:de:bb:e4:5d:4a:3c:30:22:30:
+ 69:33:ec:c2:a7:25:2e:c9:21:3d:f2:8a:d8:59:c2:
+ e1:29:a7:3d:58:ab:76:9a:cd:ae:7b:1b:84:0d:c4:
+ 30:1f:f3:1b:a4:38:16:eb:56:c6:97:6d:1d:ab:b2:
+ 79:f2:ca:11:d2:e4:5f:d6:05:3c:52:0f:52:1f:c6:
+ 9e:15:a5:7e:be:9f:a9:57:16:59:55:72:af:68:93:
+ 70:c2:b2:ba:75:99:6a:73:32:94:d1:10:44:10:2e:
+ df:82:f3:07:84:e6:74:3b:6d:71:e2:2d:0c:1b:ee:
+ 20:d5:c9:20:1d:63:29:2d:ce:ec:5e:4e:c8:93:f8:
+ 21:61:9b:34:eb:05:c6:5e:ec:5b:1a:bc:eb:c9:cf:
+ cd:ac:34:40:5f:b1:7a:66:ee:77:c8:48:a8:66:57:
+ 57:9f:54:58:8e:0c:2b:b7:4f:a7:30:d9:56:ee:ca:
+ 7b:5d:e3:ad:c9:4f:5e:e5:35:e7:31:cb:da:93:5e:
+ dc:8e:8f:80:da:b6:91:98:40:90:79:c3:78:c7:b6:
+ b1:c4:b5:6a:18:38:03:10:8d:d8:d4:37:a4:2e:05:
+ 7d:88:f5:82:3e:10:91:70:ab:55:82:41:32:d7:db:
+ 04:73:2a:6e:91:01:7c:21:4c:d4:bc:ae:1b:03:75:
+ 5d:78:66:d9:3a:31:44:9a:33:40:bf:08:d7:5a:49:
+ a4:c2:e6:a9:a0:67:dd:a4:27:bc:a1:4f:39:b5:11:
+ 58:17:f7:24:5c:46:8f:64:f7:c1:69:88:76:98:76:
+ 3d:59:5d:42:76:87:89:97:69:7a:48:f0:e0:a2:12:
+ 1b:66:9a:74:ca:de:4b:1e:e7:0e:63:ae:e6:d4:ef:
+ 92:92:3a:9e:3d:dc:00:e4:45:25:89:b6:9a:44:19:
+ 2b:7e:c0:94:b4:d2:61:6d:eb:33:d9:c5:df:4b:04:
+ 00:cc:7d:1c:95:c3:8f:f7:21:b2:b2:11:b7:bb:7f:
+ f2:d5:8c:70:2c:41:60:aa:b1:63:18:44:95:1a:76:
+ 62:7e:f6:80:b0:fb:e8:64:a6:33:d1:89:07:e1:bd:
+ b7:e6:43:a4:18:b8:a6:77:01:e1:0f:94:0c:21:1d:
+ b2:54:29:25:89:6c:e5:0e:52:51:47:74:be:26:ac:
+ b6:41:75:de:7a:ac:5f:8d:3f:c9:bc:d3:41:11:12:
+ 5b:e5:10:50:eb:31:c5:ca:72:16:22:09:df:7c:4c:
+ 75:3f:63:ec:21:5f:c4:20:51:6b:6f:b1:ab:86:8b:
+ 4f:c2:d6:45:5f:9d:20:fc:a1:1e:c5:c0:8f:a2:b1:
+ 7e:0a:26:99:f5:e4:69:2f:98:1d:2d:f5:d9:a9:b2:
+ 1d:e5:1b
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ EC:D7:E3:82:D2:71:5D:64:4C:DF:2E:67:3F:E7:BA:98:AE:1C:0F:4F
+ Signature Algorithm: sha384WithRSAEncryption
+ Signature Value:
+ bb:61:d9:7d:a9:6c:be:17:c4:91:1b:c3:a1:a2:00:8d:e3:64:
+ 68:0f:56:cf:77:ae:70:f9:fd:9a:4a:99:b9:c9:78:5c:0c:0c:
+ 5f:e4:e6:14:29:56:0b:36:49:5d:44:63:e0:ad:9c:96:18:66:
+ 1b:23:0d:3d:79:e9:6d:6b:d6:54:f8:d2:3c:c1:43:40:ae:1d:
+ 50:f5:52:fc:90:3b:bb:98:99:69:6b:c7:c1:a7:a8:68:a4:27:
+ dc:9d:f9:27:ae:30:85:b9:f6:67:4d:3a:3e:8f:59:39:22:53:
+ 44:eb:c8:5d:03:ca:ed:50:7a:7d:62:21:0a:80:c8:73:66:d1:
+ a0:05:60:5f:e8:a5:b4:a7:af:a8:f7:6d:35:9c:7c:5a:8a:d6:
+ a2:38:99:f3:78:8b:f4:4d:d2:20:0b:de:04:ee:8c:9b:47:81:
+ 72:0d:c0:14:32:ef:30:59:2e:ae:e0:71:f2:56:e4:6a:97:6f:
+ 92:50:6d:96:8d:68:7a:9a:b2:36:14:7a:06:f2:24:b9:09:11:
+ 50:d7:08:b1:b8:89:7a:84:23:61:42:29:e5:a3:cd:a2:20:41:
+ d7:d1:9c:64:d9:ea:26:a1:8b:14:d7:4c:19:b2:50:41:71:3d:
+ 3f:4d:70:23:86:0c:4a:dc:81:d2:cc:32:94:84:0d:08:09:97:
+ 1c:4f:c0:ee:6b:20:74:30:d2:e0:39:34:10:85:21:15:01:08:
+ e8:55:32:de:71:49:d9:28:17:50:4d:e6:be:4d:d1:75:ac:d0:
+ ca:fb:41:b8:43:a5:aa:d3:c3:05:44:4f:2c:36:9b:e2:fa:e2:
+ 45:b8:23:53:6c:06:6f:67:55:7f:46:b5:4c:3f:6e:28:5a:79:
+ 26:d2:a4:a8:62:97:d2:1e:e2:ed:4a:8b:bc:1b:fd:47:4a:0d:
+ df:67:66:7e:b2:5b:41:d0:3b:e4:f4:3b:f4:04:63:e9:ef:c2:
+ 54:00:51:a0:8a:2a:c9:ce:78:cc:d5:ea:87:04:18:b3:ce:af:
+ 49:88:af:f3:92:99:b6:b3:e6:61:0f:d2:85:00:e7:50:1a:e4:
+ 1b:95:9d:19:a1:b9:9c:b1:9b:b1:00:1e:ef:d0:0f:4f:42:6c:
+ c9:0a:bc:ee:43:fa:3a:71:a5:c8:4d:26:a5:35:fd:89:5d:bc:
+ 85:62:1d:32:d2:a0:2b:54:ed:9a:57:c1:db:fa:10:cf:19:b7:
+ 8b:4a:1b:8f:01:b6:27:95:53:e8:b6:89:6d:5b:bc:68:d4:23:
+ e8:8b:51:a2:56:f9:f0:a6:80:a0:d6:1e:b3:bc:0f:0f:53:75:
+ 29:aa:ea:13:77:e4:de:8c:81:21:ad:07:10:47:11:ad:87:3d:
+ 07:d1:75:bc:cf:f3:66:7e
+SHA1 Fingerprint=DD:FB:16:CD:49:31:C9:73:A2:03:7D:3F:C8:3A:4D:7D:77:5D:05:E4
diff --git a/apex/ca-certificates/files/a3896b44.0 b/apex/ca-certificates/files/a3896b44.0
new file mode 100644
index 0000000..91c59d0
--- /dev/null
+++ b/apex/ca-certificates/files/a3896b44.0
@@ -0,0 +1,78 @@
+-----BEGIN CERTIFICATE-----
+MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY
+MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t
+dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5
+WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD
+VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8
+9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ
+DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9
+Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N
+QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ
+xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G
+A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T
+AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG
+kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr
+Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5
+Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU
+JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot
+RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 0 (0x0)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=JP, O=SECOM Trust.net, OU=Security Communication RootCA1
+ Validity
+ Not Before: Sep 30 04:20:49 2003 GMT
+ Not After : Sep 30 04:20:49 2023 GMT
+ Subject: C=JP, O=SECOM Trust.net, OU=Security Communication RootCA1
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b3:b3:fe:7f:d3:6d:b1:ef:16:7c:57:a5:0c:6d:
+ 76:8a:2f:4b:bf:64:fb:4c:ee:8a:f0:f3:29:7c:f5:
+ ff:ee:2a:e0:e9:e9:ba:5b:64:22:9a:9a:6f:2c:3a:
+ 26:69:51:05:99:26:dc:d5:1c:6a:71:c6:9a:7d:1e:
+ 9d:dd:7c:6c:c6:8c:67:67:4a:3e:f8:71:b0:19:27:
+ a9:09:0c:a6:95:bf:4b:8c:0c:fa:55:98:3b:d8:e8:
+ 22:a1:4b:71:38:79:ac:97:92:69:b3:89:7e:ea:21:
+ 68:06:98:14:96:87:d2:61:36:bc:6d:27:56:9e:57:
+ ee:c0:c0:56:fd:32:cf:a4:d9:8e:c2:23:d7:8d:a8:
+ f3:d8:25:ac:97:e4:70:38:f4:b6:3a:b4:9d:3b:97:
+ 26:43:a3:a1:bc:49:59:72:4c:23:30:87:01:58:f6:
+ 4e:be:1c:68:56:66:af:cd:41:5d:c8:b3:4d:2a:55:
+ 46:ab:1f:da:1e:e2:40:3d:db:cd:7d:b9:92:80:9c:
+ 37:dd:0c:96:64:9d:dc:22:f7:64:8b:df:61:de:15:
+ 94:52:15:a0:7d:52:c9:4b:a8:21:c9:c6:b1:ed:cb:
+ c3:95:60:d1:0f:f0:ab:70:f8:df:cb:4d:7e:ec:d6:
+ fa:ab:d9:bd:7f:54:f2:a5:e9:79:fa:d9:d6:76:24:
+ 28:73
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ A0:73:49:99:68:DC:85:5B:65:E3:9B:28:2F:57:9F:BD:33:BC:07:48
+ X509v3 Key Usage:
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 68:40:a9:a8:bb:e4:4f:5d:79:b3:05:b5:17:b3:60:13:eb:c6:
+ 92:5d:e0:d1:d3:6a:fe:fb:be:9b:6d:bf:c7:05:6d:59:20:c4:
+ 1c:f0:b7:da:84:58:02:63:fa:48:16:ef:4f:a5:0b:f7:4a:98:
+ f2:3f:9e:1b:ad:47:6b:63:ce:08:47:eb:52:3f:78:9c:af:4d:
+ ae:f8:d5:4f:cf:9a:98:2a:10:41:39:52:c4:dd:d9:9b:0e:ef:
+ 93:01:ae:b2:2e:ca:68:42:24:42:6c:b0:b3:3a:3e:cd:e9:da:
+ 48:c4:15:cb:e9:f9:07:0f:92:50:49:8a:dd:31:97:5f:c9:e9:
+ 37:aa:3b:59:65:97:94:32:c9:b3:9f:3e:3a:62:58:c5:49:ad:
+ 62:0e:71:a5:32:aa:2f:c6:89:76:43:40:13:13:67:3d:a2:54:
+ 25:10:cb:f1:3a:f2:d9:fa:db:49:56:bb:a6:fe:a7:41:35:c3:
+ e0:88:61:c9:88:c7:df:36:10:22:98:59:ea:b0:4a:fb:56:16:
+ 73:6e:ac:4d:f7:22:a1:4f:ad:1d:7a:2d:45:27:e5:30:c1:5e:
+ f2:da:13:cb:25:42:51:95:47:03:8c:6c:21:cc:74:42:ed:53:
+ ff:33:8b:8f:0f:57:01:16:2f:cf:a6:ee:c9:70:22:14:bd:fd:
+ be:6c:0b:03
+SHA1 Fingerprint=36:B1:2B:49:F9:81:9E:D7:4C:9E:BC:38:0F:C6:56:8F:5D:AC:B2:F7
diff --git a/apex/ca-certificates/files/a716d4ed.0 b/apex/ca-certificates/files/a716d4ed.0
new file mode 100644
index 0000000..6e1427d
--- /dev/null
+++ b/apex/ca-certificates/files/a716d4ed.0
@@ -0,0 +1,63 @@
+-----BEGIN CERTIFICATE-----
+MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQsw
+CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS
+VVNUIEVWIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5
+NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG
+A1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB
+BAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8ZRCC
+/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rD
+wpdhQntJraOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3
+OqQo5FD4pPfsazK2/umLMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g
+PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2V2X3Jvb3Rf
+Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l
+dC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1
+c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO
+PQQDAwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CA
+y/m0sRtW9XLS/BnRAjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJb
+gfM0agPnIjhQW+0ZT0MW
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 5f:02:41:d7:7a:87:7c:4c:03:a3:ac:96:8d:fb:ff:d0
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=DE, O=D-Trust GmbH, CN=D-TRUST EV Root CA 1 2020
+ Validity
+ Not Before: Feb 11 10:00:00 2020 GMT
+ Not After : Feb 11 09:59:59 2035 GMT
+ Subject: C=DE, O=D-Trust GmbH, CN=D-TRUST EV Root CA 1 2020
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:f1:0b:dd:86:43:20:19:df:97:85:e8:22:4a:9b:
+ cf:9d:98:bf:b4:05:26:c9:cb:e3:a6:d2:8f:c5:9e:
+ 78:7b:31:89:a9:89:ad:27:3c:65:10:82:fc:df:c3:
+ 9d:4e:f0:33:23:c4:d2:32:f5:1c:b0:df:33:17:5d:
+ c5:f0:b1:8a:f9:ef:b9:b7:14:ca:29:4a:c2:0f:a9:
+ 7f:75:65:49:2a:30:67:f4:64:f7:d6:1a:77:da:c3:
+ c2:97:61:42:7b:49:ad
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 7F:10:01:16:37:3A:A4:28:E4:50:F8:A4:F7:EC:6B:32:B6:FE:E9:8B
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 CRL Distribution Points:
+ Full Name:
+ URI:http://crl.d-trust.net/crl/d-trust_ev_root_ca_1_2020.crl
+ Full Name:
+ URI:ldap://directory.d-trust.net/CN=D-TRUST%20EV%20Root%20CA%201%202020,O=D-Trust%20GmbH,C=DE?certificaterevocationlist
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:66:02:31:00:ca:3c:c6:2a:75:c2:5e:75:62:39:36:00:60:
+ 5a:8b:c1:93:99:cc:d9:db:41:3b:3b:87:99:17:3b:d5:cc:4f:
+ ca:22:f7:a0:80:cb:f9:b4:b1:1b:56:f5:72:d2:fc:19:d1:02:
+ 31:00:91:f7:30:93:3f:10:46:2b:71:a4:d0:3b:44:9b:c0:29:
+ 02:05:b2:41:77:51:f3:79:5a:9e:8e:14:a0:4e:42:d2:5b:81:
+ f3:34:6a:03:e7:22:38:50:5b:ed:19:4f:43:16
+SHA1 Fingerprint=61:DB:8C:21:59:69:03:90:D8:7C:9C:12:86:54:CF:9D:3D:F4:DD:07
diff --git a/apex/ca-certificates/files/a81e292b.0 b/apex/ca-certificates/files/a81e292b.0
new file mode 100644
index 0000000..5783f06
--- /dev/null
+++ b/apex/ca-certificates/files/a81e292b.0
@@ -0,0 +1,80 @@
+-----BEGIN CERTIFICATE-----
+MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL
+BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6
+ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw
+NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L
+cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg
+Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN
+QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT
+3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw
+3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6
+3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5
+BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN
+XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
+AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF
+AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw
+8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG
+nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP
+oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy
+d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg
+LvWpCz/UXeHPhJ/iGcJfitYgHuNztw==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 3e:8a:5d:07:ec:55:d2:32:d5:b7:e3:b6:5f:01:eb:2d:dc:e4:d6:e4
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=PL, O=Krajowa Izba Rozliczeniowa S.A., CN=SZAFIR ROOT CA2
+ Validity
+ Not Before: Oct 19 07:43:30 2015 GMT
+ Not After : Oct 19 07:43:30 2035 GMT
+ Subject: C=PL, O=Krajowa Izba Rozliczeniowa S.A., CN=SZAFIR ROOT CA2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b7:bc:3e:50:a8:4b:cd:40:b5:ce:61:e7:96:ca:
+ b4:a1:da:0c:22:b0:fa:b5:7b:76:00:77:8c:0b:cf:
+ 7d:a8:86:cc:26:51:e4:20:3d:85:0c:d6:58:e3:e7:
+ f4:2a:18:9d:da:d1:ae:26:ee:eb:53:dc:f4:90:d6:
+ 13:4a:0c:90:3c:c3:f4:da:d2:8e:0d:92:3a:dc:b1:
+ b1:ff:38:de:c3:ba:2d:5f:80:b9:02:bd:4a:9d:1b:
+ 0f:b4:c3:c2:c1:67:03:dd:dc:1b:9c:3d:b3:b0:de:
+ 00:1e:a8:34:47:bb:9a:eb:fe:0b:14:bd:36:84:da:
+ 0d:20:bf:fa:5b:cb:a9:16:20:ad:39:60:ee:2f:75:
+ b6:e7:97:9c:f9:3e:fd:7e:4d:6f:4d:2f:ef:88:0d:
+ 6a:fa:dd:f1:3d:6e:20:a5:a0:12:b4:4d:70:b9:ce:
+ d7:72:3b:89:93:a7:80:84:1c:27:49:72:49:b5:ff:
+ 3b:95:9e:c1:cc:c8:01:ec:e8:0e:8a:0a:96:e7:b3:
+ a6:87:e5:d6:f9:05:2b:0d:97:40:70:3c:ba:ac:75:
+ 5a:9c:d5:4d:9d:02:0a:d2:4b:9b:66:4b:46:07:17:
+ 65:ad:9f:6c:88:00:dc:22:89:e0:e1:64:d4:67:bc:
+ 31:79:61:3c:bb:ca:41:cd:5c:6a:00:c8:3c:38:8e:
+ 58:af
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 2E:16:A9:4A:18:B5:CB:CC:F5:6F:50:F3:23:5F:F8:5D:E7:AC:F0:C8
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ b5:73:f8:03:dc:59:5b:1d:76:e9:a3:2a:7b:90:28:b2:4d:c0:
+ 33:4f:aa:9a:b1:d4:b8:e4:27:ff:a9:96:99:ce:46:e0:6d:7c:
+ 4c:a2:38:a4:06:70:f0:f4:41:11:ec:3f:47:8d:3f:72:87:f9:
+ 3b:fd:a4:6f:2b:53:00:e0:ff:39:b9:6a:07:0e:eb:1d:1c:f6:
+ a2:72:90:cb:82:3d:11:82:8b:d2:bb:9f:2a:af:21:e6:63:86:
+ 9d:79:19:ef:f7:bb:0c:35:90:c3:8a:ed:4f:0f:f5:cc:12:d9:
+ a4:3e:bb:a0:fc:20:95:5f:4f:26:2f:11:23:83:4e:75:07:0f:
+ bf:9b:d1:b4:1d:e9:10:04:fe:ca:60:8f:a2:4c:b8:ad:cf:e1:
+ 90:0f:cd:ae:0a:c7:5d:7b:b7:50:d2:d4:61:fa:d5:15:db:d7:
+ 9f:87:51:54:eb:a5:e3:eb:c9:85:a0:25:20:37:fb:8e:ce:0c:
+ 34:84:e1:3c:81:b2:77:4e:43:a5:88:5f:86:67:a1:3d:e6:b4:
+ 5c:61:b6:3e:db:fe:b7:28:c5:a2:07:ae:b5:ca:ca:8d:2a:12:
+ ef:97:ed:c2:30:a4:c9:2a:7a:fb:f3:4d:23:1b:99:33:34:a0:
+ 2e:f5:a9:0b:3f:d4:5d:e1:cf:84:9f:e2:19:c2:5f:8a:d6:20:
+ 1e:e3:73:b7
+SHA1 Fingerprint=E2:52:FA:95:3F:ED:DB:24:60:BD:6E:28:F3:9C:CC:CF:5E:B3:3F:DE
diff --git a/apex/ca-certificates/files/a9d40e02.0 b/apex/ca-certificates/files/a9d40e02.0
new file mode 100644
index 0000000..8e71407
--- /dev/null
+++ b/apex/ca-certificates/files/a9d40e02.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV
+BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g
+Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ
+BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ
+R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF
+dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw
+vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ
+uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp
+n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs
+cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW
+xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P
+rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF
+DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx
+DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy
+LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C
+eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ
+d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq
+kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC
+b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl
+qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0
+OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c
+NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk
+ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO
+pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj
+03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk
+PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE
+1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX
+QRBdJ3NghVdJIgc=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 11:00:34:b6:4e:c6:36:2d:36
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=RO, O=CERTSIGN SA, OU=certSIGN ROOT CA G2
+ Validity
+ Not Before: Feb 6 09:27:35 2017 GMT
+ Not After : Feb 6 09:27:35 2042 GMT
+ Subject: C=RO, O=CERTSIGN SA, OU=certSIGN ROOT CA G2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:c0:c5:75:19:91:7d:44:74:74:87:fe:0e:3b:96:
+ dc:d8:01:16:cc:ee:63:91:e7:0b:6f:ce:3b:0a:69:
+ 1a:7c:c2:e3:af:82:8e:86:d7:5e:8f:57:eb:d3:21:
+ 59:fd:39:37:42:30:be:50:ea:b6:0f:a9:88:d8:2e:
+ 2d:69:21:e7:d1:37:18:4e:7d:91:d5:16:5f:6b:5b:
+ 00:c2:39:43:0d:36:85:52:b9:53:65:0f:1d:42:e5:
+ 8f:cf:05:d3:ee:dc:0c:1a:d9:b8:8b:78:22:67:e4:
+ 69:b0:68:c5:3c:e4:6c:5a:46:e7:cd:c7:fa:ef:c4:
+ ec:4b:bd:6a:a4:ac:fd:cc:28:51:ef:92:b4:29:ab:
+ ab:35:9a:4c:e4:c4:08:c6:26:cc:f8:69:9f:e4:9c:
+ f0:29:d3:5c:f9:c6:16:25:9e:23:c3:20:c1:3d:0f:
+ 3f:38:40:b0:fe:82:44:38:aa:5a:1a:8a:6b:63:58:
+ 38:b4:15:d3:b6:11:69:7b:1e:54:ee:8c:1a:22:ac:
+ 72:97:3f:23:59:9b:c9:22:84:c1:07:4f:cc:7f:e2:
+ 57:ca:12:70:bb:a6:65:f3:69:75:63:bd:95:fb:1b:
+ 97:cd:e4:a8:af:f6:d1:4e:a8:d9:8a:71:24:cd:36:
+ 3d:bc:96:c4:f1:6c:a9:ae:e5:cf:0d:6e:28:0d:b0:
+ 0e:b5:ca:51:7b:78:14:c3:20:2f:7f:fb:14:55:e1:
+ 11:99:fd:d5:0a:a1:9e:02:e3:62:5f:eb:35:4b:2c:
+ b8:72:e8:3e:3d:4f:ac:2c:bb:2e:86:e2:a3:76:8f:
+ e5:93:2a:cf:a5:ab:c8:5c:8d:4b:06:ff:12:46:ac:
+ 78:cb:14:07:35:e0:a9:df:8b:e9:af:15:4f:16:89:
+ 5b:bd:f6:8d:c6:59:ae:88:85:0e:c1:89:eb:1f:67:
+ c5:45:8e:ff:6d:37:36:2b:78:66:83:91:51:2b:3d:
+ ff:51:77:76:62:a1:ec:67:3e:3e:81:83:e0:56:a9:
+ 50:1f:1f:7a:99:ab:63:bf:84:17:77:f1:0d:3b:df:
+ f7:9c:61:b3:35:98:8a:3a:b2:ec:3c:1a:37:3f:7e:
+ 8f:92:cf:d9:12:14:64:da:10:02:15:41:ff:4f:c4:
+ eb:1c:a3:c9:fa:99:f7:46:e9:e1:18:d9:b1:b8:32:
+ 2d:cb:14:0c:50:d8:83:65:83:ee:b9:5c:cf:cb:05:
+ 5a:4c:fa:19:97:6b:d6:5d:13:d3:c2:5c:54:bc:32:
+ 73:a0:78:f5:f1:6d:1e:cb:9f:a5:a6:9f:22:dc:d1:
+ 51:9e:82:79:64:60:29:13:3e:a3:fd:4f:72:6a:ab:
+ e2:d4:e5:b8:24:55:2c:44:4b:8a:88:44:9c:ca:84:
+ d3:2a:3b
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 82:21:2D:66:C6:D7:A0:E0:15:EB:CE:4C:09:77:C4:60:9E:54:6E:03
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 60:de:1a:b8:e7:f2:60:82:d5:03:33:81:cb:06:8a:f1:22:49:
+ e9:e8:ea:91:7f:c6:33:5e:68:19:03:86:3b:43:01:cf:07:70:
+ e4:08:1e:65:85:91:e6:11:22:b7:f5:02:23:8e:ae:b9:1e:7d:
+ 1f:7e:6c:e6:bd:25:d5:95:1a:f2:05:a6:af:85:02:6f:ae:f8:
+ d6:31:ff:25:c9:4a:c8:c7:8a:a9:d9:9f:4b:49:9b:11:57:99:
+ 92:43:11:de:b6:33:a4:cc:d7:8d:64:7d:d4:cd:3c:28:2c:b4:
+ 9a:96:ea:4d:f5:c4:44:c4:25:aa:20:80:d8:29:55:f7:e0:41:
+ fc:06:26:ff:b9:36:f5:43:14:03:66:78:e1:11:b1:da:20:5f:
+ 46:00:78:00:21:a5:1e:00:28:61:78:6f:a8:01:01:8f:9d:34:
+ 9a:ff:f4:38:90:fb:b8:d1:b3:72:06:c9:71:e6:81:c5:79:ed:
+ 0b:a6:79:f2:13:0b:9c:f7:5d:0e:7b:24:93:b4:48:db:86:5f:
+ de:50:86:78:e7:40:e6:31:a8:90:76:70:61:af:9c:37:2c:11:
+ b5:82:b7:aa:ae:24:34:5b:72:0c:69:0d:cd:59:9f:f6:71:af:
+ 9c:0b:d1:0a:38:f9:06:22:83:53:25:0c:fc:51:c4:e6:be:e2:
+ 39:95:0b:24:ad:af:d1:95:e4:96:d7:74:64:6b:71:4e:02:3c:
+ aa:85:f3:20:a3:43:39:76:5b:6c:50:fe:9a:9c:14:1e:65:14:
+ 8a:15:bd:a3:82:45:5a:49:56:6a:d2:9c:b1:63:32:e5:61:e0:
+ 53:22:0e:a7:0a:49:ea:cb:7e:1f:a8:e2:62:80:f6:10:45:52:
+ 98:06:18:de:a5:cd:2f:7f:aa:d4:e9:3e:08:72:ec:23:03:02:
+ 3c:a6:aa:d8:bc:67:74:3d:14:17:fb:54:4b:17:e3:d3:79:3d:
+ 6d:6b:49:c9:28:0e:2e:74:50:bf:0c:d9:46:3a:10:86:c9:a7:
+ 3f:e9:a0:ec:7f:eb:a5:77:58:69:71:e6:83:0a:37:f2:86:49:
+ 6a:be:79:08:90:f6:02:16:64:3e:e5:da:4c:7e:0c:34:c9:f9:
+ 5f:b6:b3:28:51:a7:a7:2b:aa:49:fa:8d:65:29:4e:e3:6b:13:
+ a7:94:a3:2d:51:6d:78:0c:44:cb:df:de:08:6f:ce:a3:64:ab:
+ d3:95:84:d4:b9:52:54:72:7b:96:25:cc:bc:69:e3:48:6e:0d:
+ d0:c7:9d:27:9a:aa:f8:13:92:dd:1e:df:63:9f:35:a9:16:36:
+ ec:8c:b8:83:f4:3d:89:8f:cd:b4:17:5e:d7:b3:17:41:10:5d:
+ 27:73:60:85:57:49:22:07
+SHA1 Fingerprint=26:F9:93:B4:ED:3D:28:27:B0:B9:4B:A7:E9:15:1D:A3:8D:92:E5:32
diff --git a/apex/ca-certificates/files/ab5346f4.0 b/apex/ca-certificates/files/ab5346f4.0
new file mode 100644
index 0000000..faae901
--- /dev/null
+++ b/apex/ca-certificates/files/ab5346f4.0
@@ -0,0 +1,79 @@
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr
+MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG
+A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0
+MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp
+Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD
+QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz
+i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8
+h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV
+MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9
+UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni
+8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC
+h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB
+AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm
+KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ
+X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr
+QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5
+pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN
+QSdJQO7e5iNEOdyhIta6A/I=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA11
+ Validity
+ Not Before: Apr 8 04:56:47 2009 GMT
+ Not After : Apr 8 04:56:47 2029 GMT
+ Subject: C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA11
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:fd:77:aa:a5:1c:90:05:3b:cb:4c:9b:33:8b:5a:
+ 14:45:a4:e7:90:16:d1:df:57:d2:21:10:a4:17:fd:
+ df:ac:d6:1f:a7:e4:db:7c:f7:ec:df:b8:03:da:94:
+ 58:fd:5d:72:7c:8c:3f:5f:01:67:74:15:96:e3:02:
+ 3c:87:db:ae:cb:01:8e:c2:f3:66:c6:85:45:f4:02:
+ c6:3a:b5:62:b2:af:fa:9c:bf:a4:e6:d4:80:30:98:
+ f3:0d:b6:93:8f:a9:d4:d8:36:f2:b0:fc:8a:ca:2c:
+ a1:15:33:95:31:da:c0:1b:f2:ee:62:99:86:63:3f:
+ bf:dd:93:2a:83:a8:76:b9:13:1f:b7:ce:4e:42:85:
+ 8f:22:e7:2e:1a:f2:95:09:b2:05:b5:44:4e:77:a1:
+ 20:bd:a9:f2:4e:0a:7d:50:ad:f5:05:0d:45:4f:46:
+ 71:fd:28:3e:53:fb:04:d8:2d:d7:65:1d:4a:1b:fa:
+ cf:3b:b0:31:9a:35:6e:c8:8b:06:d3:00:91:f2:94:
+ 08:65:4c:b1:34:06:00:7a:89:e2:f0:c7:03:59:cf:
+ d5:d6:e8:a7:32:b3:e6:98:40:86:c5:cd:27:12:8b:
+ cc:7b:ce:b7:11:3c:62:60:07:23:3e:2b:40:6e:94:
+ 80:09:6d:b6:b3:6f:77:6f:35:08:50:fb:02:87:c5:
+ 3e:89
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 5B:F8:4D:4F:B2:A5:86:D4:3A:D2:F1:63:9A:A0:BE:09:F6:57:B7:DE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ a0:a1:38:16:66:2e:a7:56:1f:21:9c:06:fa:1d:ed:b9:22:c5:
+ 38:26:d8:4e:4f:ec:a3:7f:79:de:46:21:a1:87:77:8f:07:08:
+ 9a:b2:a4:c5:af:0f:32:98:0b:7c:66:29:b6:9b:7d:25:52:49:
+ 43:ab:4c:2e:2b:6e:7a:70:af:16:0e:e3:02:6c:fb:42:e6:18:
+ 9d:45:d8:55:c8:e8:3b:dd:e7:e1:f4:2e:0b:1c:34:5c:6c:58:
+ 4a:fb:8c:88:50:5f:95:1c:bf:ed:ab:22:b5:65:b3:85:ba:9e:
+ 0f:b8:ad:e5:7a:1b:8a:50:3a:1d:bd:0d:bc:7b:54:50:0b:b9:
+ 42:af:55:a0:18:81:ad:65:99:ef:be:e4:9c:bf:c4:85:ab:41:
+ b2:54:6f:dc:25:cd:ed:78:e2:8e:0c:8d:09:49:dd:63:7b:5a:
+ 69:96:02:21:a8:bd:52:59:e9:7d:35:cb:c8:52:ca:7f:81:fe:
+ d9:6b:d3:f7:11:ed:25:df:f8:e7:f9:a4:fa:72:97:84:53:0d:
+ a5:d0:32:18:51:76:59:14:6c:0f:eb:ec:5f:80:8c:75:43:83:
+ c3:85:98:ff:4c:9e:2d:0d:e4:77:83:93:4e:b5:96:07:8b:28:
+ 13:9b:8c:19:8d:41:27:49:40:ee:de:e6:23:44:39:dc:a1:22:
+ d6:ba:03:f2
+SHA1 Fingerprint=3B:C4:9F:48:F8:F3:73:A0:9C:1E:BD:F8:5B:B1:C3:65:C7:D8:11:B3
diff --git a/apex/ca-certificates/files/ab59055e.0 b/apex/ca-certificates/files/ab59055e.0
new file mode 100644
index 0000000..12f4fad
--- /dev/null
+++ b/apex/ca-certificates/files/ab59055e.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE
+BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ
+IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0
+MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV
+BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w
+HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj
+Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj
+TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u
+KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj
+qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm
+MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12
+ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP
+zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk
+L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC
+jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA
+HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC
+AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg
+p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm
+DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5
+COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry
+L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf
+JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg
+IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io
+2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV
+09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ
+XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq
+T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe
+MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 9009899650740120186 (0x7d0997fef047ea7a)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=CN, O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD., CN=GDCA TrustAUTH R5 ROOT
+ Validity
+ Not Before: Nov 26 05:13:15 2014 GMT
+ Not After : Dec 31 15:59:59 2040 GMT
+ Subject: C=CN, O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD., CN=GDCA TrustAUTH R5 ROOT
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:d9:a3:16:f0:c8:74:74:77:9b:ef:33:0d:3b:06:
+ 7e:55:fc:b5:60:8f:76:86:12:42:7d:56:66:3e:88:
+ 82:ed:72:63:0e:9e:8b:dd:34:2c:02:51:51:c3:19:
+ fd:59:54:84:c9:f1:6b:b3:4c:b0:e9:e8:46:5d:38:
+ c6:a2:a7:2e:11:57:ba:82:15:a2:9c:8f:6d:b0:99:
+ 4a:0a:f2:eb:89:70:63:4e:79:c4:b7:5b:bd:a2:5d:
+ b1:f2:41:02:2b:ad:a9:3a:a3:ec:79:0a:ec:5f:3a:
+ e3:fd:ef:80:3c:ad:34:9b:1a:ab:88:26:7b:56:a2:
+ 82:86:1f:eb:35:89:83:7f:5f:ae:29:4e:3d:b6:6e:
+ ec:ae:c1:f0:27:9b:ae:e3:f4:ec:ef:ae:7f:f7:86:
+ 3d:72:7a:eb:a5:fb:59:4e:a7:eb:95:8c:22:39:79:
+ e1:2d:08:8f:cc:bc:91:b8:41:f7:14:c1:23:a9:c3:
+ ad:9a:45:44:b3:b2:d7:2c:cd:c6:29:e2:50:10:ae:
+ 5c:cb:82:8e:17:18:36:7d:97:e6:88:9a:b0:4d:34:
+ 09:f4:2c:b9:5a:66:2a:b0:17:9b:9e:1e:76:9d:4a:
+ 66:31:41:df:3f:fb:c5:06:ef:1b:b6:7e:1a:46:36:
+ f7:64:63:3b:e3:39:18:23:e7:67:75:14:d5:75:57:
+ 92:37:bd:be:6a:1b:26:50:f2:36:26:06:90:c5:70:
+ 01:64:6d:76:66:e1:91:db:6e:07:c0:61:80:2e:b2:
+ 2e:2f:8c:70:a7:d1:3b:3c:b3:91:e4:6e:b6:c4:3b:
+ 70:f2:6c:92:97:09:cd:47:7d:18:c0:f3:bb:9e:0f:
+ d6:8b:ae:07:b6:5a:0f:ce:0b:0c:47:a7:e5:3e:b8:
+ bd:7d:c7:9b:35:a0:61:97:3a:41:75:17:cc:2b:96:
+ 77:2a:92:21:1e:d9:95:76:20:67:68:cf:0d:bd:df:
+ d6:1f:09:6a:9a:e2:cc:73:71:a4:2f:7d:12:80:b7:
+ 53:30:46:5e:4b:54:99:0f:67:c9:a5:c8:f2:20:c1:
+ 82:ec:9d:11:df:c2:02:fb:1a:3b:d1:ed:20:9a:ef:
+ 65:64:92:10:0d:2a:e2:de:70:f1:18:67:82:8c:61:
+ de:b8:bc:d1:2f:9c:fb:0f:d0:2b:ed:1b:76:b9:e4:
+ 39:55:f8:f8:a1:1d:b8:aa:80:00:4c:82:e7:b2:7f:
+ 09:b8:bc:30:a0:2f:0d:f5:52:9e:8e:f7:92:b3:0a:
+ 00:1d:00:54:97:06:e0:b1:07:d9:c7:0f:5c:65:7d:
+ 3c:6d:59:57:e4:ed:a5:8d:e9:40:53:9f:15:4b:a0:
+ 71:f6:1a:21:e3:da:70:06:21:58:14:87:85:77:79:
+ aa:82:79
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ E2:C9:40:9F:4D:CE:E8:9A:A1:7C:CF:0E:3F:65:C5:29:88:6A:19:51
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ d1:49:57:e0:a7:cc:68:58:ba:01:0f:2b:19:cd:8d:b0:61:45:
+ ac:11:ed:63:50:69:f8:1f:7f:be:16:8f:fd:9d:eb:0b:aa:32:
+ 47:76:d2:67:24:ed:bd:7c:33:32:97:2a:c7:05:86:66:0d:17:
+ 7d:14:15:1b:d4:eb:fd:1f:9a:f6:5e:97:69:b7:1a:25:a4:0a:
+ b3:91:3f:5f:36:ac:8b:ec:57:a8:3e:e7:81:8a:18:57:39:85:
+ 74:1a:42:c7:e9:5b:13:5f:8f:f9:08:e9:92:74:8d:f5:47:d2:
+ ab:3b:d6:fb:78:66:4e:36:7d:f9:e9:92:e9:04:de:fd:49:63:
+ fc:6d:fb:14:71:93:67:2f:47:4a:b7:b9:ff:1e:2a:73:70:46:
+ 30:bf:5a:f2:2f:79:a5:e1:8d:0c:d9:f9:b2:63:37:8c:37:65:
+ 85:70:6a:5c:5b:09:72:b9:ad:63:3c:b1:dd:f8:fc:32:bf:37:
+ 86:e4:bb:8e:98:27:7e:ba:1f:16:e1:70:11:f2:03:df:25:62:
+ 32:27:26:18:32:84:9f:ff:00:3a:13:ba:9a:4d:f4:4f:b8:14:
+ 70:22:b1:ca:2b:90:ce:29:c1:70:f4:2f:9d:7f:f2:90:1e:d6:
+ 5a:df:b7:46:fc:e6:86:fa:cb:e0:20:76:7a:ba:a6:cb:f5:7c:
+ de:62:a5:b1:8b:ee:de:82:66:8a:4e:3a:30:1f:3f:80:cb:ad:
+ 27:ba:0c:5e:d7:d0:b1:56:ca:77:71:b2:b5:75:a1:50:a9:40:
+ 43:17:c2:28:d9:cf:52:8b:5b:c8:63:d4:42:3e:a0:33:7a:46:
+ 2e:f7:0a:20:46:54:7e:6a:4f:31:f1:81:7e:42:74:38:65:73:
+ 27:ee:c6:7c:b8:8e:d7:a5:3a:d7:98:a1:9c:8c:10:55:d3:db:
+ 4b:ec:40:90:f2:cd:6e:57:d2:62:0e:7c:57:93:b1:a7:6d:cd:
+ 9d:83:bb:2a:e7:e5:b6:3b:71:58:ad:fd:d1:45:bc:5a:91:ee:
+ 53:15:6f:d3:45:09:75:6e:ba:90:5d:1e:04:cf:37:df:1e:a8:
+ 66:b1:8c:e6:20:6a:ef:fc:48:4e:74:98:42:af:29:6f:2e:6a:
+ c7:fb:7d:d1:66:31:22:cc:86:00:7e:66:83:0c:42:f4:bd:34:
+ 92:c3:1a:ea:4f:ca:7e:72:4d:0b:70:8c:a6:48:bb:a6:a1:14:
+ f6:fb:58:44:99:14:ae:aa:0b:93:69:a0:29:25:4a:a5:cb:2b:
+ dd:8a:66:07:16:78:15:57:71:1b:ec:f5:47:84:f3:9e:31:37:
+ 7a:d5:7f:24:ad:e4:bc:fd:fd:cc:6e:83:e8:0c:a8:b7:41:6c:
+ 07:dd:bd:3c:86:97:2f:d2
+SHA1 Fingerprint=0F:36:38:5B:81:1A:25:C3:9B:31:4E:83:CA:E9:34:66:70:CC:74:B4
diff --git a/apex/ca-certificates/files/b0ed035a.0 b/apex/ca-certificates/files/b0ed035a.0
new file mode 100644
index 0000000..180398f
--- /dev/null
+++ b/apex/ca-certificates/files/b0ed035a.0
@@ -0,0 +1,118 @@
+-----BEGIN CERTIFICATE-----
+MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx
+EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT
+VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5
+NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT
+B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG
+SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF
+10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz
+0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh
+MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH
+zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc
+46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2
+yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi
+laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP
+oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA
+BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE
+qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm
+4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
+/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL
+1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn
+LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF
+H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo
+RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+
+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh
+15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW
+6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW
+nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j
+wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz
+aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy
+KwbQBM0=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 3262 (0xcbe)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA Global Root CA
+ Validity
+ Not Before: Jun 27 06:28:33 2012 GMT
+ Not After : Dec 31 15:59:59 2030 GMT
+ Subject: C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA Global Root CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:b0:05:db:c8:eb:8c:c4:6e:8a:21:ef:8e:4d:9c:
+ 71:0a:1f:52:70:ed:6d:82:9c:97:c5:d7:4c:4e:45:
+ 49:cb:40:42:b5:12:34:6c:19:c2:74:a4:31:5f:85:
+ 02:97:ec:43:33:0a:53:d2:9c:8c:8e:b7:b8:79:db:
+ 2b:d5:6a:f2:8e:66:c4:ee:2b:01:07:92:d4:b3:d0:
+ 02:df:50:f6:55:af:66:0e:cb:e0:47:60:2f:2b:32:
+ 39:35:52:3a:28:83:f8:7b:16:c6:18:b8:62:d6:47:
+ 25:91:ce:f0:19:12:4d:ad:63:f5:d3:3f:75:5f:29:
+ f0:a1:30:1c:2a:a0:98:a6:15:bd:ee:fd:19:36:f0:
+ e2:91:43:8f:fa:ca:d6:10:27:49:4c:ef:dd:c1:f1:
+ 85:70:9b:ca:ea:a8:5a:43:fc:6d:86:6f:73:e9:37:
+ 45:a9:f0:36:c7:cc:88:75:1e:bb:6c:06:ff:9b:6b:
+ 3e:17:ec:61:aa:71:7c:c6:1d:a2:f7:49:e9:15:b5:
+ 3c:d6:a1:61:f5:11:f7:05:6f:1d:fd:11:be:d0:30:
+ 07:c2:29:b0:09:4e:26:dc:e3:a2:a8:91:6a:1f:c2:
+ 91:45:88:5c:e5:98:b8:71:a5:15:19:c9:7c:75:11:
+ cc:70:74:4f:2d:9b:1d:91:44:fd:56:28:a0:fe:bb:
+ 86:6a:c8:fa:5c:0b:58:dc:c6:4b:76:c8:ab:22:d9:
+ 73:0f:a5:f4:5a:02:89:3f:4f:9e:22:82:ee:a2:74:
+ 53:2a:3d:53:27:69:1d:6c:8e:32:2c:64:00:26:63:
+ 61:36:4e:a3:46:b7:3f:7d:b3:2d:ac:6d:90:a2:95:
+ a2:ce:cf:da:82:e7:07:34:19:96:e9:b8:21:aa:29:
+ 7e:a6:38:be:8e:29:4a:21:66:79:1f:b3:c3:b5:09:
+ 67:de:d6:d4:07:46:f3:2a:da:e6:22:37:60:cb:81:
+ b6:0f:a0:0f:e9:c8:95:7f:bf:55:91:05:7a:cf:3d:
+ 15:c0:6f:de:09:94:01:83:d7:34:1b:cc:40:a5:f0:
+ b8:9b:67:d5:98:91:3b:a7:84:78:95:26:a4:5a:08:
+ f8:2b:74:b4:00:04:3c:df:b8:14:8e:e8:df:a9:8d:
+ 6c:67:92:33:1d:c0:b7:d2:ec:92:c8:be:09:bf:2c:
+ 29:05:6f:02:6b:9e:ef:bc:bf:2a:bc:5b:c0:50:8f:
+ 41:70:71:87:b2:4d:b7:04:a9:84:a3:32:af:ae:ee:
+ 6b:17:8b:b2:b1:fe:6c:e1:90:8c:88:a8:97:48:ce:
+ c8:4d:cb:f3:06:cf:5f:6a:0a:42:b1:1e:1e:77:2f:
+ 8e:a0:e6:92:0e:06:fc:05:22:d2:26:e1:31:51:7d:
+ 32:dc:0f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 5f:34:81:76:ef:96:1d:d5:e5:b5:d9:02:63:84:16:c1:ae:a0:
+ 70:51:a7:f7:4c:47:35:c8:0b:d7:28:3d:89:71:d9:aa:33:41:
+ ea:14:1b:6c:21:00:c0:6c:42:19:7e:9f:69:5b:20:42:df:a2:
+ d2:da:c4:7c:97:4b:8d:b0:e8:ac:c8:ee:a5:69:04:99:0a:92:
+ a6:ab:27:2e:1a:4d:81:bf:84:d4:70:1e:ad:47:fe:fd:4a:9d:
+ 33:e0:f2:b9:c4:45:08:21:0a:da:69:69:73:72:0d:be:34:fe:
+ 94:8b:ad:c3:1e:35:d7:a2:83:ef:e5:38:c7:a5:85:1f:ab:cf:
+ 34:ec:3f:28:fe:0c:f1:57:86:4e:c9:55:f7:1c:d4:d8:a5:7d:
+ 06:7a:6f:d5:df:10:df:81:4e:21:65:b1:b6:e1:17:79:95:45:
+ 06:ce:5f:cc:dc:46:89:63:68:44:8d:93:f4:64:70:a0:3d:9d:
+ 28:05:c3:39:70:b8:62:7b:20:fd:e4:db:e9:08:a1:b8:9e:3d:
+ 09:c7:4f:fb:2c:f8:93:76:41:de:52:e0:e1:57:d2:9d:03:bc:
+ 77:9e:fe:9e:29:5e:f7:c1:51:60:1f:de:da:0b:b2:2d:75:b7:
+ 43:48:93:e7:f6:79:c6:84:5d:80:59:60:94:fc:78:98:8f:3c:
+ 93:51:ed:40:90:07:df:64:63:24:cb:4e:71:05:a1:d7:94:1a:
+ 88:32:f1:22:74:22:ae:a5:a6:d8:12:69:4c:60:a3:02:ee:2b:
+ ec:d4:63:92:0b:5e:be:2f:76:6b:a3:b6:26:bc:8f:03:d8:0a:
+ f2:4c:64:46:bd:39:62:e5:96:eb:34:63:11:28:cc:95:f1:ad:
+ ef:ef:dc:80:58:48:e9:4b:b8:ea:65:ac:e9:fc:80:b5:b5:c8:
+ 45:f9:ac:c1:9f:d9:b9:ea:62:88:8e:c4:f1:4b:83:12:ad:e6:
+ 8b:84:d6:9e:c2:eb:83:18:9f:6a:bb:1b:24:60:33:70:cc:ec:
+ f7:32:f3:5c:d9:79:7d:ef:9e:a4:fe:c9:23:c3:24:ee:15:92:
+ b1:3d:91:4f:26:86:bd:66:73:24:13:ea:a4:ae:63:c1:ad:7d:
+ 84:03:3c:10:78:86:1b:79:e3:c4:f3:f2:04:95:20:ae:23:82:
+ c4:b3:3a:00:62:bf:e6:36:24:e1:57:ba:c7:1e:90:75:d5:5f:
+ 3f:95:61:2b:c1:3b:cd:e5:b3:68:61:d0:46:26:a9:21:52:69:
+ 2d:eb:2e:c7:eb:77:ce:a6:3a:b5:03:33:4f:76:d1:e7:5c:54:
+ 01:5d:cb:78:f4:c9:0c:bf:cf:12:8e:17:2d:23:68:94:e7:ab:
+ fe:a9:b2:2b:06:d0:04:cd
+SHA1 Fingerprint=9C:BB:48:53:F6:A4:F6:D3:52:A4:E8:32:52:55:60:13:F5:AD:AF:65
diff --git a/apex/ca-certificates/files/b0f3e76e.0 b/apex/ca-certificates/files/b0f3e76e.0
new file mode 100644
index 0000000..32f9957
--- /dev/null
+++ b/apex/ca-certificates/files/b0f3e76e.0
@@ -0,0 +1,80 @@
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
+MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
+aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
+jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
+xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
+1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
+snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
+U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
+9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
+AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
+yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
+38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
+AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
+DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
+HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 04:00:00:00:00:01:15:4b:5a:c3:94
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA
+ Validity
+ Not Before: Sep 1 12:00:00 1998 GMT
+ Not After : Jan 28 12:00:00 2028 GMT
+ Subject: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:da:0e:e6:99:8d:ce:a3:e3:4f:8a:7e:fb:f1:8b:
+ 83:25:6b:ea:48:1f:f1:2a:b0:b9:95:11:04:bd:f0:
+ 63:d1:e2:67:66:cf:1c:dd:cf:1b:48:2b:ee:8d:89:
+ 8e:9a:af:29:80:65:ab:e9:c7:2d:12:cb:ab:1c:4c:
+ 70:07:a1:3d:0a:30:cd:15:8d:4f:f8:dd:d4:8c:50:
+ 15:1c:ef:50:ee:c4:2e:f7:fc:e9:52:f2:91:7d:e0:
+ 6d:d5:35:30:8e:5e:43:73:f2:41:e9:d5:6a:e3:b2:
+ 89:3a:56:39:38:6f:06:3c:88:69:5b:2a:4d:c5:a7:
+ 54:b8:6c:89:cc:9b:f9:3c:ca:e5:fd:89:f5:12:3c:
+ 92:78:96:d6:dc:74:6e:93:44:61:d1:8d:c7:46:b2:
+ 75:0e:86:e8:19:8a:d5:6d:6c:d5:78:16:95:a2:e9:
+ c8:0a:38:eb:f2:24:13:4f:73:54:93:13:85:3a:1b:
+ bc:1e:34:b5:8b:05:8c:b9:77:8b:b1:db:1f:20:91:
+ ab:09:53:6e:90:ce:7b:37:74:b9:70:47:91:22:51:
+ 63:16:79:ae:b1:ae:41:26:08:c8:19:2b:d1:46:aa:
+ 48:d6:64:2a:d7:83:34:ff:2c:2a:c1:6c:19:43:4a:
+ 07:85:e7:d3:7c:f6:21:68:ef:ea:f2:52:9f:7f:93:
+ 90:cf
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ d6:73:e7:7c:4f:76:d0:8d:bf:ec:ba:a2:be:34:c5:28:32:b5:
+ 7c:fc:6c:9c:2c:2b:bd:09:9e:53:bf:6b:5e:aa:11:48:b6:e5:
+ 08:a3:b3:ca:3d:61:4d:d3:46:09:b3:3e:c3:a0:e3:63:55:1b:
+ f2:ba:ef:ad:39:e1:43:b9:38:a3:e6:2f:8a:26:3b:ef:a0:50:
+ 56:f9:c6:0a:fd:38:cd:c4:0b:70:51:94:97:98:04:df:c3:5f:
+ 94:d5:15:c9:14:41:9c:c4:5d:75:64:15:0d:ff:55:30:ec:86:
+ 8f:ff:0d:ef:2c:b9:63:46:f6:aa:fc:df:bc:69:fd:2e:12:48:
+ 64:9a:e0:95:f0:a6:ef:29:8f:01:b1:15:b5:0c:1d:a5:fe:69:
+ 2c:69:24:78:1e:b3:a7:1c:71:62:ee:ca:c8:97:ac:17:5d:8a:
+ c2:f8:47:86:6e:2a:c4:56:31:95:d0:67:89:85:2b:f9:6c:a6:
+ 5d:46:9d:0c:aa:82:e4:99:51:dd:70:b7:db:56:3d:61:e4:6a:
+ e1:5c:d6:f6:fe:3d:de:41:cc:07:ae:63:52:bf:53:53:f4:2b:
+ e9:c7:fd:b6:f7:82:5f:85:d2:41:18:db:81:b3:04:1c:c5:1f:
+ a4:80:6f:15:20:c9:de:0c:88:0a:1d:d6:66:55:e2:fc:48:c9:
+ 29:26:69:e0
+SHA1 Fingerprint=B1:BC:96:8B:D4:F4:9D:62:2A:A8:9A:81:F2:15:01:52:A4:1D:82:9C
diff --git a/apex/ca-certificates/files/b30d5fda.0 b/apex/ca-certificates/files/b30d5fda.0
new file mode 100644
index 0000000..2c01aea
--- /dev/null
+++ b/apex/ca-certificates/files/b30d5fda.0
@@ -0,0 +1,63 @@
+-----BEGIN CERTIFICATE-----
+MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQsw
+CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS
+VVNUIEJSIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5
+NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG
+A1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB
+BAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7dPYS
+zuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0
+QVK5buXuQqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/
+VbNafAkl1bK6CKBrqx9tMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g
+PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2JyX3Jvb3Rf
+Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l
+dC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1
+c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO
+PQQDAwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFW
+wKrY7RjEsK70PvomAjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHV
+dWNbFJWcHwHP2NVypw87
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 7c:c9:8f:2b:84:d7:df:ea:0f:c9:65:9a:d3:4b:4d:96
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=DE, O=D-Trust GmbH, CN=D-TRUST BR Root CA 1 2020
+ Validity
+ Not Before: Feb 11 09:45:00 2020 GMT
+ Not After : Feb 11 09:44:59 2035 GMT
+ Subject: C=DE, O=D-Trust GmbH, CN=D-TRUST BR Root CA 1 2020
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:c6:cb:c7:28:d1:fb:84:f5:9a:ef:42:14:20:e1:
+ 43:6b:6e:75:ad:fc:2b:03:84:d4:76:93:25:d7:59:
+ 3b:41:65:6b:1e:e6:34:2a:bb:74:f6:12:ce:e8:6d:
+ e7:ab:e4:3c:4e:3f:44:08:8b:cd:16:71:cb:bf:92:
+ 99:f4:a4:d7:3c:50:54:52:90:85:83:78:94:67:67:
+ a3:1c:09:19:3d:75:34:85:de:ed:60:7d:c7:0c:b4:
+ 41:52:b9:6e:e5:ee:42
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 73:91:10:AB:FF:55:B3:5A:7C:09:25:D5:B2:BA:08:A0:6B:AB:1F:6D
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 CRL Distribution Points:
+ Full Name:
+ URI:http://crl.d-trust.net/crl/d-trust_br_root_ca_1_2020.crl
+ Full Name:
+ URI:ldap://directory.d-trust.net/CN=D-TRUST%20BR%20Root%20CA%201%202020,O=D-Trust%20GmbH,C=DE?certificaterevocationlist
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:66:02:31:00:94:90:2d:13:fa:e1:63:f8:61:63:e8:ad:85:
+ 78:54:91:9c:b8:93:38:3e:1a:41:da:40:16:53:42:08:ca:2f:
+ 8e:f1:3e:81:56:c0:aa:d8:ed:18:c4:b0:ae:f4:3e:fa:26:02:
+ 31:00:f3:28:e2:c6:db:2b:99:fb:b7:51:b8:24:a3:a4:94:7a:
+ 1a:3f:e6:36:e2:03:57:33:8a:30:cb:82:c7:d6:14:11:d5:75:
+ 63:5b:14:95:9c:1f:01:cf:d8:d5:72:a7:0f:3b
+SHA1 Fingerprint=1F:5B:98:F0:E3:B5:F7:74:3C:ED:E6:B0:36:7D:32:CD:F4:09:41:67
diff --git a/apex/ca-certificates/files/b3fb433b.0 b/apex/ca-certificates/files/b3fb433b.0
new file mode 100644
index 0000000..4f68fd0
--- /dev/null
+++ b/apex/ca-certificates/files/b3fb433b.0
@@ -0,0 +1,58 @@
+-----BEGIN CERTIFICATE-----
+MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG
+A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3
+d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu
+dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq
+RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy
+MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD
+VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0
+L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g
+Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi
+A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt
+ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH
+Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
+BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC
+R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX
+hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ a6:8b:79:29:00:00:00:00:50:d0:91:f9
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=US, O=Entrust, Inc., OU=See www.entrust.net\/legal-terms, OU=(c) 2012 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - EC1
+ Validity
+ Not Before: Dec 18 15:25:36 2012 GMT
+ Not After : Dec 18 15:55:36 2037 GMT
+ Subject: C=US, O=Entrust, Inc., OU=See www.entrust.net\/legal-terms, OU=(c) 2012 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - EC1
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:84:13:c9:d0:ba:6d:41:7b:e2:6c:d0:eb:55:5f:
+ 66:02:1a:24:f4:5b:89:69:47:e3:b8:c2:7d:f1:f2:
+ 02:c5:9f:a0:f6:5b:d5:8b:06:19:86:4f:53:10:6d:
+ 07:24:27:a1:a0:f8:d5:47:19:61:4c:7d:ca:93:27:
+ ea:74:0c:ef:6f:96:09:fe:63:ec:70:5d:36:ad:67:
+ 77:ae:c9:9d:7c:55:44:3a:a2:63:51:1f:f5:e3:62:
+ d4:a9:47:07:3e:cc:20
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ B7:63:E7:1A:DD:8D:E9:08:A6:55:83:A4:E0:6A:50:41:65:11:42:49
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:64:02:30:61:79:d8:e5:42:47:df:1c:ae:53:99:17:b6:6f:
+ 1c:7d:e1:bf:11:94:d1:03:88:75:e4:8d:89:a4:8a:77:46:de:
+ 6d:61:ef:02:f5:fb:b5:df:cc:fe:4e:ff:fe:a9:e6:a7:02:30:
+ 5b:99:d7:85:37:06:b5:7b:08:fd:eb:27:8b:4a:94:f9:e1:fa:
+ a7:8e:26:08:e8:7c:92:68:6d:73:d8:6f:26:ac:21:02:b8:99:
+ b7:26:41:5b:25:60:ae:d0:48:1a:ee:06
+SHA1 Fingerprint=20:D8:06:40:DF:9B:25:F5:12:25:3A:11:EA:F7:59:8A:EB:14:B5:47
diff --git a/apex/ca-certificates/files/b74d2bd5.0 b/apex/ca-certificates/files/b74d2bd5.0
new file mode 100644
index 0000000..91dc464
--- /dev/null
+++ b/apex/ca-certificates/files/b74d2bd5.0
@@ -0,0 +1,55 @@
+-----BEGIN CERTIFICATE-----
+MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG
+EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo
+bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g
+RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ
+TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s
+b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw
+djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0
+WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS
+fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB
+zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq
+hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB
+CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD
++JbNR6iC8hZVdyR+EhCVBCyj
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 3c:f6:07:a9:68:70:0e:da:8b:84
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=IN, OU=emSign PKI, O=eMudhra Technologies Limited, CN=emSign ECC Root CA - G3
+ Validity
+ Not Before: Feb 18 18:30:00 2018 GMT
+ Not After : Feb 18 18:30:00 2043 GMT
+ Subject: C=IN, OU=emSign PKI, O=eMudhra Technologies Limited, CN=emSign ECC Root CA - G3
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:23:a5:0c:b8:2d:12:f5:28:f3:b1:b2:dd:e2:02:
+ 12:80:9e:39:5f:49:4d:9f:c9:25:34:59:74:ec:bb:
+ 06:1c:e7:c0:72:af:e8:ae:2f:e1:41:54:87:14:a8:
+ 4a:b2:e8:7c:82:e6:5b:6a:b5:dc:b3:75:ce:8b:06:
+ d0:86:23:bf:46:d5:8e:0f:3f:04:f4:d7:1c:92:7e:
+ f6:a5:63:c2:f5:5f:8e:2e:4f:a1:18:19:02:2b:32:
+ 0a:82:64:7d:16:93:d1
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 7C:5D:02:84:13:D4:CC:8A:9B:81:CE:17:1C:2E:29:1E:9C:48:63:42
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:66:02:31:00:be:f3:61:cf:02:10:1d:64:95:07:b8:18:6e:
+ 88:85:05:2f:83:08:17:90:ca:1f:8a:4c:e8:0d:1b:7a:b1:ad:
+ d5:81:09:47:ef:3b:ac:08:04:7c:5c:99:b1:ed:47:07:d2:02:
+ 31:00:9d:ba:55:fc:a9:4a:e8:ed:ed:e6:76:01:42:7b:c8:f8:
+ 60:d9:8d:51:8b:55:3b:fb:8c:7b:eb:65:09:c3:f8:96:cd:47:
+ a8:82:f2:16:55:77:24:7e:12:10:95:04:2c:a3
+SHA1 Fingerprint=30:43:FA:4F:F2:57:DC:A0:C3:80:EE:2E:58:EA:78:B2:3F:E6:BB:C1
diff --git a/apex/ca-certificates/files/b7db1890.0 b/apex/ca-certificates/files/b7db1890.0
new file mode 100644
index 0000000..2a0375f
--- /dev/null
+++ b/apex/ca-certificates/files/b7db1890.0
@@ -0,0 +1,79 @@
+-----BEGIN CERTIFICATE-----
+MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES
+MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU
+V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz
+WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO
+LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm
+aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE
+AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH
+K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX
+RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z
+rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx
+3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq
+hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC
+MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls
+XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D
+lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn
+aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ
+YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA Root Certification Authority
+ Validity
+ Not Before: Aug 28 07:24:33 2008 GMT
+ Not After : Dec 31 15:59:59 2030 GMT
+ Subject: C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA Root Certification Authority
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b0:7e:72:b8:a4:03:94:e6:a7:de:09:38:91:4a:
+ 11:40:87:a7:7c:59:64:14:7b:b5:11:10:dd:fe:bf:
+ d5:c0:bb:56:e2:85:25:f4:35:72:0f:f8:53:d0:41:
+ e1:44:01:c2:b4:1c:c3:31:42:16:47:85:33:22:76:
+ b2:0a:6f:0f:e5:25:50:4f:85:86:be:bf:98:2e:10:
+ 67:1e:be:11:05:86:05:90:c4:59:d0:7c:78:10:b0:
+ 80:5c:b7:e1:c7:2b:75:cb:7c:9f:ae:b5:d1:9d:23:
+ 37:63:a7:dc:42:a2:2d:92:04:1b:50:c1:7b:b8:3e:
+ 1b:c9:56:04:8b:2f:52:9b:ad:a9:56:e9:c1:ff:ad:
+ a9:58:87:30:b6:81:f7:97:45:fc:19:57:3b:2b:6f:
+ e4:47:f4:99:45:fe:1d:f1:f8:97:a3:88:1d:37:1c:
+ 5c:8f:e0:76:25:9a:50:f8:a0:54:ff:44:90:76:23:
+ d2:32:c6:c3:ab:06:bf:fc:fb:bf:f3:ad:7d:92:62:
+ 02:5b:29:d3:35:a3:93:9a:43:64:60:5d:b2:fa:32:
+ ff:3b:04:af:4d:40:6a:f9:c7:e3:ef:23:fd:6b:cb:
+ e5:0f:8b:38:0d:ee:0a:fc:fe:0f:98:9f:30:31:dd:
+ 6c:52:65:f9:8b:81:be:22:e1:1c:58:03:ba:91:1b:
+ 89:07
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 6A:38:5B:26:8D:DE:8B:5A:F2:4F:7A:54:83:19:18:E3:08:35:A6:BA
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 3c:d5:77:3d:da:df:89:ba:87:0c:08:54:6a:20:50:92:be:b0:
+ 41:3d:b9:26:64:83:0a:2f:e8:40:c0:97:28:27:82:30:4a:c9:
+ 93:ff:6a:e7:a6:00:7f:89:42:9a:d6:11:e5:53:ce:2f:cc:f2:
+ da:05:c4:fe:e2:50:c4:3a:86:7d:cc:da:7e:10:09:3b:92:35:
+ 2a:53:b2:fe:eb:2b:05:d9:6c:5d:e6:d0:ef:d3:6a:66:9e:15:
+ 28:85:7a:e8:82:00:ac:1e:a7:09:69:56:42:d3:68:51:18:be:
+ 54:9a:bf:44:41:ba:49:be:20:ba:69:5c:ee:b8:77:cd:ce:6c:
+ 1f:ad:83:96:18:7d:0e:b5:14:39:84:f1:28:e9:2d:a3:9e:7b:
+ 1e:7a:72:5a:83:b3:79:6f:ef:b4:fc:d0:0a:a5:58:4f:46:df:
+ fb:6d:79:59:f2:84:22:52:ae:0f:cc:fb:7c:3b:e7:6a:ca:47:
+ 61:c3:7a:f8:d3:92:04:1f:b8:20:84:e1:36:54:16:c7:40:de:
+ 3b:8a:73:dc:df:c6:09:4c:df:ec:da:ff:d4:53:42:a1:c9:f2:
+ 62:1d:22:83:3c:97:c5:f9:19:62:27:ac:65:22:d7:d3:3c:c6:
+ e5:8e:b2:53:cc:49:ce:bc:30:fe:7b:0e:33:90:fb:ed:d2:14:
+ 91:1f:07:af
+SHA1 Fingerprint=CF:9E:87:6D:D3:EB:FC:42:26:97:A3:B5:A3:7A:A0:76:A9:06:23:48
diff --git a/apex/ca-certificates/files/b872f2b4.0 b/apex/ca-certificates/files/b872f2b4.0
new file mode 100644
index 0000000..7b5d2b0
--- /dev/null
+++ b/apex/ca-certificates/files/b872f2b4.0
@@ -0,0 +1,83 @@
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE
+AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG
+EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM
+FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC
+REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp
+Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM
+VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+
+SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ
+4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L
+cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi
+eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV
+HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG
+A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3
+DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j
+vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP
+DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc
+maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D
+lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv
+KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 6643877497813316402 (0x5c33cb622c5fb332)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Atos TrustedRoot 2011, O=Atos, C=DE
+ Validity
+ Not Before: Jul 7 14:58:30 2011 GMT
+ Not After : Dec 31 23:59:59 2030 GMT
+ Subject: CN=Atos TrustedRoot 2011, O=Atos, C=DE
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:95:85:3b:97:6f:2a:3b:2e:3b:cf:a6:f3:29:35:
+ be:cf:18:ac:3e:aa:d9:f8:4d:a0:3e:1a:47:b9:bc:
+ 9a:df:f2:fe:cc:3e:47:e8:7a:96:c2:24:8e:35:f4:
+ a9:0c:fc:82:fd:6d:c1:72:62:27:bd:ea:6b:eb:e7:
+ 8a:cc:54:3e:90:50:cf:80:d4:95:fb:e8:b5:82:d4:
+ 14:c5:b6:a9:55:25:57:db:b1:50:f6:b0:60:64:59:
+ 7a:69:cf:03:b7:6f:0d:be:ca:3e:6f:74:72:ea:aa:
+ 30:2a:73:62:be:49:91:61:c8:11:fe:0e:03:2a:f7:
+ 6a:20:dc:02:15:0d:5e:15:6a:fc:e3:82:c1:b5:c5:
+ 9d:64:09:6c:a3:59:98:07:27:c7:1b:96:2b:61:74:
+ 71:6c:43:f1:f7:35:89:10:e0:9e:ec:55:a1:37:22:
+ a2:87:04:05:2c:47:7d:b4:1c:b9:62:29:66:28:ca:
+ b7:e1:93:f5:a4:94:03:99:b9:70:85:b5:e6:48:ea:
+ 8d:50:fc:d9:de:cc:6f:07:0e:dd:0b:72:9d:80:30:
+ 16:07:95:3f:28:0e:fd:c5:75:4f:53:d6:74:9a:b4:
+ 24:2e:8e:02:91:cf:76:c5:9b:1e:55:74:9c:78:21:
+ b1:f0:2d:f1:0b:9f:c2:d5:96:18:1f:f0:54:22:7a:
+ 8c:07
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ A7:A5:06:B1:2C:A6:09:60:EE:D1:97:E9:70:AE:BC:3B:19:6C:DB:21
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Authority Key Identifier:
+ A7:A5:06:B1:2C:A6:09:60:EE:D1:97:E9:70:AE:BC:3B:19:6C:DB:21
+ X509v3 Certificate Policies:
+ Policy: 1.3.6.1.4.1.6189.3.4.1.1
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 26:77:34:db:94:48:86:2a:41:9d:2c:3e:06:90:60:c4:8c:ac:
+ 0b:54:b8:1f:b9:7b:d3:07:39:e4:fa:3e:7b:b2:3d:4e:ed:9f:
+ 23:bd:97:f3:6b:5c:ef:ee:fd:40:a6:df:a1:93:a1:0a:86:ac:
+ ef:20:d0:79:01:bd:78:f7:19:d8:24:31:34:04:01:a6:ba:15:
+ 9a:c3:27:dc:d8:4f:0f:cc:18:63:ff:99:0f:0e:91:6b:75:16:
+ e1:21:fc:d8:26:c7:47:b7:a6:cf:58:72:71:7e:ba:e1:4d:95:
+ 47:3b:c9:af:6d:a1:b4:c1:ec:89:f6:b4:0f:38:b5:e2:64:dc:
+ 25:cf:a6:db:eb:9a:5c:99:a1:c5:08:de:fd:e6:da:d5:d6:5a:
+ 45:0c:c4:b7:c2:b5:14:ef:b4:11:ff:0e:15:b5:f5:f5:db:c6:
+ bd:eb:5a:a7:f0:56:22:a9:3c:65:54:c6:15:a8:bd:86:9e:cd:
+ 83:96:68:7a:71:81:89:e1:0b:e1:ea:11:1b:68:08:cc:69:9e:
+ ec:9e:41:9e:44:32:26:7a:e2:87:0a:71:3d:eb:e4:5a:a4:d2:
+ db:c5:cd:c6:de:60:7f:b9:f3:4f:44:92:ef:2a:b7:18:3e:a7:
+ 19:d9:0b:7d:b1:37:41:42:b0:ba:60:1d:f2:fe:09:11:b0:f0:
+ 87:7b:a7:9d
+SHA1 Fingerprint=2B:B1:F5:3E:55:0C:1D:C5:F1:D4:E6:B7:6A:46:4B:55:06:02:AC:21
diff --git a/apex/ca-certificates/files/b92fd57f.0 b/apex/ca-certificates/files/b92fd57f.0
new file mode 100644
index 0000000..a68f55b
--- /dev/null
+++ b/apex/ca-certificates/files/b92fd57f.0
@@ -0,0 +1,123 @@
+-----BEGIN CERTIFICATE-----
+MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBs
+MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl
+c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0Eg
+Um9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUzOFoXDTQ1MDIxMzEwNTUzN1owbDEL
+MAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl
+YXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNBIFJv
+b3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569l
+mwVnlskNJLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE
+4VGC/6zStGndLuwRo0Xua2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uv
+a9of08WRiFukiZLRgeaMOVig1mlDqa2YUlhu2wr7a89o+uOkXjpFc5gH6l8Cct4M
+pbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K5FrZx40d/JiZ+yykgmvw
+Kh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEvdmn8kN3b
+LW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcY
+AuUR0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqB
+AGMUuTNe3QvboEUHGjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYq
+E613TBoYm5EPWNgGVMWX+Ko/IIqmhaZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHr
+W2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQCPxrvrNQKlr9qEgYRtaQQJKQ
+CoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE
+AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAU
+X15QvWiWkKQUEapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3
+f5Z2EMVGpdAgS1D0NTsY9FVqQRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxaja
+H6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxDQpSbIPDRzbLrLFPCU3hKTwSUQZqP
+JzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcRj88YxeMn/ibvBZ3P
+zzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5vZSt
+jBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0
+/L5H9MG0qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pT
+BGIBnfHAT+7hOtSLIBD6Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79
+aPib8qXPMThcFarmlwDB31qlpzmq6YR/PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YW
+xw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnnkf3/W9b3raYvAwtt41dU
+63ZTGI0RmLo=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 39:ca:93:1c:ef:43:f3:c6:8e:93:c7:f4:64:89:38:7e
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=GR, O=Hellenic Academic and Research Institutions CA, CN=HARICA TLS RSA Root CA 2021
+ Validity
+ Not Before: Feb 19 10:55:38 2021 GMT
+ Not After : Feb 13 10:55:37 2045 GMT
+ Subject: C=GR, O=Hellenic Academic and Research Institutions CA, CN=HARICA TLS RSA Root CA 2021
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:8b:c2:e7:af:65:9b:05:67:96:c9:0d:24:b9:d0:
+ 0e:64:fc:ce:e2:24:18:2c:84:7f:77:51:cb:04:11:
+ 36:b8:5e:ed:69:71:a7:9e:e4:25:09:97:67:c1:47:
+ c2:cf:91:16:36:62:3d:38:04:e1:51:82:ff:ac:d2:
+ b4:69:dd:2e:ec:11:a3:45:ee:6b:6b:3b:4c:bf:8c:
+ 8d:a4:1e:9d:11:b9:e9:38:f9:7a:0e:0c:98:e2:23:
+ 1d:d1:4e:63:d4:e7:b8:41:44:fb:6b:af:6b:da:1f:
+ d3:c5:91:88:5b:a4:89:92:d1:81:e6:8c:39:58:a0:
+ d6:69:43:a9:ad:98:52:58:6e:db:0a:fb:6b:cf:68:
+ fa:e3:a4:5e:3a:45:73:98:07:ea:5f:02:72:de:0c:
+ a5:b3:9f:ae:a9:1d:b7:1d:b3:fc:8a:59:e7:6e:72:
+ 65:ad:f5:30:94:23:07:f3:82:16:4b:35:98:9c:53:
+ bb:2f:ca:e4:5a:d9:c7:8d:1d:fc:98:99:fb:2c:a4:
+ 82:6b:f0:2a:1f:8e:0b:5f:71:5c:5c:ae:42:7b:29:
+ 89:81:cb:03:a3:99:ca:88:9e:0b:40:09:41:33:db:
+ e6:58:7a:fd:ae:99:70:c0:5a:0f:d6:13:86:71:2f:
+ 76:69:fc:90:dd:db:2d:6e:d1:f2:9b:f5:1a:6b:9e:
+ 6f:15:8c:7a:f0:4b:28:a0:22:38:80:24:6c:36:a4:
+ 3b:f2:30:91:f3:78:13:cf:c1:3f:35:ab:f1:1d:11:
+ 23:b5:43:22:9e:01:92:b7:18:02:e5:11:d1:82:db:
+ 15:00:cc:61:37:c1:2a:7c:9a:e1:d0:ba:b3:50:46:
+ ee:82:ac:9d:31:f8:fb:23:e2:03:00:48:70:a3:09:
+ 26:79:15:53:60:f3:38:5c:ad:38:ea:81:00:63:14:
+ b9:33:5e:dd:0b:db:a0:45:07:1a:33:09:f8:4d:b4:
+ a7:02:a6:69:f4:c2:59:05:88:65:85:56:ae:4b:cb:
+ e0:de:3c:7d:2d:1a:c8:e9:fb:1f:a3:61:4a:d6:2a:
+ 13:ad:77:4c:1a:18:9b:91:0f:58:d8:06:54:c5:97:
+ f8:aa:3f:20:8a:a6:85:a6:77:f6:a6:fc:1c:e2:ee:
+ 6e:94:33:2a:83:50:84:0a:e5:4f:86:f8:50:45:78:
+ 00:81:eb:5b:68:e3:26:8d:cc:7b:5c:51:f4:14:2c:
+ 40:be:1a:60:1d:7a:72:61:1d:1f:63:2d:88:aa:ce:
+ a2:45:90:08:fc:6b:be:b3:50:2a:5a:fd:a8:48:18:
+ 46:d6:90:40:92:90:0a:84:5e:68:31:f8:eb:ed:0d:
+ d3:1d:c6:7d:99:18:55:56:27:65:2e:8d:45:c5:24:
+ ec:ce:e3
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 0A:48:23:A6:60:A4:92:0A:33:EA:93:5B:C5:57:EA:25:4D:BD:12:EE
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 3e:90:48:aa:6e:62:15:25:66:7b:0c:d5:8c:8b:89:9d:d7:ed:
+ 4e:07:ef:9c:d0:14:5f:5e:50:bd:68:96:90:a4:14:11:aa:68:
+ 6d:09:35:39:40:09:da:f4:09:2c:34:a5:7b:59:84:49:29:97:
+ 74:c8:07:1e:47:6d:f2:ce:1c:50:26:e3:9e:3d:40:53:3f:f7:
+ 7f:96:76:10:c5:46:a5:d0:20:4b:50:f4:35:3b:18:f4:55:6a:
+ 41:1b:47:06:68:3c:bb:09:08:62:d9:5f:55:42:aa:ac:53:85:
+ ac:95:56:36:56:ab:e4:05:8c:c5:a8:da:1f:a3:69:bd:53:0f:
+ c4:ff:dc:ca:e3:7e:f2:4c:88:86:47:46:1a:f3:00:f5:80:91:
+ a2:dc:43:42:94:9b:20:f0:d1:cd:b2:eb:2c:53:c2:53:78:4a:
+ 4f:04:94:41:9a:8f:27:32:c1:e5:49:19:bf:f1:f2:c2:8b:a8:
+ 0a:39:31:28:b4:7d:62:36:2c:4d:ec:1f:33:b6:7e:77:6d:7e:
+ 50:f0:9f:0e:d7:11:8f:cf:18:c5:e3:27:fe:26:ef:05:9d:cf:
+ cf:37:c5:d0:7b:da:3b:b0:16:84:0c:3a:93:d6:be:17:db:0f:
+ 3e:0e:19:78:09:c7:a9:02:72:22:4b:f7:37:76:ba:75:c4:85:
+ 03:5a:63:d5:b1:75:05:c2:b9:bd:94:ad:8c:15:99:a7:93:7d:
+ f6:c5:f3:aa:74:cf:04:85:94:98:00:f4:e2:f9:ca:24:65:bf:
+ e0:62:af:c8:c5:fa:b2:c9:9e:56:48:da:79:fd:96:76:15:be:
+ a3:8e:56:c4:b3:34:fc:be:47:f4:c1:b4:a8:fc:d5:30:88:68:
+ ee:cb:ae:c9:63:c4:76:be:ac:38:18:e1:5e:5c:cf:ae:3a:22:
+ 51:eb:d1:8b:b3:f3:2b:33:07:54:87:fa:b4:b2:13:7b:ba:53:
+ 04:62:01:9d:f1:c0:4f:ee:e1:3a:d4:8b:20:10:fa:02:57:e6:
+ ef:c1:0b:b7:90:46:9c:19:29:8c:dc:6f:a0:4a:69:69:94:b7:
+ 24:65:a0:ff:ac:3f:ce:01:fb:21:2e:fd:68:f8:9b:f2:a5:cf:
+ 31:38:5c:15:aa:e6:97:00:c1:df:5a:a5:a7:39:aa:e9:84:7f:
+ 3c:51:a8:3a:d9:94:5b:8c:bf:4f:08:71:e5:db:a8:5c:d4:d2:
+ a6:fe:00:a3:c6:16:c7:0f:e8:80:ce:1c:28:64:74:19:08:d3:
+ 42:e3:ce:00:5d:7f:b1:dc:13:b0:e1:05:cb:d1:20:aa:86:74:
+ 9e:39:e7:91:fd:ff:5b:d6:f7:ad:a6:2f:03:0b:6d:e3:57:54:
+ eb:76:53:18:8d:11:98:ba
+SHA1 Fingerprint=02:2D:05:82:FA:88:CE:14:0C:06:79:DE:7F:14:10:E9:45:D7:A5:6D
diff --git a/apex/ca-certificates/files/b936d1c6.0 b/apex/ca-certificates/files/b936d1c6.0
new file mode 100644
index 0000000..f9cac66
--- /dev/null
+++ b/apex/ca-certificates/files/b936d1c6.0
@@ -0,0 +1,125 @@
+-----BEGIN CERTIFICATE-----
+MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx
+CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ
+WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ
+BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG
+Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/
+yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf
+BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz
+WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF
+tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z
+374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC
+IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL
+mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7
+wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS
+MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2
+ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet
+UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw
+AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H
+YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3
+LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD
+nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1
+RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM
+LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf
+77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N
+JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm
+fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp
+6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp
+1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B
+9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok
+RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv
+uu8wd+RU4riEmViAqhOLUTpPSPaLtrM=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 5d:93:8d:30:67:36:c8:06:1d:1a:c7:54:84:69:07
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=ES, O=FNMT-RCM, OU=AC RAIZ FNMT-RCM
+ Validity
+ Not Before: Oct 29 15:59:56 2008 GMT
+ Not After : Jan 1 00:00:00 2030 GMT
+ Subject: C=ES, O=FNMT-RCM, OU=AC RAIZ FNMT-RCM
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:ba:71:80:7a:4c:86:6e:7f:c8:13:6d:c0:c6:7d:
+ 1c:00:97:8f:2c:0c:23:bb:10:9a:40:a9:1a:b7:87:
+ 88:f8:9b:56:6a:fb:e6:7b:8e:8b:92:8e:a7:25:5d:
+ 59:11:db:36:2e:b7:51:17:1f:a9:08:1f:04:17:24:
+ 58:aa:37:4a:18:df:e5:39:d4:57:fd:d7:c1:2c:91:
+ 01:91:e2:22:d4:03:c0:58:fc:77:47:ec:8f:3e:74:
+ 43:ba:ac:34:8d:4d:38:76:67:8e:b0:c8:6f:30:33:
+ 58:71:5c:b4:f5:6b:6e:d4:01:50:b8:13:7e:6c:4a:
+ a3:49:d1:20:19:ee:bc:c0:29:18:65:a7:de:fe:ef:
+ dd:0a:90:21:e7:1a:67:92:42:10:98:5f:4f:30:bc:
+ 3e:1c:45:b4:10:d7:68:40:14:c0:40:fa:e7:77:17:
+ 7a:e6:0b:8f:65:5b:3c:d9:9a:52:db:b5:bd:9e:46:
+ cf:3d:eb:91:05:02:c0:96:b2:76:4c:4d:10:96:3b:
+ 92:fa:9c:7f:0f:99:df:be:23:35:45:1e:02:5c:fe:
+ b5:a8:9b:99:25:da:5e:f3:22:c3:39:f5:e4:2a:2e:
+ d3:c6:1f:c4:6c:aa:c5:1c:6a:01:05:4a:2f:d2:c5:
+ c1:a8:34:26:5d:66:a5:d2:02:21:f9:18:b7:06:f5:
+ 4e:99:6f:a8:ab:4c:51:e8:cf:50:18:c5:77:c8:39:
+ 09:2c:49:92:32:99:a8:bb:17:17:79:b0:5a:c5:e6:
+ a3:c4:59:65:47:35:83:5e:a9:e8:35:0b:99:bb:e4:
+ cd:20:c6:9b:4a:06:39:b5:68:fc:22:ba:ee:55:8c:
+ 2b:4e:ea:f3:b1:e3:fc:b6:99:9a:d5:42:fa:71:4d:
+ 08:cf:87:1e:6a:71:7d:f9:d3:b4:e9:a5:71:81:7b:
+ c2:4e:47:96:a5:f6:76:85:a3:28:8f:e9:80:6e:81:
+ 53:a5:6d:5f:b8:48:f9:c2:f9:36:a6:2e:49:ff:b8:
+ 96:c2:8c:07:b3:9b:88:58:fc:eb:1b:1c:de:2d:70:
+ e2:97:92:30:a1:89:e3:bc:55:a8:27:d6:4b:ed:90:
+ ad:8b:fa:63:25:59:2d:a8:35:dd:ca:97:33:bc:e5:
+ cd:c7:9d:d1:ec:ef:5e:0e:4a:90:06:26:63:ad:b9:
+ d9:35:2d:07:ba:76:65:2c:ac:57:8f:7d:f4:07:94:
+ d7:81:02:96:5d:a3:07:49:d5:7a:d0:57:f9:1b:e7:
+ 53:46:75:aa:b0:79:42:cb:68:71:08:e9:60:bd:39:
+ 69:ce:f4:af:c3:56:40:c7:ad:52:a2:09:e4:6f:86:
+ 47:8a:1f:eb:28:27:5d:83:20:af:04:c9:6c:56:9a:
+ 8b:46:f5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ F7:7D:C5:FD:C4:E8:9A:1B:77:64:A7:F5:1D:A0:CC:BF:87:60:9A:6D
+ X509v3 Certificate Policies:
+ Policy: X509v3 Any Policy
+ CPS: http://www.cert.fnmt.es/dpcs/
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 07:90:4a:df:f3:23:4e:f0:c3:9c:51:65:9b:9c:22:a2:8a:0c:
+ 85:f3:73:29:6b:4d:fe:01:e2:a9:0c:63:01:bf:04:67:a5:9d:
+ 98:5f:fd:01:13:fa:ec:9a:62:e9:86:fe:b6:62:d2:6e:4c:94:
+ fb:c0:75:45:7c:65:0c:f8:b2:37:cf:ac:0f:cf:8d:6f:f9:19:
+ f7:8f:ec:1e:f2:70:9e:f0:ca:b8:ef:b7:ff:76:37:76:5b:f6:
+ 6e:88:f3:af:62:32:22:93:0d:3a:6a:8e:14:66:0c:2d:53:74:
+ 57:65:1e:d5:b2:dd:23:81:3b:a5:66:23:27:67:09:8f:e1:77:
+ aa:43:cd:65:51:08:ed:51:58:fe:e6:39:f9:cb:47:84:a4:15:
+ f1:76:bb:a4:ee:a4:3b:c4:5f:ef:b2:33:96:11:18:b7:c9:65:
+ be:18:e1:a3:a4:dc:fa:18:f9:d3:bc:13:9b:39:7a:34:ba:d3:
+ 41:fb:fa:32:8a:2a:b7:2b:86:0b:69:83:38:be:cd:8a:2e:0b:
+ 70:ad:8d:26:92:ee:1e:f5:01:2b:0a:d9:d6:97:9b:6e:e0:a8:
+ 19:1c:3a:21:8b:0c:1e:40:ad:03:e7:dd:66:7e:f5:b9:20:0d:
+ 03:e8:96:f9:82:45:d4:39:e0:a0:00:5d:d7:98:e6:7d:9e:67:
+ 73:c3:9a:2a:f7:ab:8b:a1:3a:14:ef:34:bc:52:0e:89:98:9a:
+ 04:40:84:1d:7e:45:69:93:57:ce:eb:ce:f8:50:7c:4f:1c:6e:
+ 04:43:9b:f9:d6:3b:23:18:e9:ea:8e:d1:4d:46:8d:f1:3b:e4:
+ 6a:ca:ba:fb:23:b7:9b:fa:99:01:29:5a:58:5a:2d:e3:f9:d4:
+ 6d:0e:26:ad:c1:6e:34:bc:32:f8:0c:05:fa:65:a3:db:3b:37:
+ 83:22:e9:d6:dc:72:33:fd:5d:f2:20:bd:76:3c:23:da:28:f7:
+ f9:1b:eb:59:64:d5:dc:5f:72:7e:20:fc:cd:89:b5:90:67:4d:
+ 62:7a:3f:4e:ad:1d:c3:39:fe:7a:f4:28:16:df:41:f6:48:80:
+ 05:d7:0f:51:79:ac:10:ab:d4:ec:03:66:e6:6a:b0:ba:31:92:
+ 42:40:6a:be:3a:d3:72:e1:6a:37:55:bc:ac:1d:95:b7:69:61:
+ f2:43:91:74:e6:a0:d3:0a:24:46:a1:08:af:d6:da:45:19:96:
+ d4:53:1d:5b:84:79:f0:c0:f7:47:ef:8b:8f:c5:06:ae:9d:4c:
+ 62:9d:ff:46:04:f8:d3:c9:b6:10:25:40:75:fe:16:aa:c9:4a:
+ 60:86:2f:ba:ef:30:77:e4:54:e2:b8:84:99:58:80:aa:13:8b:
+ 51:3a:4f:48:f6:8b:b6:b3
+SHA1 Fingerprint=EC:50:35:07:B2:15:C4:95:62:19:E2:A8:9A:5B:42:99:2C:4C:2C:20
diff --git a/apex/ca-certificates/files/bc3f2570.0 b/apex/ca-certificates/files/bc3f2570.0
new file mode 100644
index 0000000..33bb6d8
--- /dev/null
+++ b/apex/ca-certificates/files/bc3f2570.0
@@ -0,0 +1,81 @@
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT
+EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp
+ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz
+NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH
+EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE
+AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD
+E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH
+/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy
+DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh
+GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR
+tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA
+AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
+FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX
+WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu
+9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr
+gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo
+2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
+LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI
+4uJEvlz36hz1
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 0 (0x0)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., CN=Go Daddy Root Certificate Authority - G2
+ Validity
+ Not Before: Sep 1 00:00:00 2009 GMT
+ Not After : Dec 31 23:59:59 2037 GMT
+ Subject: C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., CN=Go Daddy Root Certificate Authority - G2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:bf:71:62:08:f1:fa:59:34:f7:1b:c9:18:a3:f7:
+ 80:49:58:e9:22:83:13:a6:c5:20:43:01:3b:84:f1:
+ e6:85:49:9f:27:ea:f6:84:1b:4e:a0:b4:db:70:98:
+ c7:32:01:b1:05:3e:07:4e:ee:f4:fa:4f:2f:59:30:
+ 22:e7:ab:19:56:6b:e2:80:07:fc:f3:16:75:80:39:
+ 51:7b:e5:f9:35:b6:74:4e:a9:8d:82:13:e4:b6:3f:
+ a9:03:83:fa:a2:be:8a:15:6a:7f:de:0b:c3:b6:19:
+ 14:05:ca:ea:c3:a8:04:94:3b:46:7c:32:0d:f3:00:
+ 66:22:c8:8d:69:6d:36:8c:11:18:b7:d3:b2:1c:60:
+ b4:38:fa:02:8c:ce:d3:dd:46:07:de:0a:3e:eb:5d:
+ 7c:c8:7c:fb:b0:2b:53:a4:92:62:69:51:25:05:61:
+ 1a:44:81:8c:2c:a9:43:96:23:df:ac:3a:81:9a:0e:
+ 29:c5:1c:a9:e9:5d:1e:b6:9e:9e:30:0a:39:ce:f1:
+ 88:80:fb:4b:5d:cc:32:ec:85:62:43:25:34:02:56:
+ 27:01:91:b4:3b:70:2a:3f:6e:b1:e8:9c:88:01:7d:
+ 9f:d4:f9:db:53:6d:60:9d:bf:2c:e7:58:ab:b8:5f:
+ 46:fc:ce:c4:1b:03:3c:09:eb:49:31:5c:69:46:b3:
+ e0:47
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 3A:9A:85:07:10:67:28:B6:EF:F6:BD:05:41:6E:20:C1:94:DA:0F:DE
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 99:db:5d:79:d5:f9:97:59:67:03:61:f1:7e:3b:06:31:75:2d:
+ a1:20:8e:4f:65:87:b4:f7:a6:9c:bc:d8:e9:2f:d0:db:5a:ee:
+ cf:74:8c:73:b4:38:42:da:05:7b:f8:02:75:b8:fd:a5:b1:d7:
+ ae:f6:d7:de:13:cb:53:10:7e:8a:46:d1:97:fa:b7:2e:2b:11:
+ ab:90:b0:27:80:f9:e8:9f:5a:e9:37:9f:ab:e4:df:6c:b3:85:
+ 17:9d:3d:d9:24:4f:79:91:35:d6:5f:04:eb:80:83:ab:9a:02:
+ 2d:b5:10:f4:d8:90:c7:04:73:40:ed:72:25:a0:a9:9f:ec:9e:
+ ab:68:12:99:57:c6:8f:12:3a:09:a4:bd:44:fd:06:15:37:c1:
+ 9b:e4:32:a3:ed:38:e8:d8:64:f3:2c:7e:14:fc:02:ea:9f:cd:
+ ff:07:68:17:db:22:90:38:2d:7a:8d:d1:54:f1:69:e3:5f:33:
+ ca:7a:3d:7b:0a:e3:ca:7f:5f:39:e5:e2:75:ba:c5:76:18:33:
+ ce:2c:f0:2f:4c:ad:f7:b1:e7:ce:4f:a8:c4:9b:4a:54:06:c5:
+ 7f:7d:d5:08:0f:e2:1c:fe:7e:17:b8:ac:5e:f6:d4:16:b2:43:
+ 09:0c:4d:f6:a7:6b:b4:99:84:65:ca:7a:88:e2:e2:44:be:5c:
+ f7:ea:1c:f5
+SHA1 Fingerprint=47:BE:AB:C9:22:EA:E8:0E:78:78:34:62:A7:9F:45:C2:54:FD:E6:8B
diff --git a/apex/ca-certificates/files/bd43e1dd.0 b/apex/ca-certificates/files/bd43e1dd.0
new file mode 100644
index 0000000..329cce4
--- /dev/null
+++ b/apex/ca-certificates/files/bd43e1dd.0
@@ -0,0 +1,126 @@
+-----BEGIN CERTIFICATE-----
+MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQEL
+BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ
+SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n
+a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwMjI5NDZaFw00MjA2MDMwMjI5
+NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT
+CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMXSG9u
+Z2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
+AoICAQCziNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFO
+dem1p+/l6TWZ5Mwc50tfjTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mI
+VoBc+L0sPOFMV4i707mV78vH9toxdCim5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV
+9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOesL4jpNrcyCse2m5FHomY
+2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj0mRiikKY
+vLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+Tt
+bNe/JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZb
+x39ri1UbSsUgYT2uy1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+
+l2oBlKN8W4UdKjk60FSh0Tlxnf0h+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YK
+TE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsGxVd7GYYKecsAyVKvQv83j+Gj
+Hno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwIDAQABo2MwYTAP
+BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e
+i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEw
+DQYJKoZIhvcNAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG
+7BJ8dNVI0lkUmcDrudHr9EgwW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCk
+MpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWldy8joRTnU+kLBEUx3XZL7av9YROXr
+gZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov+BS5gLNdTaqX4fnk
+GMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDceqFS
+3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJm
+Ozj/2ZQw9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+
+l6mc1X5VTMbeRRAc6uk7nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6c
+JfTzPV4e0hz5sy229zdcxsshTrD3mUcYhcErulWuBurQB7Lcq9CClnXO0lD+mefP
+L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa
+LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG
+mpv0
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 08:16:5f:8a:4c:a5:ec:00:c9:93:40:df:c4:c6:ae:23:b8:1c:5a:a4
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=HK, ST=Hong Kong, L=Hong Kong, O=Hongkong Post, CN=Hongkong Post Root CA 3
+ Validity
+ Not Before: Jun 3 02:29:46 2017 GMT
+ Not After : Jun 3 02:29:46 2042 GMT
+ Subject: C=HK, ST=Hong Kong, L=Hong Kong, O=Hongkong Post, CN=Hongkong Post Root CA 3
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:b3:88:d7:ea:ce:0f:20:4e:be:e6:d6:03:6d:ee:
+ 59:fc:c2:57:df:29:68:a1:83:0e:3e:68:c7:68:58:
+ 9c:1c:60:4b:89:43:0c:b9:d4:15:b2:ee:c1:4e:75:
+ e9:b5:a7:ef:e5:e9:35:99:e4:cc:1c:e7:4b:5f:8d:
+ 33:30:20:33:53:d9:a6:bb:d5:3e:13:8e:e9:1f:87:
+ 49:ad:50:2d:50:ca:18:be:01:58:a2:13:70:96:bb:
+ 89:88:56:80:5c:f8:bd:2c:3c:e1:4c:57:88:bb:d3:
+ b9:95:ef:cb:c7:f6:da:31:74:28:a6:e6:54:89:f5:
+ 41:31:ca:e5:26:1a:cd:82:e0:70:da:3b:29:bb:d5:
+ 03:f5:99:ba:55:f5:64:d1:60:0e:b3:89:49:b8:8a:
+ 2f:05:d2:84:45:28:7c:8f:68:50:12:78:fc:0b:b5:
+ 53:cb:c2:98:1c:84:a3:9e:b0:be:23:a4:da:dc:c8:
+ 2b:1e:da:6e:45:1e:89:98:da:f9:00:2e:06:e9:0c:
+ 3b:70:d5:50:25:88:99:cb:cd:73:60:f7:d5:ff:35:
+ 67:c5:a1:bc:5e:ab:cd:4a:b8:45:eb:c8:68:1e:0d:
+ 0d:14:46:12:e3:d2:64:62:8a:42:98:bc:b4:c6:08:
+ 08:f8:fd:a8:4c:64:9c:76:01:bd:2f:a9:6c:33:0f:
+ d8:3f:28:b8:3c:69:01:42:86:7e:69:c1:c9:06:ca:
+ e5:7a:46:65:e9:c2:d6:50:41:2e:3f:b7:e4:ed:6c:
+ d7:bf:26:01:11:a2:16:29:4a:6b:34:06:90:ec:13:
+ d2:b6:fb:6a:76:d2:3c:ed:f0:d6:2d:dd:e1:15:ec:
+ a3:9b:2f:2c:c9:3e:2b:e4:69:3b:ff:72:25:b1:36:
+ 86:5b:c7:7f:6b:8b:55:1b:4a:c5:20:61:3d:ae:cb:
+ 50:e1:08:3a:be:b0:8f:63:41:53:30:08:59:3c:98:
+ 1d:77:ba:63:91:7a:ca:10:50:60:bf:f0:d7:bc:95:
+ 87:8f:97:c5:fe:97:6a:01:94:a3:7c:5b:85:1d:2a:
+ 39:3a:d0:54:a1:d1:39:71:9d:fd:21:f9:b5:7b:f0:
+ e2:e0:02:8f:6e:96:24:25:2c:a0:1e:2c:a8:c4:89:
+ a7:ef:ed:99:06:2f:b6:0a:4c:4f:db:a2:cc:37:1a:
+ af:47:85:2d:8a:5f:c4:34:34:4c:00:fd:18:93:67:
+ 13:d1:37:e6:48:b4:8b:06:c5:57:7b:19:86:0a:79:
+ cb:00:c9:52:af:42:ff:37:8f:e1:a3:1e:7a:3d:50:
+ ab:63:06:e7:15:b5:3f:b6:45:37:94:37:b1:7e:f2:
+ 48:c3:7f:c5:75:fe:97:8d:45:8f:1a:a7:1a:72:28:
+ 1a:40:0f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Authority Key Identifier:
+ 17:9D:CD:1E:8B:D6:39:2B:70:D3:5C:D4:A0:B8:1F:B0:00:FC:C5:61
+ X509v3 Subject Key Identifier:
+ 17:9D:CD:1E:8B:D6:39:2B:70:D3:5C:D4:A0:B8:1F:B0:00:FC:C5:61
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 56:d5:7b:6e:e6:22:01:d2:42:9b:18:d5:0e:d7:66:23:5c:e3:
+ fe:a0:c7:92:d2:e9:94:ad:4b:a2:c6:ec:12:7c:74:d5:48:d2:
+ 59:14:99:c0:eb:b9:d1:eb:f4:48:30:5b:ad:a7:57:73:99:a9:
+ d3:e5:b7:d1:2e:59:24:58:dc:68:2e:2e:62:d8:6a:e4:70:0b:
+ 2d:20:50:20:a4:32:95:d1:00:98:bb:d3:fd:f7:32:f2:49:ae:
+ c6:7a:e0:47:be:6e:ce:cb:a3:72:3a:2d:69:5d:cb:c8:e8:45:
+ 39:d4:fa:42:c1:11:4c:77:5d:92:fb:6a:ff:58:44:e5:eb:81:
+ 9e:af:a0:99:ad:be:a9:01:66:cb:38:1d:3c:df:43:1f:f4:4d:
+ 6e:b4:ba:17:46:fc:7d:fd:87:81:79:6a:0d:33:0f:fa:2f:f8:
+ 14:b9:80:b3:5d:4d:aa:97:e1:f9:e4:18:c5:f8:d5:38:8c:26:
+ 3c:fd:f2:28:e2:ee:5a:49:88:2c:df:79:3d:8e:9e:90:3c:bd:
+ 41:4a:3a:dd:5b:f6:9a:b4:ce:3f:25:30:7f:32:7d:a2:03:94:
+ d0:dc:7a:a1:52:de:6e:93:8d:18:26:fd:55:ac:bd:8f:9b:d2:
+ cf:af:e7:86:2c:cb:1f:09:6f:a3:6f:a9:84:d4:73:bf:4d:a1:
+ 74:1b:4e:23:60:f2:cc:0e:aa:7f:a4:9c:4c:25:a8:b2:66:3b:
+ 38:ff:d9:94:30:f6:72:84:be:68:55:10:0f:c6:73:2c:16:69:
+ 93:07:fe:b1:45:ed:bb:a2:55:6a:b0:da:b5:4a:02:25:27:85:
+ d7:b7:b7:86:44:16:89:6c:80:2b:3e:97:a9:9c:d5:7e:55:4c:
+ c6:de:45:10:1c:ea:e9:3b:9f:03:53:ee:ee:7a:01:02:16:78:
+ d4:e8:c2:be:46:76:88:13:3f:22:bb:48:12:1d:52:00:b4:02:
+ 7e:21:1a:1e:9c:25:f4:f3:3d:5e:1e:d2:1c:f9:b3:2d:b6:f7:
+ 37:5c:c6:cb:21:4e:b0:f7:99:47:18:85:c1:2b:ba:55:ae:06:
+ ea:d0:07:b2:dc:ab:d0:82:96:75:ce:d2:50:fe:99:e7:cf:2f:
+ 9f:e7:76:d1:61:2a:fb:21:bb:31:d0:aa:9f:47:a4:b2:22:ca:
+ 16:3a:50:57:c4:5b:43:67:c5:65:62:03:49:01:eb:43:d9:d8:
+ f8:9e:ad:cf:b1:63:0e:45:f4:a0:5a:2c:9b:2d:c5:a6:c0:ad:
+ a8:47:f4:27:4c:38:0d:2e:1b:49:3b:52:f4:e8:88:83:2b:54:
+ 28:d4:f2:35:52:b4:32:83:62:69:64:0c:91:9c:9f:97:ea:74:
+ 16:fd:1f:11:06:9a:9b:f4
+SHA1 Fingerprint=58:A2:D0:EC:20:52:81:5B:C1:F3:F8:64:02:24:4E:C2:8E:02:4B:02
diff --git a/apex/ca-certificates/files/bdacca6f.0 b/apex/ca-certificates/files/bdacca6f.0
new file mode 100644
index 0000000..a6388e8
--- /dev/null
+++ b/apex/ca-certificates/files/bdacca6f.0
@@ -0,0 +1,88 @@
+-----BEGIN CERTIFICATE-----
+MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK
+MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x
+GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx
+MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg
+Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ
+iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa
+/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ
+jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI
+HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7
+sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w
+gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw
+KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG
+AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L
+URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO
+H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm
+I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY
+iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc
+f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 07:56:22:a4:e8:d4:8a:89:4d:f4:13:c8:f0:f8:ea:a5
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=US, O=SecureTrust Corporation, CN=Secure Global CA
+ Validity
+ Not Before: Nov 7 19:42:28 2006 GMT
+ Not After : Dec 31 19:52:06 2029 GMT
+ Subject: C=US, O=SecureTrust Corporation, CN=Secure Global CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:af:35:2e:d8:ac:6c:55:69:06:71:e5:13:68:24:
+ b3:4f:d8:cc:21:47:f8:f1:60:38:89:89:03:e9:bd:
+ ea:5e:46:53:09:dc:5c:f5:5a:e8:f7:45:2a:02:eb:
+ 31:61:d7:29:33:4c:ce:c7:7c:0a:37:7e:0f:ba:32:
+ 98:e1:1d:97:af:8f:c7:dc:c9:38:96:f3:db:1a:fc:
+ 51:ed:68:c6:d0:6e:a4:7c:24:d1:ae:42:c8:96:50:
+ 63:2e:e0:fe:75:fe:98:a7:5f:49:2e:95:e3:39:33:
+ 64:8e:1e:a4:5f:90:d2:67:3c:b2:d9:fe:41:b9:55:
+ a7:09:8e:72:05:1e:8b:dd:44:85:82:42:d0:49:c0:
+ 1d:60:f0:d1:17:2c:95:eb:f6:a5:c1:92:a3:c5:c2:
+ a7:08:60:0d:60:04:10:96:79:9e:16:34:e6:a9:b6:
+ fa:25:45:39:c8:1e:65:f9:93:f5:aa:f1:52:dc:99:
+ 98:3d:a5:86:1a:0c:35:33:fa:4b:a5:04:06:15:1c:
+ 31:80:ef:aa:18:6b:c2:7b:d7:da:ce:f9:33:20:d5:
+ f5:bd:6a:33:2d:81:04:fb:b0:5c:d4:9c:a3:e2:5c:
+ 1d:e3:a9:42:75:5e:7b:d4:77:ef:39:54:ba:c9:0a:
+ 18:1b:12:99:49:2f:88:4b:fd:50:62:d1:73:e7:8f:
+ 7a:43
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ 1.3.6.1.4.1.311.20.2:
+ ...C.A
+ X509v3 Key Usage:
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ AF:44:04:C2:41:7E:48:83:DB:4E:39:02:EC:EC:84:7A:E6:CE:C9:A4
+ X509v3 CRL Distribution Points:
+ Full Name:
+ URI:http://crl.securetrust.com/SGCA.crl
+ 1.3.6.1.4.1.311.21.1:
+ ...
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 63:1a:08:40:7d:a4:5e:53:0d:77:d8:7a:ae:1f:0d:0b:51:16:
+ 03:ef:18:7c:c8:e3:af:6a:58:93:14:60:91:b2:84:dc:88:4e:
+ be:39:8a:3a:f3:e6:82:89:5d:01:37:b3:ab:24:a4:15:0e:92:
+ 35:5a:4a:44:5e:4e:57:fa:75:ce:1f:48:ce:66:f4:3c:40:26:
+ 92:98:6c:1b:ee:24:46:0c:17:b3:52:a5:db:a5:91:91:cf:37:
+ d3:6f:e7:27:08:3a:4e:19:1f:3a:a7:58:5c:17:cf:79:3f:8b:
+ e4:a7:d3:26:23:9d:26:0f:58:69:fc:47:7e:b2:d0:8d:8b:93:
+ bf:29:4f:43:69:74:76:67:4b:cf:07:8c:e6:02:f7:b5:e1:b4:
+ 43:b5:4b:2d:14:9f:f9:dc:26:0d:bf:a6:47:74:06:d8:88:d1:
+ 3a:29:30:84:ce:d2:39:80:62:1b:a8:c7:57:49:bc:6a:55:51:
+ 67:15:4a:be:35:07:e4:d5:75:98:37:79:30:14:db:29:9d:6c:
+ c5:69:cc:47:55:a2:30:f7:cc:5c:7f:c2:c3:98:1c:6b:4e:16:
+ 80:eb:7a:78:65:45:a2:00:1a:af:0c:0d:55:64:34:48:b8:92:
+ b9:f1:b4:50:29:f2:4f:23:1f:da:6c:ac:1f:44:e1:dd:23:78:
+ 51:5b:c7:16
+SHA1 Fingerprint=3A:44:73:5A:E5:81:90:1F:24:86:61:46:1E:3B:9C:C4:5F:F5:3A:1B
diff --git a/apex/ca-certificates/files/bf64f35b.0 b/apex/ca-certificates/files/bf64f35b.0
new file mode 100644
index 0000000..0a65290
--- /dev/null
+++ b/apex/ca-certificates/files/bf64f35b.0
@@ -0,0 +1,91 @@
+-----BEGIN CERTIFICATE-----
+MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC
+VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0
+Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW
+KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl
+cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw
+NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw
+NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy
+ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV
+BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo
+Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4
+4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9
+KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI
+rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi
+94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB
+sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi
+gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo
+kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE
+vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
+A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t
+O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua
+AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP
+9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/
+eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m
+0vdXcDazv/wor3ElhVsT/h5/WrQ8
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1164660820 (0x456b5054)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=US, O=Entrust, Inc., OU=www.entrust.net\/CPS is incorporated by reference, OU=(c) 2006 Entrust, Inc., CN=Entrust Root Certification Authority
+ Validity
+ Not Before: Nov 27 20:23:42 2006 GMT
+ Not After : Nov 27 20:53:42 2026 GMT
+ Subject: C=US, O=Entrust, Inc., OU=www.entrust.net\/CPS is incorporated by reference, OU=(c) 2006 Entrust, Inc., CN=Entrust Root Certification Authority
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b6:95:b6:43:42:fa:c6:6d:2a:6f:48:df:94:4c:
+ 39:57:05:ee:c3:79:11:41:68:36:ed:ec:fe:9a:01:
+ 8f:a1:38:28:fc:f7:10:46:66:2e:4d:1e:1a:b1:1a:
+ 4e:c6:d1:c0:95:88:b0:c9:ff:31:8b:33:03:db:b7:
+ 83:7b:3e:20:84:5e:ed:b2:56:28:a7:f8:e0:b9:40:
+ 71:37:c5:cb:47:0e:97:2a:68:c0:22:95:62:15:db:
+ 47:d9:f5:d0:2b:ff:82:4b:c9:ad:3e:de:4c:db:90:
+ 80:50:3f:09:8a:84:00:ec:30:0a:3d:18:cd:fb:fd:
+ 2a:59:9a:23:95:17:2c:45:9e:1f:6e:43:79:6d:0c:
+ 5c:98:fe:48:a7:c5:23:47:5c:5e:fd:6e:e7:1e:b4:
+ f6:68:45:d1:86:83:5b:a2:8a:8d:b1:e3:29:80:fe:
+ 25:71:88:ad:be:bc:8f:ac:52:96:4b:aa:51:8d:e4:
+ 13:31:19:e8:4e:4d:9f:db:ac:b3:6a:d5:bc:39:54:
+ 71:ca:7a:7a:7f:90:dd:7d:1d:80:d9:81:bb:59:26:
+ c2:11:fe:e6:93:e2:f7:80:e4:65:fb:34:37:0e:29:
+ 80:70:4d:af:38:86:2e:9e:7f:57:af:9e:17:ae:eb:
+ 1c:cb:28:21:5f:b6:1c:d8:e7:a2:04:22:f9:d3:da:
+ d8:cb
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Private Key Usage Period:
+ Not Before: Nov 27 20:23:42 2006 GMT, Not After: Nov 27 20:53:42 2026 GMT
+ X509v3 Authority Key Identifier:
+ 68:90:E4:67:A4:A6:53:80:C7:86:66:A4:F1:F7:4B:43:FB:84:BD:6D
+ X509v3 Subject Key Identifier:
+ 68:90:E4:67:A4:A6:53:80:C7:86:66:A4:F1:F7:4B:43:FB:84:BD:6D
+ 1.2.840.113533.7.65.0:
+ 0...V7.1:4.0....
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 93:d4:30:b0:d7:03:20:2a:d0:f9:63:e8:91:0c:05:20:a9:5f:
+ 19:ca:7b:72:4e:d4:b1:db:d0:96:fb:54:5a:19:2c:0c:08:f7:
+ b2:bc:85:a8:9d:7f:6d:3b:52:b3:2a:db:e7:d4:84:8c:63:f6:
+ 0f:cb:26:01:91:50:6c:f4:5f:14:e2:93:74:c0:13:9e:30:3a:
+ 50:e3:b4:60:c5:1c:f0:22:44:8d:71:47:ac:c8:1a:c9:e9:9b:
+ 9a:00:60:13:ff:70:7e:5f:11:4d:49:1b:b3:15:52:7b:c9:54:
+ da:bf:9d:95:af:6b:9a:d8:9e:e9:f1:e4:43:8d:e2:11:44:3a:
+ bf:af:bd:83:42:73:52:8b:aa:bb:a7:29:cf:f5:64:1c:0a:4d:
+ d1:bc:aa:ac:9f:2a:d0:ff:7f:7f:da:7d:ea:b1:ed:30:25:c1:
+ 84:da:34:d2:5b:78:83:56:ec:9c:36:c3:26:e2:11:f6:67:49:
+ 1d:92:ab:8c:fb:eb:ff:7a:ee:85:4a:a7:50:80:f0:a7:5c:4a:
+ 94:2e:5f:05:99:3c:52:41:e0:cd:b4:63:cf:01:43:ba:9c:83:
+ dc:8f:60:3b:f3:5a:b4:b4:7b:ae:da:0b:90:38:75:ef:81:1d:
+ 66:d2:f7:57:70:36:b3:bf:fc:28:af:71:25:85:5b:13:fe:1e:
+ 7f:5a:b4:3c
+SHA1 Fingerprint=B3:1E:B1:B7:40:E3:6C:84:02:DA:DC:37:D4:4D:F5:D4:67:49:52:F9
diff --git a/apex/ca-certificates/files/c44cc0c0.0 b/apex/ca-certificates/files/c44cc0c0.0
new file mode 100644
index 0000000..d155cf5
--- /dev/null
+++ b/apex/ca-certificates/files/c44cc0c0.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN
+MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT
+HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN
+NDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs
+IEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS87IE+
+ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG0
+2C+JFvuUAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgp
+wgscONyfMXdcvyej/Cestyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZM
+pG2T6T867jp8nVid9E6P/DsjyG244gXazOvswzH016cpVIDPRFtMbzCe88zdH5RD
+nU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnVDdXifBBiqmvwPXbzP6Po
+sMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9qTXeXAaDx
+Zre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cd
+Lvvyz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvX
+KyY//SovcfXWJL5/MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNe
+XoVPzthwiHvOAbWWl9fNff2C+MIkwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPL
+tgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4EFgQUUTMc7TZArxfTJc1paPKv
+TiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN
+AQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw
+GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7H
+PNtQOa27PShNlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLF
+O4uJ+DQtpBflF+aZfTCIITfNMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQ
+REtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/u4cnYiWB39yhL/btp/96j1EuMPik
+AdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9GOUrYU9DzLjtxpdRv
+/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh47a+
+p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw
+MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF
+qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK
+ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 08:f9:b4:78:a8:fa:7e:da:6a:33:37:89:de:7c:cf:8a
+ Signature Algorithm: sha384WithRSAEncryption
+ Issuer: C=US, O=DigiCert, Inc., CN=DigiCert TLS RSA4096 Root G5
+ Validity
+ Not Before: Jan 15 00:00:00 2021 GMT
+ Not After : Jan 14 23:59:59 2046 GMT
+ Subject: C=US, O=DigiCert, Inc., CN=DigiCert TLS RSA4096 Root G5
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:b3:d0:f4:c9:79:11:9d:fd:fc:66:81:e7:cc:d5:
+ e4:bc:ec:81:3e:6a:35:8e:2e:b7:e7:de:af:f9:07:
+ 4d:cf:30:9d:ea:09:0b:99:bd:6c:57:da:18:4a:b8:
+ 78:ac:3a:39:a8:a6:48:ac:2e:72:e5:bd:eb:f1:1a:
+ cd:e7:a4:03:a9:3f:11:b4:d8:2f:89:16:fb:94:01:
+ 3d:bb:2f:f8:13:05:a1:78:1c:8e:28:e0:45:e0:83:
+ f4:59:1b:95:b3:ae:7e:03:45:e5:be:c2:42:fe:ee:
+ f2:3c:b6:85:13:98:32:9d:16:a8:29:c2:0b:1c:38:
+ dc:9f:31:77:5c:bf:27:a3:fc:27:ac:b7:2b:bd:74:
+ 9b:17:2d:f2:81:da:5d:b0:e1:23:17:3e:88:4a:12:
+ 23:d0:ea:cf:9d:de:03:17:b1:42:4a:a0:16:4c:a4:
+ 6d:93:e9:3f:3a:ee:3a:7c:9d:58:9d:f4:4e:8f:fc:
+ 3b:23:c8:6d:b8:e2:05:da:cc:eb:ec:c3:31:f4:d7:
+ a7:29:54:80:cf:44:5b:4c:6f:30:9e:f3:cc:dd:1f:
+ 94:43:9d:4d:7f:70:70:0d:d4:3a:d1:37:f0:6c:9d:
+ 9b:c0:14:93:58:ef:cd:41:38:75:bc:13:03:95:7c:
+ 7f:e3:5c:e9:d5:0d:d5:e2:7c:10:62:aa:6b:f0:3d:
+ 76:f3:3f:a3:e8:b0:c1:fd:ef:aa:57:4d:ac:86:a7:
+ 18:b4:29:c1:2c:0e:bf:64:be:29:8c:d8:02:2d:cd:
+ 5c:2f:f2:7f:ef:15:f4:0c:15:ac:0a:b0:f1:d3:0d:
+ 4f:6a:4d:77:97:01:a0:f1:66:b7:b7:ce:ef:ce:ec:
+ ec:a5:75:ca:ac:e3:e1:63:f7:b8:a1:04:c8:bc:7b:
+ 3f:5d:2d:16:22:56:ed:48:49:fe:a7:2f:79:30:25:
+ 9b:ba:6b:2d:3f:9d:3b:c4:17:e7:1d:2e:fb:f2:cf:
+ a6:fc:e3:14:2c:96:98:21:8c:b4:91:e9:19:60:83:
+ f2:30:2b:06:73:50:d5:98:3b:06:e9:c7:8a:0c:60:
+ 8c:28:f8:52:9b:6e:e1:f6:4d:bb:06:24:9b:d7:2b:
+ 26:3f:fd:2a:2f:71:f5:d6:24:be:7f:31:9e:0f:6d:
+ e8:8f:4f:4d:a3:3f:ff:35:ea:df:49:5e:41:8f:86:
+ f9:f1:77:79:4b:1b:b4:a3:5e:2f:fb:46:02:d0:66:
+ 13:5e:5e:85:4f:ce:d8:70:88:7b:ce:01:b5:96:97:
+ d7:cd:7d:fd:82:f8:c2:24:c1:ca:01:39:4f:8d:a2:
+ c1:14:40:1f:9c:66:d5:0c:09:46:d6:f2:d0:d1:48:
+ 76:56:3a:43:cb:b6:0a:11:39:ba:8c:13:6c:06:b5:
+ 9e:cf:eb
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 51:33:1C:ED:36:40:AF:17:D3:25:CD:69:68:F2:AF:4E:23:3E:B3:41
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha384WithRSAEncryption
+ Signature Value:
+ 60:a6:af:5b:5f:57:da:89:db:4b:50:a9:c4:23:35:21:ff:d0:
+ 61:30:84:91:b7:3f:10:cf:25:8e:c9:bf:46:34:d9:c1:21:26:
+ 1c:70:19:72:1e:a3:c9:87:fe:a9:43:64:96:3a:c8:53:04:0a:
+ b6:41:bb:c4:47:00:d9:9f:18:18:3b:b2:0e:f3:34:ea:24:f7:
+ dd:af:20:60:ae:92:28:5f:36:e7:5d:e4:de:c7:3c:db:50:39:
+ ad:bb:3d:28:4d:96:7c:76:c6:5b:f4:c1:db:14:a5:ab:19:62:
+ 07:18:40:5f:97:91:dc:9c:c7:ab:b5:51:0d:e6:69:53:55:cc:
+ 39:7d:da:c5:11:55:72:c5:3b:8b:89:f8:34:2d:a4:17:e5:17:
+ e6:99:7d:30:88:21:37:cd:30:17:3d:b8:f2:bc:a8:75:a0:43:
+ dc:3e:89:4b:90:ae:6d:03:e0:1c:a3:a0:96:09:bb:7d:a3:b7:
+ 2a:10:44:4b:46:07:34:63:ed:31:b9:04:ee:a3:9b:9a:ae:e6:
+ 31:78:f4:ea:24:61:3b:ab:58:64:ff:bb:87:27:62:25:81:df:
+ dc:a1:2f:f6:ed:a7:ff:7a:8f:51:2e:30:f8:a4:01:d2:85:39:
+ 5f:01:99:96:6f:5a:5b:70:19:46:fe:86:60:3e:ad:80:10:09:
+ dd:39:25:2f:58:7f:bb:d2:74:f0:f7:46:1f:46:39:4a:d8:53:
+ d0:f3:2e:3b:71:a5:d4:6f:fc:f3:67:e4:07:8f:dd:26:19:e1:
+ 8d:5b:fa:a3:93:11:9b:e9:c8:3a:c3:55:68:9a:92:e1:52:76:
+ 38:e8:e1:ba:bd:fb:4f:d5:ef:b3:e7:48:83:31:f0:82:21:e3:
+ b6:be:a7:ab:6f:ef:9f:df:4c:cf:01:b8:62:6a:23:3d:e7:09:
+ 4d:80:1b:7b:30:a4:c3:dd:07:7f:34:be:a4:26:b2:f6:41:e8:
+ 09:1d:e3:20:98:aa:37:4f:ff:f7:f1:e2:29:70:31:47:3f:74:
+ d0:14:16:fa:21:8a:02:d5:8a:09:94:77:2e:f2:59:28:8b:7c:
+ 50:92:0a:66:78:38:83:75:c4:b5:5a:a8:11:c6:e5:c1:9d:66:
+ 55:cf:53:c4:af:d7:75:85:a9:42:13:56:ec:21:77:81:93:5a:
+ 0c:ea:96:d9:49:ca:a1:08:f2:97:3b:6d:9b:04:18:24:44:8e:
+ 7c:01:f2:dc:25:d8:5e:86:9a:b1:39:db:f5:91:32:6a:d1:a6:
+ 70:8a:a2:f7:de:a4:45:85:26:a8:1e:8c:5d:29:5b:c8:4b:d8:
+ 9a:6a:03:5e:70:f2:85:4f:6c:4b:68:2f:ca:54:f6:8c:da:32:
+ fe:c3:6b:83:3f:38:c6:7e
+SHA1 Fingerprint=A7:88:49:DC:5D:7C:75:8C:8C:DE:39:98:56:B3:AA:D0:B2:A5:71:35
diff --git a/apex/ca-certificates/files/c491639e.0 b/apex/ca-certificates/files/c491639e.0
new file mode 100644
index 0000000..b3f5d14
--- /dev/null
+++ b/apex/ca-certificates/files/c491639e.0
@@ -0,0 +1,55 @@
+-----BEGIN CERTIFICATE-----
+MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw
+CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
+ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg
+RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV
+UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu
+Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq
+hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf
+Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q
+RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
+BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD
+AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY
+JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv
+6pZjamVFkpUBtA==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 0b:a1:5a:fa:1d:df:a0:b5:49:44:af:cd:24:a0:6c:ec
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Assured ID Root G3
+ Validity
+ Not Before: Aug 1 12:00:00 2013 GMT
+ Not After : Jan 15 12:00:00 2038 GMT
+ Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Assured ID Root G3
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:19:e7:bc:ac:44:65:ed:cd:b8:3f:58:fb:8d:b1:
+ 57:a9:44:2d:05:15:f2:ef:0b:ff:10:74:9f:b5:62:
+ 52:5f:66:7e:1f:e5:dc:1b:45:79:0b:cc:c6:53:0a:
+ 9d:8d:5d:02:d9:a9:59:de:02:5a:f6:95:2a:0e:8d:
+ 38:4a:8a:49:c6:bc:c6:03:38:07:5f:55:da:7e:09:
+ 6e:e2:7f:5e:d0:45:20:0f:59:76:10:d6:a0:24:f0:
+ 2d:de:36:f2:6c:29:39
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ CB:D0:BD:A9:E1:98:05:51:A1:4D:37:A2:83:79:CE:8D:1D:2A:E4:84
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:64:02:30:25:a4:81:45:02:6b:12:4b:75:74:4f:c8:23:e3:
+ 70:f2:75:72:de:7c:89:f0:cf:91:72:61:9e:5e:10:92:59:56:
+ b9:83:c7:10:e7:38:e9:58:26:36:7d:d5:e4:34:86:39:02:30:
+ 7c:36:53:f0:30:e5:62:63:3a:99:e2:b6:a3:3b:9b:34:fa:1e:
+ da:10:92:71:5e:91:13:a7:dd:a4:6e:92:cc:32:d6:f5:21:66:
+ c7:2f:ea:96:63:6a:65:45:92:95:01:b4
+SHA1 Fingerprint=F5:17:A2:4F:9A:48:C6:C9:F8:A2:00:26:9F:DC:0F:48:2C:AB:30:89
diff --git a/apex/ca-certificates/files/c559d742.0 b/apex/ca-certificates/files/c559d742.0
new file mode 100644
index 0000000..31a2c06
--- /dev/null
+++ b/apex/ca-certificates/files/c559d742.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQsw
+CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
+MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
+MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
+Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3LvCvpt
+nfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY
+6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAu
+MC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7k
+RXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWg
+f9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1mKPV
++3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K8Yzo
+dDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW
+Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKa
+G73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCq
+gc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwID
+AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
+FgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBAB/Kzt3H
+vqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8
+0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyC
+B19m3H0Q/gxhswWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2u
+NmSRXbBoGOqKYcl3qJfEycel/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMg
+yALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVnjWQye+mew4K6Ki3pHrTgSAai/Gev
+HyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y59PYjJbigapordwj6
+xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M7YNR
+TOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924Sg
+JPFI/2R80L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV
+7LXTWtiBmelDGDfrs7vRWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl
+6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjWHYbL
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 02:03:e5:ae:c5:8d:04:25:1a:ab:11:25:aa
+ Signature Algorithm: sha384WithRSAEncryption
+ Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R2
+ Validity
+ Not Before: Jun 22 00:00:00 2016 GMT
+ Not After : Jun 22 00:00:00 2036 GMT
+ Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:ce:de:fd:a6:fb:ec:ec:14:34:3c:07:06:5a:6c:
+ 59:f7:19:35:dd:f7:c1:9d:55:aa:d3:cd:3b:a4:93:
+ 72:ef:0a:fa:6d:9d:f6:f0:85:80:5b:a1:48:52:9f:
+ 39:c5:b7:ee:28:ac:ef:cb:76:68:14:b9:df:ad:01:
+ 6c:99:1f:c4:22:1d:9f:fe:72:77:e0:2c:5b:af:e4:
+ 04:bf:4f:72:a0:1a:34:98:e8:39:68:ec:95:25:7b:
+ 76:a1:e6:69:b9:85:19:bd:89:8c:fe:ad:ed:36:ea:
+ 73:bc:ff:83:e2:cb:7d:c1:d2:ce:4a:b3:8d:05:9e:
+ 8b:49:93:df:c1:5b:d0:6e:5e:f0:2e:30:2e:82:fc:
+ fa:bc:b4:17:0a:48:e5:88:9b:c5:9b:6b:de:b0:ca:
+ b4:03:f0:da:f4:90:b8:65:64:f7:5c:4c:ad:e8:7e:
+ 66:5e:99:d7:b8:c2:3e:c8:d0:13:9d:ad:ee:e4:45:
+ 7b:89:55:f7:8a:1f:62:52:84:12:b3:c2:40:97:e3:
+ 8a:1f:47:91:a6:74:5a:d2:f8:b1:63:28:10:b8:b3:
+ 09:b8:56:77:40:a2:26:98:79:c6:fe:df:25:ee:3e:
+ e5:a0:7f:d4:61:0f:51:4b:3c:3f:8c:da:e1:70:74:
+ d8:c2:68:a1:f9:c1:0c:e9:a1:e2:7f:bb:55:3c:76:
+ 06:ee:6a:4e:cc:92:88:30:4d:9a:bd:4f:0b:48:9a:
+ 84:b5:98:a3:d5:fb:73:c1:57:61:dd:28:56:75:13:
+ ae:87:8e:e7:0c:51:09:10:75:88:4c:bc:8d:f9:7b:
+ 3c:d4:22:48:1f:2a:dc:eb:6b:bb:44:b1:cb:33:71:
+ 32:46:af:ad:4a:f1:8c:e8:74:3a:ac:e7:1a:22:73:
+ 80:d2:30:f7:25:42:c7:22:3b:3b:12:ad:96:2e:c6:
+ c3:76:07:aa:20:b7:35:49:57:e9:92:49:e8:76:16:
+ 72:31:67:2b:96:7e:8a:a3:c7:94:56:22:bf:6a:4b:
+ 7e:01:21:b2:23:32:df:e4:9a:44:6d:59:5b:5d:f5:
+ 00:a0:1c:9b:c6:78:97:8d:90:ff:9b:c8:aa:b4:af:
+ 11:51:39:5e:d9:fb:67:ad:d5:5b:11:9d:32:9a:1b:
+ bd:d5:ba:5b:a5:c9:cb:25:69:53:55:27:5c:e0:ca:
+ 36:cb:88:61:fb:1e:b7:d0:cb:ee:16:fb:d3:a6:4c:
+ de:92:a5:d4:e2:df:f5:06:54:de:2e:9d:4b:b4:93:
+ 30:aa:81:ce:dd:1a:dc:51:73:0d:4f:70:e9:e5:b6:
+ 16:21:19:79:b2:e6:89:0b:75:64:ca:d5:ab:bc:09:
+ c1:18:a1:ff:d4:54:a1:85:3c:fd:14:24:03:b2:87:
+ d3:a4:b7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ BB:FF:CA:8E:23:9F:4F:99:CA:DB:E2:68:A6:A5:15:27:17:1E:D9:0E
+ Signature Algorithm: sha384WithRSAEncryption
+ Signature Value:
+ 1f:ca:ce:dd:c7:be:a1:9f:d9:27:4c:0b:dc:17:98:11:6a:88:
+ de:3d:e6:71:56:72:b2:9e:1a:4e:9c:d5:2b:98:24:5d:9b:6b:
+ 7b:b0:33:82:09:bd:df:25:46:ea:98:9e:b6:1b:fe:83:3c:d2:
+ 62:61:c1:04:ed:ce:e0:c5:c9:c8:13:13:55:e7:a8:63:ad:8c:
+ 7b:01:fe:77:30:e1:ce:68:9b:05:f8:12:ee:79:31:a0:41:45:
+ 35:28:0a:71:a4:24:4f:8c:dc:3c:82:07:5f:66:dc:7d:10:fe:
+ 0c:61:b3:05:95:ee:e1:ae:81:0f:a8:f8:c7:8f:4d:a8:23:02:
+ 26:6b:1d:83:52:55:ce:b5:2f:00:ca:80:40:e0:e1:74:ac:60:
+ f5:87:80:9d:ae:36:64:91:5d:b0:68:18:ea:8a:61:c9:77:a8:
+ 97:c4:c9:c7:a5:fc:55:4b:f3:f0:7f:b9:65:3d:27:68:d0:cc:
+ 6b:fa:53:9d:e1:91:1a:c9:5d:1a:96:6d:32:87:ed:03:20:c8:
+ 02:ce:5a:be:d9:ea:fd:b2:4d:c4:2f:1b:df:5f:7a:f5:f8:8b:
+ c6:ee:31:3a:25:51:55:67:8d:64:32:7b:e9:9e:c3:82:ba:2a:
+ 2d:e9:1e:b4:e0:48:06:a2:fc:67:af:1f:22:02:73:fb:20:0a:
+ af:9d:54:4b:a1:cd:ff:60:47:b0:3f:5d:ef:1b:56:bd:97:21:
+ 96:2d:0a:d1:5e:9d:38:02:47:6c:b9:f4:f6:23:25:b8:a0:6a:
+ 9a:2b:77:08:fa:c4:b1:28:90:26:58:08:3c:e2:7e:aa:d7:3d:
+ 6f:ba:31:88:0a:05:eb:27:b5:a1:49:ee:a0:45:54:7b:e6:27:
+ 65:99:20:21:a8:a3:bc:fb:18:96:bb:52:6f:0c:ed:83:51:4c:
+ e9:59:e2:20:60:c5:c2:65:92:82:8c:f3:10:1f:0e:8a:97:be:
+ 77:82:6d:3f:8f:1d:5d:bc:49:27:bd:cc:4f:0f:e1:ce:76:86:
+ 04:23:c5:c0:8c:12:5b:fd:db:84:a0:24:f1:48:ff:64:7c:d0:
+ be:5c:16:d1:ef:99:ad:c0:1f:fb:cb:ae:bc:38:22:06:26:64:
+ da:da:97:0e:3f:28:15:44:a8:4f:00:ca:f0:9a:cc:cf:74:6a:
+ b4:3e:3c:eb:95:ec:b5:d3:5a:d8:81:99:e9:43:18:37:eb:b3:
+ bb:d1:58:62:41:f3:66:d2:8f:aa:78:95:54:20:c3:5a:2e:74:
+ 2b:d5:d1:be:18:69:c0:ac:d5:a4:cf:39:ba:51:84:03:65:e9:
+ 62:c0:62:fe:d8:4d:55:96:e2:d0:11:fa:48:34:11:ec:9e:ed:
+ 05:1d:e4:c8:d6:1d:86:cb
+SHA1 Fingerprint=9A:44:49:76:32:DB:DE:FA:D0:BC:FB:5A:7B:17:BD:9E:56:09:24:94
diff --git a/apex/ca-certificates/files/c7f1359b.0 b/apex/ca-certificates/files/c7f1359b.0
new file mode 100644
index 0000000..2f4dc2e
--- /dev/null
+++ b/apex/ca-certificates/files/c7f1359b.0
@@ -0,0 +1,54 @@
+-----BEGIN CERTIFICATE-----
+MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYT
+AkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYD
+VQQDEyJTZWN1cml0eSBDb21tdW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYx
+NjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTELMAkGA1UEBhMCSlAxJTAjBgNVBAoT
+HFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNVBAMTIlNlY3VyaXR5
+IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQAIgNi
+AASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+Cnnfdl
+dB9sELLo5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpK
+ULGjQjBAMB0GA1UdDgQWBBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu
+9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3LsnNdo4gIxwwCMQDAqy0O
+be0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70eN9k=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ d6:5d:9b:b3:78:81:2e:eb
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=JP, O=SECOM Trust Systems CO.,LTD., CN=Security Communication ECC RootCA1
+ Validity
+ Not Before: Jun 16 05:15:28 2016 GMT
+ Not After : Jan 18 05:15:28 2038 GMT
+ Subject: C=JP, O=SECOM Trust Systems CO.,LTD., CN=Security Communication ECC RootCA1
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:a4:a5:6f:60:03:03:c3:bd:31:f4:d3:17:9c:2b:
+ 84:75:ac:e5:fd:3d:57:6e:d7:63:bf:e6:04:89:92:
+ 8e:81:9c:e3:e9:47:6e:ca:90:12:c8:13:e0:a7:9d:
+ f7:65:74:1f:6c:10:b2:e8:e4:e9:ef:6d:85:32:99:
+ 44:b1:5e:fd:cc:76:10:d8:5b:bd:a2:c6:f9:d6:42:
+ e4:57:76:dc:90:c2:35:a9:4b:88:3c:12:47:6d:5c:
+ ff:49:4f:1a:4a:50:b1
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 86:1C:E7:FE:2D:A5:4A:8B:08:FE:28:11:FA:BE:A3:66:F8:60:59:2F
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:65:02:30:15:5d:42:3d:fc:b6:ee:f7:3b:b1:36:e8:9e:f6:
+ c4:46:28:49:33:d0:58:43:2a:63:29:cc:4d:b1:b4:7a:a2:b9:
+ 0d:38:a5:5d:48:2a:fd:cb:b2:73:5d:a3:88:08:c7:0c:02:31:
+ 00:c0:ab:2d:0e:6d:ed:18:a2:db:53:e9:25:db:55:08:e0:50:
+ cc:df:44:61:16:82:ab:49:b0:b2:81:ec:73:87:78:b4:4c:b2:
+ 62:1b:12:fa:16:4d:25:4b:63:bd:1e:37:d9
+SHA1 Fingerprint=B8:0E:26:A9:BF:D2:B2:3B:C0:EF:46:C9:BA:C7:BB:F6:1D:0D:41:41
diff --git a/apex/ca-certificates/files/c90bc37d.0 b/apex/ca-certificates/files/c90bc37d.0
new file mode 100644
index 0000000..91cfb41
--- /dev/null
+++ b/apex/ca-certificates/files/c90bc37d.0
@@ -0,0 +1,81 @@
+-----BEGIN CERTIFICATE-----
+MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
+MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
+b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI
+2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx
+1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ
+q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz
+tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ
+vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP
+BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV
+5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY
+1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4
+NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG
+Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91
+8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe
+pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
+MrY=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 03:3a:f1:e6:a7:11:a9:a0:bb:28:64:b1:1d:09:fa:e5
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G2
+ Validity
+ Not Before: Aug 1 12:00:00 2013 GMT
+ Not After : Jan 15 12:00:00 2038 GMT
+ Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:bb:37:cd:34:dc:7b:6b:c9:b2:68:90:ad:4a:75:
+ ff:46:ba:21:0a:08:8d:f5:19:54:c9:fb:88:db:f3:
+ ae:f2:3a:89:91:3c:7a:e6:ab:06:1a:6b:cf:ac:2d:
+ e8:5e:09:24:44:ba:62:9a:7e:d6:a3:a8:7e:e0:54:
+ 75:20:05:ac:50:b7:9c:63:1a:6c:30:dc:da:1f:19:
+ b1:d7:1e:de:fd:d7:e0:cb:94:83:37:ae:ec:1f:43:
+ 4e:dd:7b:2c:d2:bd:2e:a5:2f:e4:a9:b8:ad:3a:d4:
+ 99:a4:b6:25:e9:9b:6b:00:60:92:60:ff:4f:21:49:
+ 18:f7:67:90:ab:61:06:9c:8f:f2:ba:e9:b4:e9:92:
+ 32:6b:b5:f3:57:e8:5d:1b:cd:8c:1d:ab:95:04:95:
+ 49:f3:35:2d:96:e3:49:6d:dd:77:e3:fb:49:4b:b4:
+ ac:55:07:a9:8f:95:b3:b4:23:bb:4c:6d:45:f0:f6:
+ a9:b2:95:30:b4:fd:4c:55:8c:27:4a:57:14:7c:82:
+ 9d:cd:73:92:d3:16:4a:06:0c:8c:50:d1:8f:1e:09:
+ be:17:a1:e6:21:ca:fd:83:e5:10:bc:83:a5:0a:c4:
+ 67:28:f6:73:14:14:3d:46:76:c3:87:14:89:21:34:
+ 4d:af:0f:45:0c:a6:49:a1:ba:bb:9c:c5:b1:33:83:
+ 29:85
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 4E:22:54:20:18:95:E6:E3:6E:E6:0F:FA:FA:B9:12:ED:06:17:8F:39
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 60:67:28:94:6f:0e:48:63:eb:31:dd:ea:67:18:d5:89:7d:3c:
+ c5:8b:4a:7f:e9:be:db:2b:17:df:b0:5f:73:77:2a:32:13:39:
+ 81:67:42:84:23:f2:45:67:35:ec:88:bf:f8:8f:b0:61:0c:34:
+ a4:ae:20:4c:84:c6:db:f8:35:e1:76:d9:df:a6:42:bb:c7:44:
+ 08:86:7f:36:74:24:5a:da:6c:0d:14:59:35:bd:f2:49:dd:b6:
+ 1f:c9:b3:0d:47:2a:3d:99:2f:bb:5c:bb:b5:d4:20:e1:99:5f:
+ 53:46:15:db:68:9b:f0:f3:30:d5:3e:31:e2:8d:84:9e:e3:8a:
+ da:da:96:3e:35:13:a5:5f:f0:f9:70:50:70:47:41:11:57:19:
+ 4e:c0:8f:ae:06:c4:95:13:17:2f:1b:25:9f:75:f2:b1:8e:99:
+ a1:6f:13:b1:41:71:fe:88:2a:c8:4f:10:20:55:d7:f3:14:45:
+ e5:e0:44:f4:ea:87:95:32:93:0e:fe:53:46:fa:2c:9d:ff:8b:
+ 22:b9:4b:d9:09:45:a4:de:a4:b8:9a:58:dd:1b:7d:52:9f:8e:
+ 59:43:88:81:a4:9e:26:d5:6f:ad:dd:0d:c6:37:7d:ed:03:92:
+ 1b:e5:77:5f:76:ee:3c:8d:c4:5d:56:5b:a2:d9:66:6e:b3:35:
+ 37:e5:32:b6
+SHA1 Fingerprint=DF:3C:24:F9:BF:D6:66:76:1B:26:80:73:FE:06:D1:CC:8D:4F:82:A4
diff --git a/apex/ca-certificates/files/cb1c3204.0 b/apex/ca-certificates/files/cb1c3204.0
new file mode 100644
index 0000000..b14c8d2
--- /dev/null
+++ b/apex/ca-certificates/files/cb1c3204.0
@@ -0,0 +1,124 @@
+-----BEGIN CERTIFICATE-----
+MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB
+gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu
+QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG
+A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz
+OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ
+VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3
+b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA
+DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn
+0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB
+OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE
+fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E
+Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m
+o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i
+sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW
+OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez
+Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS
+adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n
+3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC
+AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ
+F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf
+CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29
+XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm
+djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/
+WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb
+AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq
+P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko
+b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj
+XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P
+5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi
+DrW5viSP
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 21:d6:d0:4a:4f:25:0f:c9:32:37:fc:aa:5e:12:8d:e9
+ Signature Algorithm: sha512WithRSAEncryption
+ Issuer: C=PL, O=Unizeto Technologies S.A., OU=Certum Certification Authority, CN=Certum Trusted Network CA 2
+ Validity
+ Not Before: Oct 6 08:39:56 2011 GMT
+ Not After : Oct 6 08:39:56 2046 GMT
+ Subject: C=PL, O=Unizeto Technologies S.A., OU=Certum Certification Authority, CN=Certum Trusted Network CA 2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:bd:f9:78:f8:e6:d5:80:0c:64:9d:86:1b:96:64:
+ 67:3f:22:3a:1e:75:01:7d:ef:fb:5c:67:8c:c9:cc:
+ 5c:6b:a9:91:e6:b9:42:e5:20:4b:9b:da:9b:7b:b9:
+ 99:5d:d9:9b:80:4b:d7:84:40:2b:27:d3:e8:ba:30:
+ bb:3e:09:1a:a7:49:95:ef:2b:40:24:c2:97:c7:a7:
+ ee:9b:25:ef:a8:0a:00:97:85:5a:aa:9d:dc:29:c9:
+ e2:35:07:eb:70:4d:4a:d6:c1:b3:56:b8:a1:41:38:
+ 9b:d1:fb:31:7f:8f:e0:5f:e1:b1:3f:0f:8e:16:49:
+ 60:d7:06:8d:18:f9:aa:26:10:ab:2a:d3:d0:d1:67:
+ 8d:1b:46:be:47:30:d5:2e:72:d1:c5:63:da:e7:63:
+ 79:44:7e:4b:63:24:89:86:2e:34:3f:29:4c:52:8b:
+ 2a:a7:c0:e2:91:28:89:b9:c0:5b:f9:1d:d9:e7:27:
+ ad:ff:9a:02:97:c1:c6:50:92:9b:02:2c:bd:a9:b9:
+ 34:59:0a:bf:84:4a:ff:df:fe:b3:9f:eb:d9:9e:e0:
+ 98:23:ec:a6:6b:77:16:2a:db:cc:ad:3b:1c:a4:87:
+ dc:46:73:5e:19:62:68:45:57:e4:90:82:42:bb:42:
+ d6:f0:61:e0:c1:a3:3d:66:a3:5d:f4:18:ee:88:c9:
+ 8d:17:45:29:99:32:75:02:31:ee:29:26:c8:6b:02:
+ e6:b5:62:45:7f:37:15:5a:23:68:89:d4:3e:de:4e:
+ 27:b0:f0:40:0c:bc:4d:17:cb:4d:a2:b3:1e:d0:06:
+ 5a:dd:f6:93:cf:57:75:99:f5:fa:86:1a:67:78:b3:
+ bf:96:fe:34:dc:bd:e7:52:56:e5:b3:e5:75:7b:d7:
+ 41:91:05:dc:5d:69:e3:95:0d:43:b9:fc:83:96:39:
+ 95:7b:6c:80:5a:4f:13:72:c6:d7:7d:29:7a:44:ba:
+ 52:a4:2a:d5:41:46:09:20:fe:22:a0:b6:5b:30:8d:
+ bc:89:0c:d5:d7:70:f8:87:52:fd:da:ef:ac:51:2e:
+ 07:b3:4e:fe:d0:09:da:70:ef:98:fa:56:e6:6d:db:
+ b5:57:4b:dc:e5:2c:25:15:c8:9e:2e:78:4e:f8:da:
+ 9c:9e:86:2c:ca:57:f3:1a:e5:c8:92:8b:1a:82:96:
+ 7a:c3:bc:50:12:69:d8:0e:5a:46:8b:3a:eb:26:fa:
+ 23:c9:b6:b0:81:be:42:00:a4:f8:d6:fe:30:2e:c7:
+ d2:46:f6:e5:8e:75:fd:f2:cc:b9:d0:87:5b:cc:06:
+ 10:60:bb:83:35:b7:5e:67:de:47:ec:99:48:f1:a4:
+ a1:15:fe:ad:8c:62:8e:39:55:4f:39:16:b9:b1:63:
+ 9d:ff:b7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ B6:A1:54:39:02:C3:A0:3F:8E:8A:BC:FA:D4:F8:1C:A6:D1:3A:0E:FD
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha512WithRSAEncryption
+ Signature Value:
+ 71:a5:0e:ce:e4:e9:bf:3f:38:d5:89:5a:c4:02:61:fb:4c:c5:
+ 14:17:2d:8b:4f:53:6b:10:17:fc:65:84:c7:10:49:90:de:db:
+ c7:26:93:88:26:6f:70:d6:02:5e:39:a0:f7:8f:ab:96:b5:a5:
+ 13:5c:81:14:6d:0e:81:82:11:1b:8a:4e:c6:4f:a5:dd:62:1e:
+ 44:df:09:59:f4:5b:77:0b:37:e9:8b:20:c6:f8:0a:4e:2e:58:
+ 1c:eb:33:d0:cf:86:60:c9:da:fb:80:2f:9e:4c:60:84:78:3d:
+ 21:64:d6:fb:41:1f:18:0f:e7:c9:75:71:bd:bd:5c:de:34:87:
+ 3e:41:b0:0e:f6:b9:d6:3f:09:13:96:14:2f:de:9a:1d:5a:b9:
+ 56:ce:35:3a:b0:5f:70:4d:5e:e3:29:f1:23:28:72:59:b6:ab:
+ c2:8c:66:26:1c:77:2c:26:76:35:8b:28:a7:69:a0:f9:3b:f5:
+ 23:dd:85:10:74:c9:90:03:56:91:e7:af:ba:47:d4:12:97:11:
+ 22:e3:a2:49:94:6c:e7:b7:94:4b:ba:2d:a4:da:33:8b:4c:a6:
+ 44:ff:5a:3c:c6:1d:64:d8:b5:31:e4:a6:3c:7a:a8:57:0b:db:
+ ed:61:1a:cb:f1:ce:73:77:63:a4:87:6f:4c:51:38:d6:e4:5f:
+ c7:9f:b6:81:2a:e4:85:48:79:58:5e:3b:f8:db:02:82:67:c1:
+ 39:db:c3:74:4b:3d:36:1e:f9:29:93:88:68:5b:a8:44:19:21:
+ f0:a7:e8:81:0d:2c:e8:93:36:b4:37:b2:ca:b0:1b:26:7a:9a:
+ 25:1f:9a:9a:80:9e:4b:2a:3f:fb:a3:9a:fe:73:32:71:c2:9e:
+ c6:72:e1:8a:68:27:f1:e4:0f:b4:c4:4c:a5:61:93:f8:97:10:
+ 07:2a:30:25:a9:b9:c8:71:b8:ef:68:cc:2d:7e:f5:e0:7e:0f:
+ 82:a8:6f:b6:ba:6c:83:43:77:cd:8a:92:17:a1:9e:5b:78:16:
+ 3d:45:e2:33:72:dd:e1:66:ca:99:d3:c9:c5:26:fd:0d:68:04:
+ 46:ae:b6:d9:9b:8c:be:19:be:b1:c6:f2:19:e3:5c:02:ca:2c:
+ d8:6f:4a:07:d9:c9:35:da:40:75:f2:c4:a7:19:6f:9e:42:10:
+ 98:75:e6:95:8b:60:bc:ed:c5:12:d7:8a:ce:d5:98:5c:56:96:
+ 03:c5:ee:77:06:35:ff:cf:e4:ee:3f:13:61:ee:db:da:2d:85:
+ f0:cd:ae:9d:b2:18:09:45:c3:92:a1:72:17:fc:47:b6:a0:0b:
+ 2c:f1:c4:de:43:68:08:6a:5f:3b:f0:76:63:fb:cc:06:2c:a6:
+ c6:e2:0e:b5:b9:be:24:8f
+SHA1 Fingerprint=D3:DD:48:3E:2B:BF:4C:05:E8:AF:10:F5:FA:76:26:CF:D3:DC:30:92
diff --git a/apex/ca-certificates/files/ccc52f49.0 b/apex/ca-certificates/files/ccc52f49.0
new file mode 100644
index 0000000..a171f2e
--- /dev/null
+++ b/apex/ca-certificates/files/ccc52f49.0
@@ -0,0 +1,52 @@
+-----BEGIN CERTIFICATE-----
+MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC
+VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ
+cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ
+BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt
+VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D
+0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9
+ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G
+A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G
+A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs
+aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I
+flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 8401224907861490260 (0x7497258ac73f7a54)
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=US, O=AffirmTrust, CN=AffirmTrust Premium ECC
+ Validity
+ Not Before: Jan 29 14:20:24 2010 GMT
+ Not After : Dec 31 14:20:24 2040 GMT
+ Subject: C=US, O=AffirmTrust, CN=AffirmTrust Premium ECC
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:0d:30:5e:1b:15:9d:03:d0:a1:79:35:b7:3a:3c:
+ 92:7a:ca:15:1c:cd:62:f3:9c:26:5c:07:3d:e5:54:
+ fa:a3:d6:cc:12:ea:f4:14:5f:e8:8e:19:ab:2f:2e:
+ 48:e6:ac:18:43:78:ac:d0:37:c3:bd:b2:cd:2c:e6:
+ 47:e2:1a:e6:63:b8:3d:2e:2f:78:c4:4f:db:f4:0f:
+ a4:68:4c:55:72:6b:95:1d:4e:18:42:95:78:cc:37:
+ 3c:91:e2:9b:65:2b:29
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 9A:AF:29:7A:C0:11:35:35:26:51:30:00:C3:6A:FE:40:D5:AE:D6:3C
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:64:02:30:17:09:f3:87:88:50:5a:af:c8:c0:42:bf:47:5f:
+ f5:6c:6a:86:e0:c4:27:74:e4:38:53:d7:05:7f:1b:34:e3:c6:
+ 2f:b3:ca:09:3c:37:9d:d7:e7:b8:46:f1:fd:a1:e2:71:02:30:
+ 42:59:87:43:d4:51:df:ba:d3:09:32:5a:ce:88:7e:57:3d:9c:
+ 5f:42:6b:f5:07:2d:b5:f0:82:93:f9:59:6f:ae:64:fa:58:e5:
+ 8b:1e:e3:63:be:b5:81:cd:6f:02:8c:79
+SHA1 Fingerprint=B8:23:6B:00:2F:1D:16:86:53:01:55:6C:11:A4:37:CA:EB:FF:C3:BB
diff --git a/apex/ca-certificates/files/cf701eeb.0 b/apex/ca-certificates/files/cf701eeb.0
new file mode 100644
index 0000000..7569699
--- /dev/null
+++ b/apex/ca-certificates/files/cf701eeb.0
@@ -0,0 +1,88 @@
+-----BEGIN CERTIFICATE-----
+MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI
+MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x
+FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz
+MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv
+cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz
+Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO
+0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao
+wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj
+7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS
+8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT
+BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
+/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg
+JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC
+NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3
+6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/
+3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm
+D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS
+CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
+3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 0c:f0:8e:5c:08:16:a5:ad:42:7f:f0:eb:27:18:59:d0
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=US, O=SecureTrust Corporation, CN=SecureTrust CA
+ Validity
+ Not Before: Nov 7 19:31:18 2006 GMT
+ Not After : Dec 31 19:40:55 2029 GMT
+ Subject: C=US, O=SecureTrust Corporation, CN=SecureTrust CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:ab:a4:81:e5:95:cd:f5:f6:14:8e:c2:4f:ca:d4:
+ e2:78:95:58:9c:41:e1:0d:99:40:24:17:39:91:33:
+ 66:e9:be:e1:83:af:62:5c:89:d1:fc:24:5b:61:b3:
+ e0:11:11:41:1c:1d:6e:f0:b8:bb:f8:de:a7:81:ba:
+ a6:48:c6:9f:1d:bd:be:8e:a9:41:3e:b8:94:ed:29:
+ 1a:d4:8e:d2:03:1d:03:ef:6d:0d:67:1c:57:d7:06:
+ ad:ca:c8:f5:fe:0e:af:66:25:48:04:96:0b:5d:a3:
+ ba:16:c3:08:4f:d1:46:f8:14:5c:f2:c8:5e:01:99:
+ 6d:fd:88:cc:86:a8:c1:6f:31:42:6c:52:3e:68:cb:
+ f3:19:34:df:bb:87:18:56:80:26:c4:d0:dc:c0:6f:
+ df:de:a0:c2:91:16:a0:64:11:4b:44:bc:1e:f6:e7:
+ fa:63:de:66:ac:76:a4:71:a3:ec:36:94:68:7a:77:
+ a4:b1:e7:0e:2f:81:7a:e2:b5:72:86:ef:a2:6b:8b:
+ f0:0f:db:d3:59:3f:ba:72:bc:44:24:9c:e3:73:b3:
+ f7:af:57:2f:42:26:9d:a9:74:ba:00:52:f2:4b:cd:
+ 53:7c:47:0b:36:85:0e:66:a9:08:97:16:34:57:c1:
+ 66:f7:80:e3:ed:70:54:c7:93:e0:2e:28:15:59:87:
+ ba:bb
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ 1.3.6.1.4.1.311.20.2:
+ ...C.A
+ X509v3 Key Usage:
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 42:32:B6:16:FA:04:FD:FE:5D:4B:7A:C3:FD:F7:4C:40:1D:5A:43:AF
+ X509v3 CRL Distribution Points:
+ Full Name:
+ URI:http://crl.securetrust.com/STCA.crl
+ 1.3.6.1.4.1.311.21.1:
+ ...
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 30:ed:4f:4a:e1:58:3a:52:72:5b:b5:a6:a3:65:18:a6:bb:51:
+ 3b:77:e9:9d:ea:d3:9f:5c:e0:45:65:7b:0d:ca:5b:e2:70:50:
+ b2:94:05:14:ae:49:c7:8d:41:07:12:73:94:7e:0c:23:21:fd:
+ bc:10:7f:60:10:5a:72:f5:98:0e:ac:ec:b9:7f:dd:7a:6f:5d:
+ d3:1c:f4:ff:88:05:69:42:a9:05:71:c8:b7:ac:26:e8:2e:b4:
+ 8c:6a:ff:71:dc:b8:b1:df:99:bc:7c:21:54:2b:e4:58:a2:bb:
+ 57:29:ae:9e:a9:a3:19:26:0f:99:2e:08:b0:ef:fd:69:cf:99:
+ 1a:09:8d:e3:a7:9f:2b:c9:36:34:7b:24:b3:78:4c:95:17:a4:
+ 06:26:1e:b6:64:52:36:5f:60:67:d9:9c:c5:05:74:0b:e7:67:
+ 23:d2:08:fc:88:e9:ae:8b:7f:e1:30:f4:37:7e:fd:c6:32:da:
+ 2d:9e:44:30:30:6c:ee:07:de:d2:34:fc:d2:ff:40:f6:4b:f4:
+ 66:46:06:54:a6:f2:32:0a:63:26:30:6b:9b:d1:dc:8b:47:ba:
+ e1:b9:d5:62:d0:a2:a0:f4:67:05:78:29:63:1a:6f:04:d6:f8:
+ c6:4c:a3:9a:b1:37:b4:8d:e5:28:4b:1d:9e:2c:c2:b8:68:bc:
+ ed:02:ee:31
+SHA1 Fingerprint=87:82:C6:C3:04:35:3B:CF:D2:96:92:D2:59:3E:7D:44:D9:34:FF:11
diff --git a/apex/ca-certificates/files/d06393bb.0 b/apex/ca-certificates/files/d06393bb.0
new file mode 100644
index 0000000..45fcc07
--- /dev/null
+++ b/apex/ca-certificates/files/d06393bb.0
@@ -0,0 +1,81 @@
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx
+KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd
+BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl
+YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1
+OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy
+aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50
+ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd
+AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC
+FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi
+1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq
+jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ
+wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj
+QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/
+WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy
+NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC
+uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw
+IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6
+g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN
+9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP
+BSeOE6Fuwg==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=DE, O=T-Systems Enterprise Services GmbH, OU=T-Systems Trust Center, CN=T-TeleSec GlobalRoot Class 2
+ Validity
+ Not Before: Oct 1 10:40:14 2008 GMT
+ Not After : Oct 1 23:59:59 2033 GMT
+ Subject: C=DE, O=T-Systems Enterprise Services GmbH, OU=T-Systems Trust Center, CN=T-TeleSec GlobalRoot Class 2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:aa:5f:da:1b:5f:e8:73:91:e5:da:5c:f4:a2:e6:
+ 47:e5:f3:68:55:60:05:1d:02:a4:b3:9b:59:f3:1e:
+ 8a:af:34:ad:fc:0d:c2:d9:48:19:ee:69:8f:c9:20:
+ fc:21:aa:07:19:ed:b0:5c:ac:65:c7:5f:ed:02:7c:
+ 7b:7c:2d:1b:d6:ba:b9:80:c2:18:82:16:84:fa:66:
+ b0:08:c6:54:23:81:e4:cd:b9:49:3f:f6:4f:6e:37:
+ 48:28:38:0f:c5:be:e7:68:70:fd:39:97:4d:d2:c7:
+ 98:91:50:aa:c4:44:b3:23:7d:39:47:e9:52:62:d6:
+ 12:93:5e:b7:31:96:42:05:fb:76:a7:1e:a3:f5:c2:
+ fc:e9:7a:c5:6c:a9:71:4f:ea:cb:78:bc:60:af:c7:
+ de:f4:d9:cb:be:7e:33:a5:6e:94:83:f0:34:fa:21:
+ ab:ea:8e:72:a0:3f:a4:de:30:5b:ef:86:4d:6a:95:
+ 5b:43:44:a8:10:15:1c:e5:01:57:c5:98:f1:e6:06:
+ 28:91:aa:20:c5:b7:53:26:51:43:b2:0b:11:95:58:
+ e1:c0:0f:76:d9:c0:8d:7c:81:f3:72:70:9e:6f:fe:
+ 1a:8e:d9:5f:35:c6:b2:6f:34:7c:be:48:4f:e2:5a:
+ 39:d7:d8:9d:78:9e:9f:86:3e:03:5e:19:8b:44:a2:
+ d5:c7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ BF:59:20:36:00:79:A0:A0:22:6B:8C:D5:F2:61:D2:B8:2C:CB:82:4A
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 31:03:a2:61:0b:1f:74:e8:72:36:c6:6d:f9:4d:9e:fa:22:a8:
+ e1:81:56:cf:cd:bb:9f:ea:ab:91:19:38:af:aa:7c:15:4d:f3:
+ b6:a3:8d:a5:f4:8e:f6:44:a9:a7:e8:21:95:ad:3e:00:62:16:
+ 88:f0:02:ba:fc:61:23:e6:33:9b:30:7a:6b:36:62:7b:ad:04:
+ 23:84:58:65:e2:db:2b:8a:e7:25:53:37:62:53:5f:bc:da:01:
+ 62:29:a2:a6:27:71:e6:3a:22:7e:c1:6f:1d:95:70:20:4a:07:
+ 34:df:ea:ff:15:80:e5:ba:d7:7a:d8:5b:75:7c:05:7a:29:47:
+ 7e:40:a8:31:13:77:cd:40:3b:b4:51:47:7a:2e:11:e3:47:11:
+ de:9d:66:d0:8b:d5:54:66:fa:83:55:ea:7c:c2:29:89:1b:e9:
+ 6f:b3:ce:e2:05:84:c9:2f:3e:78:85:62:6e:c9:5f:c1:78:63:
+ 74:58:c0:48:18:0c:99:39:eb:a4:cc:1a:b5:79:5a:8d:15:9c:
+ d8:14:0d:f6:7a:07:57:c7:22:83:05:2d:3c:9b:25:26:3d:18:
+ b3:a9:43:7c:c8:c8:ab:64:8f:0e:a3:bf:9c:1b:9d:30:db:da:
+ d0:19:2e:aa:3c:f1:fb:33:80:76:e4:cd:ad:19:4f:05:27:8e:
+ 13:a1:6e:c2
+SHA1 Fingerprint=59:0D:2D:7D:88:4F:40:2E:61:7E:A5:62:32:17:65:CF:17:D8:94:E9
diff --git a/apex/ca-certificates/files/d16a5865.0 b/apex/ca-certificates/files/d16a5865.0
new file mode 100644
index 0000000..be02f3d
--- /dev/null
+++ b/apex/ca-certificates/files/d16a5865.0
@@ -0,0 +1,129 @@
+-----BEGIN CERTIFICATE-----
+MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE
+BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h
+cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy
+MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg
+Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9
+thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM
+cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG
+L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i
+NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h
+X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b
+m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy
+Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja
+EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T
+KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF
+6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh
+OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD
+VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD
+VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp
+cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv
+ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl
+AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF
+661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9
+am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1
+ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481
+PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS
+3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k
+SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF
+3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM
+ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g
+StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz
+Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB
+jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 6047274297262753887 (0x53ec3beefbb2485f)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=ES, CN=Autoridad de Certificacion Firmaprofesional CIF A62634068
+ Validity
+ Not Before: May 20 08:38:15 2009 GMT
+ Not After : Dec 31 08:38:15 2030 GMT
+ Subject: C=ES, CN=Autoridad de Certificacion Firmaprofesional CIF A62634068
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:ca:96:6b:8e:ea:f8:fb:f1:a2:35:e0:7f:4c:da:
+ e0:c3:52:d7:7d:b6:10:c8:02:5e:b3:43:2a:c4:4f:
+ 6a:b2:ca:1c:5d:28:9a:78:11:1a:69:59:57:af:b5:
+ 20:42:e4:8b:0f:e6:df:5b:a6:03:92:2f:f5:11:e4:
+ 62:d7:32:71:38:d9:04:0c:71:ab:3d:51:7e:0f:07:
+ df:63:05:5c:e9:bf:94:6f:c1:29:82:c0:b4:da:51:
+ b0:c1:3c:bb:ad:37:4a:5c:ca:f1:4b:36:0e:24:ab:
+ bf:c3:84:77:fd:a8:50:f4:b1:e7:c6:2f:d2:2d:59:
+ 8d:7a:0a:4e:96:69:52:02:aa:36:98:ec:fc:fa:14:
+ 83:0c:37:1f:c9:92:37:7f:d7:81:2d:e5:c4:b9:e0:
+ 3e:34:fe:67:f4:3e:66:d1:d3:f4:40:cf:5e:62:34:
+ 0f:70:06:3e:20:18:5a:ce:f7:72:1b:25:6c:93:74:
+ 14:93:a3:73:b1:0e:aa:87:10:23:59:5f:20:05:19:
+ 47:ed:68:8e:92:12:ca:5d:fc:d6:2b:b2:92:3c:20:
+ cf:e1:5f:af:20:be:a0:76:7f:76:e5:ec:1a:86:61:
+ 33:3e:e7:7b:b4:3f:a0:0f:8e:a2:b9:6a:6f:b9:87:
+ 26:6f:41:6c:88:a6:50:fd:6a:63:0b:f5:93:16:1b:
+ 19:8f:b2:ed:9b:9b:c9:90:f5:01:0c:df:19:3d:0f:
+ 3e:38:23:c9:2f:8f:0c:d1:02:fe:1b:55:d6:4e:d0:
+ 8d:3c:af:4f:a4:f3:fe:af:2a:d3:05:9d:79:08:a1:
+ cb:57:31:b4:9c:c8:90:b2:67:f4:18:16:93:3a:fc:
+ 47:d8:d1:78:96:31:1f:ba:2b:0c:5f:5d:99:ad:63:
+ 89:5a:24:20:76:d8:df:fd:ab:4e:a6:22:aa:9d:5e:
+ e6:27:8a:7d:68:29:a3:e7:8a:b8:da:11:bb:17:2d:
+ 99:9d:13:24:46:f7:c5:e2:d8:9f:8e:7f:c7:8f:74:
+ 6d:5a:b2:e8:72:f5:ac:ee:24:10:ad:2f:14:da:ff:
+ 2d:9a:46:71:47:be:42:df:bb:01:db:f4:7f:d3:28:
+ 8f:31:59:5b:d3:c9:02:a6:b4:52:ca:6e:97:fb:43:
+ c5:08:26:6f:8a:f4:bb:fd:9f:28:aa:0d:d5:45:f3:
+ 13:3a:1d:d8:c0:78:8f:41:67:3c:1e:94:64:ae:7b:
+ 0b:c5:e8:d9:01:88:39:1a:97:86:64:41:d5:3b:87:
+ 0c:6e:fa:0f:c6:bd:48:14:bf:39:4d:d4:9e:41:b6:
+ 8f:96:1d:63:96:93:d9:95:06:78:31:68:9e:37:06:
+ 3b:80:89:45:61:39:23:c7:1b:44:a3:15:e5:1c:f8:
+ 92:30:bb
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE, pathlen:1
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 65:CD:EB:AB:35:1E:00:3E:7E:D5:74:C0:1C:B4:73:47:0E:1A:64:2F
+ X509v3 Certificate Policies:
+ Policy: X509v3 Any Policy
+ CPS: http://www.firmaprofesional.com/cps
+ User Notice:
+ Explicit Text:
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 17:7d:a0:f9:b4:dd:c5:c5:eb:ad:4b:24:b5:a1:02:ab:dd:a5:
+ 88:4a:b2:0f:55:4b:2b:57:8c:3b:e5:31:dd:fe:c4:32:f1:e7:
+ 5b:64:96:36:32:18:ec:a5:32:77:d7:e3:44:b6:c0:11:2a:80:
+ b9:3d:6a:6e:7c:9b:d3:ad:fc:c3:d6:a3:e6:64:29:7c:d1:e1:
+ 38:1e:82:2b:ff:27:65:af:fb:16:15:c4:2e:71:84:e5:b5:ff:
+ fa:a4:47:bd:64:32:bb:f6:25:84:a2:27:42:f5:20:b0:c2:13:
+ 10:11:cd:10:15:ba:42:90:2a:d2:44:e1:96:26:eb:31:48:12:
+ fd:2a:da:c9:06:cf:74:1e:a9:4b:d5:87:28:f9:79:34:92:3e:
+ 2e:44:e8:f6:8f:4f:8f:35:3f:25:b3:39:dc:63:2a:90:6b:20:
+ 5f:c4:52:12:4e:97:2c:2a:ac:9d:97:de:48:f2:a3:66:db:c2:
+ d2:83:95:a6:66:a7:9e:25:0f:e9:0b:33:91:65:0a:5a:c3:d9:
+ 54:12:dd:af:c3:4e:0e:1f:26:5e:0d:dc:b3:8d:ec:d5:81:70:
+ de:d2:4f:24:05:f3:6c:4e:f5:4c:49:66:8d:d1:ff:d2:0b:25:
+ 41:48:fe:51:84:c6:42:af:80:04:cf:d0:7e:64:49:e4:f2:df:
+ a2:ec:b1:4c:c0:2a:1d:e7:b4:b1:65:a2:c4:bc:f1:98:f4:aa:
+ 70:07:63:b4:b8:da:3b:4c:fa:40:22:30:5b:11:a6:f0:05:0e:
+ c6:02:03:48:ab:86:9b:85:dd:db:dd:ea:a2:76:80:73:7d:f5:
+ 9c:04:c4:45:8d:e7:b9:1c:8b:9e:ea:d7:75:d1:72:b1:de:75:
+ 44:e7:42:7d:e2:57:6b:7d:dc:99:bc:3d:83:28:ea:80:93:8d:
+ c5:4c:65:c1:70:81:b8:38:fc:43:31:b2:f6:03:34:47:b2:ac:
+ fb:22:06:cb:1e:dd:17:47:1c:5f:66:b9:d3:1a:a2:da:11:b1:
+ a4:bc:23:c9:e4:be:87:ff:b9:94:b6:f8:5d:20:4a:d4:5f:e7:
+ bd:68:7b:65:f2:15:1e:d2:3a:a9:2d:e9:d8:6b:24:ac:97:58:
+ 44:47:ad:59:18:f1:21:65:70:de:ce:34:60:a8:40:f1:f3:3c:
+ a4:c3:28:23:8c:fe:27:33:43:40:a0:17:3c:eb:ea:3b:b0:72:
+ a6:a3:b9:4a:4b:5e:16:48:f4:b2:bc:c8:8c:92:c5:9d:9f:ac:
+ 72:36:bc:34:80:34:6b:a9:8b:92:c0:b8:17:ed:ec:76:53:f5:
+ 24:01:8c:b3:22:e8:4b:7c:55:c6:9d:fa:a3:14:bb:65:85:6e:
+ 6e:4f:12:7e:0a:3c:9d:95
+SHA1 Fingerprint=AE:C5:FB:3F:C8:E1:BF:C4:E5:4F:03:07:5A:9A:E8:00:B7:F7:B6:FA
diff --git a/apex/ca-certificates/files/d16a5865.1 b/apex/ca-certificates/files/d16a5865.1
new file mode 100644
index 0000000..a81824c
--- /dev/null
+++ b/apex/ca-certificates/files/d16a5865.1
@@ -0,0 +1,129 @@
+-----BEGIN CERTIFICATE-----
+MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE
+BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h
+cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1
+MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg
+Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9
+thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM
+cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG
+L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i
+NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h
+X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b
+m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy
+Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja
+EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T
+KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF
+6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh
+OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1UdDgQWBBRlzeurNR4APn7VdMAc
+tHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4wgZswgZgGBFUd
+IAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j
+b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABC
+AG8AbgBhAG4AbwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAw
+ADEANzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9m
+iWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL4QjbEwj4KKE1soCzC1HA01aajTNF
+Sa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDbLIpgD7dvlAceHabJ
+hfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1ilI45P
+Vf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZE
+EAEeiGaPcjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV
+1aUsIC+nmCjuRfzxuIgALI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2t
+CsvMo2ebKHTEm9caPARYpoKdrcd7b/+Alun4jWq9GJAd/0kakFI3ky88Al2CdgtR
+5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH9IBk9W6VULgRfhVwOEqw
+f9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpfNIbnYrX9
+ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK
+GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1977337328857672817 (0x1b70e9d2ffae6c71)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=ES, CN=Autoridad de Certificacion Firmaprofesional CIF A62634068
+ Validity
+ Not Before: Sep 23 15:22:07 2014 GMT
+ Not After : May 5 15:22:07 2036 GMT
+ Subject: C=ES, CN=Autoridad de Certificacion Firmaprofesional CIF A62634068
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:ca:96:6b:8e:ea:f8:fb:f1:a2:35:e0:7f:4c:da:
+ e0:c3:52:d7:7d:b6:10:c8:02:5e:b3:43:2a:c4:4f:
+ 6a:b2:ca:1c:5d:28:9a:78:11:1a:69:59:57:af:b5:
+ 20:42:e4:8b:0f:e6:df:5b:a6:03:92:2f:f5:11:e4:
+ 62:d7:32:71:38:d9:04:0c:71:ab:3d:51:7e:0f:07:
+ df:63:05:5c:e9:bf:94:6f:c1:29:82:c0:b4:da:51:
+ b0:c1:3c:bb:ad:37:4a:5c:ca:f1:4b:36:0e:24:ab:
+ bf:c3:84:77:fd:a8:50:f4:b1:e7:c6:2f:d2:2d:59:
+ 8d:7a:0a:4e:96:69:52:02:aa:36:98:ec:fc:fa:14:
+ 83:0c:37:1f:c9:92:37:7f:d7:81:2d:e5:c4:b9:e0:
+ 3e:34:fe:67:f4:3e:66:d1:d3:f4:40:cf:5e:62:34:
+ 0f:70:06:3e:20:18:5a:ce:f7:72:1b:25:6c:93:74:
+ 14:93:a3:73:b1:0e:aa:87:10:23:59:5f:20:05:19:
+ 47:ed:68:8e:92:12:ca:5d:fc:d6:2b:b2:92:3c:20:
+ cf:e1:5f:af:20:be:a0:76:7f:76:e5:ec:1a:86:61:
+ 33:3e:e7:7b:b4:3f:a0:0f:8e:a2:b9:6a:6f:b9:87:
+ 26:6f:41:6c:88:a6:50:fd:6a:63:0b:f5:93:16:1b:
+ 19:8f:b2:ed:9b:9b:c9:90:f5:01:0c:df:19:3d:0f:
+ 3e:38:23:c9:2f:8f:0c:d1:02:fe:1b:55:d6:4e:d0:
+ 8d:3c:af:4f:a4:f3:fe:af:2a:d3:05:9d:79:08:a1:
+ cb:57:31:b4:9c:c8:90:b2:67:f4:18:16:93:3a:fc:
+ 47:d8:d1:78:96:31:1f:ba:2b:0c:5f:5d:99:ad:63:
+ 89:5a:24:20:76:d8:df:fd:ab:4e:a6:22:aa:9d:5e:
+ e6:27:8a:7d:68:29:a3:e7:8a:b8:da:11:bb:17:2d:
+ 99:9d:13:24:46:f7:c5:e2:d8:9f:8e:7f:c7:8f:74:
+ 6d:5a:b2:e8:72:f5:ac:ee:24:10:ad:2f:14:da:ff:
+ 2d:9a:46:71:47:be:42:df:bb:01:db:f4:7f:d3:28:
+ 8f:31:59:5b:d3:c9:02:a6:b4:52:ca:6e:97:fb:43:
+ c5:08:26:6f:8a:f4:bb:fd:9f:28:aa:0d:d5:45:f3:
+ 13:3a:1d:d8:c0:78:8f:41:67:3c:1e:94:64:ae:7b:
+ 0b:c5:e8:d9:01:88:39:1a:97:86:64:41:d5:3b:87:
+ 0c:6e:fa:0f:c6:bd:48:14:bf:39:4d:d4:9e:41:b6:
+ 8f:96:1d:63:96:93:d9:95:06:78:31:68:9e:37:06:
+ 3b:80:89:45:61:39:23:c7:1b:44:a3:15:e5:1c:f8:
+ 92:30:bb
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 65:CD:EB:AB:35:1E:00:3E:7E:D5:74:C0:1C:B4:73:47:0E:1A:64:2F
+ X509v3 Basic Constraints: critical
+ CA:TRUE, pathlen:1
+ X509v3 Certificate Policies:
+ Policy: X509v3 Any Policy
+ CPS: http://www.firmaprofesional.com/cps
+ User Notice:
+ Explicit Text:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 74:87:28:02:2b:77:1f:66:89:64:ed:8f:74:2e:46:1c:bb:a8:
+ f8:f8:0b:1d:83:b6:3a:a7:e8:45:8a:07:b7:e0:3e:20:cb:e1:
+ 08:db:13:08:f8:28:a1:35:b2:80:b3:0b:51:c0:d3:56:9a:8d:
+ 33:45:49:af:49:f0:e0:3d:07:7a:45:13:5a:ff:c8:97:d8:d3:
+ 18:2c:7d:96:f8:dd:a2:65:43:70:93:90:15:ba:90:df:e8:19:
+ b0:db:2c:8a:60:0f:b7:6f:94:07:1e:1d:a6:c9:85:f6:bd:34:
+ f8:40:78:62:10:70:3a:be:7d:4b:39:81:a9:10:d4:96:41:bb:
+ f8:5f:1c:0b:1d:08:f2:b1:b0:89:7a:f2:f7:a0:e0:c4:8f:8b:
+ 78:b5:3b:58:a5:23:8e:4f:55:fe:36:3b:e0:0c:b7:ca:2a:30:
+ 41:20:b4:80:cd:ae:fc:76:66:73:a8:ae:6e:e1:7c:da:03:e8:
+ 94:20:e6:22:a3:d0:1f:90:5d:20:53:14:26:57:da:54:97:df:
+ 16:44:10:01:1e:88:66:8f:72:38:93:dd:20:b7:34:be:d7:f1:
+ ee:63:8e:47:79:28:06:fc:f3:59:45:25:60:22:33:1b:a3:5f:
+ a8:ba:2a:da:1a:3d:cd:40:ea:8c:ee:05:15:95:d5:a5:2c:20:
+ 2f:a7:98:28:ee:45:fc:f1:b8:88:00:2c:8f:42:da:51:d5:9c:
+ e5:13:68:71:45:43:8b:9e:0b:21:3c:4b:5c:05:dc:1a:9f:98:
+ 8e:da:bd:22:9e:72:cd:ad:0a:cb:cc:a3:67:9b:28:74:c4:9b:
+ d7:1a:3c:04:58:a6:82:9d:ad:c7:7b:6f:ff:80:96:e9:f8:8d:
+ 6a:bd:18:90:1d:ff:49:1a:90:52:37:93:2f:3c:02:5d:82:76:
+ 0b:51:e7:16:c7:57:f8:38:f9:a7:cd:9b:22:54:ef:63:b0:15:
+ 6d:53:65:03:4a:5e:4a:a0:b2:a7:8e:49:00:59:38:d5:c7:f4:
+ 80:64:f5:6e:95:50:b8:11:7e:15:70:38:4a:b0:7f:d0:c4:32:
+ 70:c0:19:ff:c9:38:2d:14:2c:66:f4:42:44:e6:55:76:1b:80:
+ 15:57:ff:c0:a7:a7:aa:39:aa:d8:d3:70:d0:2e:ba:eb:94:6a:
+ fa:5f:34:86:e7:62:b5:fd:8a:f0:30:85:94:c9:af:24:02:2f:
+ 6f:d6:dd:67:fe:e3:b0:55:4f:04:98:4f:a4:41:56:e2:93:d0:
+ 6a:e8:d6:f3:fb:65:e0:ce:75:c4:31:59:0c:ee:82:c8:0c:60:
+ 33:4a:19:ba:84:67:27:0f:bc:42:5d:bd:24:54:0d:ec:1d:70:
+ 06:5f:a4:bc:fa:20:7c:55
+SHA1 Fingerprint=0B:BE:C2:27:22:49:CB:39:AA:DB:35:5C:53:E3:8C:AE:78:FF:B6:FE
diff --git a/apex/ca-certificates/files/d18e9066.0 b/apex/ca-certificates/files/d18e9066.0
new file mode 100644
index 0000000..0a4ccb4
--- /dev/null
+++ b/apex/ca-certificates/files/d18e9066.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK
+MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu
+VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw
+MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw
+JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG
+SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT
+3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU
++ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp
+S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1
+bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi
+T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL
+vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK
+Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK
+dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT
+c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv
+l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N
+iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
+/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD
+ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH
+6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt
+LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93
+nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3
++wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK
+W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT
+AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq
+l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG
+4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ
+mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A
+7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 0a:01:42:80:00:00:01:45:23:c8:44:b5:00:00:00:02
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, O=IdenTrust, CN=IdenTrust Commercial Root CA 1
+ Validity
+ Not Before: Jan 16 18:12:23 2014 GMT
+ Not After : Jan 16 18:12:23 2034 GMT
+ Subject: C=US, O=IdenTrust, CN=IdenTrust Commercial Root CA 1
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:a7:50:19:de:3f:99:3d:d4:33:46:f1:6f:51:61:
+ 82:b2:a9:4f:8f:67:89:5d:84:d9:53:dd:0c:28:d9:
+ d7:f0:ff:ae:95:43:72:99:f9:b5:5d:7c:8a:c1:42:
+ e1:31:50:74:d1:81:0d:7c:cd:9b:21:ab:43:e2:ac:
+ ad:5e:86:6e:f3:09:8a:1f:5a:32:bd:a2:eb:94:f9:
+ e8:5c:0a:ec:ff:98:d2:af:71:b3:b4:53:9f:4e:87:
+ ef:92:bc:bd:ec:4f:32:30:88:4b:17:5e:57:c4:53:
+ c2:f6:02:97:8d:d9:62:2b:bf:24:1f:62:8d:df:c3:
+ b8:29:4b:49:78:3c:93:60:88:22:fc:99:da:36:c8:
+ c2:a2:d4:2c:54:00:67:35:6e:73:bf:02:58:f0:a4:
+ dd:e5:b0:a2:26:7a:ca:e0:36:a5:19:16:f5:fd:b7:
+ ef:ae:3f:40:f5:6d:5a:04:fd:ce:34:ca:24:dc:74:
+ 23:1b:5d:33:13:12:5d:c4:01:25:f6:30:dd:02:5d:
+ 9f:e0:d5:47:bd:b4:eb:1b:a1:bb:49:49:d8:9f:5b:
+ 02:f3:8a:e4:24:90:e4:62:4f:4f:c1:af:8b:0e:74:
+ 17:a8:d1:72:88:6a:7a:01:49:cc:b4:46:79:c6:17:
+ b1:da:98:1e:07:59:fa:75:21:85:65:dd:90:56:ce:
+ fb:ab:a5:60:9d:c4:9d:f9:52:b0:8b:bd:87:f9:8f:
+ 2b:23:0a:23:76:3b:f7:33:e1:c9:00:f3:69:f9:4b:
+ a2:e0:4e:bc:7e:93:39:84:07:f7:44:70:7e:fe:07:
+ 5a:e5:b1:ac:d1:18:cc:f2:35:e5:49:49:08:ca:56:
+ c9:3d:fb:0f:18:7d:8b:3b:c1:13:c2:4d:8f:c9:4f:
+ 0e:37:e9:1f:a1:0e:6a:df:62:2e:cb:35:06:51:79:
+ 2c:c8:25:38:f4:fa:4b:a7:89:5c:9c:d2:e3:0d:39:
+ 86:4a:74:7c:d5:59:87:c2:3f:4e:0c:5c:52:f4:3d:
+ f7:52:82:f1:ea:a3:ac:fd:49:34:1a:28:f3:41:88:
+ 3a:13:ee:e8:de:ff:99:1d:5f:ba:cb:e8:1e:f2:b9:
+ 50:60:c0:31:d3:73:e5:ef:be:a0:ed:33:0b:74:be:
+ 20:20:c4:67:6c:f0:08:03:7a:55:80:7f:46:4e:96:
+ a7:f4:1e:3e:e1:f6:d8:09:e1:33:64:2b:63:d7:32:
+ 5e:9f:f9:c0:7b:0f:78:6f:97:bc:93:9a:f9:9c:12:
+ 90:78:7a:80:87:15:d7:72:74:9c:55:74:78:b1:ba:
+ e1:6e:70:04:ba:4f:a0:ba:68:c3:7b:ff:31:f0:73:
+ 3d:3d:94:2a:b1:0b:41:0e:a0:fe:4d:88:65:6b:79:
+ 33:b4:d7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ ED:44:19:C0:D3:F0:06:8B:EE:A4:7B:BE:42:E7:26:54:C8:8E:36:76
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 0d:ae:90:32:f6:a6:4b:7c:44:76:19:61:1e:27:28:cd:5e:54:
+ ef:25:bc:e3:08:90:f9:29:d7:ae:68:08:e1:94:00:58:ef:2e:
+ 2e:7e:53:52:8c:b6:5c:07:ea:88:ba:99:8b:50:94:d7:82:80:
+ df:61:09:00:93:ad:0d:14:e6:ce:c1:f2:37:94:78:b0:5f:9c:
+ b3:a2:73:b8:8f:05:93:38:cd:8d:3e:b0:b8:fb:c0:cf:b1:f2:
+ ec:2d:2d:1b:cc:ec:aa:9a:b3:aa:60:82:1b:2d:3b:c3:84:3d:
+ 57:8a:96:1e:9c:75:b8:d3:30:cd:60:08:83:90:d3:8e:54:f1:
+ 4d:66:c0:5d:74:03:40:a3:ee:85:7e:c2:1f:77:9c:06:e8:c1:
+ a7:18:5d:52:95:ed:c9:dd:25:9e:6d:fa:a9:ed:a3:3a:34:d0:
+ 59:7b:da:ed:50:f3:35:bf:ed:eb:14:4d:31:c7:60:f4:da:f1:
+ 87:9c:e2:48:e2:c6:c5:37:fb:06:10:fa:75:59:66:31:47:29:
+ da:76:9a:1c:e9:82:ae:ef:9a:b9:51:f7:88:23:9a:69:95:62:
+ 3c:e5:55:80:36:d7:54:02:ff:f1:b9:5d:ce:d4:23:6f:d8:45:
+ 84:4a:5b:65:ef:89:0c:dd:14:a7:20:cb:18:a5:25:b4:0d:f9:
+ 01:f0:a2:d2:f4:00:c8:74:8e:a1:2a:48:8e:65:db:13:c4:e2:
+ 25:17:7d:eb:be:87:5b:17:20:54:51:93:4a:53:03:0b:ec:5d:
+ ca:33:ed:62:fd:45:c7:2f:5b:dc:58:a0:80:39:e6:fa:d7:fe:
+ 13:14:a6:ed:3d:94:4a:42:74:d4:c3:77:59:73:cd:8f:46:be:
+ 55:38:ef:fa:e8:91:32:ea:97:58:04:22:de:38:c3:cc:bc:6d:
+ c9:33:3a:6a:0a:69:3f:a0:c8:ea:72:8f:8c:63:86:23:bd:6d:
+ 3c:96:9e:95:e0:49:4c:aa:a2:b9:2a:1b:9c:36:81:78:ed:c3:
+ e8:46:e2:26:59:44:75:1e:d9:75:89:51:cd:10:84:9d:61:60:
+ cb:5d:f9:97:22:4d:8e:98:e6:e3:7f:f6:5b:bb:ae:cd:ca:4a:
+ 81:6b:5e:0b:f3:51:e1:74:2b:e9:7e:27:a7:d9:99:49:4e:f8:
+ a5:80:db:25:0f:1c:63:62:8a:c9:33:67:6b:3c:10:83:c6:ad:
+ de:a8:cd:16:8e:8d:f0:07:37:71:9f:f2:ab:fc:41:f5:c1:8b:
+ ec:00:37:5d:09:e5:4e:80:ef:fa:b1:5c:38:06:a5:1b:4a:e1:
+ dc:38:2d:3c:dc:ab:1f:90:1a:d5:4a:9c:ee:d1:70:6c:cc:ee:
+ f4:57:f8:18:ba:84:6e:87
+SHA1 Fingerprint=DF:71:7E:AA:4A:D9:4E:C9:55:84:99:60:2D:48:DE:5F:BC:F0:3A:25
diff --git a/apex/ca-certificates/files/d39b0a2c.0 b/apex/ca-certificates/files/d39b0a2c.0
new file mode 100644
index 0000000..a9a1403
--- /dev/null
+++ b/apex/ca-certificates/files/d39b0a2c.0
@@ -0,0 +1,123 @@
+-----BEGIN CERTIFICATE-----
+MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM
+BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG
+T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0
+aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx
+CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD
+b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA
+iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH
+38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE
+HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz
+kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP
+szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq
+vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf
+nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG
+YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo
+0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a
+CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K
+AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I
+36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB
+Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN
+qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj
+cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm
++LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL
+hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe
+lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7
+p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8
+piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR
+LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX
+5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO
+dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul
+9XXeifdy
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 01:94:30:1e:a2:0b:dd:f5:c5:33:2a:b1:43:44:71:f8:d6:50:4d:0d
+ Signature Algorithm: sha384WithRSAEncryption
+ Issuer: C=KR, O=NAVER BUSINESS PLATFORM Corp., CN=NAVER Global Root Certification Authority
+ Validity
+ Not Before: Aug 18 08:58:42 2017 GMT
+ Not After : Aug 18 23:59:59 2037 GMT
+ Subject: C=KR, O=NAVER BUSINESS PLATFORM Corp., CN=NAVER Global Root Certification Authority
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:b6:d4:f1:93:5c:b5:40:89:0a:ab:0d:90:5b:50:
+ 63:ae:90:94:74:17:45:72:d6:7b:65:5a:29:4b:a7:
+ 56:a0:4b:b8:2f:42:75:e9:d9:7b:24:5a:31:65:ab:
+ 17:17:d1:33:3a:d9:11:dc:40:36:87:df:c7:6a:e9:
+ 26:5e:59:8a:77:e3:e8:48:9c:31:16:fa:3e:91:b1:
+ ca:c9:a3:e2:9f:ce:21:53:a3:02:36:30:cb:52:02:
+ e5:da:32:5d:c3:c5:e6:f9:ee:11:c7:8b:c9:44:1e:
+ 84:93:18:4a:b4:9f:e5:12:64:69:d0:26:85:62:01:
+ b6:c9:02:1d:be:83:51:bb:5c:da:f8:ad:15:6a:99:
+ f7:92:54:f7:34:5b:e9:bf:ea:29:81:12:d4:53:91:
+ 96:b3:91:5a:dd:fe:90:73:28:fb:30:46:b5:ca:08:
+ 07:c7:71:72:c9:66:d3:34:97:f6:8c:f4:18:4a:e1:
+ d0:3d:5a:45:b6:69:a7:29:fb:23:ce:88:d8:12:9c:
+ 00:48:a8:a6:0f:b3:3b:92:8d:71:0e:74:c5:8b:c8:
+ 4c:f9:f4:9b:8e:b8:3c:69:ed:6f:3b:50:2f:58:ed:
+ c4:b0:d0:1c:1b:6a:0c:e2:bc:44:aa:d8:cd:14:5d:
+ 94:78:61:bf:0e:6e:da:2a:bc:2f:0c:0b:71:a6:b3:
+ 16:3f:9c:e6:f9:cc:9f:53:35:e2:03:a0:a0:18:bf:
+ bb:f1:be:f4:d6:8c:87:0d:42:f7:06:b9:f1:6d:ed:
+ 04:94:a8:fe:b6:d3:06:c6:40:61:df:9d:9d:f3:54:
+ 76:ce:53:3a:01:a6:92:41:ec:04:a3:8f:0d:a2:d5:
+ 09:ca:d6:cb:9a:f1:ef:43:5d:c0:ab:a5:41:cf:5c:
+ 53:70:70:c9:88:a6:2d:d4:6b:61:73:50:26:86:61:
+ 0e:5f:1b:c2:2b:e2:8c:d5:bb:9d:c1:03:42:ba:94:
+ da:5f:a9:b0:ca:cc:4d:0a:ef:47:69:03:2f:22:fb:
+ f1:28:ce:bf:5d:50:65:a8:90:6d:b3:74:b0:08:c7:
+ ac:a8:d1:eb:3e:9c:fc:5d:1a:83:2e:2b:cb:b5:f3:
+ 44:9d:3a:a7:17:61:96:a2:71:d3:70:96:15:4d:b7:
+ 4c:73:ee:19:5c:c5:5b:3e:41:fe:ac:75:60:3b:1b:
+ 63:ce:00:dd:da:08:90:62:b4:e5:2d:ee:48:a7:6b:
+ 17:99:54:be:87:4a:e3:a9:5e:04:4c:eb:10:6d:54:
+ d6:ef:f1:e8:f2:62:16:cb:80:6b:ed:3d:ed:f5:1f:
+ 30:a5:ae:4b:c9:13:ed:8a:01:01:c9:b8:51:58:c0:
+ 66:3a:b1:66:4b:c4:d5:31:02:62:e9:74:84:0c:db:
+ 4d:46:2d
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ D2:9F:88:DF:A1:CD:2C:BD:EC:F5:3B:01:01:93:33:27:B2:EB:60:4B
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha384WithRSAEncryption
+ Signature Value:
+ 32:ca:80:b3:9d:3d:54:06:dd:d2:d2:2e:f0:a4:01:21:0b:67:
+ 48:ca:6d:8e:e0:c8:aa:0d:aa:8d:21:57:8f:c6:3e:7a:ca:db:
+ 51:d4:52:b3:d4:96:84:a5:58:60:7f:e5:0b:8e:1f:f5:dc:0a:
+ 15:81:e5:3b:b6:b7:22:2f:09:9c:13:16:b1:6c:0c:35:08:6d:
+ ab:63:72:ed:dc:be:ec:c7:57:e6:30:20:71:d6:d7:10:c1:13:
+ 55:01:8c:2a:43:e4:41:f1:cf:3a:7a:53:92:ce:a2:03:05:0d:
+ 38:df:02:bb:10:2e:d9:3b:d2:9b:7a:c0:a1:a6:f8:b5:31:e6:
+ f4:75:c9:b9:53:99:75:47:22:5a:14:15:c7:78:1b:b6:9d:e9:
+ 0c:f8:1b:76:f1:85:84:de:a1:da:12:ef:a4:e2:10:97:7a:78:
+ de:0c:51:97:a8:21:40:8b:86:bd:0d:f0:5e:4e:4b:36:bb:3b:
+ 20:1f:8a:42:56:e1:0b:1a:bf:7b:d0:22:43:2c:44:8c:fb:e5:
+ 2a:b4:6c:1c:1c:ba:94:e0:13:7e:21:e6:9a:c2:cb:c5:42:64:
+ b4:1e:94:7b:08:25:c8:71:cc:87:45:57:85:d3:9f:29:62:22:
+ 83:51:97:00:18:97:77:6a:98:92:c9:7c:60:6c:df:6c:7d:4a:
+ e4:70:4c:c2:9e:b8:1d:f7:d0:34:c7:0f:cc:fb:a7:ff:03:be:
+ ad:70:90:da:0b:dd:c8:6d:97:5f:9a:7f:09:32:41:fd:cd:a2:
+ cc:5a:6d:4c:f2:aa:49:fe:66:f8:e9:d8:35:eb:0e:28:1e:ee:
+ 48:2f:3a:d0:79:09:38:7c:a6:22:82:93:95:d0:03:be:be:02:
+ a0:05:dd:20:22:e3:6f:1d:88:34:60:c6:e6:0a:b9:09:75:0b:
+ f0:07:e8:69:96:35:c7:fb:23:81:8e:38:39:b8:45:2b:43:78:
+ a2:d1:2c:14:ff:0d:28:72:72:95:9b:5e:09:db:89:44:98:aa:
+ a1:49:bb:71:52:f2:bf:f6:ff:27:a1:36:af:b8:b6:77:88:dd:
+ 3a:a4:6d:9b:34:90:dc:14:5d:30:bf:b7:eb:17:e4:87:b7:71:
+ d0:a1:d7:77:15:d4:42:d7:f2:f3:31:99:5d:9b:dd:16:6d:3f:
+ ea:06:23:f8:46:a2:22:ed:93:f6:dd:9a:e6:2a:87:b1:98:54:
+ f1:22:f7:6b:45:e3:e2:8e:76:1d:9a:8d:c4:06:8d:36:b7:14:
+ f3:9d:54:69:b7:8e:3c:d5:a4:6d:93:81:b7:ad:f6:bd:64:7b:
+ c2:c9:68:39:a0:92:9c:cd:34:86:91:90:fa:64:51:9d:fe:fe:
+ eb:a5:f5:75:de:89:f7:72
+SHA1 Fingerprint=8F:6B:F2:A9:27:4A:DA:14:A0:C4:F4:8E:61:27:F9:C0:1E:78:5D:D1
diff --git a/apex/ca-certificates/files/d41b5e2a.0 b/apex/ca-certificates/files/d41b5e2a.0
new file mode 100644
index 0000000..590a4cc
--- /dev/null
+++ b/apex/ca-certificates/files/d41b5e2a.0
@@ -0,0 +1,53 @@
+-----BEGIN CERTIFICATE-----
+MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5
+MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
+Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
+A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
+Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi
+9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk
+M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB
+/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB
+MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw
+CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW
+1KyLa2tJElMzrdfkviT8tQp21KW8EA==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 06:6c:9f:d7:c1:bb:10:4c:29:43:e5:71:7b:7b:2c:c8:1a:c1:0e
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=US, O=Amazon, CN=Amazon Root CA 4
+ Validity
+ Not Before: May 26 00:00:00 2015 GMT
+ Not After : May 26 00:00:00 2040 GMT
+ Subject: C=US, O=Amazon, CN=Amazon Root CA 4
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:d2:ab:8a:37:4f:a3:53:0d:fe:c1:8a:7b:4b:a8:
+ 7b:46:4b:63:b0:62:f6:2d:1b:db:08:71:21:d2:00:
+ e8:63:bd:9a:27:fb:f0:39:6e:5d:ea:3d:a5:c9:81:
+ aa:a3:5b:20:98:45:5d:16:db:fd:e8:10:6d:e3:9c:
+ e0:e3:bd:5f:84:62:f3:70:64:33:a0:cb:24:2f:70:
+ ba:88:a1:2a:a0:75:f8:81:ae:62:06:c4:81:db:39:
+ 6e:29:b0:1e:fa:2e:5c
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ D3:EC:C7:3A:65:6E:CC:E1:DA:76:9A:56:FB:9C:F3:86:6D:57:E5:81
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:65:02:30:3a:8b:21:f1:bd:7e:11:ad:d0:ef:58:96:2f:d6:
+ eb:9d:7e:90:8d:2b:cf:66:55:c3:2c:e3:28:a9:70:0a:47:0e:
+ f0:37:59:12:ff:2d:99:94:28:4e:2a:4f:35:4d:33:5a:02:31:
+ 00:ea:75:00:4e:3b:c4:3a:94:12:91:c9:58:46:9d:21:13:72:
+ a7:88:9c:8a:e4:4c:4a:db:96:d4:ac:8b:6b:6b:49:12:53:33:
+ ad:d7:e4:be:24:fc:b5:0a:76:d4:a5:bc:10
+SHA1 Fingerprint=F6:10:84:07:D6:F8:BB:67:98:0C:C2:E2:44:C2:EB:AE:1C:EF:63:BE
diff --git a/apex/ca-certificates/files/d4c339cb.0 b/apex/ca-certificates/files/d4c339cb.0
new file mode 100644
index 0000000..0a095af
--- /dev/null
+++ b/apex/ca-certificates/files/d4c339cb.0
@@ -0,0 +1,124 @@
+-----BEGIN CERTIFICATE-----
+MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB
+hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
+BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5
+MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
+EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
+Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR
+6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X
+pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC
+9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV
+/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf
+Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z
++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w
+qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah
+SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC
+u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf
+Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq
+crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E
+FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB
+/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl
+wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM
+4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV
+2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna
+FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ
+CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK
+boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke
+jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL
+S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb
+QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl
+0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB
+NVOFBkpdn627G190
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 4c:aa:f9:ca:db:63:6f:e0:1f:f7:4e:d8:5b:03:86:9d
+ Signature Algorithm: sha384WithRSAEncryption
+ Issuer: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO RSA Certification Authority
+ Validity
+ Not Before: Jan 19 00:00:00 2010 GMT
+ Not After : Jan 18 23:59:59 2038 GMT
+ Subject: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO RSA Certification Authority
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:91:e8:54:92:d2:0a:56:b1:ac:0d:24:dd:c5:cf:
+ 44:67:74:99:2b:37:a3:7d:23:70:00:71:bc:53:df:
+ c4:fa:2a:12:8f:4b:7f:10:56:bd:9f:70:72:b7:61:
+ 7f:c9:4b:0f:17:a7:3d:e3:b0:04:61:ee:ff:11:97:
+ c7:f4:86:3e:0a:fa:3e:5c:f9:93:e6:34:7a:d9:14:
+ 6b:e7:9c:b3:85:a0:82:7a:76:af:71:90:d7:ec:fd:
+ 0d:fa:9c:6c:fa:df:b0:82:f4:14:7e:f9:be:c4:a6:
+ 2f:4f:7f:99:7f:b5:fc:67:43:72:bd:0c:00:d6:89:
+ eb:6b:2c:d3:ed:8f:98:1c:14:ab:7e:e5:e3:6e:fc:
+ d8:a8:e4:92:24:da:43:6b:62:b8:55:fd:ea:c1:bc:
+ 6c:b6:8b:f3:0e:8d:9a:e4:9b:6c:69:99:f8:78:48:
+ 30:45:d5:ad:e1:0d:3c:45:60:fc:32:96:51:27:bc:
+ 67:c3:ca:2e:b6:6b:ea:46:c7:c7:20:a0:b1:1f:65:
+ de:48:08:ba:a4:4e:a9:f2:83:46:37:84:eb:e8:cc:
+ 81:48:43:67:4e:72:2a:9b:5c:bd:4c:1b:28:8a:5c:
+ 22:7b:b4:ab:98:d9:ee:e0:51:83:c3:09:46:4e:6d:
+ 3e:99:fa:95:17:da:7c:33:57:41:3c:8d:51:ed:0b:
+ b6:5c:af:2c:63:1a:df:57:c8:3f:bc:e9:5d:c4:9b:
+ af:45:99:e2:a3:5a:24:b4:ba:a9:56:3d:cf:6f:aa:
+ ff:49:58:be:f0:a8:ff:f4:b8:ad:e9:37:fb:ba:b8:
+ f4:0b:3a:f9:e8:43:42:1e:89:d8:84:cb:13:f1:d9:
+ bb:e1:89:60:b8:8c:28:56:ac:14:1d:9c:0a:e7:71:
+ eb:cf:0e:dd:3d:a9:96:a1:48:bd:3c:f7:af:b5:0d:
+ 22:4c:c0:11:81:ec:56:3b:f6:d3:a2:e2:5b:b7:b2:
+ 04:22:52:95:80:93:69:e8:8e:4c:65:f1:91:03:2d:
+ 70:74:02:ea:8b:67:15:29:69:52:02:bb:d7:df:50:
+ 6a:55:46:bf:a0:a3:28:61:7f:70:d0:c3:a2:aa:2c:
+ 21:aa:47:ce:28:9c:06:45:76:bf:82:18:27:b4:d5:
+ ae:b4:cb:50:e6:6b:f4:4c:86:71:30:e9:a6:df:16:
+ 86:e0:d8:ff:40:dd:fb:d0:42:88:7f:a3:33:3a:2e:
+ 5c:1e:41:11:81:63:ce:18:71:6b:2b:ec:a6:8a:b7:
+ 31:5c:3a:6a:47:e0:c3:79:59:d6:20:1a:af:f2:6a:
+ 98:aa:72:bc:57:4a:d2:4b:9d:bb:10:fc:b0:4c:41:
+ e5:ed:1d:3d:5e:28:9d:9c:cc:bf:b3:51:da:a7:47:
+ e5:84:53
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ BB:AF:7E:02:3D:FA:A6:F1:3C:84:8E:AD:EE:38:98:EC:D9:32:32:D4
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha384WithRSAEncryption
+ Signature Value:
+ 0a:f1:d5:46:84:b7:ae:51:bb:6c:b2:4d:41:14:00:93:4c:9c:
+ cb:e5:c0:54:cf:a0:25:8e:02:f9:fd:b0:a2:0d:f5:20:98:3c:
+ 13:2d:ac:56:a2:b0:d6:7e:11:92:e9:2e:ba:9e:2e:9a:72:b1:
+ bd:19:44:6c:61:35:a2:9a:b4:16:12:69:5a:8c:e1:d7:3e:a4:
+ 1a:e8:2f:03:f4:ae:61:1d:10:1b:2a:a4:8b:7a:c5:fe:05:a6:
+ e1:c0:d6:c8:fe:9e:ae:8f:2b:ba:3d:99:f8:d8:73:09:58:46:
+ 6e:a6:9c:f4:d7:27:d3:95:da:37:83:72:1c:d3:73:e0:a2:47:
+ 99:03:38:5d:d5:49:79:00:29:1c:c7:ec:9b:20:1c:07:24:69:
+ 57:78:b2:39:fc:3a:84:a0:b5:9c:7c:8d:bf:2e:93:62:27:b7:
+ 39:da:17:18:ae:bd:3c:09:68:ff:84:9b:3c:d5:d6:0b:03:e3:
+ 57:9e:14:f7:d1:eb:4f:c8:bd:87:23:b7:b6:49:43:79:85:5c:
+ ba:eb:92:0b:a1:c6:e8:68:a8:4c:16:b1:1a:99:0a:e8:53:2c:
+ 92:bb:a1:09:18:75:0c:65:a8:7b:cb:23:b7:1a:c2:28:85:c3:
+ 1b:ff:d0:2b:62:ef:a4:7b:09:91:98:67:8c:14:01:cd:68:06:
+ 6a:63:21:75:03:80:88:8a:6e:81:c6:85:f2:a9:a4:2d:e7:f4:
+ a5:24:10:47:83:ca:cd:f4:8d:79:58:b1:06:9b:e7:1a:2a:d9:
+ 9d:01:d7:94:7d:ed:03:4a:ca:f0:db:e8:a9:01:3e:f5:56:99:
+ c9:1e:8e:49:3d:bb:e5:09:b9:e0:4f:49:92:3d:16:82:40:cc:
+ cc:59:c6:e6:3a:ed:12:2e:69:3c:6c:95:b1:fd:aa:1d:7b:7f:
+ 86:be:1e:0e:32:46:fb:fb:13:8f:75:7f:4c:8b:4b:46:63:fe:
+ 00:34:40:70:c1:c3:b9:a1:dd:a6:70:e2:04:b3:41:bc:e9:80:
+ 91:ea:64:9c:7a:e1:22:03:a9:9c:6e:6f:0e:65:4f:6c:87:87:
+ 5e:f3:6e:a0:f9:75:a5:9b:40:e8:53:b2:27:9d:4a:b9:c0:77:
+ 21:8d:ff:87:f2:de:bc:8c:ef:17:df:b7:49:0b:d1:f2:6e:30:
+ 0b:1a:0e:4e:76:ed:11:fc:f5:e9:56:b2:7d:bf:c7:6d:0a:93:
+ 8c:a5:d0:c0:b6:1d:be:3a:4e:94:a2:d7:6e:6c:0b:c2:8a:7c:
+ fa:20:f3:c4:e4:e5:cd:0d:a8:cb:91:92:b1:7c:85:ec:b5:14:
+ 69:66:0e:82:e7:cd:ce:c8:2d:a6:51:7f:21:c1:35:53:85:06:
+ 4a:5d:9f:ad:bb:1b:5f:74
+SHA1 Fingerprint=AF:E5:D2:44:A8:D1:19:42:30:FF:47:9F:E2:F8:97:BB:CD:7A:8C:B4
diff --git a/apex/ca-certificates/files/d59297b8.0 b/apex/ca-certificates/files/d59297b8.0
new file mode 100644
index 0000000..c822e56
--- /dev/null
+++ b/apex/ca-certificates/files/d59297b8.0
@@ -0,0 +1,79 @@
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl
+MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe
+U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX
+DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy
+dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj
+YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV
+OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr
+zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM
+VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ
+hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO
+ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw
+awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs
+OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
+DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF
+coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc
+okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8
+t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy
+1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/
+SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 0 (0x0)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=JP, O=SECOM Trust Systems CO.,LTD., OU=Security Communication RootCA2
+ Validity
+ Not Before: May 29 05:00:39 2009 GMT
+ Not After : May 29 05:00:39 2029 GMT
+ Subject: C=JP, O=SECOM Trust Systems CO.,LTD., OU=Security Communication RootCA2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:d0:15:39:52:b1:52:b3:ba:c5:59:82:c4:5d:52:
+ ae:3a:43:65:80:4b:c7:f2:96:bc:db:36:97:d6:a6:
+ 64:8c:a8:5e:f0:e3:0a:1c:f7:df:97:3d:4b:ae:f6:
+ 5d:ec:21:b5:41:ab:cd:b9:7e:76:9f:be:f9:3e:36:
+ 34:a0:3b:c1:f6:31:11:45:74:93:3d:57:80:c5:f9:
+ 89:99:ca:e5:ab:6a:d4:b5:da:41:90:10:c1:d6:d6:
+ 42:89:c2:bf:f4:38:12:95:4c:54:05:f7:36:e4:45:
+ 83:7b:14:65:d6:dc:0c:4d:d1:de:7e:0c:ab:3b:c4:
+ 15:be:3a:56:a6:5a:6f:76:69:52:a9:7a:b9:c8:eb:
+ 6a:9a:5d:52:d0:2d:0a:6b:35:16:09:10:84:d0:6a:
+ ca:3a:06:00:37:47:e4:7e:57:4f:3f:8b:eb:67:b8:
+ 88:aa:c5:be:53:55:b2:91:c4:7d:b9:b0:85:19:06:
+ 78:2e:db:61:1a:fa:85:f5:4a:91:a1:e7:16:d5:8e:
+ a2:39:df:94:b8:70:1f:28:3f:8b:fc:40:5e:63:83:
+ 3c:83:2a:1a:99:6b:cf:de:59:6a:3b:fc:6f:16:d7:
+ 1f:fd:4a:10:eb:4e:82:16:3a:ac:27:0c:53:f1:ad:
+ d5:24:b0:6b:03:50:c1:2d:3c:16:dd:44:34:27:1a:
+ 75:fb
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 0A:85:A9:77:65:05:98:7C:40:81:F8:0F:97:2C:38:F1:0A:EC:3C:CF
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 4c:3a:a3:44:ac:b9:45:b1:c7:93:7e:c8:0b:0a:42:df:64:ea:
+ 1c:ee:59:6c:08:ba:89:5f:6a:ca:4a:95:9e:7a:8f:07:c5:da:
+ 45:72:82:71:0e:3a:d2:cc:6f:a7:b4:a1:23:bb:f6:24:9f:cb:
+ 17:fe:8c:a6:ce:c2:d2:db:cc:8d:fc:71:fc:03:29:c1:6c:5d:
+ 33:5f:64:b6:65:3b:89:6f:18:76:78:f5:dc:a2:48:1f:19:3f:
+ 8e:93:eb:f1:fa:17:ee:cd:4e:e3:04:12:55:d6:e5:e4:dd:fb:
+ 3e:05:7c:e2:1d:5e:c6:a7:bc:97:4f:68:3a:f5:e9:2e:0a:43:
+ b6:af:57:5c:62:68:7c:b7:fd:a3:8a:84:a0:ac:62:be:2b:09:
+ 87:34:f0:6a:01:bb:9b:29:56:3c:fe:00:37:cf:23:6c:f1:4e:
+ aa:b6:74:46:12:6c:91:ee:34:d5:ec:9a:91:e7:44:be:90:31:
+ 72:d5:49:02:f6:02:e5:f4:1f:eb:7c:d9:96:55:a9:ff:ec:8a:
+ f9:99:47:ff:35:5a:02:aa:04:cb:8a:5b:87:71:29:91:bd:a4:
+ b4:7a:0d:bd:9a:f5:57:23:00:07:21:17:3f:4a:39:d1:05:49:
+ 0b:a7:b6:37:81:a5:5d:8c:aa:33:5e:81:28:7c:a7:7d:27:eb:
+ 00:ae:8d:37
+SHA1 Fingerprint=5F:3B:8C:F2:F8:10:B3:7D:78:B4:CE:EC:19:19:C3:73:34:B9:C7:74
diff --git a/apex/ca-certificates/files/d7746a63.0 b/apex/ca-certificates/files/d7746a63.0
new file mode 100644
index 0000000..0411fd8
--- /dev/null
+++ b/apex/ca-certificates/files/d7746a63.0
@@ -0,0 +1,88 @@
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF
+MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD
+bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw
+NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV
+BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn
+ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0
+3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z
+qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR
+p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8
+HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw
+ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea
+HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw
+Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh
+c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E
+RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt
+dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku
+Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp
+3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05
+nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF
+CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na
+xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX
+KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 623604 (0x983f4)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=DE, O=D-Trust GmbH, CN=D-TRUST Root Class 3 CA 2 EV 2009
+ Validity
+ Not Before: Nov 5 08:50:46 2009 GMT
+ Not After : Nov 5 08:50:46 2029 GMT
+ Subject: C=DE, O=D-Trust GmbH, CN=D-TRUST Root Class 3 CA 2 EV 2009
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:99:f1:84:34:70:ba:2f:b7:30:a0:8e:bd:7c:04:
+ cf:be:62:bc:99:fd:82:97:d2:7a:0a:67:96:38:09:
+ f6:10:4e:95:22:73:99:8d:da:15:2d:e7:05:fc:19:
+ 73:22:b7:8e:98:00:bc:3c:3d:ac:a1:6c:fb:d6:79:
+ 25:4b:ad:f0:cc:64:da:88:3e:29:b8:0f:09:d3:34:
+ dd:33:f5:62:d1:e1:cd:19:e9:ee:18:4f:4c:58:ae:
+ e2:1e:d6:0c:5b:15:5a:d8:3a:b8:c4:18:64:1e:e3:
+ 33:b2:b5:89:77:4e:0c:bf:d9:94:6b:13:97:6f:12:
+ a3:fe:99:a9:04:cc:15:ec:60:68:36:ed:08:7b:b7:
+ f5:bf:93:ed:66:31:83:8c:c6:71:34:87:4e:17:ea:
+ af:8b:91:8d:1c:56:41:ae:22:37:5e:37:f2:1d:d9:
+ d1:2d:0d:2f:69:51:a7:be:66:a6:8a:3a:2a:bd:c7:
+ 1a:b1:e1:14:f0:be:3a:1d:b9:cf:5b:b1:6a:fe:b4:
+ b1:46:20:a2:fb:1e:3b:70:ef:93:98:7d:8c:73:96:
+ f2:c5:ef:85:70:ad:29:26:fc:1e:04:3e:1c:a0:d8:
+ 0f:cb:52:83:62:7c:ee:8b:53:95:90:a9:57:a2:ea:
+ 61:05:d8:f9:4d:c4:27:fa:6e:ad:ed:f9:d7:51:f7:
+ 6b:a5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ D3:94:8A:4C:62:13:2A:19:2E:CC:AF:72:8A:7D:36:D7:9A:1C:DC:67
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 CRL Distribution Points:
+ Full Name:
+ URI:ldap://directory.d-trust.net/CN=D-TRUST%20Root%20Class%203%20CA%202%20EV%202009,O=D-Trust%20GmbH,C=DE?certificaterevocationlist
+ Full Name:
+ URI:http://www.d-trust.net/crl/d-trust_root_class_3_ca_2_ev_2009.crl
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 34:ed:7b:5a:3c:a4:94:88:ef:1a:11:75:07:2f:b3:fe:3c:fa:
+ 1e:51:26:eb:87:f6:29:de:e0:f1:d4:c6:24:09:e9:c1:cf:55:
+ 1b:b4:30:d9:ce:1a:fe:06:51:a6:15:a4:2d:ef:b2:4b:bf:20:
+ 28:25:49:d1:a6:36:77:34:e8:64:df:52:b1:11:c7:73:7a:cd:
+ 39:9e:c2:ad:8c:71:21:f2:5a:6b:af:df:3c:4e:55:af:b2:84:
+ 65:14:89:b9:77:cb:2a:31:be:cf:a3:6d:cf:6f:48:94:32:46:
+ 6f:e7:71:8c:a0:a6:84:19:37:07:f2:03:45:09:2b:86:75:7c:
+ df:5f:69:57:00:db:6e:d8:a6:72:22:4b:50:d4:75:98:56:df:
+ b7:18:ff:43:43:50:ae:7a:44:7b:f0:79:51:d7:43:3d:a7:d3:
+ 81:d3:f0:c9:4f:b9:da:c6:97:86:d0:82:c3:e4:42:6d:fe:b0:
+ e2:64:4e:0e:26:e7:40:34:26:b5:08:89:d7:08:63:63:38:27:
+ 75:1e:33:ea:6e:a8:dd:9f:99:4f:74:4d:81:89:80:4b:dd:9a:
+ 97:29:5c:2f:be:81:41:b9:8c:ff:ea:7d:60:06:9e:cd:d7:3d:
+ d3:2e:a3:15:bc:a8:e6:26:e5:6f:c3:dc:b8:03:21:ea:9f:16:
+ f1:2c:54:b5
+SHA1 Fingerprint=96:C9:1B:0B:95:B4:10:98:42:FA:D0:D8:22:79:FE:60:FA:B9:16:83
diff --git a/apex/ca-certificates/files/d96b65e2.0 b/apex/ca-certificates/files/d96b65e2.0
new file mode 100644
index 0000000..983467d
--- /dev/null
+++ b/apex/ca-certificates/files/d96b65e2.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAw
+PTELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2Vy
+dGFpbmx5IFJvb3QgUjEwHhcNMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9
+MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0
+YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANA2
+1B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O5MQT
+vqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbed
+aFySpvXl8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b0
+1C7jcvk2xusVtyWMOvwlDbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5
+r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGIXsXwClTNSaa/ApzSRKft43jvRl5tcdF5
+cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkNKPl6I7ENPT2a/Z2B7yyQ
+wHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQAjeZjOVJ
+6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA
+2CnbrlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyH
+Wyf5QBGenDPBt+U1VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMR
+eiFPCyEQtkA6qyI6BJyLm4SGcprSp6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB
+/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTgqj8ljZ9EXME66C6u
+d0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAszHQNTVfSVcOQr
+PbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d
+8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi
+1wrykXprOQ4vMMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrd
+rRT90+7iIgXr0PK3aBLXWopBGsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9di
+taY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+gjwN/KUD+nsa2UUeYNrEjvn8K8l7
+lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgHJBu6haEaBQmAupVj
+yTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7fpYn
+Kx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLy
+yCwzk5Iwx06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5n
+wXARPbv0+Em34yaXOp/SX3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6
+OV+KmalBWQewLK8=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 8e:0f:f9:4b:90:71:68:65:33:54:f4:d4:44:39:b7:e0
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, O=Certainly, CN=Certainly Root R1
+ Validity
+ Not Before: Apr 1 00:00:00 2021 GMT
+ Not After : Apr 1 00:00:00 2046 GMT
+ Subject: C=US, O=Certainly, CN=Certainly Root R1
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:d0:36:d4:1f:ea:dd:ab:e4:d1:b6:e6:fb:22:c0:
+ dd:13:0d:6a:7b:22:13:1c:97:3c:68:63:66:32:9c:
+ 03:b5:8d:a4:81:83:da:78:30:11:cf:dc:b2:2b:be:
+ 92:bf:8e:e4:c4:13:be:a4:68:4c:da:02:68:16:74:
+ be:b2:dd:04:e4:6b:2a:dd:37:1f:60:2c:db:f5:f7:
+ a1:7c:95:b7:0c:70:86:2e:f1:3a:ef:52:f7:cc:d3:
+ 9b:f9:8b:be:0e:df:31:b7:9d:68:5c:92:a6:f5:e5:
+ f3:0a:34:b5:ff:7b:a2:e4:87:a1:c6:af:17:00:ef:
+ 03:91:ed:a9:1c:4e:71:3d:d2:8b:6c:89:f4:78:86:
+ e6:6a:49:a0:ce:b5:d2:b0:ab:9b:f6:f4:d4:2e:e3:
+ 72:f9:36:c6:eb:15:b7:25:8c:3a:fc:25:0d:b3:22:
+ 73:21:74:c8:4a:96:61:92:f5:2f:0b:18:a5:f4:ad:
+ e2:ee:41:bd:01:79:fa:96:8c:8d:17:02:30:b4:f9:
+ af:78:1a:8c:b4:36:10:10:07:05:70:d0:f4:31:90:
+ 8a:51:c5:86:26:79:b2:11:88:5e:c5:f0:0a:54:cd:
+ 49:a6:bf:02:9c:d2:44:a7:ed:e3:78:ef:46:5e:6d:
+ 71:d1:79:70:1c:46:5f:51:e9:c9:37:dc:5f:7e:69:
+ 7b:41:df:34:45:e0:3b:84:f4:a1:8a:0a:36:9e:37:
+ cc:62:52:e1:89:0d:28:f9:7a:23:b1:0d:3d:3d:9a:
+ fd:9d:81:ef:2c:90:c0:7b:44:4e:bb:49:e0:0e:4a:
+ 56:92:bc:cb:b5:dd:79:17:89:91:de:61:89:74:92:
+ a8:e3:32:85:be:4e:85:a4:4b:59:cb:2b:c5:78:8e:
+ 71:54:d0:02:37:99:8c:e5:49:ea:e0:54:72:a4:11:
+ 06:2f:0b:8c:c1:5b:be:b5:a1:b0:53:6e:9c:b8:60:
+ 91:1f:59:6b:f9:2d:f4:94:0a:97:b5:ec:c5:76:03:
+ 54:1b:65:52:ba:4c:92:56:51:35:a0:40:d8:29:db:
+ ae:52:76:3b:2d:30:40:9b:8a:d0:42:56:b4:b7:88:
+ 01:a4:87:3b:53:96:cd:a3:16:8f:f3:66:aa:17:b1:
+ c7:60:e0:c1:43:05:0c:ee:9b:5b:60:6f:06:5c:87:
+ 5b:27:f9:40:11:9e:9c:33:c1:b7:e5:35:57:05:7f:
+ 27:ce:17:20:8c:1c:fc:f1:fb:da:31:29:49:ed:f5:
+ 0b:84:a7:4f:c1:f6:4e:c2:28:9c:fa:ee:e0:af:07:
+ fb:33:11:7a:21:4f:0b:21:10:b6:40:3a:ab:22:3a:
+ 04:9c:8b:9b:84:86:72:9a:d2:a7:a5:c4:b4:75:91:
+ a9:2b:23
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ E0:AA:3F:25:8D:9F:44:5C:C1:3A:E8:2E:AE:77:4C:84:3E:67:0C:F4
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ b9:57:af:b8:12:da:57:83:8f:68:0b:33:1d:03:53:55:f4:95:
+ 70:e4:2b:3d:b0:39:eb:fa:89:62:fd:f7:d6:18:04:2f:21:34:
+ dd:f1:68:f0:d5:96:5a:de:c2:80:a3:c1:8d:c6:6a:f7:59:77:
+ ae:15:64:cf:5b:79:05:77:66:ea:8c:d3:6b:0d:dd:f1:59:2c:
+ c1:33:a5:30:80:15:45:07:45:1a:31:22:b6:92:00:ab:99:4d:
+ 3a:8f:77:af:a9:22:ca:2f:63:ca:15:d6:c7:c6:f0:3d:6c:fc:
+ 1c:0d:98:10:61:9e:11:a2:22:d7:0a:f2:91:7a:6b:39:0e:2f:
+ 30:c3:36:49:9f:e0:e9:0f:02:44:50:37:94:55:7d:ea:9f:f6:
+ 3b:ba:94:a5:4c:e9:bc:3e:51:b4:e8:ca:92:36:54:6d:5c:25:
+ 28:da:dd:ad:14:fd:d3:ee:e2:22:05:eb:d0:f2:b7:68:12:d7:
+ 5a:8a:41:1a:c6:92:a5:5a:3b:63:45:4f:bf:e1:3a:77:22:2f:
+ 5c:bf:46:f9:5a:03:85:13:42:5f:ca:de:53:d7:62:b5:a6:35:
+ 04:c2:47:ff:99:fd:84:df:5c:ce:e9:5e:80:28:41:f2:7d:e7:
+ 1e:90:d8:4f:76:3e:82:3c:0d:fc:a5:03:fa:7b:1a:d9:45:1e:
+ 60:da:c4:8e:f9:fc:2b:c9:7b:95:c5:2a:ff:aa:89:df:82:31:
+ 0f:72:ff:0c:27:d7:0a:1e:56:00:50:1e:0c:90:c1:96:b5:d8:
+ 14:85:bb:a7:0d:16:c1:f8:07:24:1b:ba:85:a1:1a:05:09:80:
+ ba:95:63:c9:3a:ec:25:9f:7f:9d:ba:a4:47:15:9b:44:70:f1:
+ 6a:4b:d6:38:5e:43:f3:18:7e:50:6e:e9:5a:28:e6:65:e6:77:
+ 1b:3a:fd:1d:be:03:26:a3:db:d4:e1:bb:7e:96:27:2b:1d:ee:
+ a4:fb:da:25:54:13:03:de:39:c6:c3:1f:4d:90:ec:8f:1b:4a:
+ d2:1c:ed:85:95:38:50:79:46:d6:c1:90:50:31:a9:5c:9a:6e:
+ 1d:f5:33:56:8b:a7:99:d2:f2:c8:2c:33:93:92:30:c7:4e:8c:
+ 65:33:10:64:17:fd:24:17:96:d1:8d:c2:3a:6a:2b:eb:13:8b:
+ 44:f2:21:f3:4a:1a:b7:77:5f:d7:ed:88:a4:72:e5:39:1f:95:
+ 9d:be:67:c1:70:11:3d:bb:f4:f8:49:b7:e3:26:97:3a:9f:d2:
+ 5f:7c:fb:c0:99:7c:39:29:e0:7b:1d:bf:0d:a7:8f:d2:29:34:
+ 6e:24:15:cb:de:90:5e:bf:1a:c4:66:ea:c2:e6:ba:39:5f:8a:
+ 99:a9:41:59:07:b0:2c:af
+SHA1 Fingerprint=A0:50:EE:0F:28:71:F4:27:B2:12:6D:6F:50:96:25:BA:CC:86:42:AF
diff --git a/apex/ca-certificates/files/da7377f6.0 b/apex/ca-certificates/files/da7377f6.0
new file mode 100644
index 0000000..ed24844
--- /dev/null
+++ b/apex/ca-certificates/files/da7377f6.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH
+MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF
+eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx
+MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV
+BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog
+D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS
+sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop
+O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk
+sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi
+c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj
+VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz
+KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/
+TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G
+sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs
+1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD
+fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T
+AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN
+l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR
+ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ
+VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5
+c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp
+4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s
+t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj
+2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO
+vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C
+xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx
+cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM
+fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 4f:d2:2b:8f:f5:64:c8:33:9e:4f:34:58:66:23:70:60
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=CN, O=UniTrust, CN=UCA Extended Validation Root
+ Validity
+ Not Before: Mar 13 00:00:00 2015 GMT
+ Not After : Dec 31 00:00:00 2038 GMT
+ Subject: C=CN, O=UniTrust, CN=UCA Extended Validation Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:a9:09:07:28:13:02:b0:99:e0:64:aa:1e:43:16:
+ 7a:73:b1:91:a0:75:3e:a8:fa:e3:38:00:7a:ec:89:
+ 6a:20:0f:8b:c5:b0:9b:33:03:5a:86:c6:58:86:d5:
+ c1:85:bb:4f:c6:9c:40:4d:ca:be:ee:69:96:b8:ad:
+ 81:30:9a:7c:92:05:eb:05:2b:9a:48:d0:b8:76:3e:
+ 96:c8:20:bb:d2:b0:f1:8f:d8:ac:45:46:ff:aa:67:
+ 60:b4:77:7e:6a:1f:3c:1a:52:7a:04:3d:07:3c:85:
+ 0d:84:d0:1f:76:0a:f7:6a:14:df:72:e3:34:7c:57:
+ 4e:56:01:3e:79:f1:aa:29:3b:6c:fa:f8:8f:6d:4d:
+ c8:35:df:ae:eb:dc:24:ee:79:45:a7:85:b6:05:88:
+ de:88:5d:25:7c:97:64:67:09:d9:bf:5a:15:05:86:
+ f3:09:1e:ec:58:32:33:11:f3:77:64:b0:76:1f:e4:
+ 10:35:17:1b:f2:0e:b1:6c:a4:2a:a3:73:fc:09:1f:
+ 1e:32:19:53:11:e7:d9:b3:2c:2e:76:2e:a1:a3:de:
+ 7e:6a:88:09:e8:f2:07:8a:f8:b2:cd:10:e7:e2:73:
+ 40:93:bb:08:d1:3f:e1:fc:0b:94:b3:25:ef:7c:a6:
+ d7:d1:af:9f:ff:96:9a:f5:91:7b:98:0b:77:d4:7e:
+ e8:07:d2:62:b5:95:39:e3:f3:f1:6d:0f:0e:65:84:
+ 8a:63:54:c5:80:b6:e0:9e:4b:7d:47:26:a7:01:08:
+ 5d:d1:88:9e:d7:c3:32:44:fa:82:4a:0a:68:54:7f:
+ 38:53:03:cc:a4:00:33:64:51:59:0b:a3:82:91:7a:
+ 5e:ec:16:c2:f3:2a:e6:62:da:2a:db:59:62:10:25:
+ 4a:2a:81:0b:47:07:43:06:70:87:d2:fa:93:11:29:
+ 7a:48:4d:eb:94:c7:70:4d:af:67:d5:51:b1:80:20:
+ 01:01:b4:7a:08:a6:90:7f:4e:e0:ef:07:41:87:af:
+ 6a:a5:5e:8b:fb:cf:50:b2:9a:54:af:c3:89:ba:58:
+ 2d:f5:30:98:b1:36:72:39:7e:49:04:fd:29:a7:4c:
+ 79:e4:05:57:db:94:b9:16:53:8d:46:b3:1d:95:61:
+ 57:56:7f:af:f0:16:5b:61:58:6f:36:50:11:0b:d8:
+ ac:2b:95:16:1a:0e:1f:08:cd:36:34:65:10:62:66:
+ d5:80:5f:14:20:5f:2d:0c:a0:78:0a:68:d6:2c:d7:
+ e9:6f:2b:d2:4a:05:93:fc:9e:6f:6b:67:ff:88:f1:
+ 4e:a5:69:4a:52:37:05:ea:c6:16:8d:d2:c4:99:d1:
+ 82:2b:3b:ba:35:75:f7:51:51:58:f3:c8:07:dd:e4:
+ b4:03:7f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ D9:74:3A:E4:30:3D:0D:F7:12:DC:7E:5A:05:9F:1E:34:9A:F7:E1:14
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 36:8d:97:cc:42:15:64:29:37:9b:26:2c:d6:fb:ae:15:69:2c:
+ 6b:1a:1a:f7:5f:b6:f9:07:4c:59:ea:f3:c9:c8:b9:ae:cc:ba:
+ 2e:7a:dc:c0:f5:b0:2d:c0:3b:af:9f:70:05:11:6a:9f:25:4f:
+ 01:29:70:e3:e5:0c:e1:ea:5a:7c:dc:49:bb:c1:1e:2a:81:f5:
+ 16:4b:72:91:c8:a2:31:b9:aa:da:fc:9d:1f:f3:5d:40:02:13:
+ fc:4e:1c:06:ca:b3:14:90:54:17:19:12:1a:f1:1f:d7:0c:69:
+ 5a:f6:71:78:f4:94:7d:91:0b:8e:ec:90:54:8e:bc:6f:a1:4c:
+ ab:fc:74:64:fd:71:9a:f8:41:07:a1:cd:91:e4:3c:9a:e0:9b:
+ 32:39:73:ab:2a:d5:69:c8:78:91:26:31:7d:e2:c7:30:f1:fc:
+ 14:78:77:12:0e:13:f4:dd:16:94:bf:4b:67:7b:70:53:85:ca:
+ b0:bb:f3:38:4d:2c:90:39:c0:0d:c2:5d:6b:e9:e2:e5:d5:88:
+ 8d:d6:2c:bf:ab:1b:be:b5:28:87:12:17:74:6e:fc:7d:fc:8f:
+ d0:87:26:b0:1b:fb:b9:6c:ab:e2:9e:3d:15:c1:3b:2e:67:02:
+ 58:91:9f:ef:f8:42:1f:2c:b7:68:f5:75:ad:cf:b5:f6:ff:11:
+ 7d:c2:f0:24:a5:ad:d3:fa:a0:3c:a9:fa:5d:dc:a5:a0:ef:44:
+ a4:be:d6:e8:e5:e4:13:96:17:7b:06:3e:32:ed:c7:b7:42:bc:
+ 76:a3:d8:65:38:2b:38:35:51:21:0e:0e:6f:2e:34:13:40:e1:
+ 2b:67:0c:6d:4a:41:30:18:23:5a:32:55:99:c9:17:e0:3c:de:
+ f6:ec:79:ad:2b:58:19:a2:ad:2c:22:1a:95:8e:be:96:90:5d:
+ 42:57:c4:f9:14:03:35:2b:1c:2d:51:57:08:a7:3a:de:3f:e4:
+ c8:b4:03:73:c2:c1:26:80:bb:0b:42:1f:ad:0d:af:26:72:da:
+ cc:be:b3:a3:83:58:0d:82:c5:1f:46:51:e3:9c:18:cc:8d:9b:
+ 8d:ec:49:eb:75:50:d5:8c:28:59:ca:74:34:da:8c:0b:21:ab:
+ 1e:ea:1b:e5:c7:fd:15:3e:c0:17:aa:fb:23:6e:26:46:cb:fa:
+ f9:b1:72:6b:69:cf:22:84:0b:62:0f:ac:d9:19:00:94:a2:76:
+ 3c:d4:2d:9a:ed:04:9e:2d:06:62:10:37:52:1c:85:72:1b:27:
+ e5:cc:c6:31:ec:37:ec:63:59:9b:0b:1d:76:cc:7e:32:9a:88:
+ 95:08:36:52:bb:de:76:5f:76:49:49:ad:7f:bd:65:20:b2:c9:
+ c1:2b:76:18:76:9f:56:b1
+SHA1 Fingerprint=A3:A1:B0:6F:24:61:23:4A:E3:36:A5:C2:37:FC:A6:FF:DD:F0:D7:3A
diff --git a/apex/ca-certificates/files/dbc54cab.0 b/apex/ca-certificates/files/dbc54cab.0
new file mode 100644
index 0000000..b360d90
--- /dev/null
+++ b/apex/ca-certificates/files/dbc54cab.0
@@ -0,0 +1,120 @@
+-----BEGIN CERTIFICATE-----
+MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE
+BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz
+dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG
+A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U
+cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf
+qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ
+JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ
++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS
+s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5
+HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7
+70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG
+V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S
+qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S
+5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia
+C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX
+OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE
+FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
+BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2
+KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
+Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B
+8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ
+MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc
+0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ
+u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF
+u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH
+YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8
+GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO
+RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e
+KeC2uAloGRwYQw==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 7893706540734352110 (0x6d8c1446b1a60aee)
+ Signature Algorithm: sha384WithRSAEncryption
+ Issuer: C=US, O=AffirmTrust, CN=AffirmTrust Premium
+ Validity
+ Not Before: Jan 29 14:10:36 2010 GMT
+ Not After : Dec 31 14:10:36 2040 GMT
+ Subject: C=US, O=AffirmTrust, CN=AffirmTrust Premium
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:c4:12:df:a9:5f:fe:41:dd:dd:f5:9f:8a:e3:f6:
+ ac:e1:3c:78:9a:bc:d8:f0:7f:7a:a0:33:2a:dc:8d:
+ 20:5b:ae:2d:6f:e7:93:d9:36:70:6a:68:cf:8e:51:
+ a3:85:5b:67:04:a0:10:24:6f:5d:28:82:c1:97:57:
+ d8:48:29:13:b6:e1:be:91:4d:df:85:0c:53:18:9a:
+ 1e:24:a2:4f:8f:f0:a2:85:0b:cb:f4:29:7f:d2:a4:
+ 58:ee:26:4d:c9:aa:a8:7b:9a:d9:fa:38:de:44:57:
+ 15:e5:f8:8c:c8:d9:48:e2:0d:16:27:1d:1e:c8:83:
+ 85:25:b7:ba:aa:55:41:cc:03:22:4b:2d:91:8d:8b:
+ e6:89:af:66:c7:e9:ff:2b:e9:3c:ac:da:d2:b3:c3:
+ e1:68:9c:89:f8:7a:00:56:de:f4:55:95:6c:fb:ba:
+ 64:dd:62:8b:df:0b:77:32:eb:62:cc:26:9a:9b:bb:
+ aa:62:83:4c:b4:06:7a:30:c8:29:bf:ed:06:4d:97:
+ b9:1c:c4:31:2b:d5:5f:bc:53:12:17:9c:99:57:29:
+ 66:77:61:21:31:07:2e:25:49:9d:18:f2:ee:f3:2b:
+ 71:8c:b5:ba:39:07:49:77:fc:ef:2e:92:90:05:8d:
+ 2d:2f:77:7b:ef:43:bf:35:bb:9a:d8:f9:73:a7:2c:
+ f2:d0:57:ee:28:4e:26:5f:8f:90:68:09:2f:b8:f8:
+ dc:06:e9:2e:9a:3e:51:a7:d1:22:c4:0a:a7:38:48:
+ 6c:b3:f9:ff:7d:ab:86:57:e3:ba:d6:85:78:77:ba:
+ 43:ea:48:7f:f6:d8:be:23:6d:1e:bf:d1:36:6c:58:
+ 5c:f1:ee:a4:19:54:1a:f5:03:d2:76:e6:e1:8c:bd:
+ 3c:b3:d3:48:4b:e2:c8:f8:7f:92:a8:76:46:9c:42:
+ 65:3e:a4:1e:c1:07:03:5a:46:2d:b8:97:f3:b7:d5:
+ b2:55:21:ef:ba:dc:4c:00:97:fb:14:95:27:33:bf:
+ e8:43:47:46:d2:08:99:16:60:3b:9a:7e:d2:e6:ed:
+ 38:ea:ec:01:1e:3c:48:56:49:09:c7:4c:37:00:9e:
+ 88:0e:c0:73:e1:6f:66:e9:72:47:30:3e:10:e5:0b:
+ 03:c9:9a:42:00:6c:c5:94:7e:61:c4:8a:df:7f:82:
+ 1a:0b:59:c4:59:32:77:b3:bc:60:69:56:39:fd:b4:
+ 06:7b:2c:d6:64:36:d9:bd:48:ed:84:1f:7e:a5:22:
+ 8f:2a:b8:42:f4:82:b7:d4:53:90:78:4e:2d:1a:fd:
+ 81:6f:44:d7:3b:01:74:96:42:e0:00:e2:2e:6b:ea:
+ c5:ee:72:ac:bb:bf:fe:ea:aa:a8:f8:dc:f6:b2:79:
+ 8a:b6:67
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 9D:C0:67:A6:0C:22:D9:26:F5:45:AB:A6:65:52:11:27:D8:45:AC:63
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha384WithRSAEncryption
+ Signature Value:
+ b3:57:4d:10:62:4e:3a:e4:ac:ea:b8:1c:af:32:23:c8:b3:49:
+ 5a:51:9c:76:28:8d:79:aa:57:46:17:d5:f5:52:f6:b7:44:e8:
+ 08:44:bf:18:84:d2:0b:80:cd:c5:12:fd:00:55:05:61:87:41:
+ dc:b5:24:9e:3c:c4:d8:c8:fb:70:9e:2f:78:96:83:20:36:de:
+ 7c:0f:69:13:88:a5:75:36:98:08:a6:c6:df:ac:ce:e3:58:d6:
+ b7:3e:de:ba:f3:eb:34:40:d8:a2:81:f5:78:3f:2f:d5:a5:fc:
+ d9:a2:d4:5e:04:0e:17:ad:fe:41:f0:e5:b2:72:fa:44:82:33:
+ 42:e8:2d:58:f7:56:8c:62:3f:ba:42:b0:9c:0c:5c:7e:2e:65:
+ 26:5c:53:4f:00:b2:78:7e:a1:0d:99:2d:8d:b8:1d:8e:a2:c4:
+ b0:fd:60:d0:30:a4:8e:c8:04:62:a9:c4:ed:35:de:7a:97:ed:
+ 0e:38:5e:92:2f:93:70:a5:a9:9c:6f:a7:7d:13:1d:7e:c6:08:
+ 48:b1:5e:67:eb:51:08:25:e9:e6:25:6b:52:29:91:9c:d2:39:
+ 73:08:57:de:99:06:b4:5b:9d:10:06:e1:c2:00:a8:b8:1c:4a:
+ 02:0a:14:d0:c1:41:ca:fb:8c:35:21:7d:82:38:f2:a9:54:91:
+ 19:35:93:94:6d:6a:3a:c5:b2:d0:bb:89:86:93:e8:9b:c9:0f:
+ 3a:a7:7a:b8:a1:f0:78:46:fa:fc:37:2f:e5:8a:84:f3:df:fe:
+ 04:d9:a1:68:a0:2f:24:e2:09:95:06:d5:95:ca:e1:24:96:eb:
+ 7c:f6:93:05:bb:ed:73:e9:2d:d1:75:39:d7:e7:24:db:d8:4e:
+ 5f:43:8f:9e:d0:14:39:bf:55:70:48:99:57:31:b4:9c:ee:4a:
+ 98:03:96:30:1f:60:06:ee:1b:23:fe:81:60:23:1a:47:62:85:
+ a5:cc:19:34:80:6f:b3:ac:1a:e3:9f:f0:7b:48:ad:d5:01:d9:
+ 67:b6:a9:72:93:ea:2d:66:b5:b2:b8:e4:3d:3c:b2:ef:4c:8c:
+ ea:eb:07:bf:ab:35:9a:55:86:bc:18:a6:b5:a8:5e:b4:83:6c:
+ 6b:69:40:d3:9f:dc:f1:c3:69:6b:b9:e1:6d:09:f4:f1:aa:50:
+ 76:0a:7a:7d:7a:17:a1:55:96:42:99:31:09:dd:60:11:8d:05:
+ 30:7e:e6:8e:46:d1:9d:14:da:c7:17:e4:05:96:8c:c4:24:b5:
+ 1b:cf:14:07:b2:40:f8:a3:9e:41:86:bc:04:d0:6b:96:c8:2a:
+ 80:34:fd:bf:ef:06:a3:dd:58:c5:85:3d:3e:8f:fe:9e:29:e0:
+ b6:b8:09:68:19:1c:18:43
+SHA1 Fingerprint=D8:A6:33:2C:E0:03:6F:B1:85:F6:63:4F:7D:6A:06:65:26:32:28:27
diff --git a/apex/ca-certificates/files/dbff3a01.0 b/apex/ca-certificates/files/dbff3a01.0
new file mode 100644
index 0000000..4000b08
--- /dev/null
+++ b/apex/ca-certificates/files/dbff3a01.0
@@ -0,0 +1,80 @@
+-----BEGIN CERTIFICATE-----
+MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG
+A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg
+SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw
+MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln
+biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v
+dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ
+BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ
+HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH
+3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH
+GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c
+xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1
+aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq
+TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
+BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87
+/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4
+kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG
+YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT
++xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo
+WXzhriKi4gp6D/piq1JM4fHfyr6DDUI=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ ae:cf:00:ba:c4:cf:32:f8:43:b2
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, OU=emSign PKI, O=eMudhra Inc, CN=emSign Root CA - C1
+ Validity
+ Not Before: Feb 18 18:30:00 2018 GMT
+ Not After : Feb 18 18:30:00 2043 GMT
+ Subject: C=US, OU=emSign PKI, O=eMudhra Inc, CN=emSign Root CA - C1
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:cf:eb:a9:b9:f1:99:05:cc:d8:28:21:4a:f3:73:
+ 34:51:84:56:10:f5:a0:4f:2c:12:e3:fa:13:9a:27:
+ d0:cf:f9:79:1a:74:5f:1d:79:39:fc:5b:f8:70:8e:
+ e0:92:52:f7:e4:25:f9:54:83:d9:1d:d3:c8:5a:85:
+ 3f:5e:c7:b6:07:ee:3e:c0:ce:9a:af:ac:56:42:2a:
+ 39:25:70:d6:bf:b5:7b:36:ad:ac:f6:73:dc:cd:d7:
+ 1d:8a:83:a5:fb:2b:90:15:37:6b:1c:26:47:dc:3b:
+ 29:56:93:6a:b3:c1:6a:3a:9d:3d:f5:c1:97:38:58:
+ 05:8b:1c:11:e3:e4:b4:b8:5d:85:1d:83:fe:78:5f:
+ 0b:45:68:18:48:a5:46:73:34:3b:fe:0f:c8:76:bb:
+ c7:18:f3:05:d1:86:f3:85:ed:e7:b9:d9:32:ad:55:
+ 88:ce:a6:b6:91:b0:4f:ac:7e:15:23:96:f6:3f:f0:
+ 20:34:16:de:0a:c6:c4:04:45:79:7f:a7:fd:be:d2:
+ a9:a5:af:9c:c5:23:2a:f7:3c:21:6c:bd:af:8f:4e:
+ c5:3a:b2:f3:34:12:fc:df:80:1a:49:a4:d4:a9:95:
+ f7:9e:89:5e:a2:89:ac:94:cb:a8:68:9b:af:8a:65:
+ 27:cd:89:ee:dd:8c:b5:6b:29:70:43:a0:69:0b:e4:
+ b9:0f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ FE:A1:E0:70:1E:2A:03:39:52:5A:42:BE:5C:91:85:7A:18:AA:4D:B5
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ c2:4a:56:fa:15:21:7b:28:a2:e9:e5:1d:fb:f8:2d:c4:39:96:
+ 41:4c:3b:27:2c:c4:6c:18:15:80:c6:ac:af:47:59:2f:26:0b:
+ e3:36:b0:ef:3b:fe:43:97:49:32:99:12:15:5b:df:11:29:ff:
+ ab:53:f8:bb:c1:78:0f:ac:9c:53:af:57:bd:68:8c:3d:69:33:
+ f0:a3:a0:23:63:3b:64:67:22:44:ad:d5:71:cb:56:2a:78:92:
+ a3:4f:12:31:36:36:e2:de:fe:00:c4:a3:60:0f:27:ad:a0:b0:
+ 8a:b5:36:7a:52:a1:bd:27:f4:20:27:62:e8:4d:94:24:13:e4:
+ 0a:04:e9:3c:ab:2e:c8:43:09:4a:c6:61:04:e5:49:34:7e:d3:
+ c4:c8:f5:0f:c0:aa:e9:ba:54:5e:f3:63:2b:4f:4f:50:d4:fe:
+ b9:7b:99:8c:3d:c0:2e:bc:02:2b:d3:c4:40:e4:8a:07:31:1e:
+ 9b:ce:26:99:13:fb:11:ea:9a:22:0c:11:19:c7:5e:1b:81:50:
+ 30:c8:96:12:6e:e7:cb:41:7f:91:3b:a2:47:b7:54:80:1b:dc:
+ 00:cc:9a:90:ea:c3:c3:50:06:62:0c:30:c0:15:48:a7:a8:59:
+ 7c:e1:ae:22:a2:e2:0a:7a:0f:fa:62:ab:52:4c:e1:f1:df:ca:
+ be:83:0d:42
+SHA1 Fingerprint=E7:2E:F1:DF:FC:B2:09:28:CF:5D:D4:D5:67:37:B1:51:CB:86:4F:01
diff --git a/apex/ca-certificates/files/dc99f41e.0 b/apex/ca-certificates/files/dc99f41e.0
new file mode 100644
index 0000000..c519986
--- /dev/null
+++ b/apex/ca-certificates/files/dc99f41e.0
@@ -0,0 +1,124 @@
+-----BEGIN CERTIFICATE-----
+MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix
+DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k
+IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT
+N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v
+dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG
+A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh
+ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx
+QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1
+dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA
+4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0
+AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10
+4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C
+ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV
+9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD
+gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6
+Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq
+NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko
+LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc
+Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV
+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd
+ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I
+XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI
+M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot
+9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V
+Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea
+j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh
+X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ
+l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf
+bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4
+pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK
+e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0
+vm9qp/UsQu0yrbYhnr68
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 0 (0x0)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=GR, L=Athens, O=Hellenic Academic and Research Institutions Cert. Authority, CN=Hellenic Academic and Research Institutions RootCA 2015
+ Validity
+ Not Before: Jul 7 10:11:21 2015 GMT
+ Not After : Jun 30 10:11:21 2040 GMT
+ Subject: C=GR, L=Athens, O=Hellenic Academic and Research Institutions Cert. Authority, CN=Hellenic Academic and Research Institutions RootCA 2015
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:c2:f8:a9:3f:1b:89:fc:3c:3c:04:5d:3d:90:36:
+ b0:91:3a:79:3c:66:5a:ef:6d:39:01:49:1a:b4:b7:
+ cf:7f:4d:23:53:b7:90:00:e3:13:2a:28:a6:31:f1:
+ 91:00:e3:28:ec:ae:21:41:ce:1f:da:fd:7d:12:5b:
+ 01:83:0f:b9:b0:5f:99:e1:f2:12:83:80:4d:06:3e:
+ df:ac:af:e7:a1:88:6b:31:af:f0:8b:d0:18:33:b8:
+ db:45:6a:34:f4:02:80:24:28:0a:02:15:95:5e:76:
+ 2a:0d:99:3a:14:5b:f6:cb:cb:53:bc:13:4d:01:88:
+ 37:94:25:1b:42:bc:22:d8:8e:a3:96:5e:3a:d9:32:
+ db:3e:e8:f0:10:65:ed:74:e1:2f:a7:7c:af:27:34:
+ bb:29:7d:9b:b6:cf:09:c8:e5:d3:0a:fc:88:65:65:
+ 74:0a:dc:73:1c:5c:cd:40:b1:1c:d4:b6:84:8c:4c:
+ 50:cf:68:8e:a8:59:ae:c2:27:4e:82:a2:35:dd:14:
+ f4:1f:ff:b2:77:d5:87:2f:aa:6e:7d:24:27:e7:c6:
+ cb:26:e6:e5:fe:67:07:63:d8:45:0d:dd:3a:59:65:
+ 39:58:7a:92:99:72:3d:9c:84:5e:88:21:b8:d5:f4:
+ 2c:fc:d9:70:52:4f:78:b8:bd:3c:2b:8b:95:98:f5:
+ b3:d1:68:cf:20:14:7e:4c:5c:5f:e7:8b:e5:f5:35:
+ 81:19:37:d7:11:08:b7:66:be:d3:4a:ce:83:57:00:
+ 3a:c3:81:f8:17:cb:92:36:5d:d1:a3:d8:75:1b:e1:
+ 8b:27:ea:7a:48:41:fd:45:19:06:ad:27:99:4e:c1:
+ 70:47:dd:b5:9f:81:53:12:e5:b1:8c:48:5d:31:43:
+ 17:e3:8c:c6:7a:63:96:4b:29:30:4e:84:4e:62:19:
+ 5e:3c:ce:97:90:a5:7f:01:eb:9d:e0:f8:8b:89:dd:
+ 25:98:3d:92:b6:7e:ef:d9:f1:51:51:7d:2d:26:c8:
+ 69:59:61:e0:ac:6a:b8:2a:36:11:04:7a:50:bd:32:
+ 84:be:2f:dc:72:d5:d7:1d:16:47:e4:47:66:20:3f:
+ f4:96:c5:af:8e:01:7a:a5:0f:7a:64:f5:0d:18:87:
+ d9:ae:88:d5:fa:84:c1:3a:c0:69:28:2d:f2:0d:68:
+ 51:aa:e3:a5:77:c6:a4:90:0e:a1:37:8b:31:23:47:
+ c1:09:08:eb:6e:f7:78:9b:d7:82:fc:84:20:99:49:
+ 19:b6:12:46:b1:fb:45:55:16:a9:a3:65:ac:9c:07:
+ 0f:ea:6b:dc:1f:2e:06:72:ec:86:88:12:e4:2d:db:
+ 5f:05:2f:e4:f0:03:d3:26:33:e7:80:c2:cd:42:a1:
+ 17:34:0b
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 71:15:67:C8:C8:C9:BD:75:5D:72:D0:38:18:6A:9D:F3:71:24:54:0B
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 75:bb:6d:54:4b:aa:10:58:46:34:f2:62:d7:16:36:5d:08:5e:
+ d5:6c:c8:87:bd:b4:2e:46:f2:31:f8:7c:ea:42:b5:93:16:55:
+ dc:a1:0c:12:a0:da:61:7e:0f:58:58:73:64:72:c7:e8:45:8e:
+ dc:a9:f2:26:3f:c6:79:8c:b1:53:08:33:81:b0:56:13:be:e6:
+ 51:5c:d8:9b:0a:4f:4b:9c:56:53:02:e9:4f:f6:0d:60:ea:4d:
+ 42:55:e8:7c:1b:21:21:d3:1b:3a:cc:77:f2:b8:90:f1:68:c7:
+ f9:5a:fe:fa:2d:f4:bf:c9:f5:45:1b:ce:38:10:2a:37:8a:79:
+ a3:b4:e3:09:6c:85:86:93:ff:89:96:27:78:81:8f:67:e3:46:
+ 74:54:8e:d9:0d:69:e2:4a:f4:4d:74:03:ff:b2:77:ed:95:67:
+ 97:e4:b1:c5:ab:bf:6a:23:e8:d4:94:e2:44:28:62:c4:4b:e2:
+ f0:d8:e2:29:6b:1a:70:7e:24:61:93:7b:4f:03:32:25:0d:45:
+ 24:2b:96:b4:46:6a:bf:4a:0b:f7:9a:8f:c1:ac:1a:c5:67:f3:
+ 6f:34:d2:fa:73:63:8c:ef:16:b0:a8:a4:46:2a:f8:eb:12:ec:
+ 72:b4:ef:f8:2b:7e:8c:52:c0:8b:84:54:f9:2f:3e:e3:55:a8:
+ dc:66:b1:d9:e1:5f:d8:b3:8c:59:34:59:a4:ab:4f:6c:bb:1f:
+ 18:db:75:ab:d8:cb:92:cd:94:38:61:0e:07:06:1f:4b:46:10:
+ f1:15:be:8d:85:5c:3b:4a:2b:81:79:0f:b4:69:9f:49:50:97:
+ 4d:f7:0e:56:5d:c0:95:6a:c2:36:c3:1b:68:c9:f5:2a:dc:47:
+ 9a:be:b2:ce:c5:25:e8:fa:03:b9:da:f9:16:6e:91:84:f5:1c:
+ 28:c8:fc:26:cc:d7:1c:90:56:a7:5f:6f:3a:04:bc:cd:78:89:
+ 0b:8e:0f:2f:a3:aa:4f:a2:1b:12:3d:16:08:40:0f:f1:46:4c:
+ d7:aa:7b:08:c1:0a:f5:6d:27:de:02:8f:ca:c3:b5:2b:ca:e9:
+ eb:c8:21:53:38:a5:cc:3b:d8:77:37:30:a2:4f:d9:6f:d1:f2:
+ 40:ad:41:7a:17:c5:d6:4a:35:89:b7:41:d5:7c:86:7f:55:4d:
+ 83:4a:a5:73:20:c0:3a:af:90:f1:9a:24:8e:d9:8e:71:ca:7b:
+ b8:86:da:b2:8f:99:3e:1d:13:0d:12:11:ee:d4:ab:f0:e9:15:
+ 76:02:e4:e0:df:aa:20:1e:5b:61:85:64:40:a9:90:97:0d:ad:
+ 53:d2:5a:1d:87:6a:00:97:65:62:b4:be:6f:6a:a7:f5:2c:42:
+ ed:32:ad:b6:21:9e:be:bc
+SHA1 Fingerprint=01:0C:06:95:A6:98:19:14:FF:BF:5F:C6:B0:B6:95:EA:29:E9:12:A6
diff --git a/apex/ca-certificates/files/dfc0fe80.0 b/apex/ca-certificates/files/dfc0fe80.0
new file mode 100644
index 0000000..1b82f31
--- /dev/null
+++ b/apex/ca-certificates/files/dfc0fe80.0
@@ -0,0 +1,83 @@
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt
+MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg
+Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i
+YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x
+CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG
+b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh
+bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3
+HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx
+WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX
+1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk
+u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P
+99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r
+M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB
+BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh
+cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5
+gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO
+ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf
+aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic
+Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 76:b1:20:52:74:f0:85:87:46:b3:f8:23:1a:f6:c2:c0
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=CH, O=WISeKey, OU=OISTE Foundation Endorsed, CN=OISTE WISeKey Global Root GB CA
+ Validity
+ Not Before: Dec 1 15:00:32 2014 GMT
+ Not After : Dec 1 15:10:31 2039 GMT
+ Subject: C=CH, O=WISeKey, OU=OISTE Foundation Endorsed, CN=OISTE WISeKey Global Root GB CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:d8:17:b7:1c:4a:24:2a:d6:97:b1:ca:e2:1e:fb:
+ 7d:38:ef:98:f5:b2:39:98:4e:27:b8:11:5d:7b:d2:
+ 25:94:88:82:15:26:6a:1b:31:bb:a8:5b:21:21:2b:
+ d8:0f:4e:9f:5a:f1:b1:5a:e4:79:d6:32:23:2b:e1:
+ 53:cc:99:45:5c:7b:4f:ad:bc:bf:87:4a:0b:4b:97:
+ 5a:a8:f6:48:ec:7d:7b:0d:cd:21:06:df:9e:15:fd:
+ 41:8a:48:b7:20:f4:a1:7a:1b:57:d4:5d:50:ff:ba:
+ 67:d8:23:99:1f:c8:3f:e3:de:ff:6f:5b:77:b1:6b:
+ 6e:b8:c9:64:f7:e1:ca:41:46:0e:29:71:d0:b9:23:
+ fc:c9:81:5f:4e:f7:6f:df:bf:84:ad:73:64:bb:b7:
+ 42:8e:69:f6:d4:76:1d:7e:9d:a7:b8:57:8a:51:67:
+ 72:d7:d4:a8:b8:95:54:40:73:03:f6:ea:f4:eb:fe:
+ 28:42:77:3f:9d:23:1b:b2:b6:3d:80:14:07:4c:2e:
+ 4f:f7:d5:0a:16:0d:bd:66:43:37:7e:23:43:79:c3:
+ 40:86:f5:4c:29:da:8e:9a:ad:0d:a5:04:87:88:1e:
+ 85:e3:e9:53:d5:9b:c8:8b:03:63:78:eb:e0:19:4a:
+ 6e:bb:2f:6b:33:64:58:93:ad:69:bf:8f:1b:ef:82:
+ 48:c7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage:
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 35:0F:C8:36:63:5E:E2:A3:EC:F9:3B:66:15:CE:51:52:E3:91:9A:3D
+ 1.3.6.1.4.1.311.21.1:
+ ...
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 40:4c:fb:87:b2:99:81:90:7e:9d:c5:b0:b0:26:cd:88:7b:2b:
+ 32:8d:6e:b8:21:71:58:97:7d:ae:37:14:af:3e:e7:f7:9a:e2:
+ 7d:f6:71:98:99:04:aa:43:74:78:a3:e3:49:61:3e:73:8c:4d:
+ 94:e0:f9:71:c4:b6:16:0e:53:78:1f:d6:a2:87:2f:02:39:81:
+ 29:3c:af:15:98:21:30:fe:28:90:00:8c:d1:e1:cb:fa:5e:c8:
+ fd:f8:10:46:3b:a2:78:42:91:17:74:55:0a:de:50:67:4d:66:
+ d1:a7:ff:fd:d9:c0:b5:a8:a3:8a:ce:66:f5:0f:43:cd:a7:2b:
+ 57:7b:63:46:6a:aa:2e:52:d8:f4:ed:e1:6d:ad:29:90:78:48:
+ ba:e1:23:aa:a3:89:ec:b5:ab:96:c0:b4:4b:a2:1d:97:9e:7a:
+ f2:6e:40:71:df:68:f1:65:4d:ce:7c:05:df:53:65:a9:a5:f0:
+ b1:97:04:70:15:46:03:98:d4:d2:bf:54:b4:a0:58:7d:52:6f:
+ da:56:26:62:d4:d8:db:89:31:6f:1c:f0:22:c2:d3:62:1c:35:
+ cd:4c:69:15:54:1a:90:98:de:eb:1e:5f:ca:77:c7:cb:8e:3d:
+ 43:69:9c:9a:58:d0:24:3b:df:1b:40:96:7e:35:ad:81:c7:4e:
+ 71:ba:88:13
+SHA1 Fingerprint=0F:F9:40:76:18:D3:D7:6A:4B:98:F0:A8:35:9E:0C:FD:27:AC:CC:ED
diff --git a/apex/ca-certificates/files/e13665f9.0 b/apex/ca-certificates/files/e13665f9.0
new file mode 100644
index 0000000..c8e6115
--- /dev/null
+++ b/apex/ca-certificates/files/e13665f9.0
@@ -0,0 +1,125 @@
+-----BEGIN CERTIFICATE-----
+MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQEL
+BQAwYTELMAkGA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUg
+Q2VydGlmaWNhdGlvbiBFbGVjdHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJv
+b3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQwNDI2MDg1NzU2WjBhMQswCQYDVQQG
+EwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBDZXJ0aWZpY2F0aW9u
+IEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIwDQYJ
+KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZ
+n56eY+hz2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd
+2JQDoOw05TDENX37Jk0bbjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgF
+VwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZ
+GoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAdgjH8KcwAWJeRTIAAHDOF
+li/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViWVSHbhlnU
+r8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2
+eY8fTpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIb
+MlEsPvLfe/ZdeikZjuXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISg
+jwBUFfyRbVinljvrS5YnzWuioYasDXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB
+7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwSVXAkPcvCFDVDXSdOvsC9qnyW
+5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI04Y+oXNZtPdE
+ITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0
+90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+z
+xiD2BkewhpMl0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYu
+QEkHDVneixCwSQXi/5E/S7fdAo74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4
+FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRYYdZ2vyJ/0Adqp2RT8JeNnYA/u8EH
+22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJpadbGNjHh/PqAulxP
+xOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65xxBzn
+dFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5
+Xc0yGYuPjCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7b
+nV2UqL1g52KAdoGDDIzMMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQ
+CvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9zZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZH
+u/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3rAZ3r2OvEhJn7wAzMMujj
+d9qDRIueVSjAi1jTkD5OGwDxFa2DK5o=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 13:02:d5:e2:40:4c:92:46:86:16:67:5d:b4:bb:bb:b2:6b:3e:fc:13
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=TN, O=Agence Nationale de Certification Electronique, CN=TunTrust Root CA
+ Validity
+ Not Before: Apr 26 08:57:56 2019 GMT
+ Not After : Apr 26 08:57:56 2044 GMT
+ Subject: C=TN, O=Agence Nationale de Certification Electronique, CN=TunTrust Root CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:c3:cd:d3:fc:bd:04:53:dd:0c:20:3a:d5:88:2e:
+ 05:4b:41:f5:83:82:7e:f7:59:9f:9e:9e:63:e8:73:
+ da:f6:06:a9:4f:1f:b4:f9:0b:1f:39:8c:9a:20:d0:
+ 7e:06:d4:ec:34:d9:86:bc:75:5b:87:88:f0:d2:d9:
+ d4:a3:0a:b2:6c:1b:eb:49:2c:3e:ac:5d:d8:94:03:
+ a0:ec:34:e5:30:c4:35:7d:fb:26:4d:1b:6e:30:54:
+ d8:f5:80:45:9c:39:ad:9c:c9:25:04:4d:9a:90:3e:
+ 4e:40:6e:8a:6b:cd:29:67:c6:cc:2d:e0:74:e8:05:
+ 57:0a:48:50:fa:7a:43:da:7e:ec:5b:9a:0e:62:76:
+ fe:ea:9d:1d:85:72:ec:11:bb:35:e8:1f:27:bf:c1:
+ a1:c7:bb:48:16:dd:56:d7:cc:4e:a0:e1:b9:ac:db:
+ d5:83:19:1a:85:d1:94:97:d7:ca:a3:65:0b:f3:38:
+ f9:02:ae:dd:f6:67:cf:c9:3f:f5:8a:2c:47:1a:99:
+ 6f:05:0d:fd:d0:1d:82:31:fc:29:cc:00:58:97:91:
+ 4c:80:00:1c:33:85:96:2f:cb:41:c2:8b:10:84:c3:
+ 09:24:89:1f:b5:0f:d9:d9:77:47:18:92:94:60:5c:
+ c7:99:03:3c:fe:f7:95:a7:7d:50:a1:80:c2:a9:83:
+ ad:58:96:55:21:db:86:59:d4:af:c6:bc:dd:81:6e:
+ 07:db:60:62:fe:ec:10:6e:da:68:01:f4:83:1b:a9:
+ 3e:a2:5b:23:d7:64:c6:df:dc:a2:7d:d8:4b:ba:82:
+ d2:51:f8:66:bf:06:46:e4:79:2a:26:36:79:8f:1f:
+ 4e:99:1d:b2:8f:0c:0e:1c:ff:c9:5d:c0:fd:90:10:
+ a6:b1:37:f3:cd:3a:24:6e:b4:85:90:bf:80:b9:0c:
+ 8c:d5:9b:d6:c8:f1:56:3f:1a:80:89:7a:a9:e2:1b:
+ 32:51:2c:3e:f2:df:7b:f6:5d:7a:29:19:8e:e5:c8:
+ bd:36:71:8b:5d:4c:c2:1d:3f:ad:58:a2:cf:3d:70:
+ 4d:a6:50:98:25:dc:23:f9:b8:58:41:08:71:bf:4f:
+ b8:84:a0:8f:00:54:15:fc:91:6d:58:a7:96:3b:eb:
+ 4b:96:27:cd:6b:a2:a1:86:ac:0d:7c:54:e6:66:4c:
+ 66:5f:90:be:21:9a:02:46:2d:e4:83:c2:80:b9:cf:
+ 4b:3e:e8:7f:3c:01:ec:8f:5e:cd:7f:d2:28:42:01:
+ 95:8a:e2:97:3d:10:21:7d:f6:9d:1c:c5:34:a1:ec:
+ 2c:0e:0a:52:2c:12:55:70:24:3d:cb:c2:14:35:43:
+ 5d:27:4e:be:c0:bd:aa:7c:96:e7:fc:9e:61:ad:44:
+ d3:00:97
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 06:9A:9B:1F:53:7D:F1:F5:A4:C8:D3:86:3E:A1:73:59:B4:F7:44:21
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Authority Key Identifier:
+ 06:9A:9B:1F:53:7D:F1:F5:A4:C8:D3:86:3E:A1:73:59:B4:F7:44:21
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ aa:05:6e:b6:dd:15:c9:bf:b3:c6:20:f6:06:47:b0:86:93:25:
+ d3:8d:b9:c8:00:3f:97:f5:52:27:88:71:c9:74:fd:eb:ca:64:
+ db:5b:ef:1e:5d:ba:bf:d1:eb:ee:5c:69:ba:16:c8:f3:b9:8f:
+ d3:36:2e:40:49:07:0d:59:de:8b:10:b0:49:05:e2:ff:91:3f:
+ 4b:b7:dd:02:8e:f8:81:28:5c:cc:dc:6d:af:5f:14:9c:7d:58:
+ 78:0d:f6:80:09:b9:e9:0e:97:29:19:b8:b7:eb:f8:16:cb:55:
+ 12:e4:c6:7d:bb:c4:ec:f8:b5:1c:4e:3e:67:bf:c5:5f:1b:6d:
+ 6d:47:28:aa:04:58:61:d6:76:bf:22:7f:d0:07:6a:a7:64:53:
+ f0:97:8d:9d:80:3f:bb:c1:07:db:65:af:e6:9b:32:9a:c3:54:
+ 93:c4:1c:08:c3:44:fb:7b:63:11:43:d1:6a:1a:61:6a:79:6d:
+ 90:4f:29:8e:47:05:c1:12:69:69:d6:c6:36:31:e1:fc:fa:80:
+ ba:5c:4f:c4:eb:b7:32:ac:f8:75:61:17:d7:10:19:b9:f1:d2:
+ 09:ef:7a:42:9d:5b:5a:0b:d4:c6:95:4e:2a:ce:ff:07:d7:4f:
+ 7e:18:06:88:f1:19:b5:d9:98:bb:ae:71:c4:1c:e7:74:59:58:
+ ef:0c:89:cf:8b:1f:75:93:1a:04:14:92:48:50:a9:eb:57:29:
+ 00:16:e3:36:1c:c8:f8:bf:f0:33:d5:41:0f:c4:cc:3c:dd:e9:
+ 33:43:01:91:10:2b:1e:d1:b9:5d:cd:32:19:8b:8f:8c:20:77:
+ d7:22:c4:42:dc:84:16:9b:25:6d:e8:b4:55:71:7f:b0:7c:b3:
+ d3:71:49:b9:cf:52:a4:04:3f:dc:3d:a0:bb:af:33:9e:0a:30:
+ 60:8e:db:9d:5d:94:a8:bd:60:e7:62:80:76:81:83:0c:8c:cc:
+ 30:46:49:e2:0c:d2:a8:af:eb:61:71:ef:e7:22:62:a9:f7:5c:
+ 64:6c:9f:16:8c:67:36:27:45:f5:09:7b:bf:f6:10:0a:f1:b0:
+ 8d:54:43:8c:04:ba:a3:3f:ef:e2:35:c7:f9:74:e0:6f:34:41:
+ d0:bf:73:65:57:20:f9:9b:67:7a:66:68:24:4e:80:65:bd:10:
+ 99:06:59:f2:65:af:b8:c6:47:bb:fd:90:78:8b:41:73:2e:af:
+ 55:1f:dc:3b:92:72:6e:84:d3:d0:61:4c:0d:cc:76:57:e2:2d:
+ 85:22:15:36:0d:eb:01:9d:eb:d8:eb:c4:84:99:fb:c0:0c:cc:
+ 32:e8:e3:77:da:83:44:8b:9e:55:28:c0:8b:58:d3:90:3e:4e:
+ 1b:00:f1:15:ad:83:2b:9a
+SHA1 Fingerprint=CF:E9:70:84:0F:E0:73:0F:9D:F6:0C:7F:2C:4B:EE:20:46:34:9C:BB
diff --git a/apex/ca-certificates/files/e442e424.0 b/apex/ca-certificates/files/e442e424.0
new file mode 100644
index 0000000..e9465bc
--- /dev/null
+++ b/apex/ca-certificates/files/e442e424.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL
+BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc
+BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00
+MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
+aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG
+SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR
+/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu
+FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR
+U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c
+ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR
+FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k
+A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw
+eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl
+sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp
+VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q
+A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+
+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
+BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD
+ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px
+KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI
+FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv
+oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg
+u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP
+0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf
+3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl
+8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+
+DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN
+PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/
+ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 2e:f5:9b:02:28:a7:db:7a:ff:d5:a3:a9:ee:bd:03:a0:cf:12:6a:1d
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 3 G3
+ Validity
+ Not Before: Jan 12 20:26:32 2012 GMT
+ Not After : Jan 12 20:26:32 2042 GMT
+ Subject: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 3 G3
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:b3:cb:0e:10:67:8e:ea:14:97:a7:32:2a:0a:56:
+ 36:7f:68:4c:c7:b3:6f:3a:23:14:91:ff:19:7f:a5:
+ ca:ac:ee:b3:76:9d:7a:e9:8b:1b:ab:6b:31:db:fa:
+ 0b:53:4c:af:c5:a5:1a:79:3c:8a:4c:ff:ac:df:25:
+ de:4e:d9:82:32:0b:44:de:ca:db:8c:ac:a3:6e:16:
+ 83:3b:a6:64:4b:32:89:fb:16:16:38:7e:eb:43:e2:
+ d3:74:4a:c2:62:0a:73:0a:dd:49:b3:57:d2:b0:0a:
+ 85:9d:71:3c:de:a3:cb:c0:32:f3:01:39:20:43:1b:
+ 35:d1:53:b3:b1:ee:c5:93:69:82:3e:16:b5:28:46:
+ a1:de:ea:89:09:ed:43:b8:05:46:8a:86:f5:59:47:
+ be:1b:6f:01:21:10:b9:fd:a9:d2:28:ca:10:39:09:
+ ca:13:36:cf:9c:ad:ad:40:74:79:2b:02:3f:34:ff:
+ fa:20:69:7d:d3:ee:61:f5:ba:b3:e7:30:d0:37:23:
+ 86:72:61:45:29:48:59:68:6f:77:a6:2e:81:be:07:
+ 4d:6f:af:ce:c4:45:13:91:14:70:06:8f:1f:9f:f8:
+ 87:69:b1:0e:ef:c3:89:19:eb:ea:1c:61:fc:7a:6c:
+ 8a:dc:d6:03:0b:9e:26:ba:12:dd:d4:54:39:ab:26:
+ a3:33:ea:75:81:da:2d:cd:0f:4f:e4:03:d1:ef:15:
+ 97:1b:6b:90:c5:02:90:93:66:02:21:b1:47:de:8b:
+ 9a:4a:80:b9:55:8f:b5:a2:2f:c0:d6:33:67:da:7e:
+ c4:a7:b4:04:44:eb:47:fb:e6:58:b9:f7:0c:f0:7b:
+ 2b:b1:c0:70:29:c3:40:62:2d:3b:48:69:dc:23:3c:
+ 48:eb:7b:09:79:a9:6d:da:a8:30:98:cf:80:72:03:
+ 88:a6:5b:46:ae:72:79:7c:08:03:21:65:ae:b7:e1:
+ 1c:a5:b1:2a:a2:31:de:66:04:f7:c0:74:e8:71:de:
+ ff:3d:59:cc:96:26:12:8b:85:95:57:1a:ab:6b:75:
+ 0b:44:3d:11:28:3c:7b:61:b7:e2:8f:67:4f:e5:ec:
+ 3c:4c:60:80:69:57:38:1e:01:5b:8d:55:e8:c7:df:
+ c0:cc:77:23:34:49:75:7c:f6:98:11:eb:2d:de:ed:
+ 41:2e:14:05:02:7f:e0:fe:20:eb:35:e7:11:ac:22:
+ ce:57:3d:de:c9:30:6d:10:03:85:cd:f1:ff:8c:16:
+ b5:c1:b2:3e:88:6c:60:7f:90:4f:95:f7:f6:2d:ad:
+ 01:39:07:04:fa:75:80:7d:bf:49:50:ed:ef:c9:c4:
+ 7c:1c:eb:80:7e:db:b6:d0:dd:13:fe:c9:d3:9c:d7:
+ b2:97:a9
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ C6:17:D0:BC:A8:EA:02:43:F2:1B:06:99:5D:2B:90:20:B9:D7:9C:E4
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 34:61:d9:56:b5:12:87:55:4d:dd:a3:35:31:46:bb:a4:07:72:
+ bc:5f:61:62:e8:a5:fb:0b:37:b1:3c:b6:b3:fa:29:9d:7f:02:
+ f5:a4:c9:a8:93:b7:7a:71:28:69:8f:73:e1:52:90:da:d5:be:
+ 3a:e5:b7:76:6a:56:80:21:df:5d:e6:e9:3a:9e:e5:3e:f6:a2:
+ 69:c7:2a:0a:b0:18:47:dc:20:70:7d:52:a3:3e:59:7c:c1:ba:
+ c9:c8:15:40:61:ca:72:d6:70:ac:d2:b7:f0:1c:e4:86:29:f0:
+ ce:ef:68:63:d0:b5:20:8a:15:61:9a:7e:86:98:b4:c9:c2:76:
+ fb:cc:ba:30:16:cc:a3:61:c6:74:13:e5:6b:ef:a3:15:ea:03:
+ fe:13:8b:64:e4:d3:c1:d2:e8:84:fb:49:d1:10:4d:79:66:eb:
+ aa:fd:f4:8d:31:1e:70:14:ad:dc:de:67:13:4c:81:15:61:bc:
+ b7:d9:91:77:71:19:81:60:bb:f0:58:a5:b5:9c:0b:f7:8f:22:
+ 55:27:c0:4b:01:6d:3b:99:0d:d4:1d:9b:63:67:2f:d0:ee:0d:
+ ca:66:bc:94:4f:a6:ad:ed:fc:ee:63:ac:57:3f:65:25:cf:b2:
+ 86:8f:d0:08:ff:b8:76:14:6e:de:e5:27:ec:ab:78:b5:53:b9:
+ b6:3f:e8:20:f9:d2:a8:be:61:46:ca:87:8c:84:f3:f9:f1:a0:
+ 68:9b:22:1e:81:26:9b:10:04:91:71:c0:06:1f:dc:a0:d3:b9:
+ 56:a7:e3:98:2d:7f:83:9d:df:8c:2b:9c:32:8e:32:94:f0:01:
+ 3c:22:2a:9f:43:c2:2e:c3:98:39:07:38:7b:fc:5e:00:42:1f:
+ f3:32:26:79:83:84:f6:e5:f0:c1:51:12:c0:0b:1e:04:23:0c:
+ 54:a5:4c:2f:49:c5:4a:d1:b6:6e:60:0d:6b:fc:6b:8b:85:24:
+ 64:b7:89:0e:ab:25:47:5b:3c:cf:7e:49:bd:c7:e9:0a:c6:da:
+ f7:7e:0e:17:08:d3:48:97:d0:71:92:f0:0f:39:3e:34:6a:1c:
+ 7d:d8:f2:22:ae:bb:69:f4:33:b4:a6:48:55:d1:0f:0e:26:e8:
+ ec:b6:0b:2d:a7:85:35:cd:fd:59:c8:9f:d1:cd:3e:5a:29:34:
+ b9:3d:84:ce:b1:65:d4:59:91:91:56:75:21:c1:77:9e:f9:7a:
+ e1:60:9d:d3:ad:04:18:f4:7c:eb:5e:93:8f:53:4a:22:29:f8:
+ 48:2b:3e:4d:86:ac:5b:7f:cb:06:99:59:60:d8:58:65:95:8d:
+ 44:d1:f7:7f:7e:27:7f:7d:ae:80:f5:07:4c:b6:3e:9c:71:54:
+ 99:04:4b:fd:58:f9:98:f4
+SHA1 Fingerprint=48:12:BD:92:3C:A8:C4:39:06:E7:30:6D:27:96:E6:A4:CF:22:2E:7D
diff --git a/apex/ca-certificates/files/e48193cf.0 b/apex/ca-certificates/files/e48193cf.0
new file mode 100644
index 0000000..4de3997
--- /dev/null
+++ b/apex/ca-certificates/files/e48193cf.0
@@ -0,0 +1,78 @@
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE
+BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
+dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL
+MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp
+cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP
+Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr
+ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL
+MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1
+yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr
+VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/
+nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ
+KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG
+XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj
+vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt
+Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g
+N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC
+nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 8608355977964138876 (0x7777062726a9b17c)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, O=AffirmTrust, CN=AffirmTrust Commercial
+ Validity
+ Not Before: Jan 29 14:06:06 2010 GMT
+ Not After : Dec 31 14:06:06 2030 GMT
+ Subject: C=US, O=AffirmTrust, CN=AffirmTrust Commercial
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:f6:1b:4f:67:07:2b:a1:15:f5:06:22:cb:1f:01:
+ b2:e3:73:45:06:44:49:2c:bb:49:25:14:d6:ce:c3:
+ b7:ab:2c:4f:c6:41:32:94:57:fa:12:a7:5b:0e:e2:
+ 8f:1f:1e:86:19:a7:aa:b5:2d:b9:5f:0d:8a:c2:af:
+ 85:35:79:32:2d:bb:1c:62:37:f2:b1:5b:4a:3d:ca:
+ cd:71:5f:e9:42:be:94:e8:c8:de:f9:22:48:64:c6:
+ e5:ab:c6:2b:6d:ad:05:f0:fa:d5:0b:cf:9a:e5:f0:
+ 50:a4:8b:3b:47:a5:23:5b:7a:7a:f8:33:3f:b8:ef:
+ 99:97:e3:20:c1:d6:28:89:cf:94:fb:b9:45:ed:e3:
+ 40:17:11:d4:74:f0:0b:31:e2:2b:26:6a:9b:4c:57:
+ ae:ac:20:3e:ba:45:7a:05:f3:bd:9b:69:15:ae:7d:
+ 4e:20:63:c4:35:76:3a:07:02:c9:37:fd:c7:47:ee:
+ e8:f1:76:1d:73:15:f2:97:a4:b5:c8:7a:79:d9:42:
+ aa:2b:7f:5c:fe:ce:26:4f:a3:66:81:35:af:44:ba:
+ 54:1e:1c:30:32:65:9d:e6:3c:93:5e:50:4e:7a:e3:
+ 3a:d4:6e:cc:1a:fb:f9:d2:37:ae:24:2a:ab:57:03:
+ 22:28:0d:49:75:7f:b7:28:da:75:bf:8e:e3:dc:0e:
+ 79:31
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 9D:93:C6:53:8B:5E:CA:AF:3F:9F:1E:0F:E5:99:95:BC:24:F6:94:8F
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 58:ac:f4:04:0e:cd:c0:0d:ff:0a:fd:d4:ba:16:5f:29:bd:7b:
+ 68:99:58:49:d2:b4:1d:37:4d:7f:27:7d:46:06:5d:43:c6:86:
+ 2e:3e:73:b2:26:7d:4f:93:a9:b6:c4:2a:9a:ab:21:97:14:b1:
+ de:8c:d3:ab:89:15:d8:6b:24:d4:f1:16:ae:d8:a4:5c:d4:7f:
+ 51:8e:ed:18:01:b1:93:63:bd:bc:f8:61:80:9a:9e:b1:ce:42:
+ 70:e2:a9:7d:06:25:7d:27:a1:fe:6f:ec:b3:1e:24:da:e3:4b:
+ 55:1a:00:3b:35:b4:3b:d9:d7:5d:30:fd:81:13:89:f2:c2:06:
+ 2b:ed:67:c4:8e:c9:43:b2:5c:6b:15:89:02:bc:62:fc:4e:f2:
+ b5:33:aa:b2:6f:d3:0a:a2:50:e3:f6:3b:e8:2e:44:c2:db:66:
+ 38:a9:33:56:48:f1:6d:1b:33:8d:0d:8c:3f:60:37:9d:d3:ca:
+ 6d:7e:34:7e:0d:9f:72:76:8b:1b:9f:72:fd:52:35:41:45:02:
+ 96:2f:1c:b2:9a:73:49:21:b1:49:47:45:47:b4:ef:6a:34:11:
+ c9:4d:9a:cc:59:b7:d6:02:9e:5a:4e:65:b5:94:ae:1b:df:29:
+ b0:16:f1:bf:00:9e:07:3a:17:64:b5:04:b5:23:21:99:0a:95:
+ 3b:97:7c:ef
+SHA1 Fingerprint=F9:B5:B6:32:45:5F:9C:BE:EC:57:5F:80:DC:E9:6E:2C:C7:B2:78:B7
diff --git a/apex/ca-certificates/files/e7c037b4.0 b/apex/ca-certificates/files/e7c037b4.0
new file mode 100644
index 0000000..83d8da6
--- /dev/null
+++ b/apex/ca-certificates/files/e7c037b4.0
@@ -0,0 +1,53 @@
+-----BEGIN CERTIFICATE-----
+MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx
+CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD
+ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw
+MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex
+HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq
+R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd
+yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
+DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ
+7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8
++RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 11:d2:bb:ba:33:6e:d4:bc:e6:24:68:c5:0d:84:1d:98:e8:43
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=BE, O=GlobalSign nv-sa, CN=GlobalSign Root E46
+ Validity
+ Not Before: Mar 20 00:00:00 2019 GMT
+ Not After : Mar 20 00:00:00 2046 GMT
+ Subject: C=BE, O=GlobalSign nv-sa, CN=GlobalSign Root E46
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:9c:0e:b1:cf:b7:e8:9e:52:77:75:34:fa:a5:46:
+ a7:ad:32:19:32:b4:07:a9:27:ca:94:bb:0c:d2:0a:
+ 10:c7:da:89:b0:97:0c:70:13:09:01:8e:d8:ea:47:
+ ea:be:b2:80:2b:cd:fc:28:0d:db:ac:bc:a4:86:37:
+ ed:70:08:00:75:ea:93:0b:7b:2e:52:9c:23:68:23:
+ 06:43:ec:92:2f:53:84:db:fb:47:14:07:e8:5f:94:
+ 67:5d:c9:7a:81:3c:20
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 31:0A:90:8F:B6:C6:9D:D2:44:4B:80:B5:A2:E6:1F:B1:12:4F:1B:95
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:65:02:31:00:df:54:90:ed:9b:ef:8b:94:02:93:17:82:99:
+ be:b3:9e:2c:f6:0b:91:8c:9f:4a:14:b1:f6:64:bc:bb:68:51:
+ 13:0c:03:f7:15:8b:84:60:b9:8b:ff:52:8e:e7:8c:bc:1c:02:
+ 30:3c:f9:11:d4:8c:4e:c0:c1:61:c2:15:4c:aa:ab:1d:0b:31:
+ 5f:3b:1c:e2:00:97:44:31:e6:fe:73:96:2f:da:96:d3:fe:08:
+ 07:b3:34:89:bc:05:9f:f7:1e:86:ee:8b:70
+SHA1 Fingerprint=39:B4:6C:D5:FE:80:06:EB:E2:2F:4A:BB:08:33:A0:AF:DB:B9:DD:84
diff --git a/apex/ca-certificates/files/e8651083.0 b/apex/ca-certificates/files/e8651083.0
new file mode 100644
index 0000000..7e54709
--- /dev/null
+++ b/apex/ca-certificates/files/e8651083.0
@@ -0,0 +1,87 @@
+-----BEGIN CERTIFICATE-----
+MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD
+VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0
+ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G
+CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y
+OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx
+FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp
+Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o
+dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP
+kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc
+cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U
+fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7
+N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC
+xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1
++rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
+A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM
+Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG
+SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h
+mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk
+ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775
+tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c
+2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t
+HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ c2:7e:43:04:4e:47:3f:19
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=HU, L=Budapest, O=Microsec Ltd., CN=Microsec e-Szigno Root CA 2009/emailAddress=info@e-szigno.hu
+ Validity
+ Not Before: Jun 16 11:30:18 2009 GMT
+ Not After : Dec 30 11:30:18 2029 GMT
+ Subject: C=HU, L=Budapest, O=Microsec Ltd., CN=Microsec e-Szigno Root CA 2009/emailAddress=info@e-szigno.hu
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:e9:f8:8f:f3:63:ad:da:86:d8:a7:e0:42:fb:cf:
+ 91:de:a6:26:f8:99:a5:63:70:ad:9b:ae:ca:33:40:
+ 7d:6d:96:6e:a1:0e:44:ee:e1:13:9d:94:42:52:9a:
+ bd:75:85:74:2c:a8:0e:1d:93:b6:18:b7:8c:2c:a8:
+ cf:fb:5c:71:b9:da:ec:fe:e8:7e:8f:e4:2f:1d:b2:
+ a8:75:87:d8:b7:a1:e5:3b:cf:99:4a:46:d0:83:19:
+ 7d:c0:a1:12:1c:95:6d:4a:f4:d8:c7:a5:4d:33:2e:
+ 85:39:40:75:7e:14:7c:80:12:98:50:c7:41:67:b8:
+ a0:80:61:54:a6:6c:4e:1f:e0:9d:0e:07:e9:c9:ba:
+ 33:e7:fe:c0:55:28:2c:02:80:a7:19:f5:9e:dc:55:
+ 53:03:97:7b:07:48:ff:99:fb:37:8a:24:c4:59:cc:
+ 50:10:63:8e:aa:a9:1a:b0:84:1a:86:f9:5f:bb:b1:
+ 50:6e:a4:d1:0a:cc:d5:71:7e:1f:a7:1b:7c:f5:53:
+ 6e:22:5f:cb:2b:e6:d4:7c:5d:ae:d6:c2:c6:4c:e5:
+ 05:01:d9:ed:57:fc:c1:23:79:fc:fa:c8:24:83:95:
+ f3:b5:6a:51:01:d0:77:d6:e9:12:a1:f9:1a:83:fb:
+ 82:1b:b9:b0:97:f4:76:06:33:43:49:a0:ff:0b:b5:
+ fa:b5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ CB:0F:C6:DF:42:43:CC:3D:CB:B5:48:23:A1:1A:7A:A6:2A:BB:34:68
+ X509v3 Authority Key Identifier:
+ CB:0F:C6:DF:42:43:CC:3D:CB:B5:48:23:A1:1A:7A:A6:2A:BB:34:68
+ X509v3 Subject Alternative Name:
+ email:info@e-szigno.hu
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ c9:d1:0e:5e:2e:d5:cc:b3:7c:3e:cb:fc:3d:ff:0d:28:95:93:
+ 04:c8:bf:da:cd:79:b8:43:90:f0:a4:be:ef:f2:ef:21:98:bc:
+ d4:d4:5d:06:f6:ee:42:ec:30:6c:a0:aa:a9:ca:f1:af:8a:fa:
+ 3f:0b:73:6a:3e:ea:2e:40:7e:1f:ae:54:61:79:eb:2e:08:37:
+ d7:23:f3:8c:9f:be:1d:b1:e1:a4:75:db:a0:e2:54:14:b1:ba:
+ 1c:29:a4:18:f6:12:ba:a2:14:14:e3:31:35:c8:40:ff:b7:e0:
+ 05:76:57:c1:1c:59:f2:f8:bf:e4:ed:25:62:5c:84:f0:7e:7e:
+ 1f:b3:be:f9:b7:21:11:cc:03:01:56:70:a7:10:92:1e:1b:34:
+ 81:1e:ad:9c:1a:c3:04:3c:ed:02:61:d6:1e:06:f3:5f:3a:87:
+ f2:2b:f1:45:87:e5:3d:ac:d1:c7:57:84:bd:6b:ae:dc:d8:f9:
+ b6:1b:62:70:0b:3d:36:c9:42:f2:32:d7:7a:61:e6:d2:db:3d:
+ cf:c8:a9:c9:9b:dc:db:58:44:d7:6f:38:af:7f:78:d3:a3:ad:
+ 1a:75:ba:1c:c1:36:7c:8f:1e:6d:1c:c3:75:46:ae:35:05:a6:
+ f6:5c:3d:21:ee:56:f0:c9:82:22:2d:7a:54:ab:70:c3:7d:22:
+ 65:82:70:96
+SHA1 Fingerprint=89:DF:74:FE:5C:F4:0F:4A:80:F9:E3:37:7D:54:DA:91:E1:01:31:8E
diff --git a/apex/ca-certificates/files/ed39abd0.0 b/apex/ca-certificates/files/ed39abd0.0
new file mode 100644
index 0000000..0118a15
--- /dev/null
+++ b/apex/ca-certificates/files/ed39abd0.0
@@ -0,0 +1,55 @@
+-----BEGIN CERTIFICATE-----
+MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw
+CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
+ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe
+Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw
+EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x
+IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF
+K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG
+fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO
+Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd
+BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx
+AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/
+oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8
+sycX
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 05:55:56:bc:f2:5e:a4:35:35:c3:a4:0f:d5:ab:45:72
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G3
+ Validity
+ Not Before: Aug 1 12:00:00 2013 GMT
+ Not After : Jan 15 12:00:00 2038 GMT
+ Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G3
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:dd:a7:d9:bb:8a:b8:0b:fb:0b:7f:21:d2:f0:be:
+ be:73:f3:33:5d:1a:bc:34:ea:de:c6:9b:bc:d0:95:
+ f6:f0:cc:d0:0b:ba:61:5b:51:46:7e:9e:2d:9f:ee:
+ 8e:63:0c:17:ec:07:70:f5:cf:84:2e:40:83:9c:e8:
+ 3f:41:6d:3b:ad:d3:a4:14:59:36:78:9d:03:43:ee:
+ 10:13:6c:72:de:ae:88:a7:a1:6b:b5:43:ce:67:dc:
+ 23:ff:03:1c:a3:e2:3e
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ B3:DB:48:A4:F9:A1:C5:D8:AE:36:41:CC:11:63:69:62:29:BC:4B:C6
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:65:02:31:00:ad:bc:f2:6c:3f:12:4a:d1:2d:39:c3:0a:09:
+ 97:73:f4:88:36:8c:88:27:bb:e6:88:8d:50:85:a7:63:f9:9e:
+ 32:de:66:93:0f:f1:cc:b1:09:8f:dd:6c:ab:fa:6b:7f:a0:02:
+ 30:39:66:5b:c2:64:8d:b8:9e:50:dc:a8:d5:49:a2:ed:c7:dc:
+ d1:49:7f:17:01:b8:c8:86:8f:4e:8c:88:2b:a8:9a:a9:8a:c5:
+ d1:00:bd:f8:54:e2:9a:e5:5b:7c:b3:27:17
+SHA1 Fingerprint=7E:04:DE:89:6A:3E:66:6D:00:E6:87:D3:3F:FA:D9:3B:E8:3D:34:9E
diff --git a/apex/ca-certificates/files/edcbddb5.0 b/apex/ca-certificates/files/edcbddb5.0
new file mode 100644
index 0000000..bdf5da1
--- /dev/null
+++ b/apex/ca-certificates/files/edcbddb5.0
@@ -0,0 +1,124 @@
+-----BEGIN CERTIFICATE-----
+MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw
+CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x
+ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1
+c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMx
+OTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJVUzERMA8GA1UECAwI
+SWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2ZSBI
+b2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+ALldUShLPDeS0YLOvR29zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0Xzn
+swuvCAAJWX/NKSqIk4cXGIDtiLK0thAfLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu
+7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4BqstTnoApTAbqOl5F2brz8
+1Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9oWN0EACyW
+80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotP
+JqX+OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1l
+RtzuzWniTY+HKE40Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfw
+hI0Vcnyh78zyiGG69Gm7DIwLdVcEuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10
+coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm+9jaJXLE9gCxInm943xZYkqc
+BW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqjifLJS3tBEW1n
+twiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud
+EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1Ud
+DwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W
+0OhUKDtkLSGm+J1WE2pIPU/HPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfe
+uyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0HZJDmHvUqoai7PF35owgLEQzxPy0Q
+lG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla4gt5kNdXElE1GYhB
+aCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5RvbbE
+sLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPT
+MaCm/zjdzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qe
+qu5AvzSxnI9O4fKSTx+O856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxh
+VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8
+h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9
+EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK
+yeC2nOnOcXHebD8WpHk=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 05:f7:0e:86:da:49:f3:46:35:2e:ba:b2
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=Illinois, L=Chicago, O=Trustwave Holdings, Inc., CN=Trustwave Global Certification Authority
+ Validity
+ Not Before: Aug 23 19:34:12 2017 GMT
+ Not After : Aug 23 19:34:12 2042 GMT
+ Subject: C=US, ST=Illinois, L=Chicago, O=Trustwave Holdings, Inc., CN=Trustwave Global Certification Authority
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:b9:5d:51:28:4b:3c:37:92:d1:82:ce:bd:1d:bd:
+ cd:dd:b8:ab:cf:0a:3e:e1:5d:e5:dc:aa:09:b9:57:
+ 02:3e:e6:63:61:df:f2:0f:82:63:ae:a3:f7:ac:73:
+ d1:7c:e7:b3:0b:af:08:00:09:59:7f:cd:29:2a:88:
+ 93:87:17:18:80:ed:88:b2:b4:b6:10:1f:2d:d6:5f:
+ 55:a2:13:5d:d1:c6:eb:06:56:89:88:fe:ac:32:9d:
+ fd:5c:c3:05:c7:6e:ee:86:89:ba:88:03:9d:72:21:
+ 86:90:ae:8f:03:a5:dc:9f:88:28:cb:a3:92:49:0f:
+ ec:d0:0f:e2:6d:44:4f:80:6a:b2:d4:e7:a0:0a:53:
+ 01:ba:8e:97:91:76:6e:bc:fc:d5:6b:36:e6:40:88:
+ d6:7b:2f:5f:05:e8:2c:6d:11:f3:e7:b2:be:92:44:
+ 4c:d2:97:a4:fe:d2:72:81:43:07:9c:e9:11:3e:f5:
+ 8b:1a:59:7d:1f:68:58:dd:04:00:2c:96:f3:43:b3:
+ 7e:98:19:74:d9:9c:73:d9:18:be:41:c7:34:79:d9:
+ f4:62:c2:43:b9:b3:27:b0:22:cb:f9:3d:52:c7:30:
+ 47:b3:c9:3e:b8:6a:e2:e7:e8:81:70:5e:42:8b:4f:
+ 26:a5:fe:3a:c2:20:6e:bb:f8:16:8e:cd:0c:a9:b4:
+ 1b:6c:76:10:e1:58:79:46:3e:54:ce:80:a8:57:09:
+ 37:29:1b:99:13:8f:0c:c8:d6:2c:1c:fb:05:e8:08:
+ 95:3d:65:46:dc:ee:cd:69:e2:4d:8f:87:28:4e:34:
+ 0b:3e:cf:14:d9:bb:dd:b6:50:9a:ad:77:d4:19:d6:
+ da:1a:88:c8:4e:1b:27:75:d8:b2:08:f1:ae:83:30:
+ b9:11:0e:cd:87:f0:84:8d:15:72:7c:a1:ef:cc:f2:
+ 88:61:ba:f4:69:bb:0c:8c:0b:75:57:04:b8:4e:2a:
+ 14:2e:3d:0f:1c:1e:32:a6:62:36:ee:66:e2:22:b8:
+ 05:40:63:10:22:f3:33:1d:74:72:8a:2c:f5:39:29:
+ a0:d3:e7:1b:80:84:2d:c5:3d:e3:4d:b1:fd:1a:6f:
+ ba:65:07:3b:58:ec:42:45:26:fb:d8:da:25:72:c4:
+ f6:00:b1:22:79:bd:e3:7c:59:62:4a:9c:05:6f:3d:
+ ce:e6:d6:47:63:99:c6:24:6f:72:12:c8:ac:7f:90:
+ b4:0b:91:70:e8:b7:e6:16:10:71:17:ce:de:06:4f:
+ 48:41:7d:35:4a:a3:89:f2:c9:4b:7b:41:11:6d:67:
+ b7:08:98:4c:e5:11:19:ae:42:80:dc:fb:90:05:d4:
+ f8:50:ca:be:e4:ad:c7:c2:94:d7:16:9d:e6:17:8f:
+ af:36:fb
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 99:E0:19:67:0D:62:DB:76:B3:DA:3D:B8:5B:E8:FD:42:D2:31:0E:87
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 98:73:70:e2:b0:d3:ed:39:ec:4c:60:d9:a9:12:86:17:1e:96:
+ d0:e8:54:28:3b:64:2d:21:a6:f8:9d:56:13:6a:48:3d:4f:c7:
+ 3e:29:db:6d:58:83:54:3d:87:7d:23:05:d4:e4:1c:dc:e8:38:
+ 65:86:c5:75:a7:5a:db:35:05:bd:77:de:bb:29:37:40:05:07:
+ c3:94:52:9f:ca:64:dd:f1:1b:2b:dc:46:0a:10:02:31:fd:4a:
+ 68:0d:07:64:90:e6:1e:f5:2a:a1:a8:bb:3c:5d:f9:a3:08:0b:
+ 11:0c:f1:3f:2d:10:94:6f:fe:e2:34:87:83:d6:cf:e5:1b:35:
+ 6d:d2:03:e1:b0:0d:a8:a0:aa:46:27:82:36:a7:15:b6:08:a6:
+ 42:54:57:b6:99:5a:e2:0b:79:90:d7:57:12:51:35:19:88:41:
+ 68:25:d4:37:17:84:15:fb:01:72:dc:95:de:52:26:20:98:26:
+ e2:76:f5:27:6f:fa:00:3b:4a:61:d9:0d:cb:51:93:2a:fd:16:
+ 06:96:a7:23:9a:23:48:fe:51:bd:b6:c4:b0:b1:54:ce:de:6c:
+ 41:ad:16:67:7e:db:fd:38:cd:b9:38:4e:b2:c1:60:cb:9d:17:
+ df:58:9e:7a:62:b2:26:8f:74:95:9b:e4:5b:1d:d2:0f:dd:98:
+ 1c:9b:59:b9:23:d3:31:a0:a6:ff:38:dd:cf:20:4f:e9:58:56:
+ 3a:67:c3:d1:f6:99:99:9d:ba:36:b6:80:2f:88:47:4f:86:bf:
+ 44:3a:80:e4:37:1c:a6:ba:ea:97:98:11:d0:84:62:47:64:1e:
+ aa:ee:40:bf:34:b1:9c:8f:4e:e1:f2:92:4f:1f:8e:f3:9e:97:
+ de:f3:a6:79:6a:89:71:4f:4b:27:17:48:fe:ec:f4:50:0f:4f:
+ 49:7d:cc:45:e3:bd:7a:40:c5:41:dc:61:56:27:06:69:e5:72:
+ 41:81:d3:b6:01:89:a0:2f:3a:72:79:fe:3a:30:bf:41:ec:c7:
+ 62:3e:91:4b:c7:d9:31:76:42:f9:f7:3c:63:ec:26:8c:73:0c:
+ 7d:1a:1d:ea:a8:7c:87:a8:c2:27:7c:e1:33:41:0f:cf:cf:fc:
+ 00:a0:22:80:9e:4a:a7:6f:00:b0:41:45:b7:22:ca:68:48:c5:
+ 42:a2:ae:dd:1d:f2:e0:6e:4e:05:58:b1:c0:90:16:2a:a4:3d:
+ 10:40:be:8f:62:63:83:a9:9c:82:7d:2d:02:e9:83:30:7c:cb:
+ 27:c9:fd:1e:66:00:b0:2e:d3:21:2f:8e:33:16:6c:98:ed:10:
+ a8:07:d6:cc:93:cf:db:d1:69:1c:e4:ca:c9:e0:b6:9c:e9:ce:
+ 71:71:de:6c:3f:16:a4:79
+SHA1 Fingerprint=2F:8F:36:4F:E1:58:97:44:21:59:87:A5:2A:9A:D0:69:95:26:7F:B5
diff --git a/apex/ca-certificates/files/ee532fd5.0 b/apex/ca-certificates/files/ee532fd5.0
new file mode 100644
index 0000000..ca2ddc7
--- /dev/null
+++ b/apex/ca-certificates/files/ee532fd5.0
@@ -0,0 +1,54 @@
+-----BEGIN CERTIFICATE-----
+MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMw
+RzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAY
+BgNVBAMTEXZUcnVzIEVDQyBSb290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDcz
+MTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28u
+LEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYwEAYHKoZIzj0CAQYF
+K4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+cToL0
+v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUd
+e4BdS49nTPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYD
+VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIw
+V53dVvHH4+m4SVBrm2nDb+zDfSXkV5UTQJtS0zvzQBm8JsctBp61ezaf9SXUY2sA
+AjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQLYgmRWAD5Tfs0aNoJrSEG
+GJTO
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 6e:6a:bc:59:aa:53:be:98:39:67:a2:d2:6b:a4:3b:e6:6d:1c:d6:da
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: C=CN, O=iTrusChina Co.,Ltd., CN=vTrus ECC Root CA
+ Validity
+ Not Before: Jul 31 07:26:44 2018 GMT
+ Not After : Jul 31 07:26:44 2043 GMT
+ Subject: C=CN, O=iTrusChina Co.,Ltd., CN=vTrus ECC Root CA
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (384 bit)
+ pub:
+ 04:65:50:4a:ae:8c:79:96:4a:aa:1c:08:c3:a3:a2:
+ cd:fe:59:56:41:77:fd:26:94:42:bb:1d:cd:08:db:
+ 73:b2:5b:75:f3:cf:9c:4e:82:f4:bf:f8:61:26:85:
+ 6c:d6:85:5b:72:70:d2:fd:db:62:b4:df:53:8b:bd:
+ b1:44:58:62:42:09:c7:fa:7f:5b:10:e7:fe:40:fd:
+ c0:d8:c3:2b:32:e7:70:a6:b7:a6:20:55:1d:7b:80:
+ 5d:4b:8f:67:4c:f1:10
+ ASN1 OID: secp384r1
+ NIST CURVE: P-384
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 98:39:CD:BE:D8:B2:8C:F7:B2:AB:E1:AD:24:AF:7B:7C:A1:DB:1F:CF
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: ecdsa-with-SHA384
+ Signature Value:
+ 30:65:02:30:57:9d:dd:56:f1:c7:e3:e9:b8:49:50:6b:9b:69:
+ c3:6f:ec:c3:7d:25:e4:57:95:13:40:9b:52:d3:3b:f3:40:19:
+ bc:26:c7:2d:06:9e:b5:7b:36:9f:f5:25:d4:63:6b:00:02:31:
+ 00:e9:d3:c6:9e:56:9a:2a:cc:a1:da:3f:c8:66:2b:d3:58:9c:
+ 20:85:fa:ab:91:8a:70:70:11:38:60:64:0b:62:09:91:58:00:
+ f9:4d:fb:34:68:da:09:ad:21:06:18:94:ce
+SHA1 Fingerprint=F6:9C:DB:B0:FC:F6:02:13:B6:52:32:A6:A3:91:3F:16:70:DA:C3:E1
diff --git a/apex/ca-certificates/files/f013ecaf.0 b/apex/ca-certificates/files/f013ecaf.0
new file mode 100644
index 0000000..c2b2051
--- /dev/null
+++ b/apex/ca-certificates/files/f013ecaf.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw
+CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
+MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
+MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
+Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo
+27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w
+Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw
+TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl
+qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH
+szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8
+Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk
+MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92
+wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p
+aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN
+VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID
+AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
+FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb
+C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe
+QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy
+h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4
+7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J
+ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef
+MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/
+Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT
+6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ
+0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm
+2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb
+bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 02:03:e5:93:6f:31:b0:13:49:88:6b:a2:17
+ Signature Algorithm: sha384WithRSAEncryption
+ Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R1
+ Validity
+ Not Before: Jun 22 00:00:00 2016 GMT
+ Not After : Jun 22 00:00:00 2036 GMT
+ Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R1
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:b6:11:02:8b:1e:e3:a1:77:9b:3b:dc:bf:94:3e:
+ b7:95:a7:40:3c:a1:fd:82:f9:7d:32:06:82:71:f6:
+ f6:8c:7f:fb:e8:db:bc:6a:2e:97:97:a3:8c:4b:f9:
+ 2b:f6:b1:f9:ce:84:1d:b1:f9:c5:97:de:ef:b9:f2:
+ a3:e9:bc:12:89:5e:a7:aa:52:ab:f8:23:27:cb:a4:
+ b1:9c:63:db:d7:99:7e:f0:0a:5e:eb:68:a6:f4:c6:
+ 5a:47:0d:4d:10:33:e3:4e:b1:13:a3:c8:18:6c:4b:
+ ec:fc:09:90:df:9d:64:29:25:23:07:a1:b4:d2:3d:
+ 2e:60:e0:cf:d2:09:87:bb:cd:48:f0:4d:c2:c2:7a:
+ 88:8a:bb:ba:cf:59:19:d6:af:8f:b0:07:b0:9e:31:
+ f1:82:c1:c0:df:2e:a6:6d:6c:19:0e:b5:d8:7e:26:
+ 1a:45:03:3d:b0:79:a4:94:28:ad:0f:7f:26:e5:a8:
+ 08:fe:96:e8:3c:68:94:53:ee:83:3a:88:2b:15:96:
+ 09:b2:e0:7a:8c:2e:75:d6:9c:eb:a7:56:64:8f:96:
+ 4f:68:ae:3d:97:c2:84:8f:c0:bc:40:c0:0b:5c:bd:
+ f6:87:b3:35:6c:ac:18:50:7f:84:e0:4c:cd:92:d3:
+ 20:e9:33:bc:52:99:af:32:b5:29:b3:25:2a:b4:48:
+ f9:72:e1:ca:64:f7:e6:82:10:8d:e8:9d:c2:8a:88:
+ fa:38:66:8a:fc:63:f9:01:f9:78:fd:7b:5c:77:fa:
+ 76:87:fa:ec:df:b1:0e:79:95:57:b4:bd:26:ef:d6:
+ 01:d1:eb:16:0a:bb:8e:0b:b5:c5:c5:8a:55:ab:d3:
+ ac:ea:91:4b:29:cc:19:a4:32:25:4e:2a:f1:65:44:
+ d0:02:ce:aa:ce:49:b4:ea:9f:7c:83:b0:40:7b:e7:
+ 43:ab:a7:6c:a3:8f:7d:89:81:fa:4c:a5:ff:d5:8e:
+ c3:ce:4b:e0:b5:d8:b3:8e:45:cf:76:c0:ed:40:2b:
+ fd:53:0f:b0:a7:d5:3b:0d:b1:8a:a2:03:de:31:ad:
+ cc:77:ea:6f:7b:3e:d6:df:91:22:12:e6:be:fa:d8:
+ 32:fc:10:63:14:51:72:de:5d:d6:16:93:bd:29:68:
+ 33:ef:3a:66:ec:07:8a:26:df:13:d7:57:65:78:27:
+ de:5e:49:14:00:a2:00:7f:9a:a8:21:b6:a9:b1:95:
+ b0:a5:b9:0d:16:11:da:c7:6c:48:3c:40:e0:7e:0d:
+ 5a:cd:56:3c:d1:97:05:b9:cb:4b:ed:39:4b:9c:c4:
+ 3f:d2:55:13:6e:24:b0:d6:71:fa:f4:c1:ba:cc:ed:
+ 1b:f5:fe:81:41:d8:00:98:3d:3a:c8:ae:7a:98:37:
+ 18:05:95
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ E4:AF:2B:26:71:1A:2B:48:27:85:2F:52:66:2C:EF:F0:89:13:71:3E
+ Signature Algorithm: sha384WithRSAEncryption
+ Signature Value:
+ 9f:aa:42:26:db:0b:9b:be:ff:1e:96:92:2e:3e:a2:65:4a:6a:
+ 98:ba:22:cb:7d:c1:3a:d8:82:0a:06:c6:f6:a5:de:c0:4e:87:
+ 66:79:a1:f9:a6:58:9c:aa:f9:b5:e6:60:e7:e0:e8:b1:1e:42:
+ 41:33:0b:37:3d:ce:89:70:15:ca:b5:24:a8:cf:6b:b5:d2:40:
+ 21:98:cf:22:34:cf:3b:c5:22:84:e0:c5:0e:8a:7c:5d:88:e4:
+ 35:24:ce:9b:3e:1a:54:1e:6e:db:b2:87:a7:fc:f3:fa:81:55:
+ 14:62:0a:59:a9:22:05:31:3e:82:d6:ee:db:57:34:bc:33:95:
+ d3:17:1b:e8:27:a2:8b:7b:4e:26:1a:7a:5a:64:b6:d1:ac:37:
+ f1:fd:a0:f3:38:ec:72:f0:11:75:9d:cb:34:52:8d:e6:76:6b:
+ 17:c6:df:86:ab:27:8e:49:2b:75:66:81:10:21:a6:ea:3e:f4:
+ ae:25:ff:7c:15:de:ce:8c:25:3f:ca:62:70:0a:f7:2f:09:66:
+ 07:c8:3f:1c:fc:f0:db:45:30:df:62:88:c1:b5:0f:9d:c3:9f:
+ 4a:de:59:59:47:c5:87:22:36:e6:82:a7:ed:0a:b9:e2:07:a0:
+ 8d:7b:7a:4a:3c:71:d2:e2:03:a1:1f:32:07:dd:1b:e4:42:ce:
+ 0c:00:45:61:80:b5:0b:20:59:29:78:bd:f9:55:cb:63:c5:3c:
+ 4c:f4:b6:ff:db:6a:5f:31:6b:99:9e:2c:c1:6b:50:a4:d7:e6:
+ 18:14:bd:85:3f:67:ab:46:9f:a0:ff:42:a7:3a:7f:5c:cb:5d:
+ b0:70:1d:2b:34:f5:d4:76:09:0c:eb:78:4c:59:05:f3:33:42:
+ c3:61:15:10:1b:77:4d:ce:22:8c:d4:85:f2:45:7d:b7:53:ea:
+ ef:40:5a:94:0a:5c:20:5f:4e:40:5d:62:22:76:df:ff:ce:61:
+ bd:8c:23:78:d2:37:02:e0:8e:de:d1:11:37:89:f6:bf:ed:49:
+ 07:62:ae:92:ec:40:1a:af:14:09:d9:d0:4e:b2:a2:f7:be:ee:
+ ee:d8:ff:dc:1a:2d:de:b8:36:71:e2:fc:79:b7:94:25:d1:48:
+ 73:5b:a1:35:e7:b3:99:67:75:c1:19:3a:2b:47:4e:d3:42:8e:
+ fd:31:c8:16:66:da:d2:0c:3c:db:b3:8e:c9:a1:0d:80:0f:7b:
+ 16:77:14:bf:ff:db:09:94:b2:93:bc:20:58:15:e9:db:71:43:
+ f3:de:10:c3:00:dc:a8:2a:95:b6:c2:d6:3f:90:6b:76:db:6c:
+ fe:8c:bc:f2:70:35:0c:dc:99:19:35:dc:d7:c8:46:63:d5:36:
+ 71:ae:57:fb:b7:82:6d:dc
+SHA1 Fingerprint=E5:8C:1C:C4:91:3B:38:63:4B:E9:10:6E:E3:AD:8E:6B:9D:D9:81:4A
diff --git a/apex/ca-certificates/files/f058632f.0 b/apex/ca-certificates/files/f058632f.0
new file mode 100644
index 0000000..387d30c
--- /dev/null
+++ b/apex/ca-certificates/files/f058632f.0
@@ -0,0 +1,124 @@
+-----BEGIN CERTIFICATE-----
+MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx
+CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE
+AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1
+NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZ
+MBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+ADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ76zBq
+AMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9
+vVYiQJ3q9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9
+lRdU2HhE8Qx3FZLgmEKnpNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTOD
+n3WhUidhOPFZPY5Q4L15POdslv5e2QJltI5c0BE0312/UqeBAMN/mUWZFdUXyApT
+7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW5olWK8jjfN7j/4nlNW4o
+6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNrRBH0pUPC
+TEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6
+WT0EBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63R
+DolUK5X6wK0dmBR4M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZI
+pEYslOqodmJHixBTB0hXbOKSTbauBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGj
+YzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1UdDgQWBBRy
+rOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw
+AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ
+8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi
+0f6X+J8wfBj5tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMM
+A8iZGok1GTzTyVR8qPAs5m4HeW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBS
+SRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+Cy748fdHif64W1lZYudogsYMVoe+K
+TTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygCQMez2P2ccGrGKMOF
+6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15h2Er
+3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMt
+Ty3EHD70sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pT
+VmBds9hCG1xLEooc6+t9xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAW
+ysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQraVplI/owd8k+BsHMYeB2F326CjYSlKA
+rBPuUBQemMc=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 01:67:5f:27:d6:fe:7a:e3:e4:ac:be:09:5b:05:9e
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=FI, O=Telia Finland Oyj, CN=Telia Root CA v2
+ Validity
+ Not Before: Nov 29 11:55:54 2018 GMT
+ Not After : Nov 29 11:55:54 2043 GMT
+ Subject: C=FI, O=Telia Finland Oyj, CN=Telia Root CA v2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:b2:d0:3f:07:bc:e2:7b:d0:6b:99:f8:e2:77:69:
+ e7:ce:9d:a4:03:bc:82:6d:a1:fe:81:65:1f:4c:27:
+ ac:8e:00:ba:16:7b:eb:30:6a:00:c0:b3:74:68:7e:
+ b2:af:c7:d5:62:b3:7a:3f:50:ca:8c:36:44:24:63:
+ d2:36:e9:0c:85:f6:43:76:d5:4c:a1:60:72:67:e2:
+ 28:33:a5:cb:31:b8:3a:22:23:34:b8:7d:bd:56:22:
+ 40:9d:ea:f4:7b:03:ad:68:fc:b2:81:4f:98:d0:74:
+ ea:8d:e5:7d:cd:63:c3:a3:f6:de:92:c2:58:19:e0:
+ 96:bb:c5:c4:a9:3d:a5:74:96:fe:af:f9:89:aa:bd:
+ 95:17:54:d8:78:44:f1:0c:77:15:92:e0:98:42:a7:
+ a4:d6:aa:20:92:cd:c1:a0:b3:96:b2:3a:84:42:8d:
+ 7d:d5:95:e4:d6:db:e9:62:c4:58:b3:79:c5:8c:d3:
+ 35:33:83:9f:75:a1:52:27:61:38:f1:59:3d:8e:50:
+ e0:bd:79:3c:e7:6c:96:fe:5e:d9:02:65:b4:8e:5c:
+ d0:11:34:df:5d:bf:52:a7:81:00:c3:7f:99:45:99:
+ 15:d5:17:c8:0a:53:ec:63:f3:99:7d:cc:69:12:86:
+ c2:17:f0:01:9e:bf:84:bc:d1:52:cb:1b:92:66:ce:
+ a4:53:e5:a1:bf:c4:db:09:d6:e6:89:56:2b:c8:e3:
+ 7c:de:e3:ff:89:e5:35:6e:28:e8:6c:0b:23:51:a9:
+ 25:05:eb:48:f8:dd:b1:ca:fa:6c:08:51:ef:b7:18:
+ 6c:44:ca:26:e1:73:c6:89:06:81:e5:8a:ac:b0:e2:
+ 29:c6:b9:24:b3:6b:44:11:f4:a5:43:c2:4c:43:e5:
+ 70:36:8c:b6:33:57:7a:95:2e:82:a0:f4:5c:10:b3:
+ 61:83:f6:02:05:86:2e:7c:2d:6c:dc:03:46:6e:35:
+ 93:d5:7a:95:2f:de:20:d8:5b:7e:94:90:04:6a:ba:
+ 59:3d:04:05:75:9d:37:a2:0e:2e:3d:eb:c1:a4:52:
+ 83:fe:d0:6b:d4:66:8e:dc:c6:e9:12:4e:1d:2a:57:
+ aa:10:bc:7c:5e:82:7d:a6:a6:c9:f2:2d:b9:f5:17:
+ 27:ad:d1:0e:89:54:2b:95:fa:c0:ad:1d:98:14:78:
+ 33:42:86:0a:a9:73:b5:fb:74:0d:b7:1b:30:19:c4:
+ 5a:0e:1c:27:b7:da:18:d0:ff:8a:c8:05:ba:f1:aa:
+ 1c:a2:37:b7:e6:48:a4:46:2c:94:ea:a8:76:62:47:
+ 8b:10:53:07:48:57:6c:e2:92:4d:b6:ae:05:cb:dc:
+ c1:4a:5e:8f:ac:3d:19:4e:c2:ed:60:75:2b:db:c1:
+ ca:42:d5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Authority Key Identifier:
+ 72:AC:E4:33:79:AA:45:87:F6:FD:AC:1D:9E:D6:C7:2F:86:D8:24:39
+ X509v3 Subject Key Identifier:
+ 72:AC:E4:33:79:AA:45:87:F6:FD:AC:1D:9E:D6:C7:2F:86:D8:24:39
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ a0:3b:59:a7:09:94:3e:36:84:d2:7e:2f:39:a5:96:97:fa:11:
+ ad:fc:67:f3:71:09:f2:b2:89:84:67:44:af:b9:ef:ed:96:ec:
+ 9c:64:db:32:30:6f:67:9a:ac:7e:5f:b2:ab:01:36:7e:81:fa:
+ e4:84:5e:d2:ac:36:e0:6b:62:c5:7d:4b:0e:82:6d:d2:76:62:
+ d1:fe:97:f8:9f:30:7c:18:f9:b4:52:77:82:1d:76:db:d3:1d:
+ a9:f0:c1:9a:00:bd:6d:75:d8:7d:e7:fa:c7:38:a3:9c:70:e8:
+ 46:79:03:af:2e:74:db:75:f8:6e:53:0c:03:c8:99:1a:89:35:
+ 19:3c:d3:c9:54:7c:a8:f0:2c:e6:6e:07:79:6f:6a:e1:e6:ea:
+ 91:82:69:0a:1d:c3:7e:59:a2:9e:6b:46:15:98:5b:d3:af:46:
+ 1d:62:c8:ce:80:52:49:11:3f:c9:04:12:c3:13:7c:3f:3b:8a:
+ 96:db:3c:a0:1e:0a:b4:8b:54:b2:24:67:0d:ef:82:cb:be:3c:
+ 7d:d1:e2:7f:ae:16:d6:56:58:b9:da:20:b1:83:15:a1:ef:8a:
+ 4d:32:6f:41:2f:13:52:82:94:d7:1a:c1:78:a2:51:dd:2b:70:
+ 6d:b7:1a:f9:f7:b0:e0:67:97:56:db:7c:61:53:09:03:28:02:
+ 40:c7:b3:d8:fd:9c:70:6a:c6:28:c3:85:e9:e2:ed:1a:93:a0:
+ de:4b:98:a2:84:3e:05:77:01:96:3d:fb:b4:20:0f:9c:72:02:
+ 7a:12:2f:d5:a3:ba:51:78:af:2a:2b:44:65:4e:b5:fd:0a:e8:
+ c1:cd:79:87:61:2b:de:80:57:45:bf:67:f1:9b:91:5e:a5:a4:
+ ec:59:48:10:0d:38:c7:b0:fa:c3:44:6d:04:f5:78:50:1c:92:
+ 96:5b:da:f5:b8:2e:ba:5b:cf:e5:f0:6a:9d:4b:2f:58:73:2d:
+ 4f:2d:c4:1c:3e:f4:b3:3f:ab:15:0e:3b:19:41:8a:a4:c1:57:
+ 12:66:71:4c:fa:53:e3:57:eb:62:95:09:9e:54:dd:d1:c2:3c:
+ 57:3c:bd:38:ad:98:64:b7:b8:03:9a:53:56:60:5d:b3:d8:42:
+ 1b:5c:4b:12:8a:1c:eb:eb:7d:c6:7a:69:c7:27:7f:a4:f8:8b:
+ f2:e4:94:66:87:4b:e9:94:07:09:12:79:8a:b2:eb:74:04:dc:
+ ce:f4:44:59:e0:16:ca:c5:2c:58:d7:3c:7b:cf:62:86:6a:50:
+ 7d:35:36:66:a7:fb:37:e7:28:c7:d8:d0:ad:a5:69:94:8f:e8:
+ c1:df:24:f8:1b:07:31:87:81:d8:5d:f6:e8:28:d8:4a:52:80:
+ ac:13:ee:50:14:1e:98:c7
+SHA1 Fingerprint=B9:99:CD:D1:73:50:8A:C4:47:05:08:9C:8C:88:FB:BE:A0:2B:40:CD
diff --git a/apex/ca-certificates/files/f0cd152c.0 b/apex/ca-certificates/files/f0cd152c.0
new file mode 100644
index 0000000..aa53990
--- /dev/null
+++ b/apex/ca-certificates/files/f0cd152c.0
@@ -0,0 +1,126 @@
+-----BEGIN CERTIFICATE-----
+MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw
+gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL
+Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg
+MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw
+BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0
+MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1
+c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ
+bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg
+Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ
+2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E
+T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j
+5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM
+C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T
+DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX
+wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A
+2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm
+nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8
+dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl
+N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj
+c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS
+5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS
+Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr
+hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/
+B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI
+AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw
+H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+
+b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk
+2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol
+IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk
+5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY
+n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ d9:b5:43:7f:af:a9:39:0f:00:00:00:00:55:65:ad:58
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, O=Entrust, Inc., OU=See www.entrust.net\/legal-terms, OU=(c) 2015 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - G4
+ Validity
+ Not Before: May 27 11:11:16 2015 GMT
+ Not After : Dec 27 11:41:16 2037 GMT
+ Subject: C=US, O=Entrust, Inc., OU=See www.entrust.net\/legal-terms, OU=(c) 2015 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - G4
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:b1:ec:2c:42:ee:e2:d1:30:ff:a5:92:47:e2:2d:
+ c3:ba:64:97:6d:ca:f7:0d:b5:59:c1:b3:cb:a8:68:
+ 19:d8:af:84:6d:30:70:5d:7e:f3:2e:d2:53:99:e1:
+ fe:1f:5e:d9:48:af:5d:13:8d:db:ff:63:33:4d:d3:
+ 00:02:bc:c4:f8:d1:06:08:94:79:58:8a:15:de:29:
+ b3:fd:fd:c4:4f:e8:aa:e2:a0:3b:79:cd:bf:6b:43:
+ 32:dd:d9:74:10:b9:f7:f4:68:d4:bb:d0:87:d5:aa:
+ 4b:8a:2a:6f:2a:04:b5:b2:a6:c7:a0:7a:e6:48:ab:
+ d2:d1:59:cc:d6:7e:23:e6:97:6c:f0:42:e5:dc:51:
+ 4b:15:41:ed:49:4a:c9:de:10:97:d6:76:c1:ef:a5:
+ b5:36:14:97:35:d8:78:22:35:52:ef:43:bd:db:27:
+ db:61:56:82:34:dc:cb:88:60:0c:0b:5a:e5:2c:01:
+ c6:54:af:d7:aa:c1:10:7b:d2:05:5a:b8:40:9e:86:
+ a7:c3:90:86:02:56:52:09:7a:9c:d2:27:82:53:4a:
+ 65:52:6a:f5:3c:e7:a8:f2:9c:af:8b:bd:d3:0e:d4:
+ d4:5e:6e:87:9e:6a:3d:45:1d:d1:5d:1b:f4:e9:0a:
+ ac:60:99:fb:89:b4:ff:98:2c:cf:7c:1d:e9:02:aa:
+ 04:9a:1e:b8:dc:88:6e:25:b3:6c:66:f7:3c:90:f3:
+ 57:c1:b3:2f:f5:6d:f2:fb:ca:a1:f8:29:9d:46:8b:
+ b3:6a:f6:e6:67:07:be:2c:67:0a:2a:1f:5a:b2:3e:
+ 57:c4:d3:21:21:63:65:52:91:1b:b1:99:8e:79:7e:
+ e6:eb:8d:00:d9:5a:aa:ea:73:e8:a4:82:02:47:96:
+ fe:5b:8e:54:61:a3:eb:2f:4b:30:b0:8b:23:75:72:
+ 7c:21:3c:c8:f6:f1:74:d4:1c:7b:a3:05:55:ee:bb:
+ 4d:3b:32:be:9a:77:66:9e:ac:69:90:22:07:1f:61:
+ 3a:96:be:e5:9a:4f:cc:05:3c:28:59:d3:c1:0c:54:
+ a8:59:61:bd:c8:72:4c:e8:dc:9f:87:7f:bd:9c:48:
+ 36:5e:95:a3:0e:b9:38:24:55:fc:75:66:eb:02:e3:
+ 08:34:29:4a:c6:e3:2b:2f:33:a0:da:a3:86:a5:12:
+ 97:fd:80:2b:da:14:42:e3:92:bd:3e:f2:5d:5e:67:
+ 74:2e:1c:88:47:29:34:5f:e2:32:a8:9c:25:37:8c:
+ ba:98:00:97:8b:49:96:1e:fd:25:8a:ac:dc:da:d8:
+ 5d:74:6e:66:b0:ff:44:df:a1:18:c6:be:48:2f:37:
+ 94:78:f8:95:4a:3f:7f:13:5e:5d:59:fd:74:86:43:
+ 63:73:49
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 9F:38:C4:56:23:C3:39:E8:A0:71:6C:E8:54:4C:E4:E8:3A:B1:BF:67
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 12:e5:42:a6:7b:8b:0f:0c:e4:46:a5:b6:60:40:87:8c:25:7e:
+ ad:b8:68:2e:5b:c6:40:76:3c:03:f8:c9:59:f4:f3:ab:62:ce:
+ 10:8d:b4:5a:64:8c:68:c0:b0:72:43:34:d2:1b:0b:f6:2c:53:
+ d2:ca:90:4b:86:66:fc:aa:83:22:f4:8b:1a:6f:26:48:ac:76:
+ 77:08:bf:c5:98:5c:f4:26:89:9e:7b:c3:b9:64:32:01:7f:d3:
+ c3:dd:58:6d:ec:b1:ab:84:55:74:77:84:04:27:52:6b:86:4c:
+ ce:dd:b9:65:ff:d6:c6:5e:9f:9a:10:99:4b:75:6a:fe:6a:e9:
+ 97:20:e4:e4:76:7a:c6:d0:24:aa:90:cd:20:90:ba:47:64:fb:
+ 7f:07:b3:53:78:b5:0a:62:f2:73:43:ce:41:2b:81:6a:2e:85:
+ 16:94:53:d4:6b:5f:72:22:ab:51:2d:42:d5:00:9c:99:bf:de:
+ bb:94:3b:57:fd:9a:f5:86:cb:56:3b:5b:88:01:e5:7c:28:4b:
+ 03:f9:49:83:7c:b2:7f:7c:e3:ed:8e:a1:7f:60:53:8e:55:9d:
+ 50:34:12:0f:b7:97:7b:6c:87:4a:44:e7:f5:6d:ec:80:37:f0:
+ 58:19:6e:4a:68:76:f0:1f:92:e4:ea:b5:92:d3:61:51:10:0b:
+ ad:a7:d9:5f:c7:5f:dc:1f:a3:5c:8c:a1:7e:9b:b7:9e:d3:56:
+ 6f:66:5e:07:96:20:ed:0b:74:fb:66:4e:8b:11:15:e9:81:49:
+ 7e:6f:b0:d4:50:7f:22:d7:5f:65:02:0d:a6:f4:85:1e:d8:ae:
+ 06:4b:4a:a7:d2:31:66:c2:f8:ce:e5:08:a6:a4:02:96:44:68:
+ 57:c4:d5:33:cf:19:2f:14:c4:94:1c:7b:a4:d9:f0:9f:0e:b1:
+ 80:e2:d1:9e:11:64:a9:88:11:3a:76:82:e5:62:c2:80:d8:a4:
+ 83:ed:93:ef:7c:2f:90:b0:32:4c:96:15:68:48:52:d4:99:08:
+ c0:24:e8:1c:e3:b3:a5:21:0e:92:c0:90:1f:cf:20:5f:ca:3b:
+ 38:c7:b7:6d:3a:f3:e6:44:b8:0e:31:6b:88:8e:70:eb:9c:17:
+ 52:a8:41:94:2e:87:b6:e7:a6:12:c5:75:df:5b:c0:0a:6e:7b:
+ a4:e4:5e:86:f9:36:94:df:77:c3:e9:0d:c0:39:f1:79:bb:46:
+ 8e:ab:43:59:27:b7:20:bb:23:e9:56:40:21:ec:31:3d:65:aa:
+ 43:f2:3d:df:70:44:e1:ba:4d:26:10:3b:98:9f:f3:c8:8e:1b:
+ 38:56:21:6a:51:93:d3:91:ca:46:da:89:b7:3d:53:83:2c:08:
+ 1f:8b:8f:53:dd:ff:ac:1f
+SHA1 Fingerprint=14:88:4E:86:26:37:B0:26:AF:59:62:5C:40:77:EC:35:29:BA:96:01
diff --git a/apex/ca-certificates/files/f459871d.0 b/apex/ca-certificates/files/f459871d.0
new file mode 100644
index 0000000..e40d985
--- /dev/null
+++ b/apex/ca-certificates/files/f459871d.0
@@ -0,0 +1,81 @@
+-----BEGIN CERTIFICATE-----
+MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD
+VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU
+ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH
+MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO
+MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv
+Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz
+f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO
+8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq
+d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM
+tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt
+Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB
+o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD
+AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x
+PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM
+wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d
+GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH
+6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby
+RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx
+iN66zB+Afko=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 31:f5:e4:62:0c:6c:58:ed:d6:d8
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=IN, OU=emSign PKI, O=eMudhra Technologies Limited, CN=emSign Root CA - G1
+ Validity
+ Not Before: Feb 18 18:30:00 2018 GMT
+ Not After : Feb 18 18:30:00 2043 GMT
+ Subject: C=IN, OU=emSign PKI, O=eMudhra Technologies Limited, CN=emSign Root CA - G1
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:93:4b:bb:e9:66:8a:ee:9d:5b:d5:34:93:d0:1b:
+ 1e:c3:e7:9e:b8:64:33:7f:63:78:68:b4:cd:2e:71:
+ 75:d7:9b:20:c6:4d:29:bc:b6:68:60:8a:f7:21:9a:
+ 56:35:5a:f3:76:bd:d8:cd:9a:ff:93:56:4b:a5:59:
+ 06:a1:93:34:29:dd:16:34:75:4e:f2:81:b4:c7:96:
+ 4e:ad:19:15:52:4a:fe:3c:70:75:70:cd:af:2b:ab:
+ 15:9a:33:3c:aa:b3:8b:aa:cd:43:fd:f5:ea:70:ff:
+ ed:cf:11:3b:94:ce:4e:32:16:d3:23:40:2a:77:b3:
+ af:3c:01:2c:6c:ed:99:2c:8b:d9:4e:69:98:b2:f7:
+ 8f:41:b0:32:78:61:d6:0d:5f:c3:fa:a2:40:92:1d:
+ 5c:17:e6:70:3e:35:e7:a2:b7:c2:62:e2:ab:a4:38:
+ 4c:b5:39:35:6f:ea:03:69:fa:3a:54:68:85:6d:d6:
+ f2:2f:43:55:1e:91:0d:0e:d8:d5:6a:a4:96:d1:13:
+ 3c:2c:78:50:e8:3a:92:d2:17:56:e5:35:1a:40:1c:
+ 3e:8d:2c:ed:39:df:42:e0:83:41:74:df:a3:cd:c2:
+ 86:60:48:68:e3:69:0b:54:00:8b:e4:76:69:21:0d:
+ 79:4e:34:08:5e:14:c2:cc:b1:b7:ad:d7:7c:70:8a:
+ c7:85
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ FB:EF:0D:86:9E:B0:E3:DD:A9:B9:F1:21:17:7F:3E:FC:F0:77:2B:1A
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 59:ff:f2:8c:f5:87:7d:71:3d:a3:9f:1b:5b:d1:da:f8:d3:9c:
+ 6b:36:bd:9b:a9:61:eb:de:16:2c:74:3d:9e:e6:75:da:d7:ba:
+ a7:bc:42:17:e7:3d:91:eb:e5:7d:dd:3e:9c:f1:cf:92:ac:6c:
+ 48:cc:c2:22:3f:69:3b:c5:b6:15:2f:a3:35:c6:68:2a:1c:57:
+ af:39:ef:8d:d0:35:c3:18:0c:7b:00:56:1c:cd:8b:19:74:de:
+ be:0f:12:e0:d0:aa:a1:3f:02:34:b1:70:ce:9d:18:d6:08:03:
+ 09:46:ee:60:e0:7e:b6:c4:49:04:51:7d:70:60:bc:aa:b2:ff:
+ 79:72:7a:a6:1d:3d:5f:2a:f8:ca:e2:fd:39:b7:47:b9:eb:7e:
+ df:04:23:af:fa:9c:06:07:e9:fb:63:93:80:40:b5:c6:6c:0a:
+ 31:28:ce:0c:9f:cf:b3:23:35:80:41:8d:6c:c4:37:7b:81:2f:
+ 80:a1:40:42:85:e9:d9:38:8d:e8:a1:53:cd:01:bf:69:e8:5a:
+ 06:f2:45:0b:90:fa:ae:e1:bf:9d:f2:ae:57:3c:a5:ae:b2:56:
+ f4:8b:65:40:e9:fd:31:81:2c:f4:39:09:d8:ee:6b:a7:b4:a6:
+ 1d:15:a5:98:f7:01:81:d8:85:7d:f3:51:5c:71:88:de:ba:cc:
+ 1f:80:7e:4a
+SHA1 Fingerprint=8A:C7:AD:8F:73:AC:4E:C1:B5:75:4D:A5:40:F4:FC:CF:7C:B5:8E:8C
diff --git a/apex/ca-certificates/files/f8fc53da.0 b/apex/ca-certificates/files/f8fc53da.0
new file mode 100644
index 0000000..9f406ea
--- /dev/null
+++ b/apex/ca-certificates/files/f8fc53da.0
@@ -0,0 +1,123 @@
+-----BEGIN CERTIFICATE-----
+MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6
+MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu
+MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV
+BAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwHhcNMTgwMzE2MTIxMDEzWhcNNDMw
+MzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEg
+U3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRo
+b3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqG
+SIb3DQEBAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZ
+n0EGze2jusDbCSzBfN8pfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/q
+p1x4EaTByIVcJdPTsuclzxFUl6s1wB52HO8AU5853BSlLCIls3Jy/I2z5T4IHhQq
+NwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2fJmItdUDmj0VDT06qKhF
+8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGtg/BKEiJ3
+HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGa
+mqi4NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi
+7VdNIuJGmj8PkTQkfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSF
+ytKAQd8FqKPVhJBPC/PgP5sZ0jeJP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0P
+qafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSYnjYJdmZm/Bo/6khUHL4wvYBQ
+v3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHKHRzQ+8S1h9E6
+Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1
+vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQAD
+ggIBAEii1QALLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4
+WxmB82M+w85bj/UvXgF2Ez8sALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvo
+zMrnadyHncI013nR03e4qllY/p0m+jiGPp2Kh2RX5Rc64vmNueMzeMGQ2Ljdt4NR
+5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8CYyqOhNf6DR5UMEQ
+GfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA4kZf
+5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq
+0Uc9NneoWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7D
+P78v3DSk+yshzWePS/Tj6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTM
+qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP
+0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf
+E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 1e:bf:59:50:b8:c9:80:37:4c:06:f7:eb:55:4f:b5:ed
+ Signature Algorithm: sha512WithRSAEncryption
+ Issuer: C=PL, O=Asseco Data Systems S.A., OU=Certum Certification Authority, CN=Certum Trusted Root CA
+ Validity
+ Not Before: Mar 16 12:10:13 2018 GMT
+ Not After : Mar 16 12:10:13 2043 GMT
+ Subject: C=PL, O=Asseco Data Systems S.A., OU=Certum Certification Authority, CN=Certum Trusted Root CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:d1:2d:8e:bb:b7:36:ea:6d:37:91:9f:4e:93:a7:
+ 05:e4:29:03:25:ce:1c:82:f7:7c:99:9f:41:06:cd:
+ ed:a3:ba:c0:db:09:2c:c1:7c:df:29:7e:4b:65:2f:
+ 93:a7:d4:01:6b:03:28:18:a3:d8:9d:05:c1:2a:d8:
+ 45:f1:91:de:df:3b:d0:80:02:8c:cf:38:0f:ea:a7:
+ 5c:78:11:a4:c1:c8:85:5c:25:d3:d3:b2:e7:25:cf:
+ 11:54:97:ab:35:c0:1e:76:1c:ef:00:53:9f:39:dc:
+ 14:a5:2c:22:25:b3:72:72:fc:8d:b3:e5:3e:08:1e:
+ 14:2a:37:0b:88:3c:ca:b0:f4:c8:c2:a1:ae:bc:c1:
+ be:29:67:55:e2:fc:ad:59:5c:fe:bd:57:2c:b0:90:
+ 8d:c2:ed:37:b6:7c:99:88:b5:d5:03:9a:3d:15:0d:
+ 3d:3a:a8:a8:45:f0:95:4e:25:59:1d:cd:98:69:bb:
+ d3:cc:32:c9:8d:ef:81:fe:ad:7d:89:bb:ba:60:13:
+ ca:65:95:67:a0:f3:19:f6:03:56:d4:6a:d3:27:e2:
+ a1:ad:83:f0:4a:12:22:77:1c:05:73:e2:19:71:42:
+ c0:ec:75:46:9a:90:58:e0:6a:8e:2b:a5:46:30:04:
+ 8e:19:b2:17:e3:be:a9:ba:7f:56:f1:24:03:d7:b2:
+ 21:28:76:0e:36:30:4c:79:d5:41:9a:9a:a8:b8:35:
+ ba:0c:3a:f2:44:1b:20:88:f7:c5:25:d7:3d:c6:e3:
+ 3e:43:dd:87:fe:c4:ea:f5:53:3e:4c:65:ff:3b:4a:
+ cb:78:5a:6b:17:5f:0d:c7:c3:4f:4e:9a:2a:a2:ed:
+ 57:4d:22:e2:46:9a:3f:0f:91:34:24:7d:55:e3:8c:
+ 95:37:d3:1a:f0:09:2b:2c:d2:c9:8d:b4:0d:00:ab:
+ 67:29:28:d8:01:f5:19:04:b6:1d:be:76:fe:72:5c:
+ c4:85:ca:d2:80:41:df:05:a8:a3:d5:84:90:4f:0b:
+ f3:e0:3f:9b:19:d2:37:89:3f:f2:7b:52:1c:8c:f6:
+ e1:f7:3c:07:97:8c:0e:a2:59:81:0c:b2:90:3d:d3:
+ e3:59:46:ed:0f:a9:a7:de:80:6b:5a:aa:07:b6:19:
+ cb:bc:57:f3:97:21:7a:0c:b1:2b:74:3e:eb:da:a7:
+ 67:2d:4c:c4:98:9e:36:09:76:66:66:fc:1a:3f:ea:
+ 48:54:1c:be:30:bd:80:50:bf:7c:b5:ce:00:f6:0c:
+ 61:d9:e7:24:03:e0:e3:01:81:0e:bd:d8:85:34:88:
+ bd:b2:36:a8:7b:5c:08:e5:44:80:8c:6f:f8:2f:d5:
+ 21:ca:1d:1c:d0:fb:c4:b5:87:d1:3a:4e:c7:76:b5:
+ 35:48:b5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 8C:FB:1C:75:BC:02:D3:9F:4E:2E:48:D9:F9:60:54:AA:C4:B3:4F:FA
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha512WithRSAEncryption
+ Signature Value:
+ 48:a2:d5:00:0b:2e:d0:3f:bc:1c:d5:b5:54:49:1e:5a:6b:f4:
+ e4:f2:e0:40:37:e0:cc:14:7b:b9:c9:fa:35:b5:75:17:93:6a:
+ 05:69:85:9c:cd:4f:19:78:5b:19:81:f3:63:3e:c3:ce:5b:8f:
+ f5:2f:5e:01:76:13:3f:2c:00:b9:cd:96:52:39:49:6d:04:4e:
+ c5:e9:0f:86:0d:e1:fa:b3:5f:82:12:f1:3a:ce:66:06:24:34:
+ 2b:e8:cc:ca:e7:69:dc:87:9d:c2:34:d7:79:d1:d3:77:b8:aa:
+ 59:58:fe:9d:26:fa:38:86:3e:9d:8a:87:64:57:e5:17:3a:e2:
+ f9:8d:b9:e3:33:78:c1:90:d8:b8:dd:b7:83:51:e4:c4:cc:23:
+ d5:06:7c:e6:51:d3:cd:34:31:c0:f6:46:bb:0b:ad:fc:3d:10:
+ 05:2a:3b:4a:91:25:ee:8c:d4:84:87:80:2a:bc:09:8c:aa:3a:
+ 13:5f:e8:34:79:50:c1:10:19:f9:d3:28:1e:d4:d1:51:30:29:
+ b3:ae:90:67:d6:1f:0a:63:b1:c5:a9:c6:42:31:63:17:94:ef:
+ 69:cb:2f:fa:8c:14:7d:c4:43:18:89:d9:f0:32:40:e6:80:e2:
+ 46:5f:e5:e3:c1:00:59:a8:f9:e8:20:bc:89:2c:0e:47:34:0b:
+ ea:57:c2:53:36:fc:a7:d4:af:31:cd:fe:02:e5:75:fa:b9:27:
+ 09:f9:f3:f5:3b:ca:7d:9f:a9:22:cb:88:c9:aa:d1:47:3d:36:
+ 77:a8:59:64:6b:27:cf:ef:27:c1:e3:24:b5:86:f7:ae:7e:32:
+ 4d:b0:79:68:d1:39:e8:90:58:c3:83:bc:0f:2c:d6:97:eb:ce:
+ 0c:e1:20:c7:da:b7:3e:c3:3f:bf:2f:dc:34:a4:fb:2b:21:cd:
+ 67:8f:4b:f4:e3:ea:d4:3f:e7:4f:ba:b9:a5:93:45:1c:66:1f:
+ 21:fa:64:5e:6f:e0:76:94:32:cb:75:f5:6e:e5:f6:8f:c7:b8:
+ a4:cc:a8:96:7d:64:fb:24:5a:4a:03:6c:6b:38:c6:e8:03:43:
+ 9a:f7:57:b9:b3:29:69:93:38:f4:03:f2:bb:fb:82:6b:07:20:
+ d1:52:1f:9a:64:02:7b:98:66:db:5c:4d:5a:0f:d0:84:95:a0:
+ 3c:14:43:06:ca:ca:db:b8:41:36:da:6a:44:67:87:af:af:e3:
+ 45:11:15:69:08:b2:be:16:39:97:24:6f:12:45:d1:67:5d:09:
+ a8:c9:15:da:fa:d2:a6:5f:13:61:1f:bf:85:ac:b4:ad:ad:05:
+ 94:08:83:1e:75:17:d3:71:3b:93:50:23:59:a0:ed:3c:91:54:
+ 9d:76:00:c5:c3:b8:38:db
+SHA1 Fingerprint=C8:83:44:C0:18:AE:9F:CC:F1:87:B7:8F:22:D1:C5:D7:45:84:BA:E5
diff --git a/apex/ca-certificates/files/fb5fa911.0 b/apex/ca-certificates/files/fb5fa911.0
new file mode 100644
index 0000000..83fc9d8
--- /dev/null
+++ b/apex/ca-certificates/files/fb5fa911.0
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF
+ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
+b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL
+MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
+b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK
+gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ
+W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg
+1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K
+8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r
+2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me
+z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR
+8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj
+mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz
+7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6
++XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI
+0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB
+Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm
+UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2
+LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY
++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS
+k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl
+7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm
+btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl
+urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+
+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63
+n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE
+76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H
+9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT
+4PsJYGw=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 06:6c:9f:d2:96:35:86:9f:0a:0f:e5:86:78:f8:5b:26:bb:8a:37
+ Signature Algorithm: sha384WithRSAEncryption
+ Issuer: C=US, O=Amazon, CN=Amazon Root CA 2
+ Validity
+ Not Before: May 26 00:00:00 2015 GMT
+ Not After : May 26 00:00:00 2040 GMT
+ Subject: C=US, O=Amazon, CN=Amazon Root CA 2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:ad:96:9f:2d:9c:4a:4c:4a:81:79:51:99:ec:8a:
+ cb:6b:60:51:13:bc:4d:6d:06:fc:b0:08:8d:dd:19:
+ 10:6a:c7:26:0c:35:d8:c0:6f:20:84:e9:94:b1:9b:
+ 85:03:c3:5b:db:4a:e8:c8:f8:90:76:d9:5b:4f:e3:
+ 4c:e8:06:36:4d:cc:9a:ac:3d:0c:90:2b:92:d4:06:
+ 19:60:ac:37:44:79:85:81:82:ad:5a:37:e0:0d:cc:
+ 9d:a6:4c:52:76:ea:43:9d:b7:04:d1:50:f6:55:e0:
+ d5:d2:a6:49:85:e9:37:e9:ca:7e:ae:5c:95:4d:48:
+ 9a:3f:ae:20:5a:6d:88:95:d9:34:b8:52:1a:43:90:
+ b0:bf:6c:05:b9:b6:78:b7:ea:d0:e4:3a:3c:12:53:
+ 62:ff:4a:f2:7b:be:35:05:a9:12:34:e3:f3:64:74:
+ 62:2c:3d:00:49:5a:28:fe:32:44:bb:87:dd:65:27:
+ 02:71:3b:da:4a:f7:1f:da:cd:f7:21:55:90:4f:0f:
+ ec:ae:82:e1:9f:6b:d9:45:d3:bb:f0:5f:87:ed:3c:
+ 2c:39:86:da:3f:de:ec:72:55:eb:79:a3:ad:db:dd:
+ 7c:b0:ba:1c:ce:fc:de:4f:35:76:cf:0f:f8:78:1f:
+ 6a:36:51:46:27:61:5b:e9:9e:cf:f0:a2:55:7d:7c:
+ 25:8a:6f:2f:b4:c5:cf:84:2e:2b:fd:0d:51:10:6c:
+ fb:5f:1b:bc:1b:7e:c5:ae:3b:98:01:31:92:ff:0b:
+ 57:f4:9a:b2:b9:57:e9:ab:ef:0d:76:d1:f0:ee:f4:
+ ce:86:a7:e0:6e:e9:b4:69:a1:df:69:f6:33:c6:69:
+ 2e:97:13:9e:a5:87:b0:57:10:81:37:c9:53:b3:bb:
+ 7f:f6:92:d1:9c:d0:18:f4:92:6e:da:83:4f:a6:63:
+ 99:4c:a5:fb:5e:ef:21:64:7a:20:5f:6c:64:85:15:
+ cb:37:e9:62:0c:0b:2a:16:dc:01:2e:32:da:3e:4b:
+ f5:9e:3a:f6:17:40:94:ef:9e:91:08:86:fa:be:63:
+ a8:5a:33:ec:cb:74:43:95:f9:6c:69:52:36:c7:29:
+ 6f:fc:55:03:5c:1f:fb:9f:bd:47:eb:e7:49:47:95:
+ 0b:4e:89:22:09:49:e0:f5:61:1e:f1:bf:2e:8a:72:
+ 6e:80:59:ff:57:3a:f9:75:32:a3:4e:5f:ec:ed:28:
+ 62:d9:4d:73:f2:cc:81:17:60:ed:cd:eb:dc:db:a7:
+ ca:c5:7e:02:bd:f2:54:08:54:fd:b4:2d:09:2c:17:
+ 54:4a:98:d1:54:e1:51:67:08:d2:ed:6e:7e:6f:3f:
+ d2:2d:81:59:29:66:cb:90:39:95:11:1e:74:27:fe:
+ dd:eb:af
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ B0:0C:F0:4C:30:F4:05:58:02:48:FD:33:E5:52:AF:4B:84:E3:66:52
+ Signature Algorithm: sha384WithRSAEncryption
+ Signature Value:
+ aa:a8:80:8f:0e:78:a3:e0:a2:d4:cd:e6:f5:98:7a:3b:ea:00:
+ 03:b0:97:0e:93:bc:5a:a8:f6:2c:8c:72:87:a9:b1:fc:7f:73:
+ fd:63:71:78:a5:87:59:cf:30:e1:0d:10:b2:13:5a:6d:82:f5:
+ 6a:e6:80:9f:a0:05:0b:68:e4:47:6b:c7:6a:df:b6:fd:77:32:
+ 72:e5:18:fa:09:f4:a0:93:2c:5d:d2:8c:75:85:76:65:90:0c:
+ 03:79:b7:31:23:63:ad:78:83:09:86:68:84:ca:ff:f9:cf:26:
+ 9a:92:79:e7:cd:4b:c5:e7:61:a7:17:cb:f3:a9:12:93:93:6b:
+ a7:e8:2f:53:92:c4:60:58:b0:cc:02:51:18:5b:85:8d:62:59:
+ 63:b6:ad:b4:de:9a:fb:26:f7:00:27:c0:5d:55:37:74:99:c9:
+ 50:7f:e3:59:2e:44:e3:2c:25:ee:ec:4c:32:77:b4:9f:1a:e9:
+ 4b:5d:20:c5:da:fd:1c:87:16:c6:43:e8:d4:bb:26:9a:45:70:
+ 5e:a9:0b:37:53:e2:46:7b:27:fd:e0:46:f2:89:b7:cc:42:b6:
+ cb:28:26:6e:d9:a5:c9:3a:c8:41:13:60:f7:50:8c:15:ae:b2:
+ 6d:1a:15:1a:57:78:e6:92:2a:d9:65:90:82:3f:6c:02:af:ae:
+ 12:3a:27:96:36:04:d7:1d:a2:80:63:a9:9b:f1:e5:ba:b4:7c:
+ 14:b0:4e:c9:b1:1f:74:5f:38:f6:51:ea:9b:fa:2c:a2:11:d4:
+ a9:2d:27:1a:45:b1:af:b2:4e:71:0d:c0:58:46:d6:69:06:cb:
+ 53:cb:b3:fe:6b:41:cd:41:7e:7d:4c:0f:7c:72:79:7a:59:cd:
+ 5e:4a:0e:ac:9b:a9:98:73:79:7c:b4:f4:cc:b9:b8:07:0c:b2:
+ 74:5c:b8:c7:6f:88:a1:90:a7:f4:aa:f9:bf:67:3a:f4:1a:15:
+ 62:1e:b7:9f:be:3d:b1:29:af:67:a1:12:f2:58:10:19:53:03:
+ 30:1b:b8:1a:89:f6:9c:bd:97:03:8e:a3:09:f3:1d:8b:21:f1:
+ b4:df:e4:1c:d1:9f:65:02:06:ea:5c:d6:13:b3:84:ef:a2:a5:
+ 5c:8c:77:29:a7:68:c0:6b:ae:40:d2:a8:b4:ea:cd:f0:8d:4b:
+ 38:9c:19:9a:1b:28:54:b8:89:90:ef:ca:75:81:3e:1e:f2:64:
+ 24:c7:18:af:4e:ff:47:9e:07:f6:35:65:a4:d3:0a:56:ff:f5:
+ 17:64:6c:ef:a8:22:25:49:93:b6:df:00:17:da:58:7e:5d:ee:
+ c5:1b:b0:d1:d1:5f:21:10:c7:f9:f3:ba:02:0a:27:07:c5:f1:
+ d6:c7:d3:e0:fb:09:60:6c
+SHA1 Fingerprint=5A:8C:EF:45:D7:A6:98:59:76:7A:8C:8B:44:96:B5:78:CF:47:4B:1A
diff --git a/apex/ca-certificates/files/fd08c599.0 b/apex/ca-certificates/files/fd08c599.0
new file mode 100644
index 0000000..389bb7c
--- /dev/null
+++ b/apex/ca-certificates/files/fd08c599.0
@@ -0,0 +1,79 @@
+-----BEGIN CERTIFICATE-----
+MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
+ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
+b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
+MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
+b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
+ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
+9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
+IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
+VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
+93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
+jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
+A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
+U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
+N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
+o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
+5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
+rqXRfboQnoZsG4q5WTP468SQvvG5
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 06:6c:9f:cf:99:bf:8c:0a:39:e2:f0:78:8a:43:e6:96:36:5b:ca
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, O=Amazon, CN=Amazon Root CA 1
+ Validity
+ Not Before: May 26 00:00:00 2015 GMT
+ Not After : Jan 17 00:00:00 2038 GMT
+ Subject: C=US, O=Amazon, CN=Amazon Root CA 1
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b2:78:80:71:ca:78:d5:e3:71:af:47:80:50:74:
+ 7d:6e:d8:d7:88:76:f4:99:68:f7:58:21:60:f9:74:
+ 84:01:2f:ac:02:2d:86:d3:a0:43:7a:4e:b2:a4:d0:
+ 36:ba:01:be:8d:db:48:c8:07:17:36:4c:f4:ee:88:
+ 23:c7:3e:eb:37:f5:b5:19:f8:49:68:b0:de:d7:b9:
+ 76:38:1d:61:9e:a4:fe:82:36:a5:e5:4a:56:e4:45:
+ e1:f9:fd:b4:16:fa:74:da:9c:9b:35:39:2f:fa:b0:
+ 20:50:06:6c:7a:d0:80:b2:a6:f9:af:ec:47:19:8f:
+ 50:38:07:dc:a2:87:39:58:f8:ba:d5:a9:f9:48:67:
+ 30:96:ee:94:78:5e:6f:89:a3:51:c0:30:86:66:a1:
+ 45:66:ba:54:eb:a3:c3:91:f9:48:dc:ff:d1:e8:30:
+ 2d:7d:2d:74:70:35:d7:88:24:f7:9e:c4:59:6e:bb:
+ 73:87:17:f2:32:46:28:b8:43:fa:b7:1d:aa:ca:b4:
+ f2:9f:24:0e:2d:4b:f7:71:5c:5e:69:ff:ea:95:02:
+ cb:38:8a:ae:50:38:6f:db:fb:2d:62:1b:c5:c7:1e:
+ 54:e1:77:e0:67:c8:0f:9c:87:23:d6:3f:40:20:7f:
+ 20:80:c4:80:4c:3e:3b:24:26:8e:04:ae:6c:9a:c8:
+ aa:0d
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 84:18:CC:85:34:EC:BC:0C:94:94:2E:08:59:9C:C7:B2:10:4E:0A:08
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 98:f2:37:5a:41:90:a1:1a:c5:76:51:28:20:36:23:0e:ae:e6:
+ 28:bb:aa:f8:94:ae:48:a4:30:7f:1b:fc:24:8d:4b:b4:c8:a1:
+ 97:f6:b6:f1:7a:70:c8:53:93:cc:08:28:e3:98:25:cf:23:a4:
+ f9:de:21:d3:7c:85:09:ad:4e:9a:75:3a:c2:0b:6a:89:78:76:
+ 44:47:18:65:6c:8d:41:8e:3b:7f:9a:cb:f4:b5:a7:50:d7:05:
+ 2c:37:e8:03:4b:ad:e9:61:a0:02:6e:f5:f2:f0:c5:b2:ed:5b:
+ b7:dc:fa:94:5c:77:9e:13:a5:7f:52:ad:95:f2:f8:93:3b:de:
+ 8b:5c:5b:ca:5a:52:5b:60:af:14:f7:4b:ef:a3:fb:9f:40:95:
+ 6d:31:54:fc:42:d3:c7:46:1f:23:ad:d9:0f:48:70:9a:d9:75:
+ 78:71:d1:72:43:34:75:6e:57:59:c2:02:5c:26:60:29:cf:23:
+ 19:16:8e:88:43:a5:d4:e4:cb:08:fb:23:11:43:e8:43:29:72:
+ 62:a1:a9:5d:5e:08:d4:90:ae:b8:d8:ce:14:c2:d0:55:f2:86:
+ f6:c4:93:43:77:66:61:c0:b9:e8:41:d7:97:78:60:03:6e:4a:
+ 72:ae:a5:d1:7d:ba:10:9e:86:6c:1b:8a:b9:59:33:f8:eb:c4:
+ 90:be:f1:b9
+SHA1 Fingerprint=8D:A7:F9:65:EC:5E:FC:37:91:0F:1C:6E:59:FD:C1:CC:6A:6E:DE:16
diff --git a/apex/ca-certificates/files/fde84897.0 b/apex/ca-certificates/files/fde84897.0
new file mode 100644
index 0000000..03d23b5
--- /dev/null
+++ b/apex/ca-certificates/files/fde84897.0
@@ -0,0 +1,87 @@
+-----BEGIN CERTIFICATE-----
+MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV
+BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X
+DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ
+BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4
+QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny
+gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw
+zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q
+130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2
+JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw
+DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw
+ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT
+AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj
+AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG
+9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h
+bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc
+fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu
+HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w
+t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw
+WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ fe:dc:e3:01:0f:c9:48:ff
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=FR, O=Dhimyotis, CN=Certigna
+ Validity
+ Not Before: Jun 29 15:13:05 2007 GMT
+ Not After : Jun 29 15:13:05 2027 GMT
+ Subject: C=FR, O=Dhimyotis, CN=Certigna
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c8:68:f1:c9:d6:d6:b3:34:75:26:82:1e:ec:b4:
+ be:ea:5c:e1:26:ed:11:47:61:e1:a2:7c:16:78:40:
+ 21:e4:60:9e:5a:c8:63:e1:c4:b1:96:92:ff:18:6d:
+ 69:23:e1:2b:62:f7:dd:e2:36:2f:91:07:b9:48:cf:
+ 0e:ec:79:b6:2c:e7:34:4b:70:08:25:a3:3c:87:1b:
+ 19:f2:81:07:0f:38:90:19:d3:11:fe:86:b4:f2:d1:
+ 5e:1e:1e:96:cd:80:6c:ce:3b:31:93:b6:f2:a0:d0:
+ a9:95:12:7d:a5:9a:cc:6b:c8:84:56:8a:33:a9:e7:
+ 22:15:53:16:f0:cc:17:ec:57:5f:e9:a2:0a:98:09:
+ de:e3:5f:9c:6f:dc:48:e3:85:0b:15:5a:a6:ba:9f:
+ ac:48:e3:09:b2:f7:f4:32:de:5e:34:be:1c:78:5d:
+ 42:5b:ce:0e:22:8f:4d:90:d7:7d:32:18:b3:0b:2c:
+ 6a:bf:8e:3f:14:11:89:20:0e:77:14:b5:3d:94:08:
+ 87:f7:25:1e:d5:b2:60:00:ec:6f:2a:28:25:6e:2a:
+ 3e:18:63:17:25:3f:3e:44:20:16:f6:26:c8:25:ae:
+ 05:4a:b4:e7:63:2c:f3:8c:16:53:7e:5c:fb:11:1a:
+ 08:c1:46:62:9f:22:b8:f1:c2:8d:69:dc:fa:3a:58:
+ 06:df
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 1A:ED:FE:41:39:90:B4:24:59:BE:01:F2:52:D5:45:F6:5A:39:DC:11
+ X509v3 Authority Key Identifier:
+ keyid:1A:ED:FE:41:39:90:B4:24:59:BE:01:F2:52:D5:45:F6:5A:39:DC:11
+ DirName:/C=FR/O=Dhimyotis/CN=Certigna
+ serial:FE:DC:E3:01:0F:C9:48:FF
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Netscape Cert Type:
+ SSL CA, S/MIME CA, Object Signing CA
+ Signature Algorithm: sha1WithRSAEncryption
+ Signature Value:
+ 85:03:1e:92:71:f6:42:af:e1:a3:61:9e:eb:f3:c0:0f:f2:a5:
+ d4:da:95:e6:d6:be:68:36:3d:7e:6e:1f:4c:8a:ef:d1:0f:21:
+ 6d:5e:a5:52:63:ce:12:f8:ef:2a:da:6f:eb:37:fe:13:02:c7:
+ cb:3b:3e:22:6b:da:61:2e:7f:d4:72:3d:dd:30:e1:1e:4c:40:
+ 19:8c:0f:d7:9c:d1:83:30:7b:98:59:dc:7d:c6:b9:0c:29:4c:
+ a1:33:a2:eb:67:3a:65:84:d3:96:e2:ed:76:45:70:8f:b5:2b:
+ de:f9:23:d6:49:6e:3c:14:b5:c6:9f:35:1e:50:d0:c1:8f:6a:
+ 70:44:02:62:cb:ae:1d:68:41:a7:aa:57:e8:53:aa:07:d2:06:
+ f6:d5:14:06:0b:91:03:75:2c:6c:72:b5:61:95:9a:0d:8b:b9:
+ 0d:e7:f5:df:54:cd:de:e6:d8:d6:09:08:97:63:e5:c1:2e:b0:
+ b7:44:26:c0:26:c0:af:55:30:9e:3b:d5:36:2a:19:04:f4:5c:
+ 1e:ff:cf:2c:b7:ff:d0:fd:87:40:11:d5:11:23:bb:48:c0:21:
+ a9:a4:28:2d:fd:15:f8:b0:4e:2b:f4:30:5b:21:fc:11:91:34:
+ be:41:ef:7b:9d:97:75:ff:97:95:c0:96:58:2f:ea:bb:46:d7:
+ bb:e4:d9:2e
+SHA1 Fingerprint=B1:2E:13:63:45:86:A4:6F:1A:B2:60:68:37:58:2D:C4:AC:FD:94:97
diff --git a/apex/ca-certificates/soong/Android.bp b/apex/ca-certificates/soong/Android.bp
new file mode 100644
index 0000000..e305794
--- /dev/null
+++ b/apex/ca-certificates/soong/Android.bp
@@ -0,0 +1,26 @@
+// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE
+// CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE
+// DEPENDING ON IT IN YOUR PROJECT. ***
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "system_ca-certificates_license"
+ // to get the below license kinds:
+ // legacy_by_exception_only (by exception only)
+ default_applicable_licenses: ["apex_ca-certificates_license"],
+}
+
+// This is a temporary solution for adding certificates to the apex.
+bootstrap_go_package {
+ name: "soong-ca-certificates-apex",
+ pkgPath: "android/soong/external/conscrypt/apex/ca-certificates",
+ deps: [
+ "soong-android",
+ "soong-etc",
+ "soong-phony",
+ ],
+ srcs: [
+ "ca_certificates_apex.go",
+ ],
+ pluginFor: ["soong_build"],
+}
diff --git a/apex/ca-certificates/soong/ca_certificates_apex.go b/apex/ca-certificates/soong/ca_certificates_apex.go
new file mode 100644
index 0000000..768485b
--- /dev/null
+++ b/apex/ca-certificates/soong/ca_certificates_apex.go
@@ -0,0 +1,70 @@
+package ca_certificates_apex
+
+import (
+ "path"
+ "path/filepath"
+
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+ "android/soong/etc"
+ "android/soong/phony"
+)
+
+func init() {
+ android.RegisterModuleType("ca_certificates_apex", caCertificatesApexFactory)
+}
+
+type caCertificatesProperties struct {
+ Src_dir *string
+ Dest_dir *string
+ Module_name_prefix *string
+}
+
+func caCertificatesLoadHook(
+ ctx android.LoadHookContext, factory android.ModuleFactory, c *caCertificatesProperties) {
+ // Find all files in src_dir.
+ srcs, err := ctx.GlobWithDeps(path.Join(ctx.ModuleDir(), *c.Src_dir, "*"), nil)
+ if err != nil || len(srcs) == 0 {
+ ctx.PropertyErrorf("src_dir", "cannot find files to install")
+ return
+ }
+
+ // Scan through the found files to create a prebuilt_etc module for each of them.
+ requiredModuleNames := make([]string, len(srcs))
+ for i, src := range srcs {
+ etcProps := struct {
+ Name *string
+ Src *string
+ Sub_dir *string
+ Filename *string
+ }{}
+ filename := filepath.Base(src)
+ moduleName := *c.Module_name_prefix + filename
+ etcProps.Name = proptools.StringPtr(moduleName)
+ etcProps.Src = proptools.StringPtr(path.Join(*c.Src_dir, filename))
+ etcProps.Sub_dir = c.Dest_dir
+ etcProps.Filename = proptools.StringPtr(filename)
+ ctx.CreateModule(factory, &etcProps)
+
+ // Add it to the required module list of the parent phony rule.
+ requiredModuleNames[i] = moduleName
+ }
+
+ phonyProps := struct {
+ Required []string
+ }{}
+ phonyProps.Required = requiredModuleNames
+ ctx.AppendProperties(&phonyProps)
+}
+
+func caCertificatesApexFactory() android.Module {
+ p := phony.PhonyFactory()
+ c := &caCertificatesProperties{}
+ android.AddLoadHook(p, func(ctx android.LoadHookContext) {
+ caCertificatesLoadHook(ctx, etc.PrebuiltEtcCaCertsFactory, c)
+ })
+ p.AddProperties(c)
+
+ return p
+}
diff --git a/apex/com.android.conscrypt.avbpubkey b/apex/com.android.conscrypt.avbpubkey
new file mode 100644
index 0000000..5ce0fbd
--- /dev/null
+++ b/apex/com.android.conscrypt.avbpubkey
Binary files differ
diff --git a/apex/com.android.conscrypt.pem b/apex/com.android.conscrypt.pem
new file mode 100644
index 0000000..7979607
--- /dev/null
+++ b/apex/com.android.conscrypt.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKgIBAAKCAgEAwWI5g+8IxjlN9HY4tNVcE12z7CHRoD1EU7WUnPIJR/OeaIBm
+eDQIyfDSkcE+KQ8RbiRLHbp5xxbTvstNNt5l7cb3U6HWhNar8bEkGadSy8jer+BI
+Hn9UY14SeEh3TUfLA8VBU7H20k3lfpzvOCdzECMthqPryIx4DWK3Thir1qwak/3b
+nF5hXAUx6FJalZ3eEvZPtFy+qW/Xk6PFKfKybQCLTb/3n0ppegMCPAaWuqYT9GOz
+JKtDEqekIeEYdMIh+Lf29aVMQNusB+3Smb+t9ys1qk/Bz3CyXTej3A+m55btWW2i
+GE5j3fWvdIGsBOjoeBE7WkXnvbNEwjkRDYY/IS6kLq10Y1uhdwuHv0VpuIkrm7c/
+bazPF6z5CRLqgCrik/Y00xV7/osR9e9+ywfAhJL0NMuta1bfu0Veny6rC3PlxbhK
+4EbUaGzj4mWnIwqml15QxmQFjTVOrnqFs93kpb/3ZTtA53bR8wLKQph5/TJv6IMH
+BOAVHNxC73sCH2TlabFAHPnJzdsHcdvtOIHRp5EYdV++T4a9k1syKWGKStzyIAA2
+tZ434ca/YqQpa3m6+H9NTcJeR6cfP1repbJouNhnlTMl07ttcxFKss+mbcXJhi78
+rllwGrGqVGb2+mcY2cgvpYYo3xAwa5e3qrMkaThCxrXpdleDzh/8S+qrky0CAwEA
+AQKCAgA4g0vrkl8uDnEJj8LilbdisW9zAi8QdNcS322er9ymejtArsVDO3GWEhp3
+HdHcjdq6JUEOXwBXfgRDLYZTEosXAZ4lgpX+G/4Dk5DJLmyzwO/S1eg9gVhX8ZXU
+MNksbF6Xq317x/YpXzpB1frSnjSx8pXLUvwEj4hF4SNQX0VYZtMdjIIxICOzkJEV
+I3v1XT0YrYJ9Yt0VBuoo6yMjLxmVYSNUhVUH5+cLEPYGNKa3xPDv6nLftGzVdsgw
+XmeXN2RWGuzAvJ2cFpYfexCgfbOJF8eHDefFh1mYhDoOhURxSVnzWGaWU9I7eyDb
+G0n55VaKP/7oUqV2en0NhT/GhATOW21whRm5D34oJyWSqry5mxE3wxmwJUOcon4q
+oiRn5iBq7rnUoEAzEK1pgdTKSNxIkuGmWmo/b1n0oxCSmDS+VTp1nC6i0eZ7YXGX
+aYxnouJDcNICTOnqKo2DYEZ26jQzqw53gcdeP9NXYgRrSa1ZUT0malD/I0m1CLUl
+lwdu+VDEEmnA0FXbs9BNUzWZut1XBelz6MsDrbcNKte/2Ikk7OhpvGKdnw7rqpWW
+MEueusIcBGK7YABJlwheIpynQBtaVWGalAy3hi1bZC5NqT0xQP2V1536pljsai+t
+cdi98bn5bZa7OluZLTN1uLIKfIKjDbPt43vYYuh/qi0D7sa8wQKCAQEA6fYRE8Dw
+3dUhkitkLuhmpVsBrxjfic9d9ypgLd1u57chd7tc8HlKE8+tTY+AI4EvKUcEweiE
+eO/DAnYijZRNY89g9JZcur4exo79UvPnayWRVS4wCwf57DrvjxkDJS97vWZRI1ns
+MS9/bNtg2RCrfReHpSC4vxZAfH6Gmt1wfJZpVcOAPPqeZX19n6N7VkFSzhw8axAj
+Py3HG5uGvE3jhouiMG1vHiMumUdkOOxkc7cjMojujQ0XIVIso02/zQSKf6QUe6bl
+ZUJTkl1GHWkEFU0bmKylfwW9GVW1fxw2qjlrLWpWFaKrbgQptvae+K1zSfQsGXab
+w6mhDvdrtDKKJwKCAQEA05mjcqPcBN3E1BI57ylcsWlD/8pVsIeBmFzrng9JJ672
+P4iZ8IxkQO4Y8zoywYNTEkgeVvertghMIy+hFVW+/7dKlXPwZhurtY6FUzy79BA7
+CKJwSyPDWJY7ol0yGkv4ME5RQZ8fGw23him7RuNl1LKHQ2NIplS5ezhZUHa6ckHG
+yM1pRjy9H9TK6XtlsSME8gej3BmU9UsAMWhMBmz8UpYYX8SmgTJIwhcZ7eM3RbyG
+S7bmw5jrxe9v0RYBh0EuVkBm+iAIY8pvCL4imNu/sEmjaBDpyNSe/0DXxjHPydAZ
+K46n92I5gRF8GfeKJMuogZGagxUFXijYVsjN4FrwiwKCAQEAvIJUjisGqGajDwhB
+R35fvloOiEutSXe5CX6uUiY5xyAKKlPf9a50nnPV+klmgLUFD+g2EBtOKbdd1Czl
+eFgG5yXfxBMnEhw/5dKukFkPnIh/ijeV5D2ABPQTs6P+ocaZmCjJtYctxQ+1RzuX
+1C4XTspXtBgiY20Fdonn4P4NNYVnx/+m4vs4ByROxQLPTNeDZajgkY9GJxC2fisZ
+K75CVlVJ0GVMg+brE/uu6CKoaYglJwGn3CSw/1sbtlTd9s3y3heRnXQDH0yK08Kt
+zOKhtJwVYTWyfx9blv81Jv7PmOZ80fH8/J++Kv3VsqMRweLXor3Hjpi/tq6Fo+59
+bIrQPwKCAQEApInWuCFEyB/umv2lQRzHsEjrkG60nTVxh5nRubGnMA1z/Elrcsqo
+dnjuu8uohiNpKFEeDoA+bKkdE0tJFf78K3pKq9Zgu/WOWvp9IBGdEZbBYOB3M2aW
+0z7XFlUjzaD/WAi+VKm4FWBgMhonP2M53uAIIFWGu5gsNu3FPbVlG82cFq7ryqsW
+YTclpdLHa6uQf+eC+naGBwuQFdtFKsX6mvmN8IJI+zOvsgUmq33AkCCdyShrXvN9
+ewfJyiszeworTvR7Xsoj2/0gxAqdeoF+GEXao+Rq9jinflLctogrTIHd4KnoYIxn
+rL584vBC4oPe/wnKvV1OND7Mowc4V9o/KwKCAQEAxe9wolYg+mz64b4D3JGH4Vs1
+vmGUqpk/CjrYVR/oQ0AeZIpzCVr3bTREbAjrhm/80CXkKiUvFFHV91desQui3kSo
+JC4aMOfBF0ykHhTHnQUD2LffUO8IrXFkzDp8pLNSzj9pxAFwAzvYRsJalYv24x0N
+B2Ek6m/bkiRBGHpDryCwf9R7C3QYyZlWzNWCiPSEcPtCdmLIIsG7ZZ4IzDr6Uphi
+Uc+2xqOW19BeVNXu7gi4xGpsOh/lmQbgg5jmX+MwQutM4l7KVe+rEqJu6tFvZkq2
+MQRWfwuqlTnMMweYXordjyKeCMRU20tgxYeBnayny98mc8QT6ENi8p0d9PFulQ==
+-----END RSA PRIVATE KEY-----
diff --git a/apex/com.android.conscrypt.pk8 b/apex/com.android.conscrypt.pk8
new file mode 100644
index 0000000..4c04deb
--- /dev/null
+++ b/apex/com.android.conscrypt.pk8
Binary files differ
diff --git a/apex/com.android.conscrypt.x509.pem b/apex/com.android.conscrypt.x509.pem
new file mode 100644
index 0000000..ba914fa
--- /dev/null
+++ b/apex/com.android.conscrypt.x509.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF1DCCA7ygAwIBAgIJAN0lMAb+9i0JMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW
+aWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRyb2lkMR4wHAYDVQQD
+DBVjb20uYW5kcm9pZC5jb25zY3J5cHQwIBcNMTkwMTI1MTcxNjM3WhgPNDc1NjEy
+MjExNzE2MzdaMH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYw
+FAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQL
+DAdBbmRyb2lkMR4wHAYDVQQDDBVjb20uYW5kcm9pZC5jb25zY3J5cHQwggIiMA0G
+CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCcfdThwuWhAk0362p7+s/8xL0Hi6Fe
+orQL30Kat8iK4ZPWM5HxOY1zmktBzjgKQ0qM4fuvHzrQJr2+SLl+l2miX4XTruAL
+w7MBS1EGzh0YC4cOBq9z8IsAW/lB6MDeAJ6TuflTk5BRun+bDB70IkWd0ylYSiTi
+AWEs4LM03rBbTcxpNuoLMj1PDNkNOmWiu0rtRbO2Y5+GI9Kw2lyPsWKkU0ixifq2
+o3gHAepmwD7bt5tDFSuOW+uCeF7TzyqsE/CFvqWYUn+5rlOlcyFARAgCh1NZXqxq
+mkcyI9vmtneIUimYw0dzgNoG0dijYAvpuQgSr0HSa2JBiQOgMrJug2PtmWpH2PNk
+UubVZYSfPiO4wTB9Jus63Y27KRdo4Bz4R4n/u0FjIi/cu0Zms07MTo60NPaGHNM/
+nMJSEDDjQ7ppoPXsamn0DID8HlZMivmcQgzokWswxw4b/i1O2fUotKEDf3wvJhUB
+4U7bAgF55FNWWfcaHYqhytWc0qO4zdMUyVqFF+/Db3hz4IkhJyzjCYxBovSSx4yN
+atHa93SwM+uH1s2iI3gOJbn/SrsfKbkrU85S5zVRDEOQg9lm2d99PMnXqXED7bRw
+G9pKmUfOzMANm8yhvL/urlSXVDHxtdw+IJGSVUlzYT3OAx2eFdnpiymiQyWotr8W
+IXfOyr/lB6IkvQIDAQABo1MwUTAdBgNVHQ4EFgQU/vXb6Hy1AxgAxhDuwnO457cD
+3+owHwYDVR0jBBgwFoAU/vXb6Hy1AxgAxhDuwnO457cD3+owDwYDVR0TAQH/BAUw
+AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEARVpJBLitmnJXL/suxt+IsszEBz/pj5g1
+uwor1L3Zvb8j614BhqrKFlPia3PKlHJHotNugjs35CrQ6S4zC3Dx3R2Wb/hBOhtk
+bfpjKZuWaPvqHx1nlBsRa6H7tOKOW/6DHkkb/L5oJo7FPZT0Y0XNandFAmveBL69
+CLZS5dFnhkbVHi7PuvSwcFEXSr/fozcIMnCsQAds42cWqlWlDDVq90vYzOM+jQxS
+cctJ3cZiL0heWEyiZmG0J95Z6kB28gEmaDw8LNUwaUsyaO7U6GwXIe/KQvI2cT/F
+yjpkBmKqDr89Xvyd9DYtZv8GbndTQLwyrPhlKLNOoly3jqjbxqAZGBpyxwVDU+Mo
+/NwkCheQeEYLrGXBgv9fLfyOLSZA7yihPTc0IQcm27DnpkZmJ/lWJ5jDG0VEkNp+
+60O5GYCs2/r3tO+YoiDSFNjsFgCoTcnOQwYhbBZC7YJLOKV0lYDjfsohE6tcCUuS
+H8Ln6Em9HhFAXZBVQU0N+OyC0bAuDTD72ClvbMQikyeWwhdvY3F0x5dDima0liqe
+0jMTJxlizLoa2YKOiLqLomLt6+sJawF0+bGSKSHpcy0NoopXTb3UBlkFpxRp9UnN
+vrnN6KyRzj7OssDEHfXSZgSR0ZAVrAsgP3vc+lBpze9jtNbITDV1gOxUBX771hdU
+UIxewtyODcY=
+-----END CERTIFICATE-----
diff --git a/apex/hiddenapi/OWNERS b/apex/hiddenapi/OWNERS
new file mode 100644
index 0000000..ac8a2b6
--- /dev/null
+++ b/apex/hiddenapi/OWNERS
@@ -0,0 +1,5 @@
+# soong-team@ as the hiddenapi files are tightly coupled with Soong
+file:platform/build/soong:/OWNERS
+
+# compat-team@ for changes to hiddenapi files
+file:tools/platform-compat:/OWNERS
diff --git a/apex/hiddenapi/hiddenapi-max-target-o-low-priority.txt b/apex/hiddenapi/hiddenapi-max-target-o-low-priority.txt
new file mode 100644
index 0000000..bd3d12b
--- /dev/null
+++ b/apex/hiddenapi/hiddenapi-max-target-o-low-priority.txt
@@ -0,0 +1,277 @@
+Lcom/android/org/conscrypt/AbstractConscryptSocket;-><init>()V
+Lcom/android/org/conscrypt/AbstractConscryptSocket;-><init>(Ljava/lang/String;I)V
+Lcom/android/org/conscrypt/AbstractConscryptSocket;-><init>(Ljava/lang/String;ILjava/net/InetAddress;I)V
+Lcom/android/org/conscrypt/AbstractConscryptSocket;-><init>(Ljava/net/InetAddress;I)V
+Lcom/android/org/conscrypt/AbstractConscryptSocket;-><init>(Ljava/net/InetAddress;ILjava/net/InetAddress;I)V
+Lcom/android/org/conscrypt/AbstractConscryptSocket;->getFileDescriptor$()Ljava/io/FileDescriptor;
+Lcom/android/org/conscrypt/AbstractConscryptSocket;->getTlsUnique()[B
+Lcom/android/org/conscrypt/AbstractConscryptSocket;->peerInfoProvider()Lcom/android/org/conscrypt/PeerInfoProvider;
+Lcom/android/org/conscrypt/AbstractConscryptSocket;->setApplicationProtocolSelector(Lcom/android/org/conscrypt/ApplicationProtocolSelector;)V
+Lcom/android/org/conscrypt/ApplicationProtocolSelector;-><init>()V
+Lcom/android/org/conscrypt/ApplicationProtocolSelector;->selectApplicationProtocol(Ljavax/net/ssl/SSLEngine;Ljava/util/List;)Ljava/lang/String;
+Lcom/android/org/conscrypt/ApplicationProtocolSelector;->selectApplicationProtocol(Ljavax/net/ssl/SSLSocket;Ljava/util/List;)Ljava/lang/String;
+Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;-><init>(Ljavax/net/ssl/SSLEngine;Lcom/android/org/conscrypt/ApplicationProtocolSelector;)V
+Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;-><init>(Ljavax/net/ssl/SSLSocket;Lcom/android/org/conscrypt/ApplicationProtocolSelector;)V
+Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;->engine:Ljavax/net/ssl/SSLEngine;
+Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;->NO_PROTOCOL_SELECTED:I
+Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;->selectApplicationProtocol([B)I
+Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;->selector:Lcom/android/org/conscrypt/ApplicationProtocolSelector;
+Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;->socket:Ljavax/net/ssl/SSLSocket;
+Lcom/android/org/conscrypt/CertBlacklist;-><init>(Ljava/util/Set;Ljava/util/Set;)V
+Lcom/android/org/conscrypt/CertBlacklist;->closeQuietly(Ljava/io/Closeable;)V
+Lcom/android/org/conscrypt/CertBlacklist;->getDefault()Lcom/android/org/conscrypt/CertBlacklist;
+Lcom/android/org/conscrypt/CertBlacklist;->HEX_TABLE:[B
+Lcom/android/org/conscrypt/CertBlacklist;->isHex(Ljava/lang/String;)Z
+Lcom/android/org/conscrypt/CertBlacklist;->isPubkeyHash(Ljava/lang/String;)Z
+Lcom/android/org/conscrypt/CertBlacklist;->isPublicKeyBlackListed(Ljava/security/PublicKey;)Z
+Lcom/android/org/conscrypt/CertBlacklist;->isSerialNumberBlackListed(Ljava/math/BigInteger;)Z
+Lcom/android/org/conscrypt/CertBlacklist;->logger:Ljava/util/logging/Logger;
+Lcom/android/org/conscrypt/CertBlacklist;->pubkeyBlacklist:Ljava/util/Set;
+Lcom/android/org/conscrypt/CertBlacklist;->readBlacklist(Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/org/conscrypt/CertBlacklist;->readFileAsBytes(Ljava/lang/String;)Ljava/io/ByteArrayOutputStream;
+Lcom/android/org/conscrypt/CertBlacklist;->readFileAsString(Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/org/conscrypt/CertBlacklist;->readPublicKeyBlackList(Ljava/lang/String;)Ljava/util/Set;
+Lcom/android/org/conscrypt/CertBlacklist;->readSerialBlackList(Ljava/lang/String;)Ljava/util/Set;
+Lcom/android/org/conscrypt/CertBlacklist;->serialBlacklist:Ljava/util/Set;
+Lcom/android/org/conscrypt/CertBlacklist;->toHex([B)[B
+Lcom/android/org/conscrypt/CertificatePriorityComparator;-><init>()V
+Lcom/android/org/conscrypt/CertificatePriorityComparator;->ALGORITHM_OID_PRIORITY_MAP:Ljava/util/Map;
+Lcom/android/org/conscrypt/CertificatePriorityComparator;->compare(Ljava/lang/Object;Ljava/lang/Object;)I
+Lcom/android/org/conscrypt/CertificatePriorityComparator;->compare(Ljava/security/cert/X509Certificate;Ljava/security/cert/X509Certificate;)I
+Lcom/android/org/conscrypt/CertificatePriorityComparator;->compareKeyAlgorithm(Ljava/security/PublicKey;Ljava/security/PublicKey;)I
+Lcom/android/org/conscrypt/CertificatePriorityComparator;->compareKeySize(Ljava/security/PublicKey;Ljava/security/PublicKey;)I
+Lcom/android/org/conscrypt/CertificatePriorityComparator;->compareSignatureAlgorithm(Ljava/security/cert/X509Certificate;Ljava/security/cert/X509Certificate;)I
+Lcom/android/org/conscrypt/CertificatePriorityComparator;->compareStrength(Ljava/security/cert/X509Certificate;Ljava/security/cert/X509Certificate;)I
+Lcom/android/org/conscrypt/CertificatePriorityComparator;->getKeySize(Ljava/security/PublicKey;)I
+Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_MD5:Ljava/lang/Integer;
+Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_SHA1:Ljava/lang/Integer;
+Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_SHA224:Ljava/lang/Integer;
+Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_SHA256:Ljava/lang/Integer;
+Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_SHA384:Ljava/lang/Integer;
+Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_SHA512:Ljava/lang/Integer;
+Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_UNKNOWN:Ljava/lang/Integer;
+Lcom/android/org/conscrypt/CertPinManager;->checkChainPinning(Ljava/lang/String;Ljava/util/List;)V
+Lcom/android/org/conscrypt/ConscryptSocketBase;-><init>()V
+Lcom/android/org/conscrypt/ConscryptSocketBase;-><init>(Ljava/lang/String;I)V
+Lcom/android/org/conscrypt/ConscryptSocketBase;-><init>(Ljava/lang/String;ILjava/net/InetAddress;I)V
+Lcom/android/org/conscrypt/ConscryptSocketBase;-><init>(Ljava/net/InetAddress;I)V
+Lcom/android/org/conscrypt/ConscryptSocketBase;-><init>(Ljava/net/InetAddress;ILjava/net/InetAddress;I)V
+Lcom/android/org/conscrypt/ConscryptSocketBase;-><init>(Ljava/net/Socket;Ljava/lang/String;IZ)V
+Lcom/android/org/conscrypt/ConscryptSocketBase;->autoClose:Z
+Lcom/android/org/conscrypt/ConscryptSocketBase;->checkOpen()V
+Lcom/android/org/conscrypt/ConscryptSocketBase;->getActiveSession()Ljavax/net/ssl/SSLSession;
+Lcom/android/org/conscrypt/ConscryptSocketBase;->getFileDescriptor$()Ljava/io/FileDescriptor;
+Lcom/android/org/conscrypt/ConscryptSocketBase;->isDelegating()Z
+Lcom/android/org/conscrypt/ConscryptSocketBase;->listeners:Ljava/util/List;
+Lcom/android/org/conscrypt/ConscryptSocketBase;->notifyHandshakeCompletedListeners()V
+Lcom/android/org/conscrypt/ConscryptSocketBase;->peerHostname:Ljava/lang/String;
+Lcom/android/org/conscrypt/ConscryptSocketBase;->peerInfoProvider()Lcom/android/org/conscrypt/PeerInfoProvider;
+Lcom/android/org/conscrypt/ConscryptSocketBase;->peerInfoProvider:Lcom/android/org/conscrypt/PeerInfoProvider;
+Lcom/android/org/conscrypt/ConscryptSocketBase;->peerPort:I
+Lcom/android/org/conscrypt/ConscryptSocketBase;->readTimeoutMilliseconds:I
+Lcom/android/org/conscrypt/ConscryptSocketBase;->setApplicationProtocolSelector(Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;)V
+Lcom/android/org/conscrypt/NativeRef$EC_GROUP;-><init>(J)V
+Lcom/android/org/conscrypt/NativeRef$EC_GROUP;->doFree(J)V
+Lcom/android/org/conscrypt/NativeRef$EC_POINT;-><init>(J)V
+Lcom/android/org/conscrypt/NativeRef$EC_POINT;->doFree(J)V
+Lcom/android/org/conscrypt/NativeRef$EVP_CIPHER_CTX;-><init>(J)V
+Lcom/android/org/conscrypt/NativeRef$EVP_CIPHER_CTX;->doFree(J)V
+Lcom/android/org/conscrypt/NativeRef$EVP_MD_CTX;-><init>(J)V
+Lcom/android/org/conscrypt/NativeRef$EVP_MD_CTX;->doFree(J)V
+Lcom/android/org/conscrypt/NativeRef$EVP_PKEY;-><init>(J)V
+Lcom/android/org/conscrypt/NativeRef$EVP_PKEY;->doFree(J)V
+Lcom/android/org/conscrypt/NativeRef$EVP_PKEY_CTX;-><init>(J)V
+Lcom/android/org/conscrypt/NativeRef$EVP_PKEY_CTX;->doFree(J)V
+Lcom/android/org/conscrypt/NativeRef$HMAC_CTX;-><init>(J)V
+Lcom/android/org/conscrypt/NativeRef$HMAC_CTX;->doFree(J)V
+Lcom/android/org/conscrypt/NativeRef$SSL_SESSION;-><init>(J)V
+Lcom/android/org/conscrypt/NativeRef$SSL_SESSION;->doFree(J)V
+Lcom/android/org/conscrypt/NativeRef;-><init>(J)V
+Lcom/android/org/conscrypt/NativeRef;->context:J
+Lcom/android/org/conscrypt/NativeRef;->doFree(J)V
+Lcom/android/org/conscrypt/OpenSSLKey;-><init>(JZ)V
+Lcom/android/org/conscrypt/OpenSSLKey;->ctx:Lcom/android/org/conscrypt/NativeRef$EVP_PKEY;
+Lcom/android/org/conscrypt/OpenSSLKey;->fromECPrivateKeyForTLSStackOnly(Ljava/security/PrivateKey;Ljava/security/spec/ECParameterSpec;)Lcom/android/org/conscrypt/OpenSSLKey;
+Lcom/android/org/conscrypt/OpenSSLKey;->fromKeyMaterial(Ljava/security/PrivateKey;)Lcom/android/org/conscrypt/OpenSSLKey;
+Lcom/android/org/conscrypt/OpenSSLKey;->fromPrivateKeyForTLSStackOnly(Ljava/security/PrivateKey;Ljava/security/PublicKey;)Lcom/android/org/conscrypt/OpenSSLKey;
+Lcom/android/org/conscrypt/OpenSSLKey;->fromPrivateKeyPemInputStream(Ljava/io/InputStream;)Lcom/android/org/conscrypt/OpenSSLKey;
+Lcom/android/org/conscrypt/OpenSSLKey;->fromPublicKey(Ljava/security/PublicKey;)Lcom/android/org/conscrypt/OpenSSLKey;
+Lcom/android/org/conscrypt/OpenSSLKey;->fromPublicKeyPemInputStream(Ljava/io/InputStream;)Lcom/android/org/conscrypt/OpenSSLKey;
+Lcom/android/org/conscrypt/OpenSSLKey;->getOpenSSLKey(Ljava/security/PrivateKey;)Lcom/android/org/conscrypt/OpenSSLKey;
+Lcom/android/org/conscrypt/OpenSSLKey;->getPrivateKey()Ljava/security/PrivateKey;
+Lcom/android/org/conscrypt/OpenSSLKey;->getPrivateKey(Ljava/security/spec/PKCS8EncodedKeySpec;I)Ljava/security/PrivateKey;
+Lcom/android/org/conscrypt/OpenSSLKey;->getPublicKey(Ljava/security/spec/X509EncodedKeySpec;I)Ljava/security/PublicKey;
+Lcom/android/org/conscrypt/OpenSSLKey;->isWrapped()Z
+Lcom/android/org/conscrypt/OpenSSLKey;->wrapJCAPrivateKeyForTLSStackOnly(Ljava/security/PrivateKey;Ljava/security/PublicKey;)Lcom/android/org/conscrypt/OpenSSLKey;
+Lcom/android/org/conscrypt/OpenSSLKey;->wrapped:Z
+Lcom/android/org/conscrypt/OpenSSLKey;->wrapPrivateKey(Ljava/security/PrivateKey;)Lcom/android/org/conscrypt/OpenSSLKey;
+Lcom/android/org/conscrypt/OpenSSLSocketImpl;-><init>()V
+Lcom/android/org/conscrypt/OpenSSLSocketImpl;-><init>(Ljava/lang/String;I)V
+Lcom/android/org/conscrypt/OpenSSLSocketImpl;-><init>(Ljava/lang/String;ILjava/net/InetAddress;I)V
+Lcom/android/org/conscrypt/OpenSSLSocketImpl;-><init>(Ljava/net/InetAddress;I)V
+Lcom/android/org/conscrypt/OpenSSLSocketImpl;-><init>(Ljava/net/InetAddress;ILjava/net/InetAddress;I)V
+Lcom/android/org/conscrypt/OpenSSLSocketImpl;-><init>(Ljava/net/Socket;Ljava/lang/String;IZ)V
+Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getFileDescriptor$()Ljava/io/FileDescriptor;
+Lcom/android/org/conscrypt/OpenSSLX509Certificate;-><init>(J)V
+Lcom/android/org/conscrypt/OpenSSLX509Certificate;-><init>(JLjava/util/Date;Ljava/util/Date;)V
+Lcom/android/org/conscrypt/OpenSSLX509Certificate;->alternativeNameArrayToList([[Ljava/lang/Object;)Ljava/util/Collection;
+Lcom/android/org/conscrypt/OpenSSLX509Certificate;->fromCertificate(Ljava/security/cert/Certificate;)Lcom/android/org/conscrypt/OpenSSLX509Certificate;
+Lcom/android/org/conscrypt/OpenSSLX509Certificate;->fromPkcs7DerInputStream(Ljava/io/InputStream;)Ljava/util/List;
+Lcom/android/org/conscrypt/OpenSSLX509Certificate;->fromPkcs7PemInputStream(Ljava/io/InputStream;)Ljava/util/List;
+Lcom/android/org/conscrypt/OpenSSLX509Certificate;->fromX509Der([B)Lcom/android/org/conscrypt/OpenSSLX509Certificate;
+Lcom/android/org/conscrypt/OpenSSLX509Certificate;->fromX509DerInputStream(Ljava/io/InputStream;)Lcom/android/org/conscrypt/OpenSSLX509Certificate;
+Lcom/android/org/conscrypt/OpenSSLX509Certificate;->getContext()J
+Lcom/android/org/conscrypt/OpenSSLX509Certificate;->mHashCode:Ljava/lang/Integer;
+Lcom/android/org/conscrypt/OpenSSLX509Certificate;->notAfter:Ljava/util/Date;
+Lcom/android/org/conscrypt/OpenSSLX509Certificate;->notBefore:Ljava/util/Date;
+Lcom/android/org/conscrypt/OpenSSLX509Certificate;->toDate(J)Ljava/util/Date;
+Lcom/android/org/conscrypt/OpenSSLX509Certificate;->verifyInternal(Ljava/security/PublicKey;Ljava/lang/String;)V
+Lcom/android/org/conscrypt/OpenSSLX509Certificate;->verifyOpenSSL(Lcom/android/org/conscrypt/OpenSSLKey;)V
+Lcom/android/org/conscrypt/OpenSSLX509Certificate;->withDeletedExtension(Ljava/lang/String;)Lcom/android/org/conscrypt/OpenSSLX509Certificate;
+Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;-><init>()V
+Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;->fromPkcs7DerInputStream(Ljava/io/InputStream;)Ljava/util/List;
+Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;->fromPkcs7PemInputStream(Ljava/io/InputStream;)Ljava/util/List;
+Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;->fromX509DerInputStream(Ljava/io/InputStream;)Ljava/lang/Object;
+Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;->fromX509PemInputStream(Ljava/io/InputStream;)Ljava/lang/Object;
+Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;->generateItem(Ljava/io/InputStream;)Ljava/lang/Object;
+Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;->generateItems(Ljava/io/InputStream;)Ljava/util/Collection;
+Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$ParsingException;-><init>(Ljava/lang/Exception;)V
+Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$ParsingException;-><init>(Ljava/lang/String;)V
+Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$ParsingException;-><init>(Ljava/lang/String;Ljava/lang/Exception;)V
+Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory;-><init>()V
+Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory;->certificateParser:Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;
+Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory;->crlParser:Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;
+Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory;->PKCS7_MARKER:[B
+Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory;->PUSHBACK_SIZE:I
+Lcom/android/org/conscrypt/OpenSSLX509CRL;-><init>(J)V
+Lcom/android/org/conscrypt/OpenSSLX509CRL;->fromPkcs7DerInputStream(Ljava/io/InputStream;)Ljava/util/List;
+Lcom/android/org/conscrypt/OpenSSLX509CRL;->fromPkcs7PemInputStream(Ljava/io/InputStream;)Ljava/util/List;
+Lcom/android/org/conscrypt/OpenSSLX509CRL;->fromX509DerInputStream(Ljava/io/InputStream;)Lcom/android/org/conscrypt/OpenSSLX509CRL;
+Lcom/android/org/conscrypt/OpenSSLX509CRL;->fromX509PemInputStream(Ljava/io/InputStream;)Lcom/android/org/conscrypt/OpenSSLX509CRL;
+Lcom/android/org/conscrypt/OpenSSLX509CRL;->mContext:J
+Lcom/android/org/conscrypt/OpenSSLX509CRL;->nextUpdate:Ljava/util/Date;
+Lcom/android/org/conscrypt/OpenSSLX509CRL;->thisUpdate:Ljava/util/Date;
+Lcom/android/org/conscrypt/OpenSSLX509CRL;->toDate(J)Ljava/util/Date;
+Lcom/android/org/conscrypt/OpenSSLX509CRL;->verifyInternal(Ljava/security/PublicKey;Ljava/lang/String;)V
+Lcom/android/org/conscrypt/OpenSSLX509CRL;->verifyOpenSSL(Lcom/android/org/conscrypt/OpenSSLKey;)V
+Lcom/android/org/conscrypt/PeerInfoProvider;-><init>()V
+Lcom/android/org/conscrypt/PeerInfoProvider;->forHostAndPort(Ljava/lang/String;I)Lcom/android/org/conscrypt/PeerInfoProvider;
+Lcom/android/org/conscrypt/PeerInfoProvider;->getHostname()Ljava/lang/String;
+Lcom/android/org/conscrypt/PeerInfoProvider;->getHostnameOrIP()Ljava/lang/String;
+Lcom/android/org/conscrypt/PeerInfoProvider;->getPort()I
+Lcom/android/org/conscrypt/PeerInfoProvider;->nullProvider()Lcom/android/org/conscrypt/PeerInfoProvider;
+Lcom/android/org/conscrypt/PeerInfoProvider;->NULL_PEER_INFO_PROVIDER:Lcom/android/org/conscrypt/PeerInfoProvider;
+Lcom/android/org/conscrypt/SSLClientSessionCache;->getSessionData(Ljava/lang/String;I)[B
+Lcom/android/org/conscrypt/SSLClientSessionCache;->putSessionData(Ljavax/net/ssl/SSLSession;[B)V
+Lcom/android/org/conscrypt/TrustedCertificateIndex;-><init>()V
+Lcom/android/org/conscrypt/TrustedCertificateIndex;-><init>(Ljava/util/Set;)V
+Lcom/android/org/conscrypt/TrustedCertificateIndex;->findAllByIssuerAndSignature(Ljava/security/cert/X509Certificate;)Ljava/util/Set;
+Lcom/android/org/conscrypt/TrustedCertificateIndex;->findByIssuerAndSignature(Ljava/security/cert/X509Certificate;)Ljava/security/cert/TrustAnchor;
+Lcom/android/org/conscrypt/TrustedCertificateIndex;->findBySubjectAndPublicKey(Ljava/security/cert/X509Certificate;)Ljava/security/cert/TrustAnchor;
+Lcom/android/org/conscrypt/TrustedCertificateIndex;->findBySubjectAndPublicKey(Ljava/security/cert/X509Certificate;Ljava/util/Collection;)Ljava/security/cert/TrustAnchor;
+Lcom/android/org/conscrypt/TrustedCertificateIndex;->index(Ljava/security/cert/TrustAnchor;)V
+Lcom/android/org/conscrypt/TrustedCertificateIndex;->index(Ljava/security/cert/X509Certificate;)Ljava/security/cert/TrustAnchor;
+Lcom/android/org/conscrypt/TrustedCertificateIndex;->index(Ljava/util/Set;)V
+Lcom/android/org/conscrypt/TrustedCertificateIndex;->reset()V
+Lcom/android/org/conscrypt/TrustedCertificateIndex;->reset(Ljava/util/Set;)V
+Lcom/android/org/conscrypt/TrustedCertificateIndex;->subjectToTrustAnchors:Ljava/util/Map;
+Lcom/android/org/conscrypt/TrustedCertificateStore$CertSelector;->match(Ljava/security/cert/X509Certificate;)Z
+Lcom/android/org/conscrypt/TrustedCertificateStore$PreloadHolder;-><init>()V
+Lcom/android/org/conscrypt/TrustedCertificateStore$PreloadHolder;->defaultCaCertsAddedDir:Ljava/io/File;
+Lcom/android/org/conscrypt/TrustedCertificateStore$PreloadHolder;->defaultCaCertsDeletedDir:Ljava/io/File;
+Lcom/android/org/conscrypt/TrustedCertificateStore$PreloadHolder;->defaultCaCertsSystemDir:Ljava/io/File;
+Lcom/android/org/conscrypt/TrustedCertificateStore;-><init>(Ljava/io/File;Ljava/io/File;Ljava/io/File;)V
+Lcom/android/org/conscrypt/TrustedCertificateStore;->addAliases(Ljava/util/Set;Ljava/lang/String;Ljava/io/File;)V
+Lcom/android/org/conscrypt/TrustedCertificateStore;->addedDir:Ljava/io/File;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->aliases()Ljava/util/Set;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->allSystemAliases()Ljava/util/Set;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->CERT_FACTORY:Ljava/security/cert/CertificateFactory;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->containsAlias(Ljava/lang/String;)Z
+Lcom/android/org/conscrypt/TrustedCertificateStore;->containsAlias(Ljava/lang/String;Z)Z
+Lcom/android/org/conscrypt/TrustedCertificateStore;->convertToOpenSSLIfNeeded(Ljava/security/cert/X509Certificate;)Lcom/android/org/conscrypt/OpenSSLX509Certificate;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->deleteCertificateEntry(Ljava/lang/String;)V
+Lcom/android/org/conscrypt/TrustedCertificateStore;->deletedDir:Ljava/io/File;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->file(Ljava/io/File;Ljava/lang/String;I)Ljava/io/File;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->fileForAlias(Ljava/lang/String;)Ljava/io/File;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->findAllIssuers(Ljava/security/cert/X509Certificate;)Ljava/util/Set;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->findCert(Ljava/io/File;Ljavax/security/auth/x500/X500Principal;Lcom/android/org/conscrypt/TrustedCertificateStore$CertSelector;Ljava/lang/Class;)Ljava/lang/Object;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->findIssuer(Ljava/security/cert/X509Certificate;)Ljava/security/cert/X509Certificate;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificate(Ljava/lang/String;)Ljava/security/cert/Certificate;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificate(Ljava/lang/String;Z)Ljava/security/cert/Certificate;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificateAlias(Ljava/security/cert/Certificate;)Ljava/lang/String;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificateAlias(Ljava/security/cert/Certificate;Z)Ljava/lang/String;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificateFile(Ljava/io/File;Ljava/security/cert/X509Certificate;)Ljava/io/File;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->getCreationDate(Ljava/lang/String;)Ljava/util/Date;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->getTrustAnchor(Ljava/security/cert/X509Certificate;)Ljava/security/cert/X509Certificate;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->hash(Ljavax/security/auth/x500/X500Principal;)Ljava/lang/String;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->installCertificate(Ljava/security/cert/X509Certificate;)V
+Lcom/android/org/conscrypt/TrustedCertificateStore;->isDeletedSystemCertificate(Ljava/security/cert/X509Certificate;)Z
+Lcom/android/org/conscrypt/TrustedCertificateStore;->isSelfIssuedCertificate(Lcom/android/org/conscrypt/OpenSSLX509Certificate;)Z
+Lcom/android/org/conscrypt/TrustedCertificateStore;->isSystem(Ljava/lang/String;)Z
+Lcom/android/org/conscrypt/TrustedCertificateStore;->isTombstone(Ljava/io/File;)Z
+Lcom/android/org/conscrypt/TrustedCertificateStore;->isUser(Ljava/lang/String;)Z
+Lcom/android/org/conscrypt/TrustedCertificateStore;->isUserAddedCertificate(Ljava/security/cert/X509Certificate;)Z
+Lcom/android/org/conscrypt/TrustedCertificateStore;->PREFIX_SYSTEM:Ljava/lang/String;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->PREFIX_USER:Ljava/lang/String;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->readCertificate(Ljava/io/File;)Ljava/security/cert/X509Certificate;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->removeUnnecessaryTombstones(Ljava/lang/String;)V
+Lcom/android/org/conscrypt/TrustedCertificateStore;->setDefaultUserDirectory(Ljava/io/File;)V
+Lcom/android/org/conscrypt/TrustedCertificateStore;->systemDir:Ljava/io/File;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->userAliases()Ljava/util/Set;
+Lcom/android/org/conscrypt/TrustedCertificateStore;->writeCertificate(Ljava/io/File;Ljava/security/cert/X509Certificate;)V
+Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;-><init>(ZLjava/security/cert/X509Certificate;)V
+Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->clientAuth:Z
+Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->EKU_anyExtendedKeyUsage:Ljava/lang/String;
+Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->EKU_clientAuth:Ljava/lang/String;
+Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->EKU_msSGC:Ljava/lang/String;
+Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->EKU_nsSGC:Ljava/lang/String;
+Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->EKU_OID:Ljava/lang/String;
+Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->EKU_serverAuth:Ljava/lang/String;
+Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->leaf:Ljava/security/cert/X509Certificate;
+Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->SUPPORTED_EXTENSIONS:Ljava/util/Set;
+Lcom/android/org/conscrypt/TrustManagerImpl$TrustAnchorComparator;-><init>()V
+Lcom/android/org/conscrypt/TrustManagerImpl$TrustAnchorComparator;->CERT_COMPARATOR:Lcom/android/org/conscrypt/CertificatePriorityComparator;
+Lcom/android/org/conscrypt/TrustManagerImpl$TrustAnchorComparator;->compare(Ljava/lang/Object;Ljava/lang/Object;)I
+Lcom/android/org/conscrypt/TrustManagerImpl$TrustAnchorComparator;->compare(Ljava/security/cert/TrustAnchor;Ljava/security/cert/TrustAnchor;)I
+Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;Lcom/android/org/conscrypt/CertPinManager;)V
+Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;Lcom/android/org/conscrypt/CertPinManager;Lcom/android/org/conscrypt/TrustedCertificateStore;)V
+Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;Lcom/android/org/conscrypt/CertPinManager;Lcom/android/org/conscrypt/TrustedCertificateStore;Lcom/android/org/conscrypt/CertBlacklist;)V
+Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;Lcom/android/org/conscrypt/CertPinManager;Lcom/android/org/conscrypt/TrustedCertificateStore;Lcom/android/org/conscrypt/CertBlacklist;Lcom/android/org/conscrypt/ct/CTLogStore;Lcom/android/org/conscrypt/ct/CTVerifier;Lcom/android/org/conscrypt/ct/CTPolicy;)V
+Lcom/android/org/conscrypt/TrustManagerImpl;->acceptedIssuers(Ljava/security/KeyStore;)[Ljava/security/cert/X509Certificate;
+Lcom/android/org/conscrypt/TrustManagerImpl;->acceptedIssuers:[Ljava/security/cert/X509Certificate;
+Lcom/android/org/conscrypt/TrustManagerImpl;->blacklist:Lcom/android/org/conscrypt/CertBlacklist;
+Lcom/android/org/conscrypt/TrustManagerImpl;->checkBlacklist(Ljava/security/cert/X509Certificate;)V
+Lcom/android/org/conscrypt/TrustManagerImpl;->checkClientTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
+Lcom/android/org/conscrypt/TrustManagerImpl;->checkCT(Ljava/lang/String;Ljava/util/List;[B[B)V
+Lcom/android/org/conscrypt/TrustManagerImpl;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljavax/net/ssl/SSLSession;)Ljava/util/List;
+Lcom/android/org/conscrypt/TrustManagerImpl;->checkTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljavax/net/ssl/SSLSession;Ljavax/net/ssl/SSLParameters;Z)Ljava/util/List;
+Lcom/android/org/conscrypt/TrustManagerImpl;->checkTrusted([Ljava/security/cert/X509Certificate;[B[BLjava/lang/String;Ljava/lang/String;Z)Ljava/util/List;
+Lcom/android/org/conscrypt/TrustManagerImpl;->checkTrustedRecursive([Ljava/security/cert/X509Certificate;[B[BLjava/lang/String;ZLjava/util/ArrayList;Ljava/util/ArrayList;Ljava/util/Set;)Ljava/util/List;
+Lcom/android/org/conscrypt/TrustManagerImpl;->ctEnabledOverride:Z
+Lcom/android/org/conscrypt/TrustManagerImpl;->ctPolicy:Lcom/android/org/conscrypt/ct/CTPolicy;
+Lcom/android/org/conscrypt/TrustManagerImpl;->ctVerifier:Lcom/android/org/conscrypt/ct/CTVerifier;
+Lcom/android/org/conscrypt/TrustManagerImpl;->err:Ljava/lang/Exception;
+Lcom/android/org/conscrypt/TrustManagerImpl;->factory:Ljava/security/cert/CertificateFactory;
+Lcom/android/org/conscrypt/TrustManagerImpl;->findAllTrustAnchorsByIssuerAndSignature(Ljava/security/cert/X509Certificate;)Ljava/util/Set;
+Lcom/android/org/conscrypt/TrustManagerImpl;->findTrustAnchorBySubjectAndPublicKey(Ljava/security/cert/X509Certificate;)Ljava/security/cert/TrustAnchor;
+Lcom/android/org/conscrypt/TrustManagerImpl;->getHandshakeSessionOrThrow(Ljavax/net/ssl/SSLSocket;)Ljavax/net/ssl/SSLSession;
+Lcom/android/org/conscrypt/TrustManagerImpl;->getOcspDataFromSession(Ljavax/net/ssl/SSLSession;)[B
+Lcom/android/org/conscrypt/TrustManagerImpl;->getTlsSctDataFromSession(Ljavax/net/ssl/SSLSession;)[B
+Lcom/android/org/conscrypt/TrustManagerImpl;->getTrustedChainForServer([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/net/Socket;)Ljava/util/List;
+Lcom/android/org/conscrypt/TrustManagerImpl;->getTrustedChainForServer([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljavax/net/ssl/SSLEngine;)Ljava/util/List;
+Lcom/android/org/conscrypt/TrustManagerImpl;->handleTrustStorageUpdate()V
+Lcom/android/org/conscrypt/TrustManagerImpl;->intermediateIndex:Lcom/android/org/conscrypt/TrustedCertificateIndex;
+Lcom/android/org/conscrypt/TrustManagerImpl;->isUserAddedCertificate(Ljava/security/cert/X509Certificate;)Z
+Lcom/android/org/conscrypt/TrustManagerImpl;->pinManager:Lcom/android/org/conscrypt/CertPinManager;
+Lcom/android/org/conscrypt/TrustManagerImpl;->rootKeyStore:Ljava/security/KeyStore;
+Lcom/android/org/conscrypt/TrustManagerImpl;->setCTEnabledOverride(Z)V
+Lcom/android/org/conscrypt/TrustManagerImpl;->setCTPolicy(Lcom/android/org/conscrypt/ct/CTPolicy;)V
+Lcom/android/org/conscrypt/TrustManagerImpl;->setCTVerifier(Lcom/android/org/conscrypt/ct/CTVerifier;)V
+Lcom/android/org/conscrypt/TrustManagerImpl;->setOcspResponses(Ljava/security/cert/PKIXParameters;Ljava/security/cert/X509Certificate;[B)V
+Lcom/android/org/conscrypt/TrustManagerImpl;->sortPotentialAnchors(Ljava/util/Set;)Ljava/util/Collection;
+Lcom/android/org/conscrypt/TrustManagerImpl;->trustAnchors([Ljava/security/cert/X509Certificate;)Ljava/util/Set;
+Lcom/android/org/conscrypt/TrustManagerImpl;->trustedCertificateIndex:Lcom/android/org/conscrypt/TrustedCertificateIndex;
+Lcom/android/org/conscrypt/TrustManagerImpl;->trustedCertificateStore:Lcom/android/org/conscrypt/TrustedCertificateStore;
+Lcom/android/org/conscrypt/TrustManagerImpl;->TRUST_ANCHOR_COMPARATOR:Lcom/android/org/conscrypt/TrustManagerImpl$TrustAnchorComparator;
+Lcom/android/org/conscrypt/TrustManagerImpl;->validator:Ljava/security/cert/CertPathValidator;
+Lcom/android/org/conscrypt/TrustManagerImpl;->verifyChain(Ljava/util/List;Ljava/util/List;Ljava/lang/String;Z[B[B)Ljava/util/List;
diff --git a/apex/ld.config.txt b/apex/ld.config.txt
new file mode 100644
index 0000000..9e213aa
--- /dev/null
+++ b/apex/ld.config.txt
@@ -0,0 +1,50 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Bionic loader config file for the Conscrypt APEX.
+
+dir.conscrypt = /apex/com.android.conscrypt/bin/
+
+[conscrypt]
+additional.namespaces = platform
+
+# This configuration is only intended to support bin/boringssl_self_test{32,64}
+# loading libcrypto.so from the APEX.
+#
+# If there is a binary that needs the APEX exported library libjavacrypto.so
+# then this config should be replaced by the full namespace configs for the
+# "conscrypt" namespace in system/core/rootdir/etc/ld.config*.txt and its
+# dependencies "platform" and "runtime".
+
+namespace.default.search.paths = /apex/com.android.conscrypt/${LIB}
+namespace.default.asan.search.paths = /apex/com.android.conscrypt/${LIB}
+namespace.default.permitted.paths = /system/${LIB}
+namespace.default.asan.permitted.paths = /system/${LIB}
+namespace.default.links = platform
+namespace.default.link.platform.shared_libs = libc.so
+namespace.default.link.platform.shared_libs += libm.so
+namespace.default.link.platform.shared_libs += libdl.so
+namespace.default.link.platform.shared_libs += liblog.so
+namespace.default.link.platform.shared_libs += libclang_rt.hwasan-aarch64-android.so
+
+###############################################################################
+# "platform" namespace
+#
+# Corresponds to the default namespace in /system/etc/ld.config.txt, but
+# minimized to support the dependencies above.
+###############################################################################
+namespace.platform.isolated = true
+
+namespace.platform.search.paths = /system/${LIB}
+namespace.platform.asan.search.paths = /data/asan/system/${LIB}
+
+# /system/lib/libc.so, etc are symlinks to
+# /apex/com.android.runtime/lib/bionic/libc.so, etc. Add the path to the
+# permitted paths because linker uses realpath(3) to check the accessibility
+# of the lib. We could add this to search.paths instead but that makes the
+# resolution of bionic libs be dependent on the order of /system/lib and
+# /apex/.../lib/bionic in search.paths. If the latter is after the former,
+# then the latter is never tried because libc.so is always found in
+# /system/lib but fails to pass the accessibility test because of its realpath.
+# It's better to not depend on the ordering if possible.
+namespace.platform.permitted.paths = /apex/com.android.runtime/${LIB}/bionic
+namespace.platform.asan.permitted.paths = /apex/com.android.runtime/${LIB}/bionic
diff --git a/apex/testing/Android.bp b/apex/testing/Android.bp
new file mode 100644
index 0000000..8a1c102
--- /dev/null
+++ b/apex/testing/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2019 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.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "external_conscrypt_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["external_conscrypt_license"],
+}
+
+apex_test {
+ name: "test_com.android.conscrypt",
+ visibility: [
+ "//system/apex/tests",
+ "//vendor:__subpackages__",
+ ],
+ defaults: ["com.android.conscrypt-defaults"],
+ manifest: "test_apex_manifest.json",
+ file_contexts: ":com.android.conscrypt-file_contexts",
+ // Test APEX, should never be installed
+ installable: false,
+}
diff --git a/apex/testing/test_apex_manifest.json b/apex/testing/test_apex_manifest.json
new file mode 100644
index 0000000..97d7cf5
--- /dev/null
+++ b/apex/testing/test_apex_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.conscrypt",
+ "version": 2147483647
+}
diff --git a/apex/tests/Android.bp b/apex/tests/Android.bp
new file mode 100644
index 0000000..d42476e
--- /dev/null
+++ b/apex/tests/Android.bp
@@ -0,0 +1,73 @@
+// Copyright (C) 2020 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.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "external_conscrypt_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["external_conscrypt_license"],
+}
+
+android_test {
+ name: "MtsConscryptTestCases",
+ platform_apis: true,
+ static_libs: [
+ "conscrypt-support",
+ "conscrypt-tests",
+ "core-test-rules",
+ "ctstestrunner-axt",
+ "libcore-crypto-tests",
+ "junit",
+ ],
+
+ min_sdk_version: "29",
+ libs: [
+ "android.test.base.stubs",
+ ],
+
+ // Tag this module as an mts test artifact
+ test_suites: [
+ "general-tests",
+ "mts-conscrypt",
+ ],
+
+}
+
+android_test {
+ name: "MtsConscryptFdSocketTestCases",
+ platform_apis: true,
+ static_libs: [
+ "conscrypt-support",
+ "conscrypt-tests",
+ "core-test-rules",
+ "ctstestrunner-axt",
+ "libcore-crypto-tests",
+ "junit",
+ ],
+
+ test_config: "FdSocket.xml",
+ min_sdk_version: "29",
+ libs: [
+ "android.test.base.stubs",
+ ],
+
+ // Tag this module as an mts test artifact
+ test_suites: [
+ "general-tests",
+ "mts-conscrypt",
+ ],
+
+}
diff --git a/apex/tests/AndroidManifest.xml b/apex/tests/AndroidManifest.xml
new file mode 100644
index 0000000..f8cb64d
--- /dev/null
+++ b/apex/tests/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.conscrypt.mts">
+
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.conscrypt.mts"
+ android:label="MTS tests for the Conscrypt mainline module">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+
+</manifest>
+
diff --git a/apex/tests/AndroidTest.xml b/apex/tests/AndroidTest.xml
new file mode 100644
index 0000000..7d03650
--- /dev/null
+++ b/apex/tests/AndroidTest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+<configuration description="Config for MTS tests for the Conscrypt mainline module">
+ <option name="test-suite-tag" value="mts" />
+ <option name="config-descriptor:metadata" key="component" value="libcore" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.conscrypt.apex" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="MtsConscryptTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.conscrypt.mts" />
+ <!-- module-libs APIs are not accessible to app code by default intentionally. -->
+ <option name="hidden-api-checks" value="false" />
+ <option name="runtime-hint" value="1m" />
+ <!-- test-timeout unit is ms, value = 20 min -->
+ <option name="test-timeout" value="1200000" />
+ <option name="device-listeners" value="org.conscrypt.ConscryptInstrumentationListener" />
+ <option name="instrumentation-arg" key="conscrypt_sslsocket_implementation" value="engine" />
+ </test>
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <option name="mainline-module-package-name" value="com.google.android.conscrypt" />
+ </object>
+</configuration>
diff --git a/apex/tests/FdSocket.xml b/apex/tests/FdSocket.xml
new file mode 100644
index 0000000..58b080d
--- /dev/null
+++ b/apex/tests/FdSocket.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.
+ ~
+ ~ Re-runs a subset of MtsConscryptTestCases using Conscrypt's file-descriptor based
+ ~ implementation to ensure there are no regressions in this implementation before
+ ~ it is fully deprecated.
+ ~
+ ~ Apart from the include filters and SSLSocket implementation this test suite is
+ ~ identical to MtsConscryptTestCases.
+ -->
+<configuration description="Config for MTS tests for the Conscrypt mainline module">
+ <option name="test-suite-tag" value="mts" />
+ <option name="config-descriptor:metadata" key="component" value="libcore" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.conscrypt.apex" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="MtsConscryptFdSocketTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.conscrypt.mts" />
+ <option name="include-filter" value="libcore.javax.net.ssl" />
+ <option name="include-filter" value="com.android.org.conscrypt.javax.net.ssl" />
+ <option name="include-filter" value="org.apache.harmony.tests.javax.net.ssl" />
+ <!-- module-libs APIs are not accessible to app code by default intentionally. -->
+ <option name="hidden-api-checks" value="false" />
+ <option name="runtime-hint" value="1m" />
+ <!-- test-timeout unit is ms, value = 20 min -->
+ <option name="test-timeout" value="1200000" />
+ <option name="device-listeners" value="org.conscrypt.ConscryptInstrumentationListener" />
+ <option name="instrumentation-arg" key="conscrypt_sslsocket_implementation" value="fd" />
+ </test>
+
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <option name="mainline-module-package-name" value="com.google.android.conscrypt" />
+ </object>
+</configuration>
diff --git a/apex/tests/TEST_MAPPING b/apex/tests/TEST_MAPPING
new file mode 100644
index 0000000..76428bd
--- /dev/null
+++ b/apex/tests/TEST_MAPPING
@@ -0,0 +1,47 @@
+{
+ "mainline-presubmit": [
+ {
+ "name": "MtsConscryptTestCases[com.google.android.conscrypt.apex]",
+ "options": [
+ {
+ "exclude-filter": "org.apache.harmony.crypto.tests.javax.crypto.func.KeyAgreementFunctionalTest#test_KeyAgreement"
+ },
+ {
+ "exclude-filter": "com.android.org.conscrypt.java.security.AlgorithmParameterGeneratorTestDH#testAlgorithmParameterGenerator"
+ },
+ {
+ "exclude-filter": "org.apache.harmony.crypto.tests.javax.crypto.KeyAgreementTest#test_generateSecretLjava_lang_String"
+ },
+ {
+ "exclude-filter": "org.apache.harmony.tests.javax.net.ssl.TrustManagerFactory1Test#test_initLjavax_net_ssl_ManagerFactoryParameters"
+ },
+ {
+ "exclude-filter": "com.android.org.conscrypt.java.security.SignatureTest#test_getInstance"
+ },
+ {
+ "exclude-filter": "com.android.org.conscrypt.javax.crypto.CipherTest#test_PBKDF2WITHHMACSHA1_SKFactory_and_PBEAESCBC_Cipher_noIV"
+ }
+ ]
+ },
+ {
+ "name": "MtsConscryptFdSocketTestCases[com.google.android.conscrypt.apex]",
+ "options": [
+ {
+ "exclude-filter": "org.apache.harmony.crypto.tests.javax.crypto.func.KeyAgreementFunctionalTest#test_KeyAgreement"
+ },
+ {
+ "exclude-filter": "com.android.org.conscrypt.java.security.AlgorithmParameterGeneratorTestDH#testAlgorithmParameterGenerator"
+ },
+ {
+ "exclude-filter": "org.apache.harmony.crypto.tests.javax.crypto.KeyAgreementTest#test_generateSecretLjava_lang_String"
+ },
+ {
+ "exclude-filter": "org.apache.harmony.tests.javax.net.ssl.TrustManagerFactory1Test#test_initLjavax_net_ssl_ManagerFactoryParameters"
+ },
+ {
+ "exclude-filter": "com.android.org.conscrypt.javax.crypto.CipherTest#test_PBKDF2WITHHMACSHA1_SKFactory_and_PBEAESCBC_Cipher_noIV"
+ }
+ ]
+ }
+ ]
+}
diff --git a/api/intra/current.txt b/api/intra/current.txt
new file mode 100644
index 0000000..6fce26f
--- /dev/null
+++ b/api/intra/current.txt
@@ -0,0 +1,40 @@
+// Signature format: 2.0
+package com.android.org.conscrypt {
+
+ public class OpenSSLMessageDigestJDK extends java.security.MessageDigestSpi implements java.lang.Cloneable {
+ }
+
+ public static final class OpenSSLMessageDigestJDK.MD5 extends com.android.org.conscrypt.OpenSSLMessageDigestJDK {
+ ctor public OpenSSLMessageDigestJDK.MD5() throws java.security.NoSuchAlgorithmException;
+ }
+
+ public static final class OpenSSLMessageDigestJDK.SHA1 extends com.android.org.conscrypt.OpenSSLMessageDigestJDK {
+ ctor public OpenSSLMessageDigestJDK.SHA1() throws java.security.NoSuchAlgorithmException;
+ }
+
+ public static final class OpenSSLMessageDigestJDK.SHA224 extends com.android.org.conscrypt.OpenSSLMessageDigestJDK {
+ ctor public OpenSSLMessageDigestJDK.SHA224() throws java.security.NoSuchAlgorithmException;
+ }
+
+ public static final class OpenSSLMessageDigestJDK.SHA256 extends com.android.org.conscrypt.OpenSSLMessageDigestJDK {
+ ctor public OpenSSLMessageDigestJDK.SHA256() throws java.security.NoSuchAlgorithmException;
+ }
+
+ public static final class OpenSSLMessageDigestJDK.SHA384 extends com.android.org.conscrypt.OpenSSLMessageDigestJDK {
+ ctor public OpenSSLMessageDigestJDK.SHA384() throws java.security.NoSuchAlgorithmException;
+ }
+
+ public static final class OpenSSLMessageDigestJDK.SHA512 extends com.android.org.conscrypt.OpenSSLMessageDigestJDK {
+ ctor public OpenSSLMessageDigestJDK.SHA512() throws java.security.NoSuchAlgorithmException;
+ }
+
+ public final class OpenSSLProvider extends java.security.Provider {
+ ctor public OpenSSLProvider();
+ }
+
+ public final class OpenSSLRandom extends java.security.SecureRandomSpi implements java.io.Serializable {
+ ctor public OpenSSLRandom();
+ }
+
+}
+
diff --git a/api/intra/last-api.txt b/api/intra/last-api.txt
new file mode 100644
index 0000000..6fce26f
--- /dev/null
+++ b/api/intra/last-api.txt
@@ -0,0 +1,40 @@
+// Signature format: 2.0
+package com.android.org.conscrypt {
+
+ public class OpenSSLMessageDigestJDK extends java.security.MessageDigestSpi implements java.lang.Cloneable {
+ }
+
+ public static final class OpenSSLMessageDigestJDK.MD5 extends com.android.org.conscrypt.OpenSSLMessageDigestJDK {
+ ctor public OpenSSLMessageDigestJDK.MD5() throws java.security.NoSuchAlgorithmException;
+ }
+
+ public static final class OpenSSLMessageDigestJDK.SHA1 extends com.android.org.conscrypt.OpenSSLMessageDigestJDK {
+ ctor public OpenSSLMessageDigestJDK.SHA1() throws java.security.NoSuchAlgorithmException;
+ }
+
+ public static final class OpenSSLMessageDigestJDK.SHA224 extends com.android.org.conscrypt.OpenSSLMessageDigestJDK {
+ ctor public OpenSSLMessageDigestJDK.SHA224() throws java.security.NoSuchAlgorithmException;
+ }
+
+ public static final class OpenSSLMessageDigestJDK.SHA256 extends com.android.org.conscrypt.OpenSSLMessageDigestJDK {
+ ctor public OpenSSLMessageDigestJDK.SHA256() throws java.security.NoSuchAlgorithmException;
+ }
+
+ public static final class OpenSSLMessageDigestJDK.SHA384 extends com.android.org.conscrypt.OpenSSLMessageDigestJDK {
+ ctor public OpenSSLMessageDigestJDK.SHA384() throws java.security.NoSuchAlgorithmException;
+ }
+
+ public static final class OpenSSLMessageDigestJDK.SHA512 extends com.android.org.conscrypt.OpenSSLMessageDigestJDK {
+ ctor public OpenSSLMessageDigestJDK.SHA512() throws java.security.NoSuchAlgorithmException;
+ }
+
+ public final class OpenSSLProvider extends java.security.Provider {
+ ctor public OpenSSLProvider();
+ }
+
+ public final class OpenSSLRandom extends java.security.SecureRandomSpi implements java.io.Serializable {
+ ctor public OpenSSLRandom();
+ }
+
+}
+
diff --git a/api/intra/last-incompatibilities.txt b/api/intra/last-incompatibilities.txt
new file mode 100644
index 0000000..9a97707
--- /dev/null
+++ b/api/intra/last-incompatibilities.txt
@@ -0,0 +1 @@
+// Baseline format: 1.0
diff --git a/api/intra/last-removed.txt b/api/intra/last-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/api/intra/last-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/api/intra/removed.txt b/api/intra/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/api/intra/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/api/platform/current.txt b/api/platform/current.txt
new file mode 100644
index 0000000..b645383
--- /dev/null
+++ b/api/platform/current.txt
@@ -0,0 +1,100 @@
+// Signature format: 2.0
+package com.android.org.conscrypt {
+
+ public interface CertPinManager {
+ }
+
+ public final class ClientSessionContext implements javax.net.ssl.SSLSessionContext {
+ method public final java.util.Enumeration<byte[]> getIds();
+ method public final javax.net.ssl.SSLSession getSession(byte[]);
+ method public final int getSessionCacheSize();
+ method public final int getSessionTimeout();
+ method public void setPersistentCache(com.android.org.conscrypt.SSLClientSessionCache);
+ method public final void setSessionCacheSize(int) throws java.lang.IllegalArgumentException;
+ method public final void setSessionTimeout(int) throws java.lang.IllegalArgumentException;
+ }
+
+ public final class Conscrypt {
+ method public static javax.net.ssl.X509TrustManager getDefaultX509TrustManager() throws java.security.KeyManagementException;
+ }
+
+ public interface ConscryptCertStore {
+ }
+
+ public final class FileClientSessionCache {
+ method public static com.android.org.conscrypt.SSLClientSessionCache usingDirectory(java.io.File) throws java.io.IOException;
+ }
+
+ public final class OpenSSLProvider extends java.security.Provider {
+ ctor public OpenSSLProvider();
+ }
+
+ public abstract class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket {
+ method public void addHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener);
+ method public final void connect(java.net.SocketAddress) throws java.io.IOException;
+ method public final void connect(java.net.SocketAddress, int) throws java.io.IOException;
+ method @Deprecated public final byte[] getAlpnSelectedProtocol();
+ method @Deprecated public final byte[] getNpnSelectedProtocol();
+ method public final int getPort();
+ method public final int getSoTimeout() throws java.net.SocketException;
+ method public void removeHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener);
+ method public final void sendUrgentData(int) throws java.io.IOException;
+ method @Deprecated public final void setAlpnProtocols(byte[]);
+ method public abstract void setChannelIdPrivateKey(java.security.PrivateKey);
+ method public void setHandshakeTimeout(int) throws java.net.SocketException;
+ method public void setHostname(String);
+ method @Deprecated public final void setNpnProtocols(byte[]);
+ method public final void setOOBInline(boolean) throws java.net.SocketException;
+ method public final void setSoTimeout(int) throws java.net.SocketException;
+ method public void setSoWriteTimeout(int) throws java.net.SocketException;
+ method public abstract void setUseSessionTickets(boolean);
+ }
+
+ public interface SSLClientSessionCache {
+ }
+
+ public final class TrustManagerImpl extends javax.net.ssl.X509ExtendedTrustManager {
+ ctor public TrustManagerImpl(java.security.KeyStore);
+ ctor public TrustManagerImpl(java.security.KeyStore, com.android.org.conscrypt.CertPinManager, com.android.org.conscrypt.ConscryptCertStore);
+ method public void checkClientTrusted(java.security.cert.X509Certificate[], String) throws java.security.cert.CertificateException;
+ method public void checkClientTrusted(java.security.cert.X509Certificate[], String, java.net.Socket) throws java.security.cert.CertificateException;
+ method public void checkClientTrusted(java.security.cert.X509Certificate[], String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
+ method public java.util.List<java.security.cert.X509Certificate> checkServerTrusted(java.security.cert.X509Certificate[], String, String) throws java.security.cert.CertificateException;
+ method public java.util.List<java.security.cert.X509Certificate> getTrustedChainForServer(java.security.cert.X509Certificate[], String, java.net.Socket) throws java.security.cert.CertificateException;
+ method public java.util.List<java.security.cert.X509Certificate> getTrustedChainForServer(java.security.cert.X509Certificate[], String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
+ method public void handleTrustStorageUpdate();
+ }
+
+ public final class TrustedCertificateIndex {
+ ctor public TrustedCertificateIndex();
+ method public java.util.Set<java.security.cert.TrustAnchor> findAllByIssuerAndSignature(java.security.cert.X509Certificate);
+ method public java.security.cert.TrustAnchor findByIssuerAndSignature(java.security.cert.X509Certificate);
+ method public java.security.cert.TrustAnchor findBySubjectAndPublicKey(java.security.cert.X509Certificate);
+ method public java.security.cert.TrustAnchor index(java.security.cert.X509Certificate);
+ }
+
+ public class TrustedCertificateStore implements com.android.org.conscrypt.ConscryptCertStore {
+ ctor public TrustedCertificateStore();
+ method public java.util.Set<java.lang.String> aliases();
+ method public java.util.Set<java.lang.String> allSystemAliases();
+ method public boolean containsAlias(String);
+ method public void deleteCertificateEntry(String) throws java.security.cert.CertificateException, java.io.IOException;
+ method public java.util.Set<java.security.cert.X509Certificate> findAllIssuers(java.security.cert.X509Certificate);
+ method public java.security.cert.X509Certificate findIssuer(java.security.cert.X509Certificate);
+ method public java.security.cert.Certificate getCertificate(String);
+ method public java.security.cert.Certificate getCertificate(String, boolean);
+ method public String getCertificateAlias(java.security.cert.Certificate);
+ method public String getCertificateAlias(java.security.cert.Certificate, boolean);
+ method public java.util.List<java.security.cert.X509Certificate> getCertificateChain(java.security.cert.X509Certificate) throws java.security.cert.CertificateException;
+ method public java.io.File getCertificateFile(java.io.File, java.security.cert.X509Certificate);
+ method public java.util.Date getCreationDate(String);
+ method public java.security.cert.X509Certificate getTrustAnchor(java.security.cert.X509Certificate);
+ method public void installCertificate(java.security.cert.X509Certificate) throws java.security.cert.CertificateException, java.io.IOException;
+ method public static final boolean isUser(String);
+ method public boolean isUserAddedCertificate(java.security.cert.X509Certificate);
+ method public static void setDefaultUserDirectory(java.io.File);
+ method public java.util.Set<java.lang.String> userAliases();
+ }
+
+}
+
diff --git a/api/platform/last-api.txt b/api/platform/last-api.txt
new file mode 100644
index 0000000..b645383
--- /dev/null
+++ b/api/platform/last-api.txt
@@ -0,0 +1,100 @@
+// Signature format: 2.0
+package com.android.org.conscrypt {
+
+ public interface CertPinManager {
+ }
+
+ public final class ClientSessionContext implements javax.net.ssl.SSLSessionContext {
+ method public final java.util.Enumeration<byte[]> getIds();
+ method public final javax.net.ssl.SSLSession getSession(byte[]);
+ method public final int getSessionCacheSize();
+ method public final int getSessionTimeout();
+ method public void setPersistentCache(com.android.org.conscrypt.SSLClientSessionCache);
+ method public final void setSessionCacheSize(int) throws java.lang.IllegalArgumentException;
+ method public final void setSessionTimeout(int) throws java.lang.IllegalArgumentException;
+ }
+
+ public final class Conscrypt {
+ method public static javax.net.ssl.X509TrustManager getDefaultX509TrustManager() throws java.security.KeyManagementException;
+ }
+
+ public interface ConscryptCertStore {
+ }
+
+ public final class FileClientSessionCache {
+ method public static com.android.org.conscrypt.SSLClientSessionCache usingDirectory(java.io.File) throws java.io.IOException;
+ }
+
+ public final class OpenSSLProvider extends java.security.Provider {
+ ctor public OpenSSLProvider();
+ }
+
+ public abstract class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket {
+ method public void addHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener);
+ method public final void connect(java.net.SocketAddress) throws java.io.IOException;
+ method public final void connect(java.net.SocketAddress, int) throws java.io.IOException;
+ method @Deprecated public final byte[] getAlpnSelectedProtocol();
+ method @Deprecated public final byte[] getNpnSelectedProtocol();
+ method public final int getPort();
+ method public final int getSoTimeout() throws java.net.SocketException;
+ method public void removeHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener);
+ method public final void sendUrgentData(int) throws java.io.IOException;
+ method @Deprecated public final void setAlpnProtocols(byte[]);
+ method public abstract void setChannelIdPrivateKey(java.security.PrivateKey);
+ method public void setHandshakeTimeout(int) throws java.net.SocketException;
+ method public void setHostname(String);
+ method @Deprecated public final void setNpnProtocols(byte[]);
+ method public final void setOOBInline(boolean) throws java.net.SocketException;
+ method public final void setSoTimeout(int) throws java.net.SocketException;
+ method public void setSoWriteTimeout(int) throws java.net.SocketException;
+ method public abstract void setUseSessionTickets(boolean);
+ }
+
+ public interface SSLClientSessionCache {
+ }
+
+ public final class TrustManagerImpl extends javax.net.ssl.X509ExtendedTrustManager {
+ ctor public TrustManagerImpl(java.security.KeyStore);
+ ctor public TrustManagerImpl(java.security.KeyStore, com.android.org.conscrypt.CertPinManager, com.android.org.conscrypt.ConscryptCertStore);
+ method public void checkClientTrusted(java.security.cert.X509Certificate[], String) throws java.security.cert.CertificateException;
+ method public void checkClientTrusted(java.security.cert.X509Certificate[], String, java.net.Socket) throws java.security.cert.CertificateException;
+ method public void checkClientTrusted(java.security.cert.X509Certificate[], String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
+ method public java.util.List<java.security.cert.X509Certificate> checkServerTrusted(java.security.cert.X509Certificate[], String, String) throws java.security.cert.CertificateException;
+ method public java.util.List<java.security.cert.X509Certificate> getTrustedChainForServer(java.security.cert.X509Certificate[], String, java.net.Socket) throws java.security.cert.CertificateException;
+ method public java.util.List<java.security.cert.X509Certificate> getTrustedChainForServer(java.security.cert.X509Certificate[], String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
+ method public void handleTrustStorageUpdate();
+ }
+
+ public final class TrustedCertificateIndex {
+ ctor public TrustedCertificateIndex();
+ method public java.util.Set<java.security.cert.TrustAnchor> findAllByIssuerAndSignature(java.security.cert.X509Certificate);
+ method public java.security.cert.TrustAnchor findByIssuerAndSignature(java.security.cert.X509Certificate);
+ method public java.security.cert.TrustAnchor findBySubjectAndPublicKey(java.security.cert.X509Certificate);
+ method public java.security.cert.TrustAnchor index(java.security.cert.X509Certificate);
+ }
+
+ public class TrustedCertificateStore implements com.android.org.conscrypt.ConscryptCertStore {
+ ctor public TrustedCertificateStore();
+ method public java.util.Set<java.lang.String> aliases();
+ method public java.util.Set<java.lang.String> allSystemAliases();
+ method public boolean containsAlias(String);
+ method public void deleteCertificateEntry(String) throws java.security.cert.CertificateException, java.io.IOException;
+ method public java.util.Set<java.security.cert.X509Certificate> findAllIssuers(java.security.cert.X509Certificate);
+ method public java.security.cert.X509Certificate findIssuer(java.security.cert.X509Certificate);
+ method public java.security.cert.Certificate getCertificate(String);
+ method public java.security.cert.Certificate getCertificate(String, boolean);
+ method public String getCertificateAlias(java.security.cert.Certificate);
+ method public String getCertificateAlias(java.security.cert.Certificate, boolean);
+ method public java.util.List<java.security.cert.X509Certificate> getCertificateChain(java.security.cert.X509Certificate) throws java.security.cert.CertificateException;
+ method public java.io.File getCertificateFile(java.io.File, java.security.cert.X509Certificate);
+ method public java.util.Date getCreationDate(String);
+ method public java.security.cert.X509Certificate getTrustAnchor(java.security.cert.X509Certificate);
+ method public void installCertificate(java.security.cert.X509Certificate) throws java.security.cert.CertificateException, java.io.IOException;
+ method public static final boolean isUser(String);
+ method public boolean isUserAddedCertificate(java.security.cert.X509Certificate);
+ method public static void setDefaultUserDirectory(java.io.File);
+ method public java.util.Set<java.lang.String> userAliases();
+ }
+
+}
+
diff --git a/api/platform/last-incompatibilities.txt b/api/platform/last-incompatibilities.txt
new file mode 100644
index 0000000..9a97707
--- /dev/null
+++ b/api/platform/last-incompatibilities.txt
@@ -0,0 +1 @@
+// Baseline format: 1.0
diff --git a/api/platform/last-removed.txt b/api/platform/last-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/api/platform/last-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/api/platform/lint-baseline.txt b/api/platform/lint-baseline.txt
new file mode 100644
index 0000000..2c02e00
--- /dev/null
+++ b/api/platform/lint-baseline.txt
@@ -0,0 +1,21 @@
+// Baseline format: 1.0
+AcronymName: com.android.org.conscrypt.OpenSSLSocketImpl#getOOBInline():
+ Acronyms should not be capitalized in method names: was `getOOBInline`, should this be `getOobInline`?
+
+
+MissingNullability: com.android.org.conscrypt.OpenSSLSocketImpl#bind(java.net.SocketAddress) parameter #0:
+ Missing nullability on parameter `bindpoint` in method `bind`
+MissingNullability: com.android.org.conscrypt.OpenSSLSocketImpl#getChannel():
+ Missing nullability on method `getChannel` return
+MissingNullability: com.android.org.conscrypt.OpenSSLSocketImpl#getInetAddress():
+ Missing nullability on method `getInetAddress` return
+MissingNullability: com.android.org.conscrypt.OpenSSLSocketImpl#getInputStream():
+ Missing nullability on method `getInputStream` return
+MissingNullability: com.android.org.conscrypt.OpenSSLSocketImpl#getLocalAddress():
+ Missing nullability on method `getLocalAddress` return
+MissingNullability: com.android.org.conscrypt.OpenSSLSocketImpl#getLocalSocketAddress():
+ Missing nullability on method `getLocalSocketAddress` return
+MissingNullability: com.android.org.conscrypt.OpenSSLSocketImpl#getOutputStream():
+ Missing nullability on method `getOutputStream` return
+MissingNullability: com.android.org.conscrypt.OpenSSLSocketImpl#getRemoteSocketAddress():
+ Missing nullability on method `getRemoteSocketAddress` return
diff --git a/api/platform/removed.txt b/api/platform/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/api/platform/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/api/public/current.txt b/api/public/current.txt
new file mode 100644
index 0000000..809495c
--- /dev/null
+++ b/api/public/current.txt
@@ -0,0 +1,17 @@
+// Signature format: 2.0
+package android.net.ssl {
+
+ public class SSLEngines {
+ method @Nullable public static byte[] exportKeyingMaterial(@NonNull javax.net.ssl.SSLEngine, @NonNull String, @Nullable byte[], int) throws javax.net.ssl.SSLException;
+ method public static boolean isSupportedEngine(@NonNull javax.net.ssl.SSLEngine);
+ method public static void setUseSessionTickets(@NonNull javax.net.ssl.SSLEngine, boolean);
+ }
+
+ public class SSLSockets {
+ method @Nullable public static byte[] exportKeyingMaterial(@NonNull javax.net.ssl.SSLSocket, @NonNull String, @Nullable byte[], int) throws javax.net.ssl.SSLException;
+ method public static boolean isSupportedSocket(@NonNull javax.net.ssl.SSLSocket);
+ method public static void setUseSessionTickets(@NonNull javax.net.ssl.SSLSocket, boolean);
+ }
+
+}
+
diff --git a/api/public/module-lib-current.txt b/api/public/module-lib-current.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/api/public/module-lib-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/api/public/module-lib-removed.txt b/api/public/module-lib-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/api/public/module-lib-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/api/public/removed.txt b/api/public/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/api/public/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/api/public/system-current.txt b/api/public/system-current.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/api/public/system-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/api/public/system-removed.txt b/api/public/system-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/api/public/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/build.gradle b/build.gradle
index 9d90d6a..e504bbc 100644
--- a/build.gradle
+++ b/build.gradle
@@ -100,7 +100,7 @@
// Test dependencies.
bouncycastle_apis: 'org.bouncycastle:bcpkix-jdk15on:1.63',
bouncycastle_provider: 'org.bouncycastle:bcprov-jdk15on:1.63',
- junit : 'junit:junit:4.13.2',
+ junit : 'junit:junit:4.12',
mockito: 'org.mockito:mockito-core:2.28.2',
truth : 'com.google.truth:truth:1.0',
diff --git a/common/src/jni/main/cpp/conscrypt/jniutil.cc b/common/src/jni/main/cpp/conscrypt/jniutil.cc
index acbd28e..cae86d0 100644
--- a/common/src/jni/main/cpp/conscrypt/jniutil.cc
+++ b/common/src/jni/main/cpp/conscrypt/jniutil.cc
@@ -112,36 +112,34 @@
sslHandshakeCallbacks_verifyCertificateChain =
getMethodRef(env, sslHandshakeCallbacksClass, "verifyCertificateChain", "([[BLjava/lang/String;)V");
sslHandshakeCallbacks_onSSLStateChange =
- getMethodRef(env, sslHandshakeCallbacksClass, "onSSLStateChange", "(II)V");
- sslHandshakeCallbacks_clientCertificateRequested =
- getMethodRef(env, sslHandshakeCallbacksClass, "clientCertificateRequested", "([B[I[[B)V");
+ getMethodRef(env, sslHandshakeCallbacksClass, "onSSLStateChange", "(II)V");
+ sslHandshakeCallbacks_clientCertificateRequested = getMethodRef(
+ env, sslHandshakeCallbacksClass, "clientCertificateRequested", "([B[I[[B)V");
sslHandshakeCallbacks_serverCertificateRequested =
- getMethodRef(env, sslHandshakeCallbacksClass, "serverCertificateRequested", "()V");
- sslHandshakeCallbacks_clientPSKKeyRequested =
- getMethodRef(env, sslHandshakeCallbacksClass, "clientPSKKeyRequested", "(Ljava/lang/String;[B[B)I");
+ getMethodRef(env, sslHandshakeCallbacksClass, "serverCertificateRequested", "()V");
+ sslHandshakeCallbacks_clientPSKKeyRequested = getMethodRef(
+ env, sslHandshakeCallbacksClass, "clientPSKKeyRequested", "(Ljava/lang/String;[B[B)I");
sslHandshakeCallbacks_serverPSKKeyRequested =
- getMethodRef(env, sslHandshakeCallbacksClass, "serverPSKKeyRequested", "(Ljava/lang/String;Ljava/lang/String;[B)I");
+ getMethodRef(env, sslHandshakeCallbacksClass, "serverPSKKeyRequested",
+ "(Ljava/lang/String;Ljava/lang/String;[B)I");
sslHandshakeCallbacks_onNewSessionEstablished =
- getMethodRef(env, sslHandshakeCallbacksClass, "onNewSessionEstablished", "(J)V");
+ getMethodRef(env, sslHandshakeCallbacksClass, "onNewSessionEstablished", "(J)V");
sslHandshakeCallbacks_serverSessionRequested =
- getMethodRef(env, sslHandshakeCallbacksClass, "serverSessionRequested", "([B)J");
+ getMethodRef(env, sslHandshakeCallbacksClass, "serverSessionRequested", "([B)J");
sslHandshakeCallbacks_selectApplicationProtocol =
- getMethodRef(env, sslHandshakeCallbacksClass, "selectApplicationProtocol", "([B)I");
- cryptoUpcallsClass_rawSignMethod = env->GetStaticMethodID(cryptoUpcallsClass,
- "ecSignDigestWithPrivateKey",
- "(Ljava/security/PrivateKey;[B)[B");
+ getMethodRef(env, sslHandshakeCallbacksClass, "selectApplicationProtocol", "([B)I");
+ cryptoUpcallsClass_rawSignMethod = env->GetStaticMethodID(
+ cryptoUpcallsClass, "ecSignDigestWithPrivateKey", "(Ljava/security/PrivateKey;[B)[B");
if (cryptoUpcallsClass_rawSignMethod == nullptr) {
env->FatalError("Could not find ecSignDigestWithPrivateKey");
}
- cryptoUpcallsClass_rsaSignMethod = env->GetStaticMethodID(cryptoUpcallsClass,
- "rsaSignDigestWithPrivateKey",
- "(Ljava/security/PrivateKey;I[B)[B");
+ cryptoUpcallsClass_rsaSignMethod = env->GetStaticMethodID(
+ cryptoUpcallsClass, "rsaSignDigestWithPrivateKey", "(Ljava/security/PrivateKey;I[B)[B");
if (cryptoUpcallsClass_rsaSignMethod == nullptr) {
env->FatalError("Could not find rsaSignDigestWithPrivateKey");
}
- cryptoUpcallsClass_rsaDecryptMethod = env->GetStaticMethodID(cryptoUpcallsClass,
- "rsaDecryptWithPrivateKey",
- "(Ljava/security/PrivateKey;I[B)[B");
+ cryptoUpcallsClass_rsaDecryptMethod = env->GetStaticMethodID(
+ cryptoUpcallsClass, "rsaDecryptWithPrivateKey", "(Ljava/security/PrivateKey;I[B)[B");
if (cryptoUpcallsClass_rsaDecryptMethod == nullptr) {
env->FatalError("Could not find rsaDecryptWithPrivateKey");
}
diff --git a/common/src/jni/main/cpp/conscrypt/native_crypto.cc b/common/src/jni/main/cpp/conscrypt/native_crypto.cc
index f7ef1c3..ae54a30 100644
--- a/common/src/jni/main/cpp/conscrypt/native_crypto.cc
+++ b/common/src/jni/main/cpp/conscrypt/native_crypto.cc
@@ -531,8 +531,7 @@
return reinterpret_cast<jbyteArray>(env->CallStaticObjectMethod(
conscrypt::jniutil::cryptoUpcallsClass,
- conscrypt::jniutil::cryptoUpcallsClass_rawSignMethod,
- privateKey, messageArray.get()));
+ conscrypt::jniutil::cryptoUpcallsClass_rawSignMethod, privateKey, messageArray.get()));
}
static jbyteArray rsaSignDigestWithPrivateKey(JNIEnv* env, jobject privateKey, jint padding,
@@ -559,10 +558,9 @@
}
return reinterpret_cast<jbyteArray>(
- env->CallStaticObjectMethod(
- conscrypt::jniutil::cryptoUpcallsClass,
- conscrypt::jniutil::cryptoUpcallsClass_rsaSignMethod,
- privateKey, padding, messageArray.get()));
+ env->CallStaticObjectMethod(conscrypt::jniutil::cryptoUpcallsClass,
+ conscrypt::jniutil::cryptoUpcallsClass_rsaSignMethod,
+ privateKey, padding, messageArray.get()));
}
// rsaDecryptWithPrivateKey uses privateKey to decrypt |ciphertext_len| bytes
@@ -593,10 +591,9 @@
}
return reinterpret_cast<jbyteArray>(
- env->CallStaticObjectMethod(
- conscrypt::jniutil::cryptoUpcallsClass,
- conscrypt::jniutil::cryptoUpcallsClass_rsaDecryptMethod,
- privateKey, padding, ciphertextArray.get()));
+ env->CallStaticObjectMethod(conscrypt::jniutil::cryptoUpcallsClass,
+ conscrypt::jniutil::cryptoUpcallsClass_rsaDecryptMethod,
+ privateKey, padding, ciphertextArray.get()));
}
// *********************************************
@@ -6739,7 +6736,7 @@
JNI_TRACE("ssl=%p info_callback calling onSSLStateChange", ssl);
env->CallVoidMethod(sslHandshakeCallbacks,
- conscrypt::jniutil::sslHandshakeCallbacks_onSSLStateChange, type, value);
+ conscrypt::jniutil::sslHandshakeCallbacks_onSSLStateChange, type, value);
if (env->ExceptionCheck()) {
JNI_TRACE("ssl=%p info_callback exception", ssl);
@@ -10320,50 +10317,6 @@
return FIPS_mode();
}
-/**
- * Scrypt support
- */
-
-static jbyteArray NativeCrypto_Scrypt_generate_key(JNIEnv* env, jclass, jbyteArray password, jbyteArray salt,
- jint n, jint r, jint p, jint key_len) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("Scrypt_generate_key(%p, %p, %d, %d, %d, %d)", password, salt, n, r, p, key_len);
-
- if (password == nullptr) {
- conscrypt::jniutil::throwNullPointerException(env, "password == null");
- JNI_TRACE("Scrypt_generate_key() => password == null");
- return nullptr;
- }
- if (salt == nullptr) {
- conscrypt::jniutil::throwNullPointerException(env, "salt == null");
- JNI_TRACE("Scrypt_generate_key() => salt == null");
- return nullptr;
- }
-
- jbyteArray key_bytes = env->NewByteArray(static_cast<jsize>(key_len));
- ScopedByteArrayRW out_key(env, key_bytes);
- if (out_key.get() == nullptr) {
- conscrypt::jniutil::throwNullPointerException(env, "out_key == null");
- JNI_TRACE("Scrypt_generate_key() => out_key == null");
- return nullptr;
- }
-
- size_t memory_limit = 1u << 29;
- ScopedByteArrayRO password_bytes(env, password);
- ScopedByteArrayRO salt_bytes(env, salt);
-
- int result = EVP_PBE_scrypt(reinterpret_cast<const char*>(password_bytes.get()), password_bytes.size(),
- reinterpret_cast<const uint8_t*>(salt_bytes.get()), salt_bytes.size(),
- n, r, p, memory_limit,
- reinterpret_cast<uint8_t*>(out_key.get()), key_len);
-
- if (result <= 0) {
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "Scrypt_generate_key");
- return nullptr;
- }
- return key_bytes;
-}
-
// TESTING METHODS BEGIN
static int NativeCrypto_BIO_read(JNIEnv* env, jclass, jlong bioRef, jbyteArray outputJavaBytes) {
@@ -10825,7 +10778,6 @@
CONSCRYPT_NATIVE_METHOD(ENGINE_SSL_force_read, "(J" REF_SSL SSL_CALLBACKS ")V"),
CONSCRYPT_NATIVE_METHOD(ENGINE_SSL_shutdown, "(J" REF_SSL SSL_CALLBACKS ")V"),
CONSCRYPT_NATIVE_METHOD(usesBoringSsl_FIPS_mode, "()Z"),
- CONSCRYPT_NATIVE_METHOD(Scrypt_generate_key, "([B[BIIII)[B"),
// Used for testing only.
CONSCRYPT_NATIVE_METHOD(BIO_read, "(J[B)I"),
diff --git a/common/src/main/java/org/conscrypt/BufferUtils.java b/common/src/main/java/org/conscrypt/BufferUtils.java
index eb0806b..e42506d 100644
--- a/common/src/main/java/org/conscrypt/BufferUtils.java
+++ b/common/src/main/java/org/conscrypt/BufferUtils.java
@@ -21,13 +21,18 @@
import java.nio.ByteBuffer;
-final class BufferUtils {
+/**
+ * Utility methods for dealing with arrays of ByteBuffers.
+ *
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class BufferUtils {
private BufferUtils() {}
/**
* Throws {@link IllegalArgumentException} if any of the buffers in the array are null.
*/
- static void checkNotNull(ByteBuffer[] buffers) {
+ public static void checkNotNull(ByteBuffer[] buffers) {
for (ByteBuffer buffer : buffers) {
if (buffer == null) {
throw new IllegalArgumentException("Null buffer in array");
@@ -38,7 +43,7 @@
/**
* Returns the total number of bytes remaining in the buffer array.
*/
- static long remaining(ByteBuffer[] buffers) {
+ public static long remaining(ByteBuffer[] buffers) {
long size = 0;
for (ByteBuffer buffer : buffers) {
size += buffer.remaining();
@@ -51,7 +56,7 @@
*
* @throws IllegalArgumentException if there are fewer than {@code toConsume} bytes remaining
*/
- static void consume(ByteBuffer[] sourceBuffers, int toConsume) {
+ public static void consume(ByteBuffer[] sourceBuffers, int toConsume) {
for (ByteBuffer sourceBuffer : sourceBuffers) {
int amount = min(sourceBuffer.remaining(), toConsume);
if (amount > 0) {
@@ -71,7 +76,7 @@
* Looks for a buffer in the buffer array which EITHER is larger than {@code minSize} AND
* has no preceding non-empty buffers OR is the only non-empty buffer in the array.
*/
- static ByteBuffer getBufferLargerThan(ByteBuffer[] buffers, int minSize) {
+ public static ByteBuffer getBufferLargerThan(ByteBuffer[] buffers, int minSize) {
int length = buffers.length;
for (int i = 0; i < length; i++) {
ByteBuffer buffer = buffers[i];
@@ -99,11 +104,11 @@
* {@code consume()} method.
*
*/
- static ByteBuffer copyNoConsume(ByteBuffer[] buffers, ByteBuffer destination, int maxAmount) {
- checkArgument(destination.remaining() >= maxAmount, "Destination buffer too small");
- int needed = maxAmount;
+ public static ByteBuffer copyNoConsume(ByteBuffer[] buffers, ByteBuffer destination, int maxAmount) {
+ checkArgument(destination.remaining() >= maxAmount, "Destination buffer too small");
+ int needed = maxAmount;
for (ByteBuffer buffer : buffers) {
- int remaining = buffer.remaining();
+ int remaining = buffer.remaining();
if (remaining > 0) {
// If this buffer can fit completely then copy it all, otherwise temporarily
// adjust its limit to fill so as to the output buffer completely
diff --git a/common/src/main/java/org/conscrypt/ConscryptEngineSocket.java b/common/src/main/java/org/conscrypt/ConscryptEngineSocket.java
index f05fe25..8b23ea6 100644
--- a/common/src/main/java/org/conscrypt/ConscryptEngineSocket.java
+++ b/common/src/main/java/org/conscrypt/ConscryptEngineSocket.java
@@ -516,6 +516,7 @@
// Close the engine.
engine.closeInbound();
engine.closeOutbound();
+
// Closing the outbound direction of a connected engine will trigger a TLS close
// notify, which we should try and send.
// If we don't, then closeOutbound won't be able to free resources because there are
diff --git a/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java b/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java
index 1392963..be0ec97 100644
--- a/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java
+++ b/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java
@@ -45,7 +45,7 @@
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
import javax.security.auth.x500.X500Principal;
-
+import org.conscrypt.ExternalSession.Provider;
import org.conscrypt.NativeRef.SSL_SESSION;
/**
diff --git a/common/src/main/java/org/conscrypt/NativeCrypto.java b/common/src/main/java/org/conscrypt/NativeCrypto.java
index 7395f2d..84de32f 100644
--- a/common/src/main/java/org/conscrypt/NativeCrypto.java
+++ b/common/src/main/java/org/conscrypt/NativeCrypto.java
@@ -1447,11 +1447,6 @@
throws IOException;
/**
- * Generates a key from a password and salt using Scrypt.
- */
- static native byte[] Scrypt_generate_key(byte[] password, byte[] salt, int n, int r, int p, int key_len);
-
- /**
* Return {@code true} if BoringSSL has been built in FIPS mode.
*/
static native boolean usesBoringSsl_FIPS_mode();
diff --git a/common/src/main/java/org/conscrypt/OpenSSLContextImpl.java b/common/src/main/java/org/conscrypt/OpenSSLContextImpl.java
index 2f53217..a70e5a9 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLContextImpl.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLContextImpl.java
@@ -66,6 +66,12 @@
serverSessionContext = new ServerSessionContext();
}
+ // BEGIN Android-added: Restore missing constructor that is used by apps
+ private OpenSSLContextImpl() throws GeneralSecurityException, IOException {
+ this(NativeCrypto.TLSV13_PROTOCOLS, true);
+ }
+ // END Android-added: Restore missing constructor that is used by apps
+
/**
* Constuctor for the DefaultSSLContextImpl. The unused boolean parameter is solely to
* indicate that this constructor is desired.
diff --git a/common/src/main/java/org/conscrypt/OpenSSLMac.java b/common/src/main/java/org/conscrypt/OpenSSLMac.java
index c216c4c..8091226 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLMac.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLMac.java
@@ -80,11 +80,7 @@
throw new InvalidKeyException("key cannot be encoded");
}
- try {
- resetContext();
- } catch (RuntimeException e) {
- throw new InvalidKeyException("invalid key", e);
- }
+ resetContext();
}
@Override
diff --git a/common/src/main/java/org/conscrypt/OpenSSLProvider.java b/common/src/main/java/org/conscrypt/OpenSSLProvider.java
index 138f388..5ca5e09 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLProvider.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLProvider.java
@@ -215,9 +215,6 @@
/* == SecretKeyFactory == */
put("SecretKeyFactory.DESEDE", PREFIX + "DESEDESecretKeyFactory");
put("Alg.Alias.SecretKeyFactory.TDEA", "DESEDE");
- put("SecretKeyFactory.SCRYPT", PREFIX + "ScryptSecretKeyFactory");
- put("Alg.Alias.SecretKeyFactory.1.3.6.1.4.1.11591.4.11", "SCRYPT");
- put("Alg.Alias.SecretKeyFactory.OID.1.3.6.1.4.1.11591.4.11", "SCRYPT");
/* == KeyAgreement == */
putECDHKeyAgreementImplClass("OpenSSLECDHKeyAgreement");
diff --git a/common/src/main/java/org/conscrypt/ScryptKeySpec.java b/common/src/main/java/org/conscrypt/ScryptKeySpec.java
deleted file mode 100644
index 809459f..0000000
--- a/common/src/main/java/org/conscrypt/ScryptKeySpec.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-
-package org.conscrypt;
-
-import java.security.spec.KeySpec;
-
-/**
- * Mirrors the <a
- * href="https://javadoc.io/static/org.bouncycastle/bcprov-jdk15on/1.68/org/bouncycastle/jcajce/spec/ScryptKeySpec.html">class
- * of the same name</a> from BouncyCastle.
- */
-public class ScryptKeySpec implements KeySpec {
- private final char[] password;
- private final byte[] salt;
- private final int costParameter;
- private final int blockSize;
- private final int parallelizationParameter;
- private final int keyOutputBits;
-
- public ScryptKeySpec(
- char[] password,
- byte[] salt,
- int costParameter,
- int blockSize,
- int parallelizationParameter,
- int keyOutputBits) {
- this.password = password;
- this.salt = salt;
- this.costParameter = costParameter;
- this.blockSize = blockSize;
- this.parallelizationParameter = parallelizationParameter;
- this.keyOutputBits = keyOutputBits;
- }
-
- public char[] getPassword() {
- return password;
- }
-
- public byte[] getSalt() {
- return salt;
- }
-
- public int getCostParameter() {
- return costParameter;
- }
-
- public int getBlockSize() {
- return blockSize;
- }
-
- public int getParallelizationParameter() {
- return parallelizationParameter;
- }
-
- public int getKeyLength() {
- return keyOutputBits;
- }
-}
diff --git a/common/src/main/java/org/conscrypt/ScryptSecretKeyFactory.java b/common/src/main/java/org/conscrypt/ScryptSecretKeyFactory.java
deleted file mode 100644
index a58cfee..0000000
--- a/common/src/main/java/org/conscrypt/ScryptSecretKeyFactory.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-
-package org.conscrypt;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.nio.charset.StandardCharsets;
-import java.security.InvalidKeyException;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactorySpi;
-
-@Internal
-public class ScryptSecretKeyFactory extends SecretKeyFactorySpi {
-
- @Override
- protected SecretKey engineGenerateSecret(KeySpec inKeySpec) throws InvalidKeySpecException {
-
- char[] password;
- byte[] salt;
- int n, r, p, keyOutputBits;
-
- if (inKeySpec instanceof ScryptKeySpec) {
- ScryptKeySpec spec = (ScryptKeySpec) inKeySpec;
- password = spec.getPassword();
- salt = spec.getSalt();
- n = spec.getCostParameter();
- r = spec.getBlockSize();
- p = spec.getParallelizationParameter();
- keyOutputBits = spec.getKeyLength();
- } else {
- // Extract parameters from any `KeySpec` that has getters with the correct name. This
- // allows, for example, code to use BouncyCastle's KeySpec with the Conscrypt provider.
- try {
- password = (char[]) getValue(inKeySpec, "getPassword");
- salt = (byte[]) getValue(inKeySpec, "getSalt");
- n = (int) getValue(inKeySpec, "getCostParameter");
- r = (int) getValue(inKeySpec, "getBlockSize");
- p = (int) getValue(inKeySpec, "getParallelizationParameter");
- keyOutputBits = (int) getValue(inKeySpec, "getKeyLength");
- } catch (Exception e) {
- throw new InvalidKeySpecException("Not a valid scrypt KeySpec", e);
- }
- }
-
- if (keyOutputBits % 8 != 0) {
- throw new InvalidKeySpecException("Cannot produce fractional-byte outputs");
- }
-
- return new ScryptKey(
- NativeCrypto.Scrypt_generate_key(
- new String(password).getBytes(StandardCharsets.UTF_8),
- salt, n, r, p, keyOutputBits / 8));
- }
-
- private Object getValue(KeySpec spec, String methodName)
- throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
- Method method = spec.getClass().getMethod(methodName, (Class<?>[]) null);
- return method.invoke(spec);
- }
-
- @Override
- protected KeySpec engineGetKeySpec(
- SecretKey secretKey, @SuppressWarnings("rawtypes") Class aClass)
- throws InvalidKeySpecException {
- if (secretKey == null) {
- throw new InvalidKeySpecException("Null KeySpec");
- }
- throw new NotImplementedException();
- }
-
- @Override
- protected SecretKey engineTranslateKey(SecretKey secretKey) throws InvalidKeyException {
- if (secretKey == null) {
- throw new InvalidKeyException("Null SecretKey");
- }
- throw new NotImplementedException();
- }
-
- private static class ScryptKey implements SecretKey {
- private static final long serialVersionUID = 2024924811854189128L;
- private final byte[] key;
-
- public ScryptKey(byte[] key) {
- this.key = key;
- }
-
- @Override
- public String getAlgorithm() {
- // Capitalised because BouncyCastle does it.
- return "SCRYPT";
- }
-
- @Override
- public String getFormat() {
- return "RAW";
- }
-
- @Override
- public byte[] getEncoded() {
- return key;
- }
- }
-
- private static class NotImplementedException extends RuntimeException {
- private static final long serialVersionUID = -7755435858585859108L;
-
- NotImplementedException() {
- super("Not implemented");
- }
- }
-}
diff --git a/common/src/test/java/org/conscrypt/ConscryptSuite.java b/common/src/test/java/org/conscrypt/ConscryptSuite.java
index da5bf43..214be41 100644
--- a/common/src/test/java/org/conscrypt/ConscryptSuite.java
+++ b/common/src/test/java/org/conscrypt/ConscryptSuite.java
@@ -51,7 +51,6 @@
import org.conscrypt.javax.crypto.CipherTest;
import org.conscrypt.javax.crypto.ECDHKeyAgreementTest;
import org.conscrypt.javax.crypto.KeyGeneratorTest;
-import org.conscrypt.javax.crypto.ScryptTest;
import org.conscrypt.javax.crypto.XDHKeyAgreementTest;
import org.conscrypt.javax.net.ssl.HttpsURLConnectionTest;
import org.conscrypt.javax.net.ssl.KeyManagerFactoryTest;
@@ -131,7 +130,6 @@
KeyStoreBuilderParametersTest.class,
OptionalMethodTest.class,
ProtocolTest.class,
- ScryptTest.class,
SNIHostNameTest.class,
SSLContextTest.class,
SSLEngineTest.class,
diff --git a/common/src/test/java/org/conscrypt/HostnameVerifierTest.java b/common/src/test/java/org/conscrypt/HostnameVerifierTest.java
index a369ecd..253ca34 100644
--- a/common/src/test/java/org/conscrypt/HostnameVerifierTest.java
+++ b/common/src/test/java/org/conscrypt/HostnameVerifierTest.java
@@ -617,7 +617,8 @@
}
// END Android-added: Verify behaviour with top level wildcard SAN. http://b/144694112
- @Test public void verifyAsIpAddress() {
+ // Android-changed: OkHostnameVerifier.verifyAsIpAddress not accessible on platform builds
+ @Test @Ignore public void verifyAsIpAddress() {
// IPv4
assertTrue(OkHostnameVerifier.verifyAsIpAddress("127.0.0.1"));
assertTrue(OkHostnameVerifier.verifyAsIpAddress("1.2.3.4"));
@@ -651,4 +652,4 @@
private SSLSession session(String certificate) throws Exception {
return new FakeSSLSession(certificate(certificate));
}
-}
\ No newline at end of file
+}
diff --git a/common/src/test/java/org/conscrypt/MacTest.java b/common/src/test/java/org/conscrypt/MacTest.java
index d10c225..a80065a 100644
--- a/common/src/test/java/org/conscrypt/MacTest.java
+++ b/common/src/test/java/org/conscrypt/MacTest.java
@@ -22,7 +22,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
import java.io.IOException;
@@ -165,7 +164,7 @@
}
@Test
- public void invalidKeyTypeThrows() {
+ public void invalidKeyThrows() {
newMacServiceTester()
// BC actually accepts RSA public keys for these algorithms for some reason.
.skipCombination("BC", "PBEWITHHMACSHA")
@@ -189,16 +188,6 @@
}
@Test
- public void invalidCmacKeySizeThrows() throws Exception {
- // TODO(prb): extend to other Macs, deal with inconsistencies between providers.
- Mac mac = Mac.getInstance("AESCMAC", conscryptProvider);
- byte[] keyBytes = new byte[1];
- SecretKeySpec key = new SecretKeySpec(keyBytes, "RawBytes");
-
- assertThrows(InvalidKeyException.class, () -> mac.init(key));
- }
-
- @Test
public void uninitializedMacThrows() {
newMacServiceTester()
.run(new ServiceTester.Test() {
diff --git a/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestAES.java b/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestAES.java
index 49b9d23..fe3c229 100644
--- a/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestAES.java
+++ b/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestAES.java
@@ -21,8 +21,11 @@
import java.security.AlgorithmParameters;
import java.security.Provider;
import javax.crypto.spec.IvParameterSpec;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
import org.conscrypt.TestUtils;
+import org.junit.ClassRule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import tests.util.ServiceTester;
@@ -30,6 +33,14 @@
@RunWith(JUnit4.class)
public class AlgorithmParametersTestAES extends AbstractAlgorithmParametersTest {
+ // BEGIN Android-added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work. See http://b/141919026 for more information.
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
private static final byte[] parameterData = new byte[] {
(byte) 0x04, (byte) 0x08, (byte) 0x68, (byte) 0xC8,
(byte) 0xFF, (byte) 0x64, (byte) 0x72, (byte) 0xF5,
diff --git a/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestDESede.java b/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestDESede.java
index a0e8581..d4e4781 100644
--- a/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestDESede.java
+++ b/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestDESede.java
@@ -21,8 +21,11 @@
import java.security.AlgorithmParameters;
import java.security.Provider;
import javax.crypto.spec.IvParameterSpec;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
import org.conscrypt.TestUtils;
+import org.junit.ClassRule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import tests.util.ServiceTester;
@@ -30,6 +33,14 @@
@RunWith(JUnit4.class)
public class AlgorithmParametersTestDESede extends AbstractAlgorithmParametersTest {
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
private static final byte[] parameterData = new byte[] {
(byte) 0x04, (byte) 0x08, (byte) 0x68, (byte) 0xC8,
(byte) 0xFF, (byte) 0x64, (byte) 0x72, (byte) 0xF5 };
diff --git a/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestEC.java b/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestEC.java
index 4c22fdd..ea615dd 100644
--- a/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestEC.java
+++ b/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestEC.java
@@ -24,8 +24,11 @@
import java.security.spec.InvalidParameterSpecException;
import java.util.Arrays;
import java.util.List;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
import org.conscrypt.TestUtils;
+import org.junit.ClassRule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import tests.util.ServiceTester;
@@ -33,6 +36,14 @@
@RunWith(JUnit4.class)
public class AlgorithmParametersTestEC extends AbstractAlgorithmParametersTest {
+ // BEGIN Android-added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work. See http://b/141919026 for more information.
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
private static final String CURVE_NAME = "secp384r1";
private static final String CURVE_OID = "1.3.132.0.34";
diff --git a/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestGCM.java b/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestGCM.java
index 1c435d3..9fe913a 100644
--- a/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestGCM.java
+++ b/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestGCM.java
@@ -22,8 +22,11 @@
import java.security.AlgorithmParameters;
import java.security.Provider;
import javax.crypto.spec.GCMParameterSpec;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
import org.conscrypt.TestUtils;
+import org.junit.ClassRule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import tests.util.ServiceTester;
@@ -31,6 +34,14 @@
@RunWith(JUnit4.class)
public class AlgorithmParametersTestGCM extends AbstractAlgorithmParametersTest {
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
private static final byte[] IV = new byte[] {
(byte) 0x04, (byte) 0x08, (byte) 0x68, (byte) 0xC8,
(byte) 0xFF, (byte) 0x64, (byte) 0x72, (byte) 0xF5,
diff --git a/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestOAEP.java b/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestOAEP.java
index fb97173..acb40e2 100644
--- a/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestOAEP.java
+++ b/common/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestOAEP.java
@@ -24,8 +24,11 @@
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import javax.crypto.spec.PSource.PSpecified;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
import org.conscrypt.TestUtils;
+import org.junit.ClassRule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import tests.util.ServiceTester;
@@ -33,6 +36,14 @@
@RunWith(JUnit4.class)
public class AlgorithmParametersTestOAEP extends AbstractAlgorithmParametersTest {
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
// The ASN.1 encoding for OAEP params (specified in RFC 4055 section 4.1) specifies
// default values for all parameters, so we need to consider encodings with those
// values both explicitly specified and unspecified. When encoding values, it is required
diff --git a/common/src/test/java/org/conscrypt/java/security/KeyFactoryTestEC.java b/common/src/test/java/org/conscrypt/java/security/KeyFactoryTestEC.java
index ee8fd51..938629e 100644
--- a/common/src/test/java/org/conscrypt/java/security/KeyFactoryTestEC.java
+++ b/common/src/test/java/org/conscrypt/java/security/KeyFactoryTestEC.java
@@ -21,16 +21,26 @@
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.ECPublicKeySpec;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.List;
+import org.junit.ClassRule;
+import org.junit.rules.TestRule;
+import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import tests.util.ServiceTester;
@RunWith(JUnit4.class)
-public class KeyFactoryTestEC extends
- AbstractKeyFactoryTest<ECPublicKeySpec, ECPrivateKeySpec> {
+public class KeyFactoryTestEC extends AbstractKeyFactoryTest<ECPublicKeySpec, ECPrivateKeySpec> {
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
public KeyFactoryTestEC() {
super("EC", ECPublicKeySpec.class, ECPrivateKeySpec.class);
diff --git a/common/src/test/java/org/conscrypt/java/security/KeyFactoryTestRSA.java b/common/src/test/java/org/conscrypt/java/security/KeyFactoryTestRSA.java
index d96fe54..571c1a7 100644
--- a/common/src/test/java/org/conscrypt/java/security/KeyFactoryTestRSA.java
+++ b/common/src/test/java/org/conscrypt/java/security/KeyFactoryTestRSA.java
@@ -38,15 +38,25 @@
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
import java.util.Arrays;
import java.util.List;
+import org.junit.ClassRule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class KeyFactoryTestRSA extends
AbstractKeyFactoryTest<RSAPublicKeySpec, RSAPrivateKeySpec> {
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
public KeyFactoryTestRSA() {
super("RSA", RSAPublicKeySpec.class, RSAPrivateKeySpec.class);
diff --git a/common/src/test/java/org/conscrypt/java/security/KeyPairGeneratorTest.java b/common/src/test/java/org/conscrypt/java/security/KeyPairGeneratorTest.java
index 3ef73a2..67721da 100644
--- a/common/src/test/java/org/conscrypt/java/security/KeyPairGeneratorTest.java
+++ b/common/src/test/java/org/conscrypt/java/security/KeyPairGeneratorTest.java
@@ -53,8 +53,11 @@
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
import org.conscrypt.TestUtils;
+import org.junit.ClassRule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import tests.util.ServiceTester;
@@ -62,6 +65,14 @@
@RunWith(JUnit4.class)
public class KeyPairGeneratorTest {
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
@Test
public void test_getInstance() throws Exception {
ServiceTester.test("KeyPairGenerator")
diff --git a/common/src/test/java/org/conscrypt/java/security/MessageDigestTest.java b/common/src/test/java/org/conscrypt/java/security/MessageDigestTest.java
index 599b3f4..c711dc1 100644
--- a/common/src/test/java/org/conscrypt/java/security/MessageDigestTest.java
+++ b/common/src/test/java/org/conscrypt/java/security/MessageDigestTest.java
@@ -24,8 +24,11 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
import org.conscrypt.TestUtils;
+import org.junit.ClassRule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import tests.util.ServiceTester;
@@ -33,6 +36,14 @@
@RunWith(JUnit4.class)
public final class MessageDigestTest {
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
private final byte[] sha_456 = {
-24, 9, -59, -47, -50, -92, 123, 69, -29, 71,
1, -46, 63, 96, -118, -102, 88, 3, 77, -55
diff --git a/common/src/test/java/org/conscrypt/java/security/SignatureTest.java b/common/src/test/java/org/conscrypt/java/security/SignatureTest.java
index 389ae92..bba0863 100644
--- a/common/src/test/java/org/conscrypt/java/security/SignatureTest.java
+++ b/common/src/test/java/org/conscrypt/java/security/SignatureTest.java
@@ -68,11 +68,14 @@
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
import org.conscrypt.Conscrypt;
import org.conscrypt.TestUtils;
import org.conscrypt.testing.BrokenProvider;
import org.conscrypt.testing.OpaqueProvider;
+import org.junit.ClassRule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import tests.util.ServiceTester;
@@ -80,6 +83,14 @@
@RunWith(JUnit4.class)
public class SignatureTest {
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
// 20 bytes for DSA
private final byte[] EMPTY_DATA = new byte[20];
diff --git a/common/src/test/java/org/conscrypt/java/security/cert/CertificateFactoryTest.java b/common/src/test/java/org/conscrypt/java/security/cert/CertificateFactoryTest.java
index ffdf4f0..b5da74a 100644
--- a/common/src/test/java/org/conscrypt/java/security/cert/CertificateFactoryTest.java
+++ b/common/src/test/java/org/conscrypt/java/security/cert/CertificateFactoryTest.java
@@ -57,6 +57,7 @@
import java.util.List;
import java.util.TimeZone;
import javax.security.auth.x500.X500Principal;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
@@ -65,7 +66,9 @@
import org.conscrypt.Conscrypt;
import org.conscrypt.TestUtils;
import org.conscrypt.java.security.StandardNames;
+import org.junit.ClassRule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import tests.util.ServiceTester;
@@ -73,6 +76,14 @@
@RunWith(JUnit4.class)
public class CertificateFactoryTest {
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
private static final String VALID_CERTIFICATE_PEM =
"-----BEGIN CERTIFICATE-----\n"
+ "MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BAQUFADBM\n"
diff --git a/common/src/test/java/org/conscrypt/java/security/cert/X509CRLTest.java b/common/src/test/java/org/conscrypt/java/security/cert/X509CRLTest.java
index 2653446..50b1688 100644
--- a/common/src/test/java/org/conscrypt/java/security/cert/X509CRLTest.java
+++ b/common/src/test/java/org/conscrypt/java/security/cert/X509CRLTest.java
@@ -33,8 +33,11 @@
import java.security.cert.X509CRLEntry;
import java.security.cert.X509Certificate;
import java.util.Collections;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
import org.conscrypt.TestUtils;
+import org.junit.ClassRule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import tests.util.ServiceTester;
@@ -42,6 +45,14 @@
@RunWith(JUnit4.class)
public class X509CRLTest {
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
private static final String CA_CERT =
"-----BEGIN CERTIFICATE-----\n"
+ "MIIC0DCCAjmgAwIBAgIBADANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJHQjEk\n"
diff --git a/common/src/test/java/org/conscrypt/java/security/cert/X509CertificateTest.java b/common/src/test/java/org/conscrypt/java/security/cert/X509CertificateTest.java
index 26217b0..581e866 100644
--- a/common/src/test/java/org/conscrypt/java/security/cert/X509CertificateTest.java
+++ b/common/src/test/java/org/conscrypt/java/security/cert/X509CertificateTest.java
@@ -33,6 +33,7 @@
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateParsingException;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
@@ -45,7 +46,9 @@
import java.util.TimeZone;
import javax.security.auth.x500.X500Principal;
import org.conscrypt.TestUtils;
+import org.junit.ClassRule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import tests.util.Pair;
@@ -54,6 +57,14 @@
@RunWith(JUnit4.class)
public class X509CertificateTest {
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
private static final String VALID_CERT =
"-----BEGIN CERTIFICATE-----\n"
+ "MIIFMjCCAxqgAwIBAgIJAL0mG5fOeJ7xMA0GCSqGSIb3DQEBCwUAMC0xCzAJBgNV\n"
diff --git a/common/src/test/java/org/conscrypt/javax/crypto/CipherTest.java b/common/src/test/java/org/conscrypt/javax/crypto/CipherTest.java
index 38c0140..082b854 100644
--- a/common/src/test/java/org/conscrypt/javax/crypto/CipherTest.java
+++ b/common/src/test/java/org/conscrypt/javax/crypto/CipherTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -69,6 +70,7 @@
import javax.crypto.spec.PBEParameterSpec;
import javax.crypto.spec.PSource;
import javax.crypto.spec.SecretKeySpec;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.conscrypt.Conscrypt;
import org.conscrypt.TestUtils;
@@ -76,13 +78,23 @@
import org.conscrypt.java.security.TestKeyStore;
import org.junit.Assume;
import org.junit.BeforeClass;
+import org.junit.ClassRule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public final class CipherTest {
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
@BeforeClass
public static void setUp() {
TestUtils.assumeAllowsUnsignedCrypto();
@@ -4650,11 +4662,7 @@
* http://b/27994930
* Check that a PBKDF2WITHHMACSHA1 secret key factory works well with a
* PBEWITHSHAAND128BITAES-CBC-BC cipher. The former is PKCS5 and the latter is PKCS12, and so
- * mixing them is not recommended. However, until 1.52 BouncyCastle was accepting this mixture,
- * assuming the IV was a 0 vector. Some apps still use this functionality. This
- * compatibility is likely to be removed in later versions of Android.
- * TODO(27995180): consider whether we keep this compatibility. Consider whether we only allow
- * if an IV is passed in the parameters.
+ * mixing them is not recommended.
*/
@Test
public void test_PBKDF2WITHHMACSHA1_SKFactory_and_PBEAESCBC_Cipher_noIV() throws Exception {
@@ -4674,12 +4682,8 @@
Cipher cipher =
Cipher.getInstance("PBEWITHSHAAND128BITAES-CBC-BC");
PBEParameterSpec paramSpec = new PBEParameterSpec("salt".getBytes(TestUtils.UTF_8), 100);
- cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec);
- assertEquals(Arrays.toString(ciphertext), Arrays.toString(cipher.doFinal(plaintext)));
-
- secretKey = skf.generateSecret(pbeks);
- cipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec);
- assertEquals(Arrays.toString(plaintext), Arrays.toString(cipher.doFinal(ciphertext)));
+ assertThrows(InvalidAlgorithmParameterException.class,
+ () -> cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec));
}
/**
diff --git a/common/src/test/java/org/conscrypt/javax/crypto/ECDHKeyAgreementTest.java b/common/src/test/java/org/conscrypt/javax/crypto/ECDHKeyAgreementTest.java
index 94ddbc5..6464ba9 100644
--- a/common/src/test/java/org/conscrypt/javax/crypto/ECDHKeyAgreementTest.java
+++ b/common/src/test/java/org/conscrypt/javax/crypto/ECDHKeyAgreementTest.java
@@ -50,10 +50,13 @@
import javax.crypto.SecretKey;
import javax.crypto.ShortBufferException;
import junit.framework.AssertionFailedError;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
import org.conscrypt.Conscrypt;
import org.conscrypt.TestUtils;
import org.junit.BeforeClass;
+import org.junit.ClassRule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -63,6 +66,14 @@
@RunWith(JUnit4.class)
public class ECDHKeyAgreementTest {
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
// Two key pairs and the resulting shared secret for the Known Answer Test
private static final byte[] KAT_PUBLIC_KEY1_X509 = TestUtils.decodeHex(
"3059301306072a8648ce3d020106082a8648ce3d030107034200049fc2f71f85446b1371244491d83"
@@ -452,6 +463,19 @@
if (providers == null) {
return new Provider[0];
}
+
+ // Do not test AndroidKeyStore as KeyAgreement provider. It only handles Android
+ // Keystore-backed keys. It's OKish not to test AndroidKeyStore here because it's tested by
+ // cts/tests/test/keystore.
+ List<Provider> filteredProvidersList = new ArrayList<Provider>(providers.length);
+ for (Provider provider : providers) {
+ if ("AndroidKeyStore".equals(provider.getName())) {
+ continue;
+ }
+ filteredProvidersList.add(provider);
+ }
+ providers = filteredProvidersList.toArray(new Provider[filteredProvidersList.size()]);
+
// Sort providers by name to guarantee deterministic order in which providers are used in
// the tests.
return sortByName(providers);
diff --git a/common/src/test/java/org/conscrypt/javax/crypto/KeyGeneratorTest.java b/common/src/test/java/org/conscrypt/javax/crypto/KeyGeneratorTest.java
index 4ebafb7..1f25e21 100644
--- a/common/src/test/java/org/conscrypt/javax/crypto/KeyGeneratorTest.java
+++ b/common/src/test/java/org/conscrypt/javax/crypto/KeyGeneratorTest.java
@@ -27,10 +27,13 @@
import java.util.Map;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
import org.conscrypt.TestUtils;
import org.conscrypt.java.security.StandardNames;
import org.junit.BeforeClass;
+import org.junit.ClassRule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import tests.util.ServiceTester;
@@ -38,6 +41,14 @@
@RunWith(JUnit4.class)
public class KeyGeneratorTest {
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
private static boolean isUnsupported(KeyGenerator kg) {
// Don't bother testing "Sun..." KeyGenerators or BC outside of Android
return kg.getProvider().getName().startsWith("Sun")
diff --git a/common/src/test/java/org/conscrypt/javax/crypto/ScryptTest.java b/common/src/test/java/org/conscrypt/javax/crypto/ScryptTest.java
deleted file mode 100644
index 133306c..0000000
--- a/common/src/test/java/org/conscrypt/javax/crypto/ScryptTest.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-
-package org.conscrypt.javax.crypto;
-
-import static org.conscrypt.TestUtils.decodeHex;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.security.spec.KeySpec;
-import java.util.List;
-import javax.crypto.Cipher;
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.SecretKeySpec;
-import org.conscrypt.ScryptKeySpec;
-import org.conscrypt.TestUtils;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public final class ScryptTest {
- @Parameters(name = "{0}")
- public static String[] params() {
- return new String[] {
- "SCRYPT",
- "1.3.6.1.4.1.11591.4.11",
- "OID.1.3.6.1.4.1.11591.4.11"
- };
- }
-
- @Parameter
- public String alias;
-
- // One of the test vectors from RFC 7914
- private static final char[] TEST_PASSWORD = "password".toCharArray();
- private static final byte[] TEST_SALT = "NaCl".getBytes(StandardCharsets.UTF_8);
- private static final int TEST_COST = 1024;
- private static final int TEST_BLOCKSIZE = 8;
- private static final int TEST_PARALLELIZATION = 16;
- private static final int TEST_KEY_SIZE = 512;
- private static final byte[] TEST_KEY = decodeHex(
- "fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b373162"
- + "2eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640");
-
-
- private final List<String[]> testVectors = readTestVectors();
-
- // Column indices in test vector CSV file
- private static final int PASSWORD_INDEX = 0;
- private static final int SALT_INDEX = 1;
- private static final int N_INDEX = 2;
- private static final int R_INDEX = 3;
- private static final int P_INDEX = 4;
- private static final int KEY_INDEX = 5;
-
- @BeforeClass
- public static void setUp() {
- TestUtils.assumeAllowsUnsignedCrypto();
- }
-
- @Test
- public void smokeTest() throws Exception {
- SecretKeyFactory factory = SecretKeyFactory.getInstance(alias);
- assertEquals(alias, factory.getAlgorithm());
-
- ScryptKeySpec spec = new ScryptKeySpec(TEST_PASSWORD, TEST_SALT,
- TEST_COST, TEST_BLOCKSIZE, TEST_PARALLELIZATION, TEST_KEY_SIZE);
- SecretKey key = factory.generateSecret(spec);
- assertArrayEquals(TEST_KEY, key.getEncoded());
-
- // Convert for use with AES
- SecretKeySpec aesKey = makeAesKeySpec(key);
-
- // Make sure we can actually use the result
- checkKeyIsUsableWithAes(aesKey);
- }
-
- @Test
- public void duckTypingTest() throws Exception {
- SecretKeyFactory factory = SecretKeyFactory.getInstance(alias);
-
- KeySpec spec = new MyPrivateKeySpec(TEST_PASSWORD, TEST_SALT,
- TEST_COST, TEST_BLOCKSIZE, TEST_PARALLELIZATION, TEST_KEY_SIZE);
-
- SecretKey key = factory.generateSecret(spec);
- assertArrayEquals(TEST_KEY, key.getEncoded());
- }
-
- private SecretKeySpec makeAesKeySpec(SecretKey key) {
- assertEquals("RAW", key.getFormat());
- byte[] bytes = key.getEncoded();
- // Truncate to first 32 bytes if necessary
- int len = Math.min(32, bytes.length);
- return new SecretKeySpec(bytes, 0, len, "AES");
- }
-
- private void checkKeyIsUsableWithAes(SecretKeySpec spec) throws Exception {
- // Terrible encryption mode but saves messing with IVs which don't matter here.
- Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
-
- cipher.init(Cipher.ENCRYPT_MODE, spec);
- byte[] input = "The quick brown fox jumps over the lazy dog".getBytes(StandardCharsets.UTF_8);
- byte[] encrypted = cipher.doFinal(input);
- assertNotEquals(encrypted[0], input[0]);
-
- cipher.init(Cipher.DECRYPT_MODE, spec);
- byte[] decrypted = cipher.doFinal(encrypted);
- assertArrayEquals(input, decrypted);
- }
-
- @Test
- public void knownAnswerTest() throws Exception {
- for (String[] entry : testVectors) {
- char[] password = entry[PASSWORD_INDEX].toCharArray();
- byte[] salt = entry[SALT_INDEX].getBytes(StandardCharsets.UTF_8);
- int n = Integer.parseInt(entry[N_INDEX]);
- int r = Integer.parseInt(entry[R_INDEX]);
- int p = Integer.parseInt(entry[P_INDEX]);
- byte[] expectedBytes = decodeHex(entry[KEY_INDEX]);
-
- ScryptKeySpec spec = new ScryptKeySpec(password, salt, n, r, p, expectedBytes.length * 8);
- SecretKeyFactory factory = SecretKeyFactory.getInstance(alias);
- SecretKey key = factory.generateSecret(spec);
- assertNotNull(key);
- assertArrayEquals(expectedBytes, key.getEncoded());
- }
- }
-
- private List<String[]> readTestVectors() {
- try {
- return TestUtils.readCsvResource("crypto/scrypt.csv");
-
- } catch (IOException e) {
- throw new AssertionError("Unable to load Scrypt test vectors", e);
- }
- }
-
- public static class MyPrivateKeySpec implements KeySpec {
- private final char[] password;
- private final byte[] salt;
- private final int n;
- private final int r;
- private final int p;
- private final int keyOutputBits;
-
- public MyPrivateKeySpec(char[] password, byte[] salt, int n, int r, int p, int keyOutputBits) {
- this.password = password;
- this.salt = salt;
- this.n = n;
- this.r = r;
- this.p = p;
- this.keyOutputBits = keyOutputBits;
- }
-
- public char[] getPassword() {
- return password;
- }
-
- public byte[] getSalt() {
- return salt;
- }
-
- public int getCostParameter() {
- return n;
- }
-
- public int getBlockSize() {
- return r;
- }
-
- public int getParallelizationParameter() {
- return p;
- }
-
- public int getKeyLength() {
- return keyOutputBits;
- }
- }
-}
diff --git a/common/src/test/java/org/conscrypt/javax/crypto/XDHKeyAgreementTest.java b/common/src/test/java/org/conscrypt/javax/crypto/XDHKeyAgreementTest.java
index 4cd0843..9f64315 100644
--- a/common/src/test/java/org/conscrypt/javax/crypto/XDHKeyAgreementTest.java
+++ b/common/src/test/java/org/conscrypt/javax/crypto/XDHKeyAgreementTest.java
@@ -85,6 +85,10 @@
@Test
public void test_XDHKeyAgreement() throws Exception {
for (Provider p : Security.getProviders("KeyAgreement.XDH")) {
+ // Skip testing Android Keystore as it's covered by CTS tests.
+ if ("AndroidKeyStore".equals(p.getName())) {
+ continue;
+ }
setupKeys(p);
KeyAgreement ka = KeyAgreement.getInstance("XDH", p);
diff --git a/common/src/test/java/org/conscrypt/javax/net/ssl/SSLEngineTest.java b/common/src/test/java/org/conscrypt/javax/net/ssl/SSLEngineTest.java
index c496489..bb81f3c 100644
--- a/common/src/test/java/org/conscrypt/javax/net/ssl/SSLEngineTest.java
+++ b/common/src/test/java/org/conscrypt/javax/net/ssl/SSLEngineTest.java
@@ -585,10 +585,6 @@
// By the point of the handshake where we're validating certificates,
// the hostname is known and the cipher suite should be agreed
assertEquals(referenceContext.host.getHostName(), session.getPeerHost());
-
- // The negotiated cipher suite should be one of the enabled ones, but
- // BoringSSL may have reordered them based on things like hardware support,
- // so we don't know which one may have been negotiated.
String sessionSuite = session.getCipherSuite();
List<String> enabledSuites =
Arrays.asList(referenceEngine.getEnabledCipherSuites());
diff --git a/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java b/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java
index c457660..ba84285 100644
--- a/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java
+++ b/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java
@@ -485,10 +485,6 @@
// By the point of the handshake where we're validating certificates,
// the hostname is known and the cipher suite should be agreed
assertEquals(referenceContext.host.getHostName(), session.getPeerHost());
-
- // The negotiated cipher suite should be one of the enabled ones, but
- // BoringSSL may have reordered them based on things like hardware support,
- // so we don't know which one may have been negotiated.
String sessionSuite = session.getCipherSuite();
List<String> enabledSuites =
Arrays.asList(referenceClientSocket.getEnabledCipherSuites());
diff --git a/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java b/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java
index 5ce4d5f..707cbab 100644
--- a/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java
+++ b/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java
@@ -1606,6 +1606,8 @@
underlying, c.host.getHostName(), c.port, true);
final byte[] data = new byte[1024 * 64];
+ // TODO(b/161347005): Re-enable once engine-based socket interruption works correctly.
+ assumeFalse(isConscryptEngineSocket(wrapping));
Future<Void> clientFuture = runAsync(new Callable<Void>() {
@Override
public Void call() throws Exception {
diff --git a/common/src/test/resources/crypto/scrypt.csv b/common/src/test/resources/crypto/scrypt.csv
deleted file mode 100644
index 88bdfb8..0000000
--- a/common/src/test/resources/crypto/scrypt.csv
+++ /dev/null
@@ -1,8 +0,0 @@
-# Scrypt test vectors from RFC 7914
-# Data is in the format:
-# password,salt,n,r,p,key
-,,16,1,1,77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906
-password,NaCl,1024,8,16,fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640
-pleaseletmein,SodiumChloride,16384,8,1,7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887
-# Following vector exceeds memory limits with defaults
-# pleaseletmein,SodiumChloride,1048576,8,1,2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049e8a952fbcbf45c6fa77a41a4
diff --git a/constants/src/gen/cpp/generate_constants.cc b/constants/src/gen/cpp/generate_constants.cc
index 60fe93d..515202d 100644
--- a/constants/src/gen/cpp/generate_constants.cc
+++ b/constants/src/gen/cpp/generate_constants.cc
@@ -41,10 +41,16 @@
" * See the License for the specific language governing permissions and\n"
" * limitations under the License. */\n";
-int main(int /* argc */, char ** /* argv */) {
+int main(int argc, char **argv) {
+ const char *package;
+ if (argc == 1) {
+ package = "org.conscrypt";
+ } else {
+ package = argv[1];
+ }
printf("%s\n", kCopyright);
printf("/* This file was generated by generate_constants.cc. */\n\n");
- printf("package org.conscrypt;\n\n");
+ printf("package %s;\n\n", package);
printf("final class NativeConstants {\n");
#define CONST(x) \
diff --git a/lint-baseline.xml b/lint-baseline.xml
new file mode 100644
index 0000000..70db717
--- /dev/null
+++ b/lint-baseline.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
+
+ <issue
+ id="NewApi"
+ message="Call requires API level R (current min is 29): `android.system.ErrnoException#rethrowAsSocketException`"
+ errorLine1=" throw errnoException.rethrowAsSocketException();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="external/conscrypt/repackaged/platform/src/main/java/com/android/org/conscrypt/Platform.java"
+ line="134"
+ column="34"/>
+ </issue>
+
+</issues>
diff --git a/openjdk/src/test/java/org/conscrypt/OpenSSLServerSocketImplTest.java b/openjdk/src/test/java/org/conscrypt/OpenSSLServerSocketImplTest.java
new file mode 100644
index 0000000..1618e8a
--- /dev/null
+++ b/openjdk/src/test/java/org/conscrypt/OpenSSLServerSocketImplTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2017 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.
+ */
+
+package org.conscrypt;
+
+import static org.conscrypt.TestUtils.LOCALHOST;
+import static org.conscrypt.TestUtils.getConscryptServerSocketFactory;
+import static org.conscrypt.TestUtils.getJdkSocketFactory;
+import static org.conscrypt.TestUtils.getProtocols;
+import static org.conscrypt.TestUtils.newTextMessage;
+import static org.conscrypt.TestUtils.pickUnusedPort;
+import static org.junit.Assert.assertArrayEquals;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class OpenSSLServerSocketImplTest {
+ private static final String CIPHER = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256";
+ private static final int MESSAGE_SIZE = 4096;
+
+ /**
+ * Various factories for SSL server sockets.
+ */
+ public enum SocketType {
+ DEFAULT(getConscryptServerSocketFactory(false)),
+ ENGINE(getConscryptServerSocketFactory(true));
+
+ @SuppressWarnings("ImmutableEnumChecker")
+ private final SSLServerSocketFactory serverSocketFactory;
+
+ SocketType(SSLServerSocketFactory serverSocketFactory) {
+ this.serverSocketFactory = serverSocketFactory;
+ }
+
+ final SSLServerSocket newServerSocket(String cipher) {
+ try {
+ int port = pickUnusedPort();
+ SSLServerSocket sslSocket =
+ (SSLServerSocket) serverSocketFactory.createServerSocket(port);
+ sslSocket.setEnabledProtocols(getProtocols());
+ sslSocket.setEnabledCipherSuites(new String[] {cipher});
+ return sslSocket;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ @Parameters(name = "{0}")
+ public static Iterable<SocketType> data() {
+ // Android-changed: Temporarily (2017 Q2) disable ENGINE tests. http://b/37271061#comment9
+ // This experimental (unused by default) implementation is unstable and causing test
+ // failures on Android.
+ // return Arrays.asList(SocketType.DEFAULT, SocketType.ENGINE);
+ return Arrays.asList(SocketType.DEFAULT);
+ }
+
+ @Parameter public SocketType socketType;
+
+ private TestClient client;
+ private TestServer server;
+
+ @Before
+ public void setup() throws Exception {
+ // Create and start the server.
+ server = new TestServer(socketType.newServerSocket(CIPHER), MESSAGE_SIZE);
+ Future<?> connectedFuture = server.start();
+
+ // Create and start the client.
+ SSLSocketFactory socketFactory = getJdkSocketFactory();
+ SSLSocket socket = (SSLSocket) socketFactory.createSocket(LOCALHOST, server.port());
+ socket.setEnabledProtocols(getProtocols());
+ socket.setEnabledCipherSuites(new String[] {CIPHER});
+ client = new TestClient(socket);
+ client.start();
+
+ // Wait for the initial connection to complete.
+ connectedFuture.get(5, TimeUnit.SECONDS);
+ }
+
+ @After
+ public void teardown() throws Exception {
+ client.stop();
+ server.stop();
+ }
+
+ @Test
+ public void pingPong() throws IOException {
+ byte[] request = newTextMessage(MESSAGE_SIZE);
+ byte[] responseBuffer = new byte[MESSAGE_SIZE];
+ client.sendMessage(request);
+ client.flush();
+ int numBytes = client.readMessage(responseBuffer);
+ byte[] response = Arrays.copyOfRange(responseBuffer, 0, numBytes);
+ assertArrayEquals(request, response);
+ }
+}
diff --git a/platform/src/main/java/org/conscrypt/TrustedCertificateStore.java b/platform/src/main/java/org/conscrypt/TrustedCertificateStore.java
index 333450d..5eef4f5 100644
--- a/platform/src/main/java/org/conscrypt/TrustedCertificateStore.java
+++ b/platform/src/main/java/org/conscrypt/TrustedCertificateStore.java
@@ -81,8 +81,7 @@
*/
@Internal
public class TrustedCertificateStore implements ConscryptCertStore {
-
- private static final String PREFIX_SYSTEM = "system:";
+ private static String PREFIX_SYSTEM = "system:";
private static final String PREFIX_USER = "user:";
public static final boolean isSystem(String alias) {
@@ -100,7 +99,15 @@
static {
String ANDROID_ROOT = System.getenv("ANDROID_ROOT");
String ANDROID_DATA = System.getenv("ANDROID_DATA");
- defaultCaCertsSystemDir = new File(ANDROID_ROOT + "/etc/security/cacerts");
+ File updatableDir = new File("/apex/com.android.conscrypt/cacerts");
+ if ((System.getProperty("system.certs.enabled") != null)
+ && (System.getProperty("system.certs.enabled")).equals("true")) {
+ defaultCaCertsSystemDir = new File(ANDROID_ROOT + "/etc/security/cacerts");
+ } else if (updatableDir.exists() && !(updatableDir.list().length == 0)) {
+ defaultCaCertsSystemDir = updatableDir;
+ } else {
+ defaultCaCertsSystemDir = new File(ANDROID_ROOT + "/etc/security/cacerts");
+ }
setDefaultUserDirectory(new File(ANDROID_DATA + "/misc/keychain"));
}
}
@@ -128,6 +135,10 @@
PreloadHolder.defaultCaCertsDeletedDir);
}
+ public TrustedCertificateStore(File baseDir) {
+ this(baseDir, PreloadHolder.defaultCaCertsAddedDir, PreloadHolder.defaultCaCertsDeletedDir);
+ }
+
public TrustedCertificateStore(File systemDir, File addedDir, File deletedDir) {
this.systemDir = systemDir;
this.addedDir = addedDir;
@@ -229,7 +240,7 @@
}
long time = file.lastModified();
if (time == 0) {
- return null;
+ time = 1672531200L; // Jan 1st, 2023
}
return new Date(time);
}
diff --git a/platform/src/test/java/org/conscrypt/TrustedCertificateStoreTest.java b/platform/src/test/java/org/conscrypt/TrustedCertificateStoreTest.java
index d2095a3..5e5d0d8 100644
--- a/platform/src/test/java/org/conscrypt/TrustedCertificateStoreTest.java
+++ b/platform/src/test/java/org/conscrypt/TrustedCertificateStoreTest.java
@@ -24,6 +24,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.security.KeyStore;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.KeyStore.TrustedCertificateEntry;
@@ -46,16 +48,23 @@
import javax.security.auth.x500.X500Principal;
import junit.framework.TestCase;
import org.conscrypt.java.security.TestKeyStore;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
@SuppressWarnings("unused")
+@RunWith(Parameterized.class)
public class TrustedCertificateStoreTest extends TestCase {
private static final Random tempFileRandom = new Random();
- private final File dirTest = new File(System.getProperty("java.io.tmpdir", "."),
- "cert-store-test" + tempFileRandom.nextInt());
- private final File dirSystem = new File(dirTest, "system");
- private final File dirAdded = new File(dirTest, "added");
- private final File dirDeleted = new File(dirTest, "removed");
+ private static File dirTest;
+ private static File dirSystem;
+ private static File dirAdded;
+ private static File dirDeleted;
private static X509Certificate CA1;
private static X509Certificate CA2;
@@ -390,9 +399,22 @@
}
}
+ @Parameters(name = "{0}")
+ public static Object[] data() {
+ return new Object[] {"true", "false"};
+ }
+
+ @Parameter public String mApexCertsEnabled;
+
private TrustedCertificateStore store;
- @Override protected void setUp() {
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ dirTest = Files.createTempDirectory("cert-store-test").toFile();
+ dirSystem = new File(dirTest, "system");
+ dirAdded = new File(dirTest, "added");
+ dirDeleted = new File(dirTest, "removed");
setupStore();
}
@@ -403,10 +425,13 @@
}
private void createStore() {
+ System.setProperty("system.certs.enabled", mApexCertsEnabled);
store = new TrustedCertificateStore(dirSystem, dirAdded, dirDeleted);
}
- @Override protected void tearDown() {
+ @After
+ @Override
+ public void tearDown() {
cleanStore();
}
@@ -428,10 +453,12 @@
setupStore();
}
+ @Test
public void testEmptyDirectories() throws Exception {
assertEmpty();
}
+ @Test
public void testOneSystemOneDeleted() throws Exception {
install(getCa1(), getAliasSystemCa1());
store.deleteCertificateEntry(getAliasSystemCa1());
@@ -439,6 +466,7 @@
assertDeleted(getCa1(), getAliasSystemCa1());
}
+ @Test
public void testTwoSystemTwoDeleted() throws Exception {
install(getCa1(), getAliasSystemCa1());
store.deleteCertificateEntry(getAliasSystemCa1());
@@ -449,6 +477,7 @@
assertDeleted(getCa2(), getAliasSystemCa2());
}
+ @Test
public void testPartialFileIsIgnored() throws Exception {
File file = file(getAliasSystemCa1());
file.getParentFile().mkdirs();
@@ -521,26 +550,31 @@
assertTrue(userFiles == null || userFiles.length == 0);
}
+ @Test
public void testTwoSystem() throws Exception {
testTwo(getCa1(), getAliasSystemCa1(),
getCa2(), getAliasSystemCa2());
}
+ @Test
public void testTwoUser() throws Exception {
testTwo(getCa1(), getAliasUserCa1(),
getCa2(), getAliasUserCa2());
}
+ @Test
public void testOneSystemOneUser() throws Exception {
testTwo(getCa1(), getAliasSystemCa1(),
getCa2(), getAliasUserCa2());
}
+ @Test
public void testTwoSystemSameSubject() throws Exception {
testTwo(getCa1(), getAliasSystemCa1(),
getCa3WithCa1Subject(), getAliasSystemCa3Collision());
}
+ @Test
public void testTwoUserSameSubject() throws Exception {
testTwo(getCa1(), getAliasUserCa1(),
getCa3WithCa1Subject(), getAliasUserCa3Collision());
@@ -558,6 +592,7 @@
assertEmpty();
}
+ @Test
public void testOneSystemOneUserSameSubject() throws Exception {
testTwo(getCa1(), getAliasSystemCa1(),
getCa3WithCa1Subject(), getAliasUserCa3());
@@ -574,7 +609,7 @@
assertAliases(alias1, alias2);
}
-
+ @Test
public void testOneSystemOneUserOneDeleted() throws Exception {
install(getCa1(), getAliasSystemCa1());
store.installCertificate(getCa2());
@@ -584,6 +619,7 @@
assertAliases(getAliasUserCa2());
}
+ @Test
public void testOneSystemOneUserOneDeletedSameSubject() throws Exception {
install(getCa1(), getAliasSystemCa1());
store.installCertificate(getCa3WithCa1Subject());
@@ -593,6 +629,7 @@
assertAliases(getAliasUserCa3());
}
+ @Test
public void testUserMaskingSystem() throws Exception {
install(getCa1(), getAliasSystemCa1());
install(getCa1(), getAliasUserCa1());
@@ -601,6 +638,7 @@
assertAliases(getAliasSystemCa1(), getAliasUserCa1());
}
+ @Test
public void testChain() throws Exception {
testChain(getAliasSystemChain1(), getAliasSystemChain2());
testChain(getAliasSystemChain1(), getAliasUserChain2());
@@ -628,12 +666,14 @@
resetStore();
}
+ @Test
public void testMissingSystemDirectory() throws Exception {
cleanStore();
createStore();
assertEmpty();
}
+ @Test
public void testWithExistingUserDirectories() throws Exception {
dirAdded.mkdirs();
dirDeleted.mkdirs();
@@ -642,6 +682,7 @@
assertAliases(getAliasSystemCa1());
}
+ @Test
public void testIsTrustAnchorWithReissuedgetCa() throws Exception {
PublicKey publicKey = getPrivate().getCertificate().getPublicKey();
PrivateKey privateKey = getPrivate().getPrivateKey();
@@ -666,6 +707,7 @@
resetStore();
}
+ @Test
public void testInstallEmpty() throws Exception {
store.installCertificate(getCa1());
assertRootCa(getCa1(), getAliasUserCa1());
@@ -677,6 +719,7 @@
assertAliases(getAliasUserCa1());
}
+ @Test
public void testInstallEmptySystemExists() throws Exception {
install(getCa1(), getAliasSystemCa1());
assertRootCa(getCa1(), getAliasSystemCa1());
@@ -686,9 +729,9 @@
store.installCertificate(getCa1());
assertRootCa(getCa1(), getAliasSystemCa1());
assertAliases(getAliasSystemCa1());
-
}
+ @Test
public void testInstallEmptyDeletedSystemExists() throws Exception {
install(getCa1(), getAliasSystemCa1());
store.deleteCertificateEntry(getAliasSystemCa1());
@@ -701,12 +744,14 @@
assertAliases(getAliasSystemCa1());
}
+ @Test
public void testDeleteEmpty() throws Exception {
store.deleteCertificateEntry(getAliasSystemCa1());
assertEmpty();
assertDeleted(getCa1(), getAliasSystemCa1());
}
+ @Test
public void testDeleteUser() throws Exception {
store.installCertificate(getCa1());
assertRootCa(getCa1(), getAliasUserCa1());
@@ -718,6 +763,7 @@
assertNoTombstone(getAliasUserCa1());
}
+ @Test
public void testDeleteSystem() throws Exception {
install(getCa1(), getAliasSystemCa1());
assertRootCa(getCa1(), getAliasSystemCa1());
@@ -733,6 +779,7 @@
assertDeleted(getCa1(), getAliasSystemCa1());
}
+ @Test
public void testGetLoopedCert() throws Exception {
install(getCertLoopEe(), getAliasCertLoopEe());
install(getCertLoopCa1(), getAliasCertLoopCa1());
@@ -760,6 +807,7 @@
assertEquals(getCertLoopCa2(), certs.get(2));
}
+ @Test
public void testIsUserAddedCertificate() throws Exception {
assertFalse(store.isUserAddedCertificate(getCa1()));
assertFalse(store.isUserAddedCertificate(getCa2()));
@@ -780,13 +828,25 @@
assertFalse(store.isUserAddedCertificate(getCa2()));
}
+ @Test
public void testSystemCaCertsUseCorrectFileNames() throws Exception {
- TrustedCertificateStore store = new TrustedCertificateStore();
+ File dir = new File(System.getenv("ANDROID_ROOT") + "/etc/security/cacerts");
+ useCorrectFileNamesTest(dir);
+ }
+
+ @Test
+ public void testSystemCaCertsUseCorrectFileNamesUpdatable() throws Exception {
+ File dir = new File("/apex/com.android.conscrypt/cacerts");
+ useCorrectFileNamesTest(dir);
+ }
+
+ private void useCorrectFileNamesTest(File dir) throws Exception {
+ TrustedCertificateStore store = new TrustedCertificateStore(dir.getAbsoluteFile());
// Assert that all the certificates in the system cacerts directory are stored in files with
// expected names.
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
- File dir = new File(System.getenv("ANDROID_ROOT") + "/etc/security/cacerts");
+ assertTrue(dir.exists());
int systemCertFileCount = 0;
for (File actualFile : listFilesNoNull(dir)) {
if (!actualFile.isFile()) {
@@ -797,19 +857,20 @@
new ByteArrayInputStream(readFully(actualFile)));
File expectedFile = store.getCertificateFile(dir, cert);
- assertEquals("System certificate stored in the wrong file",
+ assertEquals("Updatable certificate stored in the wrong file",
expectedFile.getAbsolutePath(), actualFile.getAbsolutePath());
// The two statements below indirectly assert that the certificate can be looked up
// from a file (hopefully the same one as the expectedFile above). As opposed to
- // getCertifiacteFile above, these are the actual methods used when verifying chain of
+ // getCertificateFile above, these are the actual methods used when verifying chain of
// trust. Thus, we assert that they work as expected for all system certificates.
- assertNotNull("Issuer certificate not found for system certificate " + actualFile,
+ assertNotNull("Issuer certificate not found for updatable certificate " + actualFile,
store.findIssuer(cert));
- assertNotNull("Trust anchor not found for system certificate " + actualFile,
+ assertNotNull("Trust anchor not found for updatable certificate " + actualFile,
store.getTrustAnchor(cert));
}
+ assertTrue(systemCertFileCount > 0);
// Assert that all files corresponding to all system certs/aliases known to the store are
// present.
int systemCertAliasCount = 0;
@@ -833,6 +894,7 @@
systemCertFileCount, systemCertAliasCount);
}
+ @Test
public void testMultipleIssuers() throws Exception {
Set<X509Certificate> result;
install(getMultipleIssuersCa1(), getAliasMultipleIssuersCa1());
diff --git a/platform/src/test/java/org/conscrypt/metrics/MetricsTest.java b/platform/src/test/java/org/conscrypt/metrics/MetricsTest.java
index 56b45e9..6212fbd 100644
--- a/platform/src/test/java/org/conscrypt/metrics/MetricsTest.java
+++ b/platform/src/test/java/org/conscrypt/metrics/MetricsTest.java
@@ -20,17 +20,18 @@
import android.util.StatsEvent;
import org.conscrypt.TestUtils;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-
@RunWith(JUnit4.class)
public class MetricsTest {
public static final int TLS_HANDSHAKE_REPORTED = 317;
// Tests that ReflexiveEvent produces the same event as framework's.
@Test
+ @Ignore // Ignore on CTS 12 only: b/259508875
public void test_reflexiveEvent() throws Exception {
TestUtils.assumeStatsLogAvailable();
diff --git a/publicapi/src/main/java/android/net/ssl/SSLEngines.java b/publicapi/src/main/java/android/net/ssl/SSLEngines.java
new file mode 100644
index 0000000..e5967db
--- /dev/null
+++ b/publicapi/src/main/java/android/net/ssl/SSLEngines.java
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+package android.net.ssl;
+
+import com.android.org.conscrypt.Conscrypt;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLException;
+import libcore.util.NonNull;
+import libcore.util.Nullable;
+
+/**
+ * Static utility methods for accessing additional functionality of supported instances of
+ * {@link SSLEngine}. Engines from the platform TLS provider will be compatible with all
+ * methods in this class.
+ */
+public class SSLEngines {
+ private SSLEngines() {}
+
+ /**
+ * Returns whether the given engine can be used with the methods in this class. In general,
+ * only engines from the platform TLS provider are supported.
+ */
+ public static boolean isSupportedEngine(@NonNull SSLEngine engine) {
+ return Conscrypt.isConscrypt(engine);
+ }
+
+ private static void checkSupported(@NonNull SSLEngine e) {
+ if (!isSupportedEngine(e)) {
+ throw new IllegalArgumentException("Engine is not a supported engine.");
+ }
+ }
+
+ /**
+ * Enables or disables the use of session tickets.
+ *
+ * <p>This function must be called before the handshake is started or it will have no effect.
+ *
+ * @param engine the engine
+ * @param useSessionTickets whether to enable or disable the use of session tickets
+ * @throws IllegalArgumentException if the given engine is not a platform engine
+ */
+ public static void setUseSessionTickets(@NonNull SSLEngine engine, boolean useSessionTickets) {
+ checkSupported(engine);
+ Conscrypt.setUseSessionTickets(engine, useSessionTickets);
+ }
+
+ /**
+ * Exports a value derived from the TLS master secret as described in RFC 5705.
+ *
+ * A number of protocols leverage Transport Layer Security (TLS) to perform key
+ * establishment but then use some of the keying material for their own purposes.
+ *
+ * This method allows an application to export keying material from a TLS connection.
+ * The exported material will be the same on the client and server if they pass in
+ * the same values for {@code label} and {@code context}. See RFC 5705 for further
+ * details.
+ *
+ * @param engine the engine to use for exporting keying material
+ * @param label the label to use in calculating the exported value. This must be
+ * an ASCII-only string.
+ * @param context the application-specific context value to use in calculating the
+ * exported value. This may be {@code null} to use no application context, which is
+ * treated differently than an empty byte array.
+ * @param length the number of bytes of keying material to return.
+ * @return a value of the specified length, or {@code null} if the handshake has not yet
+ * completed or the connection has been closed.
+ * @throws SSLException if the value could not be exported.
+ */
+ @Nullable
+ public static byte[] exportKeyingMaterial(@NonNull SSLEngine engine, @NonNull String label,
+ @Nullable byte[] context, int length) throws SSLException {
+ checkSupported(engine);
+ return Conscrypt.exportKeyingMaterial(engine, label, context, length);
+ }
+}
diff --git a/publicapi/src/main/java/android/net/ssl/SSLSockets.java b/publicapi/src/main/java/android/net/ssl/SSLSockets.java
new file mode 100644
index 0000000..0c04428
--- /dev/null
+++ b/publicapi/src/main/java/android/net/ssl/SSLSockets.java
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+package android.net.ssl;
+
+import com.android.org.conscrypt.Conscrypt;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSocket;
+import libcore.util.NonNull;
+import libcore.util.Nullable;
+
+/**
+ * Static utility methods for accessing additional functionality of supported instances of
+ * {@link SSLSocket}. Sockets from the platform TLS provider will be compatible with all
+ * methods in this class.
+ */
+public class SSLSockets {
+ private SSLSockets() {}
+
+ /**
+ * Returns whether the given socket can be used with the methods in this class. In general,
+ * only sockets from the platform TLS provider are supported.
+ */
+ public static boolean isSupportedSocket(@NonNull SSLSocket socket) {
+ return Conscrypt.isConscrypt(socket);
+ }
+
+ private static void checkSupported(@NonNull SSLSocket s) {
+ if (!isSupportedSocket(s)) {
+ throw new IllegalArgumentException("Socket is not a supported socket.");
+ }
+ }
+
+ /**
+ * Enables or disables the use of session tickets.
+ *
+ * <p>This function must be called before the handshake is started or it will have no effect.
+ *
+ * @param socket the socket
+ * @param useSessionTickets whether to enable or disable the use of session tickets
+ * @throws IllegalArgumentException if the given socket is not a platform socket
+ */
+ public static void setUseSessionTickets(@NonNull SSLSocket socket, boolean useSessionTickets) {
+ checkSupported(socket);
+ Conscrypt.setUseSessionTickets(socket, useSessionTickets);
+ }
+
+ /**
+ * Exports a value derived from the TLS master secret as described in RFC 5705.
+ *
+ * A number of protocols leverage Transport Layer Security (TLS) to perform key
+ * establishment but then use some of the keying material for their own purposes.
+ *
+ * This method allows an application to export keying material from a TLS connection.
+ * The exported material will be the same on the client and server if they pass in
+ * the same values for {@code label} and {@code context}. See RFC 5705 for further
+ * details.
+ *
+ * @param socket the socket to use for exporting keying material
+ * @param label the label to use in calculating the exported value. This must be
+ * an ASCII-only string.
+ * @param context the application-specific context value to use in calculating the
+ * exported value. This may be {@code null} to use no application context, which is
+ * treated differently than an empty byte array.
+ * @param length the number of bytes of keying material to return.
+ * @return a value of the specified length, or {@code null} if the handshake has not yet
+ * completed or the connection has been closed.
+ * @throws SSLException if the value could not be exported.
+ */
+ @Nullable
+ public static byte[] exportKeyingMaterial(@NonNull SSLSocket socket, @NonNull String label,
+ @Nullable byte[] context, int length) throws SSLException {
+ checkSupported(socket);
+ return Conscrypt.exportKeyingMaterial(socket, label, context, length);
+ }
+}
diff --git a/publicapi/src/main/java/android/net/ssl/TEST_MAPPING b/publicapi/src/main/java/android/net/ssl/TEST_MAPPING
new file mode 100644
index 0000000..996e0e7
--- /dev/null
+++ b/publicapi/src/main/java/android/net/ssl/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsLibcoreTestCases",
+ "options": [
+ {
+ "include-filter": "android.net.ssl"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/publicapi/src/test/java/android/net/ssl/SSLEnginesTest.java b/publicapi/src/test/java/android/net/ssl/SSLEnginesTest.java
new file mode 100644
index 0000000..e4285f7
--- /dev/null
+++ b/publicapi/src/test/java/android/net/ssl/SSLEnginesTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+package android.net.ssl;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.android.org.conscrypt.javax.net.ssl.TestSSLContext;
+import com.android.org.conscrypt.javax.net.ssl.TestSSLEnginePair;
+import com.android.org.conscrypt.tlswire.TlsTester;
+import com.android.org.conscrypt.tlswire.handshake.ClientHello;
+import com.android.org.conscrypt.tlswire.handshake.HelloExtension;
+import java.nio.ByteBuffer;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLSession;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class SSLEnginesTest {
+
+ private static class BrokenSSLEngine extends SSLEngine {
+ @Override public SSLEngineResult wrap(ByteBuffer[] byteBuffers, int i, int i1,
+ ByteBuffer byteBuffer) { throw new AssertionError(); }
+ @Override public SSLEngineResult unwrap(ByteBuffer byteBuffer, ByteBuffer[] byteBuffers,
+ int i, int i1) { throw new AssertionError(); }
+ @Override public Runnable getDelegatedTask() { throw new AssertionError(); }
+ @Override public void closeInbound() { throw new AssertionError(); }
+ @Override public boolean isInboundDone() { throw new AssertionError(); }
+ @Override public void closeOutbound() { throw new AssertionError(); }
+ @Override public boolean isOutboundDone() { throw new AssertionError(); }
+ @Override public String[] getSupportedCipherSuites() { throw new AssertionError(); }
+ @Override public String[] getEnabledCipherSuites() { throw new AssertionError(); }
+ @Override public void setEnabledCipherSuites(String[] strings) { throw new AssertionError(); }
+ @Override public String[] getSupportedProtocols() { throw new AssertionError(); }
+ @Override public String[] getEnabledProtocols() { throw new AssertionError(); }
+ @Override public void setEnabledProtocols(String[] strings) { throw new AssertionError(); }
+ @Override public SSLSession getSession() { throw new AssertionError(); }
+ @Override public void beginHandshake() { throw new AssertionError(); }
+ @Override public SSLEngineResult.HandshakeStatus getHandshakeStatus() { throw new AssertionError(); }
+ @Override public void setUseClientMode(boolean b) { throw new AssertionError(); }
+ @Override public boolean getUseClientMode() { throw new AssertionError(); }
+ @Override public void setNeedClientAuth(boolean b) { throw new AssertionError(); }
+ @Override public boolean getNeedClientAuth() { throw new AssertionError(); }
+ @Override public void setWantClientAuth(boolean b) { throw new AssertionError(); }
+ @Override public boolean getWantClientAuth() { throw new AssertionError(); }
+ @Override public void setEnableSessionCreation(boolean b) { throw new AssertionError(); }
+ @Override public boolean getEnableSessionCreation() { throw new AssertionError(); }
+ }
+
+ private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);
+
+ @Test
+ public void testIsSupported() throws Exception {
+ SSLEngine e = SSLContext.getDefault().createSSLEngine();
+ assertTrue(SSLEngines.isSupportedEngine(e));
+
+ e = new BrokenSSLEngine();
+ assertFalse(SSLEngines.isSupportedEngine(e));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void useSessionTickets_InvalidEngine() {
+ SSLEngines.setUseSessionTickets(new BrokenSSLEngine(), true);
+ }
+
+ @Test
+ public void useSessionTickets_ValidEngine() throws Exception {
+ SSLEngine e = SSLContext.getDefault().createSSLEngine();
+ e.setUseClientMode(true);
+ SSLEngines.setUseSessionTickets(e, true);
+
+ ClientHello hello = getClientHello(e);
+ assertNotNull(hello.findExtensionByType(HelloExtension.TYPE_SESSION_TICKET));
+
+ e = SSLContext.getDefault().createSSLEngine();
+ e.setUseClientMode(true);
+ SSLEngines.setUseSessionTickets(e, false);
+
+ hello = getClientHello(e);
+ assertNull(hello.findExtensionByType(HelloExtension.TYPE_SESSION_TICKET));
+ }
+
+ private static ClientHello getClientHello(SSLEngine e) throws Exception {
+ ByteBuffer out = ByteBuffer.allocate(64 * 1024);
+
+ e.wrap(EMPTY_BUFFER, out);
+ out.flip();
+ byte[] data = new byte[out.limit()];
+ out.get(data);
+
+ return TlsTester.parseClientHello(data);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void exportKeyingMaterial_InvalidEngine() throws Exception {
+ SSLEngines.exportKeyingMaterial(new BrokenSSLEngine(), "label", null, 20);
+ }
+
+ @Test
+ public void exportKeyingMaterial_ValidEngine() throws Exception {
+ String label = "Some label";
+ int keyLength = 32;
+
+ TestSSLEnginePair pair = TestSSLEnginePair.create(TestSSLContext.create());
+
+ byte[] clientEkm = SSLEngines.exportKeyingMaterial(pair.client, label, null, keyLength);
+ byte[] serverEkm = SSLEngines.exportKeyingMaterial(pair.server, label, null, keyLength);
+ assertNotNull(clientEkm);
+ assertNotNull(serverEkm);
+ assertEquals(keyLength, clientEkm.length);
+ assertEquals(keyLength, serverEkm.length);
+ assertArrayEquals(clientEkm, serverEkm);
+ }
+}
diff --git a/publicapi/src/test/java/android/net/ssl/SSLSocketsTest.java b/publicapi/src/test/java/android/net/ssl/SSLSocketsTest.java
new file mode 100644
index 0000000..78a42c5
--- /dev/null
+++ b/publicapi/src/test/java/android/net/ssl/SSLSocketsTest.java
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ */
+
+package android.net.ssl;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.android.org.conscrypt.javax.net.ssl.TestSSLSocketPair;
+import com.android.org.conscrypt.tlswire.TlsTester;
+import com.android.org.conscrypt.tlswire.handshake.ClientHello;
+import com.android.org.conscrypt.tlswire.handshake.HelloExtension;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.net.DelegatingSSLSocketFactory;
+
+@RunWith(JUnit4.class)
+public class SSLSocketsTest {
+
+ private static class BrokenSSLSocket extends SSLSocket {
+ @Override public String[] getSupportedCipherSuites() { throw new AssertionError(); }
+ @Override public String[] getEnabledCipherSuites() { throw new AssertionError(); }
+ @Override public void setEnabledCipherSuites(String[] strings) { throw new AssertionError(); }
+ @Override public String[] getSupportedProtocols() { throw new AssertionError(); }
+ @Override public String[] getEnabledProtocols() { throw new AssertionError(); }
+ @Override public void setEnabledProtocols(String[] strings) { throw new AssertionError(); }
+ @Override public SSLSession getSession() { throw new AssertionError(); }
+ @Override public void addHandshakeCompletedListener(
+ HandshakeCompletedListener handshakeCompletedListener) { throw new AssertionError(); }
+ @Override public void removeHandshakeCompletedListener(
+ HandshakeCompletedListener handshakeCompletedListener) { throw new AssertionError(); }
+ @Override public void startHandshake() { throw new AssertionError(); }
+ @Override public void setUseClientMode(boolean b) { throw new AssertionError(); }
+ @Override public boolean getUseClientMode() { throw new AssertionError(); }
+ @Override public void setNeedClientAuth(boolean b) { throw new AssertionError(); }
+ @Override public boolean getNeedClientAuth() { throw new AssertionError(); }
+ @Override public void setWantClientAuth(boolean b) { throw new AssertionError(); }
+ @Override public boolean getWantClientAuth() { throw new AssertionError(); }
+ @Override public void setEnableSessionCreation(boolean b) { throw new AssertionError(); }
+ @Override public boolean getEnableSessionCreation() { throw new AssertionError(); }
+ }
+
+ private ExecutorService executor;
+
+ @Before
+ public void setUp() {
+ executor = Executors.newCachedThreadPool();
+ }
+
+ @After
+ public void tearDown() throws InterruptedException {
+ executor.shutdown();
+ executor.awaitTermination(1, TimeUnit.SECONDS);
+ }
+
+ @Test
+ public void testIsSupported() throws Exception {
+ SSLSocket s = (SSLSocket) SSLSocketFactory.getDefault().createSocket();
+ assertTrue(SSLSockets.isSupportedSocket(s));
+
+ s = new BrokenSSLSocket();
+ assertFalse(SSLSockets.isSupportedSocket(s));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void setUseSessionTickets_InvalidSocket() {
+ SSLSockets.setUseSessionTickets(new BrokenSSLSocket(), true);
+ }
+
+ @Test
+ public void setUseSessionTickets_ValidSocket() throws Exception {
+ SSLSocket s = (SSLSocket) SSLSocketFactory.getDefault().createSocket();
+ SSLSockets.setUseSessionTickets(s, true);
+
+ ClientHello hello = TlsTester.captureTlsHandshakeClientHello(executor,
+ new DelegatingSSLSocketFactory((SSLSocketFactory) SSLSocketFactory.getDefault()) {
+ @Override public SSLSocket configureSocket(SSLSocket socket) {
+ SSLSockets.setUseSessionTickets(socket, true);
+ return socket;
+ }
+ });
+ assertNotNull(hello.findExtensionByType(HelloExtension.TYPE_SESSION_TICKET));
+
+ hello = TlsTester.captureTlsHandshakeClientHello(executor,
+ new DelegatingSSLSocketFactory((SSLSocketFactory) SSLSocketFactory.getDefault()) {
+ @Override public SSLSocket configureSocket(SSLSocket socket) {
+ SSLSockets.setUseSessionTickets(socket, false);
+ return socket;
+ }
+ });
+ assertNull(hello.findExtensionByType(HelloExtension.TYPE_SESSION_TICKET));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void exportKeyingMaterial_InvalidSocket() throws Exception {
+ SSLSockets.exportKeyingMaterial(new BrokenSSLSocket(), "label", null, 20);
+ }
+
+ @Test
+ public void exportKeyingMaterial_ValidSocket() throws Exception {
+ TestSSLSocketPair pair = TestSSLSocketPair.create();
+ String label = "Some label";
+ int keyLength = 32;
+
+ pair.connect();
+
+ byte[] clientEkm = SSLSockets.exportKeyingMaterial(pair.client, label, null, keyLength);
+ byte[] serverEkm = SSLSockets.exportKeyingMaterial(pair.server, label, null, keyLength);
+ assertNotNull(clientEkm);
+ assertNotNull(serverEkm);
+ assertEquals(keyLength, clientEkm.length);
+ assertEquals(keyLength, serverEkm.length);
+ assertArrayEquals(clientEkm, serverEkm);
+ }
+}
diff --git a/repackaged/benchmark-android/src/main/java/com/android/org/conscrypt/AndroidEndpointFactory.java b/repackaged/benchmark-android/src/main/java/com/android/org/conscrypt/AndroidEndpointFactory.java
new file mode 100644
index 0000000..321c908
--- /dev/null
+++ b/repackaged/benchmark-android/src/main/java/com/android/org/conscrypt/AndroidEndpointFactory.java
@@ -0,0 +1,65 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt;
+
+import java.io.IOException;
+import java.security.Provider;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * Utility for creating test client and server instances.
+ * @hide This class is not part of the Android public SDK API
+ */
+@SuppressWarnings("ImmutableEnumChecker")
+public enum AndroidEndpointFactory implements EndpointFactory {
+ @SuppressWarnings("unused")
+ CONSCRYPT(newConscryptFactories(false)),
+ CONSCRYPT_ENGINE(newConscryptFactories(true));
+
+ private final Factories factories;
+
+ AndroidEndpointFactory(Factories factories) {
+ this.factories = factories;
+ }
+
+ @Override
+ public ClientEndpoint newClient(ChannelType channelType, int port, String[] protocols,
+ String[] ciphers) throws IOException {
+ return new ClientEndpoint(
+ factories.clientFactory, channelType, port, protocols, ciphers);
+ }
+
+ @Override
+ public ServerEndpoint newServer(ChannelType channelType, int messageSize,
+ String[] protocols, String[] ciphers) throws IOException {
+ return new ServerEndpoint(factories.serverFactory, factories.serverSocketFactory,
+ channelType, messageSize, protocols, ciphers);
+ }
+
+ private static final class Factories {
+ final SSLSocketFactory clientFactory;
+ final SSLSocketFactory serverFactory;
+ final SSLServerSocketFactory serverSocketFactory;
+
+ private Factories(SSLSocketFactory clientFactory, SSLSocketFactory serverFactory,
+ SSLServerSocketFactory serverSocketFactory) {
+ this.clientFactory = clientFactory;
+ this.serverFactory = serverFactory;
+ this.serverSocketFactory = serverSocketFactory;
+ }
+ }
+
+ private static Factories newConscryptFactories(boolean useEngineSocket) {
+ Provider provider = TestUtils.getConscryptProvider();
+ SSLContext clientContext = TestUtils.newClientSslContext(provider);
+ SSLContext serverContext = TestUtils.newServerSslContext(provider);
+ final SSLSocketFactory clientFactory = clientContext.getSocketFactory();
+ final SSLSocketFactory serverFactory = serverContext.getSocketFactory();
+ final SSLServerSocketFactory serverSocketFactory = serverContext.getServerSocketFactory();
+ TestUtils.setUseEngineSocket(clientFactory, useEngineSocket);
+ TestUtils.setUseEngineSocket(serverFactory, useEngineSocket);
+ TestUtils.setUseEngineSocket(serverSocketFactory, useEngineSocket);
+ return new Factories(clientFactory, serverFactory, serverSocketFactory);
+ }
+}
diff --git a/repackaged/benchmark-android/src/main/java/com/android/org/conscrypt/AndroidEngineFactory.java b/repackaged/benchmark-android/src/main/java/com/android/org/conscrypt/AndroidEngineFactory.java
new file mode 100644
index 0000000..4978114
--- /dev/null
+++ b/repackaged/benchmark-android/src/main/java/com/android/org/conscrypt/AndroidEngineFactory.java
@@ -0,0 +1,103 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+package com.android.org.conscrypt;
+
+import java.security.Security;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+
+/**
+ * Enumeration of various types of engines for use with engine-based benchmarks.
+ * @hide This class is not part of the Android public SDK API
+ */
+@SuppressWarnings({"ImmutableEnumChecker", "unused"})
+public enum AndroidEngineFactory implements EngineFactory {
+ CONSCRYPT_UNPOOLED {
+ private final SSLContext clientContext = newConscryptClientContext();
+ private final SSLContext serverContext = newConscryptServerContext();
+
+ @Override
+ public SSLEngine newClientEngine(String cipher, boolean useAlpn) {
+ SSLEngine engine = initEngine(clientContext.createSSLEngine(), cipher, true);
+ if (useAlpn) {
+ Conscrypt.setApplicationProtocols(engine, new String[] {"h2"});
+ }
+ return engine;
+ }
+
+ @Override
+ public SSLEngine newServerEngine(String cipher, boolean useAlpn) {
+ SSLEngine engine = initEngine(serverContext.createSSLEngine(), cipher, false);
+ if (useAlpn) {
+ Conscrypt.setApplicationProtocols(engine, new String[] {"h2"});
+ }
+ return engine;
+ }
+
+ @Override
+ public void dispose(SSLEngine engine) {
+ engine.closeOutbound();
+ }
+ },
+ PLATFORM {
+ private final SSLContext clientContext =
+ TestUtils.newClientSslContext(Security.getProvider("AndroidOpenSSL"));
+ private final SSLContext serverContext =
+ TestUtils.newServerSslContext(Security.getProvider("AndroidOpenSSL"));
+
+ @Override
+ public SSLEngine newClientEngine(String cipher, boolean useAlpn) {
+ SSLEngine engine = initEngine(clientContext.createSSLEngine(), cipher, true);
+ if (useAlpn) {
+ Conscrypt.setApplicationProtocols(engine, new String[] {"h2"});
+ }
+ return engine;
+ }
+
+ @Override
+ public SSLEngine newServerEngine(String cipher, boolean useAlpn) {
+ SSLEngine engine = initEngine(serverContext.createSSLEngine(), cipher, false);
+ if (useAlpn) {
+ Conscrypt.setApplicationProtocols(engine, new String[] {"h2"});
+ }
+ return engine;
+ }
+
+ @Override
+ public void dispose(SSLEngine engine) {
+ engine.closeOutbound();
+ }
+ };
+
+ @Override
+ public void dispose(SSLEngine engine) {}
+
+ private static SSLContext newConscryptClientContext() {
+ return TestUtils.newClientSslContext(TestUtils.getConscryptProvider());
+ }
+
+ private static SSLContext newConscryptServerContext() {
+ return TestUtils.newServerSslContext(TestUtils.getConscryptProvider());
+ }
+
+ static SSLEngine initEngine(SSLEngine engine, String cipher, boolean client) {
+ engine.setEnabledProtocols(new String[]{"TLSv1.2"});
+ engine.setEnabledCipherSuites(new String[] {cipher});
+ engine.setUseClientMode(client);
+ return engine;
+ }
+}
diff --git a/repackaged/benchmark-android/src/main/java/com/android/org/conscrypt/CaliperAlpnBenchmark.java b/repackaged/benchmark-android/src/main/java/com/android/org/conscrypt/CaliperAlpnBenchmark.java
new file mode 100644
index 0000000..c181662
--- /dev/null
+++ b/repackaged/benchmark-android/src/main/java/com/android/org/conscrypt/CaliperAlpnBenchmark.java
@@ -0,0 +1,87 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import com.google.caliper.BeforeExperiment;
+import com.google.caliper.Benchmark;
+import com.google.caliper.Param;
+import com.android.org.conscrypt.EngineHandshakeBenchmark.Config;
+
+/**
+ * Cipher benchmarks. Only runs on AES currently because of the combinatorial
+ * explosion of the test as it stands.
+ * @hide This class is not part of the Android public SDK API
+ */
+@SuppressWarnings("unused")
+public class CaliperAlpnBenchmark {
+ private final CaliperConfig config = new CaliperConfig();
+
+ @Param({TestUtils.TEST_CIPHER})
+ public String a_cipher;
+
+ @Param
+ public BufferType b_buffer;
+
+ @Param({"CONSCRYPT_UNPOOLED"}) public AndroidEngineFactory c_engine;
+
+ private EngineHandshakeBenchmark benchmark;
+
+ @BeforeExperiment
+ public void setUp() throws Exception {
+ benchmark = new EngineHandshakeBenchmark(config);
+ }
+
+ @Benchmark
+ public void timeHandshake(int reps) throws Exception {
+ for (int i = 0; i < reps; ++i) {
+ benchmark.handshake();
+ }
+ }
+
+ private final class CaliperConfig implements Config {
+ @Override
+ public BufferType bufferType() {
+ return b_buffer;
+ }
+
+ @Override
+ public EngineFactory engineFactory() {
+ return c_engine;
+ }
+
+ @Override
+ public String cipher() {
+ return a_cipher;
+ }
+
+ @Override
+ public boolean useAlpn() {
+ return true;
+ }
+
+ @Override
+ public BenchmarkProtocol protocol() {
+ return BenchmarkProtocol.TLSv12;
+ }
+
+ @Override
+ public int rttMillis() {
+ return 0;
+ }
+ }
+}
diff --git a/repackaged/benchmark-android/src/main/java/com/android/org/conscrypt/CaliperClientSocketBenchmark.java b/repackaged/benchmark-android/src/main/java/com/android/org/conscrypt/CaliperClientSocketBenchmark.java
new file mode 100644
index 0000000..c444952
--- /dev/null
+++ b/repackaged/benchmark-android/src/main/java/com/android/org/conscrypt/CaliperClientSocketBenchmark.java
@@ -0,0 +1,99 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import com.google.caliper.AfterExperiment;
+import com.google.caliper.BeforeExperiment;
+import com.google.caliper.Benchmark;
+import com.google.caliper.Param;
+import com.android.org.conscrypt.ClientSocketBenchmark.Config;
+
+/**
+ * Benchmark for comparing performance of client socket implementations.
+ * @hide This class is not part of the Android public SDK API
+ */
+@SuppressWarnings("unused")
+public class CaliperClientSocketBenchmark {
+
+ private final CaliperConfig config = new CaliperConfig();
+
+ @Param
+ public AndroidEndpointFactory socketType;
+
+ @Param({"64", "512", "4096"})
+ public int messageSize;
+
+ @Param({TestUtils.TEST_CIPHER})
+ public String cipher;
+
+ @Param
+ public BenchmarkProtocol protocol;
+
+ @Param
+ public ChannelType channelType;
+
+ private ClientSocketBenchmark benchmark;
+
+ @BeforeExperiment
+ public void setup() throws Exception {
+ benchmark = new ClientSocketBenchmark(config);
+ }
+
+ @AfterExperiment
+ public void teardown() throws Exception {
+ benchmark.close();
+ }
+
+ @Benchmark
+ public final void time(int numMessages) throws Exception {
+ benchmark.time(numMessages);
+ }
+
+ private final class CaliperConfig implements Config {
+ @Override
+ public EndpointFactory clientFactory() {
+ return socketType;
+ }
+
+ @Override
+ public EndpointFactory serverFactory() {
+ // Use the same server for all benchmarks, since we're looking at the perf of the client.
+ return AndroidEndpointFactory.CONSCRYPT_ENGINE;
+ }
+
+ @Override
+ public int messageSize() {
+ return messageSize;
+ }
+
+ @Override
+ public String cipher() {
+ return cipher;
+ }
+
+ @Override
+ public ChannelType channelType() {
+ return channelType;
+ }
+
+ @Override
+ public BenchmarkProtocol protocol() {
+ return protocol;
+ }
+ }
+}
diff --git a/repackaged/benchmark-android/src/main/java/com/android/org/conscrypt/CaliperEngineHandshakeBenchmark.java b/repackaged/benchmark-android/src/main/java/com/android/org/conscrypt/CaliperEngineHandshakeBenchmark.java
new file mode 100644
index 0000000..a43c74e
--- /dev/null
+++ b/repackaged/benchmark-android/src/main/java/com/android/org/conscrypt/CaliperEngineHandshakeBenchmark.java
@@ -0,0 +1,108 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+/*
+ * Copyright 2017 The Netty Project
+ *
+ * The Netty Project licenses this file to you 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.
+ */
+
+package com.android.org.conscrypt;
+
+import com.google.caliper.BeforeExperiment;
+import com.google.caliper.Benchmark;
+import com.google.caliper.Param;
+import com.android.org.conscrypt.EngineHandshakeBenchmark.Config;
+
+/**
+ * Benchmark comparing handshake performance of various engine implementations.
+ * @hide This class is not part of the Android public SDK API
+ */
+@SuppressWarnings("unused")
+public class CaliperEngineHandshakeBenchmark {
+ private final CaliperConfig config = new CaliperConfig();
+
+ @Param({TestUtils.TEST_CIPHER})
+ public String a_cipher;
+
+ @Param
+ public BufferType b_buffer;
+
+ @Param({"CONSCRYPT_UNPOOLED"}) public AndroidEngineFactory c_engine;
+
+ @Param
+ public BenchmarkProtocol d_protocol;
+
+ @Param({"100"})
+ public int e_rtt;
+
+ private EngineHandshakeBenchmark benchmark;
+
+ @BeforeExperiment
+ public void setUp() throws Exception {
+ benchmark = new EngineHandshakeBenchmark(config);
+ }
+
+ @Benchmark
+ public void timeHandshake(int reps) throws Exception {
+ for (int i = 0; i < reps; ++i) {
+ benchmark.handshake();
+ }
+ }
+
+ private final class CaliperConfig implements Config {
+ @Override
+ public BufferType bufferType() {
+ return b_buffer;
+ }
+
+ @Override
+ public EngineFactory engineFactory() {
+ return c_engine;
+ }
+
+ @Override
+ public String cipher() {
+ return a_cipher;
+ }
+
+ @Override
+ public boolean useAlpn() {
+ return false;
+ }
+
+ @Override
+ public BenchmarkProtocol protocol() {
+ return d_protocol;
+ }
+
+ @Override
+ public int rttMillis() {
+ return e_rtt;
+ }
+ }
+}
diff --git a/repackaged/benchmark-android/src/main/java/com/android/org/conscrypt/CaliperEngineWrapBenchmark.java b/repackaged/benchmark-android/src/main/java/com/android/org/conscrypt/CaliperEngineWrapBenchmark.java
new file mode 100644
index 0000000..4268c1e
--- /dev/null
+++ b/repackaged/benchmark-android/src/main/java/com/android/org/conscrypt/CaliperEngineWrapBenchmark.java
@@ -0,0 +1,109 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+/*
+ * Copyright 2017 The Netty Project
+ *
+ * The Netty Project licenses this file to you 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.
+ */
+
+package com.android.org.conscrypt;
+
+import com.google.caliper.AfterExperiment;
+import com.google.caliper.BeforeExperiment;
+import com.google.caliper.Benchmark;
+import com.google.caliper.Param;
+import javax.net.ssl.SSLException;
+import com.android.org.conscrypt.EngineWrapBenchmark.Config;
+
+/**
+ * Benchmark comparing performance of various engine implementations to conscrypt.
+ * @hide This class is not part of the Android public SDK API
+ */
+@SuppressWarnings("unused")
+public class CaliperEngineWrapBenchmark {
+ private final CaliperConfig config = new CaliperConfig();
+
+ @Param({TestUtils.TEST_CIPHER})
+ public String a_cipher;
+
+ @Param
+ public BufferType b_buffer;
+
+ @Param({"64", "512", "4096"})
+ public int c_message;
+
+ @Param({"CONSCRYPT_UNPOOLED"}) public AndroidEngineFactory d_engine;
+
+ private EngineWrapBenchmark benchmark;
+
+ @BeforeExperiment
+ public void setUp() throws Exception {
+ benchmark = new EngineWrapBenchmark(config);
+ }
+
+ @AfterExperiment
+ public void teardown() {
+ benchmark.teardown();
+ }
+
+ @Benchmark
+ public void timeWrap(int reps) throws SSLException {
+ for (int i = 0; i < reps; ++i) {
+ benchmark.wrap();
+ }
+ }
+
+ public void timeWrapAndUnwrap(int reps) throws SSLException {
+ for (int i = 0; i < reps; ++i) {
+ benchmark.wrapAndUnwrap();
+ }
+ }
+
+ private final class CaliperConfig implements Config {
+
+ @Override
+ public BufferType bufferType() {
+ return b_buffer;
+ }
+
+ @Override
+ public EngineFactory engineFactory() {
+ return d_engine;
+ }
+
+ @Override
+ public int messageSize() {
+ return c_message;
+ }
+
+ @Override
+ public String cipher() {
+ return a_cipher;
+ }
+ }
+}
diff --git a/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/BenchmarkProtocol.java b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/BenchmarkProtocol.java
new file mode 100644
index 0000000..c31bb80
--- /dev/null
+++ b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/BenchmarkProtocol.java
@@ -0,0 +1,22 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@SuppressWarnings("ImmutableEnumChecker")
+public enum BenchmarkProtocol {
+
+ TLSv13("TLSv1.3"),
+ TLSv12("TLSv1.2");
+
+ private final String[] protocols;
+
+ BenchmarkProtocol(String... protocols) {
+ this.protocols = protocols;
+ }
+
+ public String[] getProtocols() {
+ return protocols.clone();
+ }
+}
diff --git a/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/BufferType.java b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/BufferType.java
new file mode 100644
index 0000000..a2a62d3
--- /dev/null
+++ b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/BufferType.java
@@ -0,0 +1,50 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+package com.android.org.conscrypt;
+
+import java.nio.ByteBuffer;
+import javax.net.ssl.SSLEngine;
+
+/**
+ * Enumeration that provides allocation of direct or heap buffers.
+ * @hide This class is not part of the Android public SDK API
+ */
+@SuppressWarnings("unused")
+public enum BufferType {
+ HEAP {
+ @Override
+ ByteBuffer newBuffer(int size) {
+ return ByteBuffer.allocate(size);
+ }
+ },
+ DIRECT {
+ @Override
+ ByteBuffer newBuffer(int size) {
+ return ByteBuffer.allocateDirect(size);
+ }
+ };
+
+ abstract ByteBuffer newBuffer(int size);
+
+ ByteBuffer newApplicationBuffer(SSLEngine engine) {
+ return newBuffer(engine.getSession().getApplicationBufferSize());
+ }
+
+ ByteBuffer newPacketBuffer(SSLEngine engine) {
+ return newBuffer(engine.getSession().getPacketBufferSize());
+ }
+}
diff --git a/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/CipherEncryptBenchmark.java b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/CipherEncryptBenchmark.java
new file mode 100644
index 0000000..71fa3c4
--- /dev/null
+++ b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/CipherEncryptBenchmark.java
@@ -0,0 +1,162 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.nio.ByteBuffer;
+import java.security.Key;
+import javax.crypto.Cipher;
+
+/**
+ * Benchmark for comparing cipher encrypt performance.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class CipherEncryptBenchmark {
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public enum BufferType {
+ ARRAY,
+ HEAP_HEAP,
+ HEAP_DIRECT,
+ DIRECT_DIRECT,
+ DIRECT_HEAP
+ }
+
+ /**
+ * Provider for the benchmark configuration
+ */
+ interface Config {
+ BufferType bufferType();
+ CipherFactory cipherFactory();
+ Transformation transformation();
+ }
+
+ private final EncryptStrategy encryptStrategy;
+
+ CipherEncryptBenchmark(Config config) throws Exception {
+ switch (config.bufferType()) {
+ case ARRAY:
+ encryptStrategy = new ArrayStrategy(config);
+ break;
+ default:
+ encryptStrategy = new ByteBufferStrategy(config);
+ break;
+ }
+ }
+
+ int encrypt() throws Exception {
+ return encryptStrategy.encrypt();
+ }
+
+ private static abstract class EncryptStrategy {
+ private final Key key;
+ final Cipher cipher;
+ final int outputSize;
+
+ EncryptStrategy(Config config) throws Exception {
+ Transformation tx = config.transformation();
+ key = tx.newEncryptKey();
+ cipher = config.cipherFactory().newCipher(tx.toFormattedString());
+ initCipher();
+
+ int messageSize = messageSize(tx.toFormattedString());
+ outputSize = cipher.getOutputSize(messageSize);
+ }
+
+ final void initCipher() throws Exception {
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ }
+
+ final int messageSize(String transformation) throws Exception {
+ Cipher conscryptCipher = Cipher.getInstance(transformation, TestUtils.getConscryptProvider());
+ conscryptCipher.init(Cipher.ENCRYPT_MODE, key);
+ return conscryptCipher.getBlockSize() > 0 ? conscryptCipher.getBlockSize() : 128;
+ }
+
+ final byte[] newMessage() {
+ return TestUtils.newTextMessage(cipher.getBlockSize());
+ }
+
+ abstract int encrypt() throws Exception;
+ }
+
+ private static final class ArrayStrategy extends EncryptStrategy {
+ private final byte[] plainBytes;
+ private final byte[] cipherBytes;
+
+ ArrayStrategy(Config config) throws Exception {
+ super(config);
+
+ plainBytes = newMessage();
+ cipherBytes = new byte[outputSize];
+ }
+
+ @Override
+ int encrypt() throws Exception {
+ initCipher();
+ return cipher.doFinal(plainBytes, 0, plainBytes.length, cipherBytes, 0);
+ }
+ }
+
+ private static final class ByteBufferStrategy extends EncryptStrategy {
+ private final ByteBuffer input;
+ private final ByteBuffer output;
+
+ ByteBufferStrategy(Config config) throws Exception {
+ super(config);
+
+ switch (config.bufferType()) {
+ case HEAP_HEAP:
+ input = ByteBuffer.wrap(newMessage());
+ output = ByteBuffer.allocate(outputSize);
+ break;
+ case HEAP_DIRECT:
+ input = ByteBuffer.wrap(newMessage());
+ output = ByteBuffer.allocateDirect(outputSize);
+ break;
+ case DIRECT_DIRECT:
+ input = toDirect(newMessage());
+ output = ByteBuffer.allocateDirect(outputSize);
+ break;
+ case DIRECT_HEAP:
+ input = toDirect(newMessage());
+ output = ByteBuffer.allocate(outputSize);
+ break;
+ default: {
+ throw new IllegalStateException(
+ "Unexpected buffertype: " + config.bufferType());
+ }
+ }
+ }
+
+ @Override
+ int encrypt() throws Exception {
+ initCipher();
+ input.position(0);
+ output.clear();
+ return cipher.doFinal(input, output);
+ }
+
+ private static ByteBuffer toDirect(byte[] data) {
+ ByteBuffer buffer = ByteBuffer.allocateDirect(data.length);
+ buffer.put(data);
+ buffer.flip();
+ return buffer;
+ }
+ }
+}
diff --git a/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/CipherFactory.java b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/CipherFactory.java
new file mode 100644
index 0000000..f1ae323
--- /dev/null
+++ b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/CipherFactory.java
@@ -0,0 +1,29 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+package com.android.org.conscrypt;
+
+import java.security.NoSuchAlgorithmException;
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+
+/**
+ * Factory for {@link Cipher} instances.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface CipherFactory {
+ Cipher newCipher(String transformation) throws NoSuchPaddingException, NoSuchAlgorithmException;
+}
diff --git a/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/ClientEndpoint.java b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/ClientEndpoint.java
new file mode 100644
index 0000000..fd38975
--- /dev/null
+++ b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/ClientEndpoint.java
@@ -0,0 +1,109 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.nio.channels.ClosedChannelException;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * Client-side endpoint. Provides basic services for sending/receiving messages from the client
+ * socket.
+ */
+final class ClientEndpoint {
+ private final SSLSocket socket;
+ private InputStream input;
+ private OutputStream output;
+
+ ClientEndpoint(SSLSocketFactory socketFactory, ChannelType channelType, int port,
+ String[] protocols, String[] ciphers) throws IOException {
+ socket = channelType.newClientSocket(socketFactory, InetAddress.getLoopbackAddress(), port);
+ socket.setEnabledProtocols(protocols);
+ socket.setEnabledCipherSuites(ciphers);
+ }
+
+ void start() {
+ try {
+ socket.startHandshake();
+ input = socket.getInputStream();
+ output = socket.getOutputStream();
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
+ }
+
+ void stop() {
+ try {
+ socket.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ int readMessage(byte[] buffer) {
+ try {
+ int totalBytesRead = 0;
+ while (totalBytesRead < buffer.length) {
+ int remaining = buffer.length - totalBytesRead;
+ int bytesRead = input.read(buffer, totalBytesRead, remaining);
+ if (bytesRead == -1) {
+ break;
+ }
+ totalBytesRead += bytesRead;
+ }
+ return totalBytesRead;
+ } catch (SSLException e) {
+ if (e.getCause() instanceof EOFException) {
+ return -1;
+ }
+ throw new RuntimeException(e);
+ } catch (ClosedChannelException e) {
+ // Thrown for channel-based sockets. Just treat like EOF.
+ return -1;
+ } catch (SocketException e) {
+ // The socket was broken. Just treat like EOF.
+ return -1;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ void sendMessage(byte[] data) {
+ try {
+ output.write(data);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ void flush() {
+ try {
+ output.flush();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/ClientSocketBenchmark.java b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/ClientSocketBenchmark.java
new file mode 100644
index 0000000..1bb35b4
--- /dev/null
+++ b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/ClientSocketBenchmark.java
@@ -0,0 +1,149 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.TestUtils.newTextMessage;
+
+import java.io.OutputStream;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Benchmark for comparing performance of client socket implementations.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class ClientSocketBenchmark {
+ /**
+ * Provider for the benchmark configuration
+ */
+ interface Config {
+ EndpointFactory clientFactory();
+ EndpointFactory serverFactory();
+ int messageSize();
+ String cipher();
+ ChannelType channelType();
+ BenchmarkProtocol protocol();
+ }
+
+ private ClientEndpoint client;
+ private ServerEndpoint server;
+ private byte[] message;
+ private ExecutorService executor;
+ private Future<?> sendingFuture;
+ private volatile boolean stopping;
+
+ private static final AtomicLong bytesCounter = new AtomicLong();
+ private AtomicBoolean recording = new AtomicBoolean();
+
+ ClientSocketBenchmark(Config config) throws Exception {
+ recording.set(false);
+
+ message = newTextMessage(config.messageSize());
+
+ // Always use the same server for consistency across the benchmarks.
+ server = config.serverFactory().newServer(
+ ChannelType.CHANNEL, config.messageSize(), config.protocol().getProtocols(),
+ ciphers(config));
+
+ server.setMessageProcessor(new ServerEndpoint.MessageProcessor() {
+ @Override
+ public void processMessage(byte[] inMessage, int numBytes, OutputStream os) {
+ if (recording.get()) {
+ // Server received a message, increment the count.
+ bytesCounter.addAndGet(numBytes);
+ }
+ }
+ });
+ Future<?> connectedFuture = server.start();
+
+ client = config.clientFactory().newClient(
+ config.channelType(), server.port(), config.protocol().getProtocols(), ciphers(config));
+ client.start();
+
+ // Wait for the initial connection to complete.
+ connectedFuture.get(5, TimeUnit.SECONDS);
+
+ executor = Executors.newSingleThreadExecutor();
+ sendingFuture = executor.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Thread thread = Thread.currentThread();
+ while (!stopping && !thread.isInterrupted()) {
+ client.sendMessage(message);
+ }
+ } finally {
+ client.flush();
+ }
+ }
+ });
+ }
+
+ void close() throws Exception {
+ stopping = true;
+
+ // Wait for the sending thread to stop.
+ sendingFuture.get(5, TimeUnit.SECONDS);
+
+ client.stop();
+ server.stop();
+ executor.shutdown();
+ executor.awaitTermination(5, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Simple benchmark for the amount of time to send a given number of messages (used by
+ * Caliper).
+ */
+ void time(final int numMessages) throws Exception {
+ reset();
+ recording.set(true);
+
+ while (bytesCounter.get() < numMessages) {
+ Thread.sleep(50);
+ }
+
+ recording.set(false);
+ }
+
+ /**
+ * Simple benchmark for throughput (used by JMH).
+ */
+ void throughput() throws Exception {
+ recording.set(true);
+ // Send as many messages as we can in a second.
+ Thread.sleep(1001);
+ recording.set(false);
+ }
+
+ static void reset() {
+ bytesCounter.set(0);
+ }
+
+ static long bytesPerSecond() {
+ return bytesCounter.get();
+ }
+
+ private String[] ciphers(Config config) {
+ return new String[] {config.cipher()};
+ }
+}
diff --git a/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/EndpointFactory.java b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/EndpointFactory.java
new file mode 100644
index 0000000..0b09579
--- /dev/null
+++ b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/EndpointFactory.java
@@ -0,0 +1,15 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt;
+
+import java.io.IOException;
+
+/**
+ * Utility for creating test client and server endpoints.
+ */
+interface EndpointFactory {
+ ClientEndpoint newClient(ChannelType channelType, int port, String[] protocols,
+ String[] ciphers) throws IOException;
+
+ ServerEndpoint newServer(ChannelType channelType, int messageSize,
+ String[] protocols, String[] ciphers) throws IOException;
+}
diff --git a/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/EngineFactory.java b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/EngineFactory.java
new file mode 100644
index 0000000..662b3e9
--- /dev/null
+++ b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/EngineFactory.java
@@ -0,0 +1,31 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+package com.android.org.conscrypt;
+
+import javax.net.ssl.SSLEngine;
+
+/**
+ * Factory for {@link SSLEngine} instances.
+ */
+interface EngineFactory {
+
+ SSLEngine newClientEngine(String cipher, boolean useAlpn);
+
+ SSLEngine newServerEngine(String cipher, boolean useAlpn);
+
+ void dispose(SSLEngine engine);
+}
diff --git a/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/EngineHandshakeBenchmark.java b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/EngineHandshakeBenchmark.java
new file mode 100644
index 0000000..015b982
--- /dev/null
+++ b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/EngineHandshakeBenchmark.java
@@ -0,0 +1,168 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+/*
+ * Copyright 2017 The Netty Project
+ *
+ * The Netty Project licenses this file to you 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.nio.ByteBuffer;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLException;
+
+/**
+ * Benchmark comparing handshake performance of various engine implementations to conscrypt.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class EngineHandshakeBenchmark {
+ /**
+ * Provider for the benchmark configuration
+ */
+ interface Config {
+ BufferType bufferType();
+ EngineFactory engineFactory();
+ String cipher();
+ boolean useAlpn();
+ BenchmarkProtocol protocol();
+ int rttMillis();
+ }
+
+ private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocateDirect(0);
+
+ private final EngineFactory engineFactory;
+ private final String cipher;
+ private final boolean useAlpn;
+ private final String[] protocols;
+ private final int rttMillis;
+
+ private final ByteBuffer clientApplicationBuffer;
+ private final ByteBuffer clientPacketBuffer;
+ private final ByteBuffer serverApplicationBuffer;
+ private final ByteBuffer serverPacketBuffer;
+
+ EngineHandshakeBenchmark(Config config) throws Exception {
+ engineFactory = config.engineFactory();
+ cipher = config.cipher();
+ useAlpn = config.useAlpn();
+ protocols = config.protocol().getProtocols();
+ rttMillis = config.rttMillis();
+ BufferType bufferType = config.bufferType();
+
+ SSLEngine clientEngine = engineFactory.newClientEngine(cipher, useAlpn);
+ SSLEngine serverEngine = engineFactory.newServerEngine(cipher, useAlpn);
+
+ // Create the application and packet buffers for both endpoints.
+ clientApplicationBuffer = bufferType.newApplicationBuffer(clientEngine);
+ serverApplicationBuffer = bufferType.newApplicationBuffer(serverEngine);
+ clientPacketBuffer = bufferType.newPacketBuffer(clientEngine);
+ serverPacketBuffer = bufferType.newPacketBuffer(serverEngine);
+
+ engineFactory.dispose(clientEngine);
+ engineFactory.dispose(serverEngine);
+ }
+
+ void handshake() throws SSLException {
+ SSLEngine client = engineFactory.newClientEngine(cipher, useAlpn);
+ SSLEngine server = engineFactory.newServerEngine(cipher, useAlpn);
+ clientApplicationBuffer.clear();
+ clientPacketBuffer.clear();
+ serverApplicationBuffer.clear();
+ serverPacketBuffer.clear();
+
+ client.setEnabledProtocols(protocols);
+ server.setEnabledProtocols(protocols);
+
+ client.beginHandshake();
+ server.beginHandshake();
+
+ doHandshake(client, server);
+
+ engineFactory.dispose(client);
+ engineFactory.dispose(server);
+ }
+
+ private void doHandshake(SSLEngine client, SSLEngine server) throws SSLException {
+ while (true) {
+ // Send as many client-to-server messages as possible
+ doHalfHandshake(client, server, clientPacketBuffer, serverApplicationBuffer);
+
+ if (client.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING
+ && server.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING) {
+ return;
+ }
+
+ // Do the same with server-to-client messages
+ doHalfHandshake(server, client, serverPacketBuffer, clientApplicationBuffer);
+
+ if (client.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING
+ && server.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING) {
+ return;
+ }
+ }
+ }
+
+ private void doHalfHandshake(SSLEngine sender, SSLEngine receiver,
+ ByteBuffer senderPacketBuffer, ByteBuffer receiverApplicationBuffer)
+ throws SSLException {
+ SSLEngineResult senderResult;
+ SSLEngineResult receiverResult;
+
+ do {
+ senderResult = sender.wrap(EMPTY_BUFFER, senderPacketBuffer);
+ runDelegatedTasks(senderResult, sender);
+ senderPacketBuffer.flip();
+ receiverResult = receiver.unwrap(senderPacketBuffer, receiverApplicationBuffer);
+ runDelegatedTasks(receiverResult, receiver);
+ senderPacketBuffer.compact();
+ } while (senderResult.getHandshakeStatus() == HandshakeStatus.NEED_WRAP);
+
+ if (rttMillis > 0) {
+ try {
+ Thread.sleep(rttMillis / 2);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private static void runDelegatedTasks(SSLEngineResult result, SSLEngine engine) {
+ if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) {
+ for (;;) {
+ Runnable task = engine.getDelegatedTask();
+ if (task == null) {
+ break;
+ }
+ task.run();
+ }
+ }
+ }
+}
diff --git a/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/EngineWrapBenchmark.java b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/EngineWrapBenchmark.java
new file mode 100644
index 0000000..5595485
--- /dev/null
+++ b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/EngineWrapBenchmark.java
@@ -0,0 +1,161 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+/*
+ * Copyright 2017 The Netty Project
+ *
+ * The Netty Project licenses this file to you 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.TestUtils.doEngineHandshake;
+import static com.android.org.conscrypt.TestUtils.newTextMessage;
+import static org.junit.Assert.assertEquals;
+
+import java.nio.ByteBuffer;
+import java.util.Locale;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+
+/**
+ * Benchmark comparing performance of various engine implementations to conscrypt.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class EngineWrapBenchmark {
+ /**
+ * Provider for the benchmark configuration
+ */
+ interface Config {
+ BufferType bufferType();
+ EngineFactory engineFactory();
+ int messageSize();
+ String cipher();
+ }
+
+ private final EngineFactory engineFactory;
+ private final String cipher;
+ private final SSLEngine clientEngine;
+ private final SSLEngine serverEngine;
+
+ private final ByteBuffer messageBuffer;
+ private final ByteBuffer clientApplicationBuffer;
+ private final ByteBuffer clientPacketBuffer;
+ private final ByteBuffer serverApplicationBuffer;
+ private final ByteBuffer serverPacketBuffer;
+ private final ByteBuffer preEncryptedBuffer;
+
+ EngineWrapBenchmark(Config config) throws Exception {
+ engineFactory = config.engineFactory();
+ cipher = config.cipher();
+ BufferType bufferType = config.bufferType();
+
+ clientEngine = engineFactory.newClientEngine(cipher, false);
+ serverEngine = engineFactory.newServerEngine(cipher, false);
+
+ // Create the application and packet buffers for both endpoints.
+ clientApplicationBuffer = bufferType.newApplicationBuffer(clientEngine);
+ serverApplicationBuffer = bufferType.newApplicationBuffer(serverEngine);
+ clientPacketBuffer = bufferType.newPacketBuffer(clientEngine);
+ serverPacketBuffer = bufferType.newPacketBuffer(serverEngine);
+
+ // Generate the message to be sent from the client.
+ int messageSize = config.messageSize();
+ messageBuffer = bufferType.newBuffer(messageSize);
+ messageBuffer.put(newTextMessage(messageSize));
+ messageBuffer.flip();
+
+ // Complete the initial TLS handshake.
+ doEngineHandshake(clientEngine, serverEngine, clientApplicationBuffer, clientPacketBuffer,
+ serverApplicationBuffer, serverPacketBuffer, true);
+
+ // Populate the pre-encrypted buffer for use with the unwrap benchmark.
+ preEncryptedBuffer = bufferType.newBuffer(clientEngine.getSession().getPacketBufferSize());
+ doWrap(messageBuffer, preEncryptedBuffer);
+ doUnwrap(preEncryptedBuffer, serverApplicationBuffer);
+ }
+
+ void teardown() {
+ engineFactory.dispose(clientEngine);
+ engineFactory.dispose(serverEngine);
+ }
+
+ void wrap() throws SSLException {
+ // Reset the buffers.
+ messageBuffer.position(0);
+ clientPacketBuffer.clear();
+
+ // Wrap the original message and create the encrypted data.
+ doWrap(messageBuffer, clientPacketBuffer);
+
+ // Lightweight comparison - just make sure the data length is correct.
+ assertEquals(preEncryptedBuffer.limit(), clientPacketBuffer.limit());
+ }
+
+ /**
+ * Simple benchmark that sends a single message from client to server.
+ */
+ void wrapAndUnwrap() throws SSLException {
+ // Reset the buffers.
+ messageBuffer.position(0);
+ clientPacketBuffer.clear();
+ serverApplicationBuffer.clear();
+
+ // Wrap the original message and create the encrypted data.
+ doWrap(messageBuffer, clientPacketBuffer);
+
+ // Unwrap the encrypted data and get back the original result.
+ doUnwrap(clientPacketBuffer, serverApplicationBuffer);
+
+ // Lightweight comparison - just make sure the unencrypted data length is correct.
+ assertEquals(messageBuffer.limit(), serverApplicationBuffer.limit());
+ }
+
+ private void doWrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
+ // Wrap the original message and create the encrypted data.
+ verifyResult(src, clientEngine.wrap(src, dst));
+ dst.flip();
+ }
+
+ private void doUnwrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
+ verifyResult(src, serverEngine.unwrap(src, dst));
+ dst.flip();
+ }
+
+ private void verifyResult(ByteBuffer src, SSLEngineResult result) {
+ if (result.getStatus() != SSLEngineResult.Status.OK) {
+ throw new RuntimeException("Operation returned unexpected result " + result);
+ }
+ if (result.bytesConsumed() != src.limit()) {
+ throw new RuntimeException(
+ String.format(Locale.US,
+ "Operation didn't consume all bytes. Expected %d, consumed %d.",
+ src.limit(), result.bytesConsumed()));
+ }
+ }
+}
diff --git a/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/ServerEndpoint.java b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/ServerEndpoint.java
new file mode 100644
index 0000000..b15cc79
--- /dev/null
+++ b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/ServerEndpoint.java
@@ -0,0 +1,200 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.SocketException;
+import java.nio.channels.ClosedChannelException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * A simple socket-based test server.
+ */
+final class ServerEndpoint {
+ /**
+ * A processor for receipt of a single message.
+ * @hide This class is not part of the Android public SDK API
+ */
+ public interface MessageProcessor {
+ void processMessage(byte[] message, int numBytes, OutputStream os);
+ }
+
+ /**
+ * A {@link MessageProcessor} that simply echos back the received message to the client.
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class EchoProcessor implements MessageProcessor {
+ @Override
+ public void processMessage(byte[] message, int numBytes, OutputStream os) {
+ try {
+ os.write(message, 0, numBytes);
+ os.flush();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private final ServerSocket serverSocket;
+ private final ChannelType channelType;
+ private final SSLSocketFactory socketFactory;
+ private final int messageSize;
+ private final String[] protocols;
+ private final String[] cipherSuites;
+ private final byte[] buffer;
+ private SSLSocket socket;
+ private ExecutorService executor;
+ private InputStream inputStream;
+ private OutputStream outputStream;
+ private volatile boolean stopping;
+ private volatile MessageProcessor messageProcessor = new EchoProcessor();
+ private volatile Future<?> processFuture;
+
+ ServerEndpoint(SSLSocketFactory socketFactory, SSLServerSocketFactory serverSocketFactory,
+ ChannelType channelType, int messageSize, String[] protocols,
+ String[] cipherSuites) throws IOException {
+ this.serverSocket = channelType.newServerSocket(serverSocketFactory);
+ this.socketFactory = socketFactory;
+ this.channelType = channelType;
+ this.messageSize = messageSize;
+ this.protocols = protocols;
+ this.cipherSuites = cipherSuites;
+ buffer = new byte[messageSize];
+ }
+
+ void setMessageProcessor(MessageProcessor messageProcessor) {
+ this.messageProcessor = messageProcessor;
+ }
+
+ Future<?> start() throws IOException {
+ executor = Executors.newSingleThreadExecutor();
+ return executor.submit(new AcceptTask());
+ }
+
+ void stop() {
+ try {
+ stopping = true;
+
+ if (socket != null) {
+ socket.close();
+ socket = null;
+ }
+
+ if (processFuture != null) {
+ processFuture.get(5, TimeUnit.SECONDS);
+ }
+
+ serverSocket.close();
+
+ if (executor != null) {
+ executor.shutdown();
+ executor.awaitTermination(5, TimeUnit.SECONDS);
+ executor = null;
+ }
+ } catch (IOException | InterruptedException | ExecutionException | TimeoutException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public int port() {
+ return serverSocket.getLocalPort();
+ }
+
+ private final class AcceptTask implements Runnable {
+ @Override
+ public void run() {
+ try {
+ if (stopping) {
+ return;
+ }
+ socket = channelType.accept(serverSocket, socketFactory);
+ socket.setEnabledProtocols(protocols);
+ socket.setEnabledCipherSuites(cipherSuites);
+
+ socket.startHandshake();
+
+ inputStream = socket.getInputStream();
+ outputStream = socket.getOutputStream();
+
+ if (stopping) {
+ return;
+ }
+ processFuture = executor.submit(new ProcessTask());
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private final class ProcessTask implements Runnable {
+ @Override
+ public void run() {
+ try {
+ Thread thread = Thread.currentThread();
+ while (!stopping && !thread.isInterrupted()) {
+ int bytesRead = readMessage();
+ if (!stopping && !thread.isInterrupted()) {
+ messageProcessor.processMessage(buffer, bytesRead, outputStream);
+ }
+ }
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private int readMessage() throws IOException {
+ int totalBytesRead = 0;
+ while (!stopping && totalBytesRead < messageSize) {
+ try {
+ int remaining = messageSize - totalBytesRead;
+ int bytesRead = inputStream.read(buffer, totalBytesRead, remaining);
+ if (bytesRead == -1) {
+ break;
+ }
+ totalBytesRead += bytesRead;
+ } catch (SSLException e) {
+ if (e.getCause() instanceof EOFException) {
+ break;
+ }
+ throw e;
+ } catch (ClosedChannelException e) {
+ // Thrown for channel-based sockets. Just treat like EOF.
+ break;
+ } catch (SocketException e) {
+ // The socket was broken. Just treat like EOF.
+ break;
+ }
+ }
+ return totalBytesRead;
+ }
+ }
+}
diff --git a/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/ServerSocketBenchmark.java b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/ServerSocketBenchmark.java
new file mode 100644
index 0000000..03a9715
--- /dev/null
+++ b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/ServerSocketBenchmark.java
@@ -0,0 +1,151 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.TestUtils.getCommonProtocolSuites;
+import static com.android.org.conscrypt.TestUtils.newTextMessage;
+import static org.junit.Assert.assertEquals;
+
+import com.android.org.conscrypt.ServerEndpoint.MessageProcessor;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.SocketException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Benchmark for comparing performance of server socket implementations.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class ServerSocketBenchmark {
+ /**
+ * Provider for the benchmark configuration
+ */
+ interface Config {
+ EndpointFactory clientFactory();
+ EndpointFactory serverFactory();
+ int messageSize();
+ String cipher();
+ ChannelType channelType();
+ }
+
+ private ClientEndpoint client;
+ private ServerEndpoint server;
+ private ExecutorService executor;
+ private Future<?> receivingFuture;
+ private volatile boolean stopping;
+ private static final AtomicLong bytesCounter = new AtomicLong();
+ private AtomicBoolean recording = new AtomicBoolean();
+
+ ServerSocketBenchmark(final Config config) throws Exception {
+ recording.set(false);
+
+ byte[] message = newTextMessage(config.messageSize());
+
+ final ChannelType channelType = config.channelType();
+
+ server = config.serverFactory().newServer(
+ channelType, config.messageSize(), getCommonProtocolSuites(), ciphers(config));
+ server.setMessageProcessor(new MessageProcessor() {
+ @Override
+ public void processMessage(byte[] inMessage, int numBytes, OutputStream os) {
+ try {
+ try {
+ while (!stopping) {
+ os.write(inMessage, 0, numBytes);
+ }
+ } finally {
+ os.flush();
+ }
+ } catch (SocketException e) {
+ // Just ignore.
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+
+ Future<?> connectedFuture = server.start();
+
+ // Always use the same client for consistency across the benchmarks.
+ client = config.clientFactory().newClient(
+ ChannelType.CHANNEL, server.port(), getCommonProtocolSuites(), ciphers(config));
+ client.start();
+
+ // Wait for the initial connection to complete.
+ connectedFuture.get(5, TimeUnit.SECONDS);
+
+ // Start the server-side streaming by sending a message to the server.
+ client.sendMessage(message);
+ client.flush();
+
+ executor = Executors.newSingleThreadExecutor();
+ receivingFuture = executor.submit(new Runnable() {
+ @Override
+ public void run() {
+ Thread thread = Thread.currentThread();
+ byte[] buffer = new byte[config.messageSize()];
+ while (!stopping && !thread.isInterrupted()) {
+ int numBytes = client.readMessage(buffer);
+ if (numBytes < 0) {
+ return;
+ }
+ assertEquals(config.messageSize(), numBytes);
+
+ // Increment the message counter if we're recording.
+ if (recording.get()) {
+ bytesCounter.addAndGet(numBytes);
+ }
+ }
+ }
+ });
+ }
+
+ void close() throws Exception {
+ stopping = true;
+ // Stop and wait for sending to complete.
+ server.stop();
+ client.stop();
+ executor.shutdown();
+ receivingFuture.get(5, TimeUnit.SECONDS);
+ executor.awaitTermination(5, TimeUnit.SECONDS);
+ }
+
+ void throughput() throws Exception {
+ recording.set(true);
+ // Send as many messages as we can in a second.
+ Thread.sleep(1001);
+ recording.set(false);
+ }
+
+ static void reset() {
+ bytesCounter.set(0);
+ }
+
+ static long bytesPerSecond() {
+ return bytesCounter.get();
+ }
+
+ private String[] ciphers(Config config) {
+ return new String[] {config.cipher()};
+ }
+}
diff --git a/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/Transformation.java b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/Transformation.java
new file mode 100644
index 0000000..f50cad5
--- /dev/null
+++ b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/Transformation.java
@@ -0,0 +1,89 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import javax.crypto.KeyGenerator;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+/**
+ * Supported cipher transformations.
+ * @hide This class is not part of the Android public SDK API
+ */
+@SuppressWarnings({"ImmutableEnumChecker", "unused"})
+public enum Transformation {
+ AES_CBC_PKCS5("AES", "CBC", "PKCS5Padding", new AesKeyGen()),
+ AES_ECB_PKCS5("AES", "ECB", "PKCS5Padding", new AesKeyGen()),
+ AES_GCM_NO("AES", "GCM", "NoPadding", new AesKeyGen()),
+ RSA_ECB_PKCS1("RSA", "ECB", "PKCS1Padding", new RsaKeyGen());
+
+ Transformation(String algorithm, String mode, String padding, KeyGen keyGen) {
+ this.algorithm = algorithm;
+ this.mode = mode;
+ this.padding = padding;
+ this.keyGen = keyGen;
+ }
+
+ final String algorithm;
+ final String mode;
+ final String padding;
+ final KeyGen keyGen;
+
+ String toFormattedString() {
+ return algorithm + "/" + mode + "/" + padding;
+ }
+
+ Key newEncryptKey() {
+ return keyGen.newEncryptKey();
+ }
+
+ private interface KeyGen { Key newEncryptKey(); }
+
+ private static final class RsaKeyGen implements KeyGen {
+ @Override
+ public Key newEncryptKey() {
+ try {
+ // Use Bouncy castle
+ KeyPairGenerator generator =
+ KeyPairGenerator.getInstance("RSA", new BouncyCastleProvider());
+ generator.initialize(2048);
+ KeyPair pair = generator.generateKeyPair();
+ return pair.getPublic();
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private static final class AesKeyGen implements KeyGen {
+ @Override
+ public Key newEncryptKey() {
+ try {
+ // Just use the JDK's provider.
+ KeyGenerator keyGen = KeyGenerator.getInstance("AES");
+ keyGen.init(256);
+ return keyGen.generateKey();
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/AbstractConscryptEngine.java b/repackaged/common/src/main/java/com/android/org/conscrypt/AbstractConscryptEngine.java
new file mode 100644
index 0000000..a79178d
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/AbstractConscryptEngine.java
@@ -0,0 +1,184 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.nio.ByteBuffer;
+import java.security.PrivateKey;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+
+/**
+ * Abstract base class for all Conscrypt {@link SSLEngine} classes.
+ */
+abstract class AbstractConscryptEngine extends SSLEngine {
+ abstract void setBufferAllocator(BufferAllocator bufferAllocator);
+
+ /**
+ * Returns the maximum overhead, in bytes, of sealing a record with SSL.
+ */
+ abstract int maxSealOverhead();
+
+ /**
+ * Enables/disables TLS Channel ID for this server engine.
+ *
+ * <p>This method needs to be invoked before the handshake starts.
+ *
+ * @throws IllegalStateException if this is a client engine or if the handshake has already
+ * started.
+ */
+ abstract void setChannelIdEnabled(boolean enabled);
+
+ /**
+ * Gets the TLS Channel ID for this server engine. Channel ID is only available once the
+ * handshake completes.
+ *
+ * @return channel ID or {@code null} if not available.
+ *
+ * @throws IllegalStateException if this is a client engine or if the handshake has not yet
+ * completed.
+ * @throws SSLException if channel ID is available but could not be obtained.
+ */
+ abstract byte[] getChannelId() throws SSLException;
+
+ /**
+ * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client engine.
+ *
+ * <p>This method needs to be invoked before the handshake starts.
+ *
+ * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables
+ * TLS Channel ID). The private key must be an Elliptic Curve (EC) key based on the NIST
+ * P-256 curve (aka SECG secp256r1 or ANSI X9.62 prime256v1).
+ *
+ * @throws IllegalStateException if this is a server engine or if the handshake has already
+ * started.
+ */
+ abstract void setChannelIdPrivateKey(PrivateKey privateKey);
+
+ /**
+ * Sets the listener for the completion of the TLS handshake.
+ */
+ abstract void setHandshakeListener(HandshakeListener handshakeListener);
+
+ /**
+ * This method enables Server Name Indication (SNI) and overrides the {@link PeerInfoProvider}
+ * supplied during engine creation.
+ */
+ abstract void setHostname(String hostname);
+
+ /**
+ * Returns the hostname from {@link #setHostname(String)} or supplied by the
+ * {@link PeerInfoProvider} upon creation. No DNS resolution is attempted before
+ * returning the hostname.
+ */
+ abstract String getHostname();
+
+ @Override public abstract String getPeerHost();
+
+ @Override public abstract int getPeerPort();
+
+ /* @Override */
+ @SuppressWarnings("MissingOverride") // For compilation with Java 6.
+ public final SSLSession getHandshakeSession() {
+ return handshakeSession();
+ }
+
+ /**
+ * Work-around to allow this method to be called on older versions of Android.
+ */
+ abstract SSLSession handshakeSession();
+
+ @Override
+ public abstract SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException;
+
+ @Override
+ public abstract SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts) throws SSLException;
+
+ @Override
+ public abstract SSLEngineResult unwrap(final ByteBuffer src, final ByteBuffer[] dsts,
+ final int offset, final int length) throws SSLException;
+
+ abstract SSLEngineResult unwrap(final ByteBuffer[] srcs, final ByteBuffer[] dsts)
+ throws SSLException;
+
+ abstract SSLEngineResult unwrap(final ByteBuffer[] srcs, int srcsOffset, final int srcsLength,
+ final ByteBuffer[] dsts, final int dstsOffset, final int dstsLength)
+ throws SSLException;
+
+ @Override
+ public abstract SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException;
+
+ @Override
+ public abstract SSLEngineResult wrap(
+ ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer dst) throws SSLException;
+
+ /**
+ * This method enables session ticket support.
+ *
+ * @param useSessionTickets True to enable session tickets
+ */
+ abstract void setUseSessionTickets(boolean useSessionTickets);
+
+ /**
+ * Sets the list of ALPN protocols.
+ *
+ * @param protocols the list of ALPN protocols
+ */
+ abstract void setApplicationProtocols(String[] protocols);
+
+ /**
+ * Returns the list of supported ALPN protocols.
+ */
+ abstract String[] getApplicationProtocols();
+
+ @SuppressWarnings("MissingOverride") // For compiling pre Java 9.
+ public abstract String getApplicationProtocol();
+
+ @SuppressWarnings("MissingOverride") // For compiling pre Java 9.
+ public abstract String getHandshakeApplicationProtocol();
+
+ /**
+ * Sets an application-provided ALPN protocol selector. If provided, this will override
+ * the list of protocols set by {@link #setApplicationProtocols(String[])}.
+ */
+ abstract void setApplicationProtocolSelector(ApplicationProtocolSelector selector);
+
+ /**
+ * Returns the tls-unique channel binding value for this connection, per RFC 5929. This
+ * will return {@code null} if there is no such value available, such as if the handshake
+ * has not yet completed or this connection is closed.
+ */
+ abstract byte[] getTlsUnique();
+
+ /**
+ * Exports a value derived from the TLS master secret as described in RFC 5705.
+ *
+ * @param label the label to use in calculating the exported value. This must be
+ * an ASCII-only string.
+ * @param context the application-specific context value to use in calculating the
+ * exported value. This may be {@code null} to use no application context, which is
+ * treated differently than an empty byte array.
+ * @param length the number of bytes of keying material to return.
+ * @return a value of the specified length, or {@code null} if the handshake has not yet
+ * completed or the connection has been closed.
+ * @throws SSLException if the value could not be exported.
+ */
+ abstract byte[] exportKeyingMaterial(String label, byte[] context, int length)
+ throws SSLException;
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/AbstractConscryptSocket.java b/repackaged/common/src/main/java/com/android/org/conscrypt/AbstractConscryptSocket.java
new file mode 100644
index 0000000..ea6d989
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/AbstractConscryptSocket.java
@@ -0,0 +1,800 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.Preconditions.checkArgument;
+import static com.android.org.conscrypt.Preconditions.checkNotNull;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.channels.SocketChannel;
+import java.security.PrivateKey;
+import java.util.ArrayList;
+import java.util.List;
+import javax.net.ssl.HandshakeCompletedEvent;
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+
+/**
+ * Abstract base class for all Conscrypt {@link SSLSocket} classes.
+ */
+abstract class AbstractConscryptSocket extends SSLSocket {
+ final Socket socket;
+ private final boolean autoClose;
+
+ /**
+ * The peer's DNS hostname if it was supplied during creation. Note that
+ * this may be a raw IP address, so it should be checked before use with
+ * extensions that don't use it like Server Name Indication (SNI).
+ */
+ private String peerHostname;
+
+ /**
+ * The peer's port if it was supplied during creation. Should only be set if
+ * {@link #peerHostname} is also set.
+ */
+ private final int peerPort;
+
+ private final PeerInfoProvider peerInfoProvider = new PeerInfoProvider() {
+ @Override
+ String getHostname() {
+ return AbstractConscryptSocket.this.getHostname();
+ }
+
+ @Override
+ String getHostnameOrIP() {
+ return AbstractConscryptSocket.this.getHostnameOrIP();
+ }
+
+ @Override
+ int getPort() {
+ return AbstractConscryptSocket.this.getPort();
+ }
+ };
+
+ private final List<HandshakeCompletedListener> listeners =
+ new ArrayList<HandshakeCompletedListener>(2);
+
+ /**
+ * Local cache of timeout to avoid getsockopt on every read and
+ * write for non-wrapped sockets. Note that this is not used when delegating
+ * to another socket.
+ */
+ private int readTimeoutMilliseconds;
+
+ AbstractConscryptSocket() throws IOException {
+ this.socket = this;
+ this.peerHostname = null;
+ this.peerPort = -1;
+ this.autoClose = false;
+ }
+
+ AbstractConscryptSocket(String hostname, int port) throws IOException {
+ super(hostname, port);
+ this.socket = this;
+ this.peerHostname = hostname;
+ this.peerPort = port;
+ this.autoClose = false;
+ }
+
+ AbstractConscryptSocket(InetAddress address, int port) throws IOException {
+ super(address, port);
+ this.socket = this;
+ this.peerHostname = null;
+ this.peerPort = -1;
+ this.autoClose = false;
+ }
+
+ AbstractConscryptSocket(String hostname, int port, InetAddress clientAddress, int clientPort)
+ throws IOException {
+ super(hostname, port, clientAddress, clientPort);
+ this.socket = this;
+ this.peerHostname = hostname;
+ this.peerPort = port;
+ this.autoClose = false;
+ }
+
+ AbstractConscryptSocket(InetAddress address, int port, InetAddress clientAddress,
+ int clientPort) throws IOException {
+ super(address, port, clientAddress, clientPort);
+ this.socket = this;
+ this.peerHostname = null;
+ this.peerPort = -1;
+ this.autoClose = false;
+ }
+
+ AbstractConscryptSocket(Socket socket, String hostname, int port, boolean autoClose)
+ throws IOException {
+ this.socket = checkNotNull(socket, "socket");
+ this.peerHostname = hostname;
+ this.peerPort = port;
+ this.autoClose = autoClose;
+ }
+
+ @Override
+ public final void connect(SocketAddress endpoint) throws IOException {
+ connect(endpoint, 0);
+ }
+
+ /**
+ * Try to extract the peer's hostname if it's available from the endpoint address.
+ */
+ @Override
+ public final void connect(SocketAddress endpoint, int timeout) throws IOException {
+ if (peerHostname == null && endpoint instanceof InetSocketAddress) {
+ peerHostname =
+ Platform.getHostStringFromInetSocketAddress((InetSocketAddress) endpoint);
+ }
+
+ if (isDelegating()) {
+ socket.connect(endpoint, timeout);
+ } else {
+ super.connect(endpoint, timeout);
+ }
+ }
+
+ @Override
+ public void bind(SocketAddress bindpoint) throws IOException {
+ if (isDelegating()) {
+ socket.bind(bindpoint);
+ } else {
+ super.bind(bindpoint);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("UnsynchronizedOverridesSynchronized")
+ public void close() throws IOException {
+ if (isDelegating()) {
+ if (autoClose && !socket.isClosed()) {
+ socket.close();
+ }
+ } else {
+ if (!super.isClosed()) {
+ super.close();
+ }
+ }
+ }
+
+ @Override
+ public InetAddress getInetAddress() {
+ if (isDelegating()) {
+ return socket.getInetAddress();
+ }
+ return super.getInetAddress();
+ }
+
+ @Override
+ public InetAddress getLocalAddress() {
+ if (isDelegating()) {
+ return socket.getLocalAddress();
+ }
+ return super.getLocalAddress();
+ }
+
+ @Override
+ public int getLocalPort() {
+ if (isDelegating()) {
+ return socket.getLocalPort();
+ }
+ return super.getLocalPort();
+ }
+
+ @Override
+ public SocketAddress getRemoteSocketAddress() {
+ if (isDelegating()) {
+ return socket.getRemoteSocketAddress();
+ }
+ return super.getRemoteSocketAddress();
+ }
+
+ @Override
+ public SocketAddress getLocalSocketAddress() {
+ if (isDelegating()) {
+ return socket.getLocalSocketAddress();
+ }
+ return super.getLocalSocketAddress();
+ }
+
+ @Override
+ public final int getPort() {
+ if (isDelegating()) {
+ return socket.getPort();
+ }
+
+ if (peerPort != -1) {
+ // Return the port that has been explicitly set in the constructor.
+ return peerPort;
+ }
+ return super.getPort();
+ }
+
+ @Override
+ public void addHandshakeCompletedListener(HandshakeCompletedListener listener) {
+ checkArgument(listener != null, "Provided listener is null");
+ listeners.add(listener);
+ }
+
+ @Override
+ public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) {
+ checkArgument(listener != null, "Provided listener is null");
+ if (!listeners.remove(listener)) {
+ throw new IllegalArgumentException("Provided listener is not registered");
+ }
+ }
+
+ /* @Override */
+ public FileDescriptor getFileDescriptor$() {
+ if (isDelegating()) {
+ return Platform.getFileDescriptor(socket);
+ }
+ return Platform.getFileDescriptorFromSSLSocket(this);
+ }
+
+ @Override
+ @SuppressWarnings("UnsynchronizedOverridesSynchronized")
+ public final void setSoTimeout(int readTimeoutMilliseconds) throws SocketException {
+ if (isDelegating()) {
+ socket.setSoTimeout(readTimeoutMilliseconds);
+ } else {
+ super.setSoTimeout(readTimeoutMilliseconds);
+ this.readTimeoutMilliseconds = readTimeoutMilliseconds;
+ }
+ }
+
+ @Override
+ @SuppressWarnings("UnsynchronizedOverridesSynchronized")
+ public final int getSoTimeout() throws SocketException {
+ if (isDelegating()) {
+ return socket.getSoTimeout();
+ }
+ return readTimeoutMilliseconds;
+ }
+
+ @Override
+ public final void sendUrgentData(int data) throws IOException {
+ throw new SocketException("Method sendUrgentData() is not supported.");
+ }
+
+ @Override
+ public final void setOOBInline(boolean on) throws SocketException {
+ throw new SocketException("Method setOOBInline() is not supported.");
+ }
+
+ @Override
+ public boolean getOOBInline() throws SocketException {
+ return false;
+ }
+
+ @Override
+ public SocketChannel getChannel() {
+ // TODO(nmittler): Support channels?
+ return null;
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ if (isDelegating()) {
+ return socket.getInputStream();
+ }
+ return super.getInputStream();
+ }
+
+ @Override
+ public OutputStream getOutputStream() throws IOException {
+ if (isDelegating()) {
+ return socket.getOutputStream();
+ }
+ return super.getOutputStream();
+ }
+
+ @Override
+ public void setTcpNoDelay(boolean on) throws SocketException {
+ if (isDelegating()) {
+ socket.setTcpNoDelay(on);
+ } else {
+ super.setTcpNoDelay(on);
+ }
+ }
+
+ @Override
+ public boolean getTcpNoDelay() throws SocketException {
+ if (isDelegating()) {
+ return socket.getTcpNoDelay();
+ }
+ return super.getTcpNoDelay();
+ }
+
+ @Override
+ public void setSoLinger(boolean on, int linger) throws SocketException {
+ if (isDelegating()) {
+ socket.setSoLinger(on, linger);
+ } else {
+ super.setSoLinger(on, linger);
+ }
+ }
+
+ @Override
+ public int getSoLinger() throws SocketException {
+ if (isDelegating()) {
+ return socket.getSoLinger();
+ }
+ return super.getSoLinger();
+ }
+
+ @Override
+ @SuppressWarnings("UnsynchronizedOverridesSynchronized")
+ public void setSendBufferSize(int size) throws SocketException {
+ if (isDelegating()) {
+ socket.setSendBufferSize(size);
+ } else {
+ super.setSendBufferSize(size);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("UnsynchronizedOverridesSynchronized")
+ public int getSendBufferSize() throws SocketException {
+ if (isDelegating()) {
+ return socket.getSendBufferSize();
+ }
+ return super.getSendBufferSize();
+ }
+
+ @Override
+ @SuppressWarnings("UnsynchronizedOverridesSynchronized")
+ public void setReceiveBufferSize(int size) throws SocketException {
+ if (isDelegating()) {
+ socket.setReceiveBufferSize(size);
+ } else {
+ super.setReceiveBufferSize(size);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("UnsynchronizedOverridesSynchronized")
+ public int getReceiveBufferSize() throws SocketException {
+ if (isDelegating()) {
+ return socket.getReceiveBufferSize();
+ }
+ return super.getReceiveBufferSize();
+ }
+
+ @Override
+ public void setKeepAlive(boolean on) throws SocketException {
+ if (isDelegating()) {
+ socket.setKeepAlive(on);
+ } else {
+ super.setKeepAlive(on);
+ }
+ }
+
+ @Override
+ public boolean getKeepAlive() throws SocketException {
+ if (isDelegating()) {
+ return socket.getKeepAlive();
+ }
+ return super.getKeepAlive();
+ }
+
+ @Override
+ public void setTrafficClass(int tc) throws SocketException {
+ if (isDelegating()) {
+ socket.setTrafficClass(tc);
+ } else {
+ super.setTrafficClass(tc);
+ }
+ }
+
+ @Override
+ public int getTrafficClass() throws SocketException {
+ if (isDelegating()) {
+ return socket.getTrafficClass();
+ }
+ return super.getTrafficClass();
+ }
+
+ @Override
+ public void setReuseAddress(boolean on) throws SocketException {
+ if (isDelegating()) {
+ socket.setReuseAddress(on);
+ } else {
+ super.setReuseAddress(on);
+ }
+ }
+
+ @Override
+ public boolean getReuseAddress() throws SocketException {
+ if (isDelegating()) {
+ return socket.getReuseAddress();
+ }
+ return super.getReuseAddress();
+ }
+
+ @Override
+ public void shutdownInput() throws IOException {
+ if (isDelegating()) {
+ socket.shutdownInput();
+ } else {
+ super.shutdownInput();
+ }
+ }
+
+ @Override
+ public void shutdownOutput() throws IOException {
+ if (isDelegating()) {
+ socket.shutdownOutput();
+ } else {
+ super.shutdownOutput();
+ }
+ }
+
+ @Override
+ public boolean isConnected() {
+ if (isDelegating()) {
+ return socket.isConnected();
+ }
+ return super.isConnected();
+ }
+
+ @Override
+ public boolean isBound() {
+ if (isDelegating()) {
+ return socket.isBound();
+ }
+ return super.isBound();
+ }
+
+ @Override
+ public boolean isClosed() {
+ if (isDelegating()) {
+ return socket.isClosed();
+ }
+ return super.isClosed();
+ }
+
+ @Override
+ public boolean isInputShutdown() {
+ if (isDelegating()) {
+ return socket.isInputShutdown();
+ }
+ return super.isInputShutdown();
+ }
+
+ @Override
+ public boolean isOutputShutdown() {
+ if (isDelegating()) {
+ return socket.isOutputShutdown();
+ }
+ return super.isOutputShutdown();
+ }
+
+ @Override
+ public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
+ if (isDelegating()) {
+ socket.setPerformancePreferences(connectionTime, latency, bandwidth);
+ } else {
+ super.setPerformancePreferences(connectionTime, latency, bandwidth);
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("SSL socket over ");
+ if (isDelegating()) {
+ builder.append(socket.toString());
+ } else {
+ builder.append(super.toString());
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Returns the hostname that was supplied during socket creation. No DNS resolution is
+ * attempted before returning the hostname.
+ */
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ String getHostname() {
+ return peerHostname;
+ }
+
+ /**
+ * This method enables Server Name Indication
+ *
+ * @param hostname the desired SNI hostname, or null to disable
+ */
+ @android.compat.annotation.
+ UnsupportedAppUsage(maxTargetSdk = dalvik.annotation.compat.VersionCodes.Q,
+ publicAlternatives = "Use {@code javax.net.ssl.SSLParameters#setServerNames}.")
+ void
+ setHostname(String hostname) {
+ peerHostname = hostname;
+ }
+
+ /**
+ * For the purposes of an SSLSession, we want a way to represent the supplied hostname
+ * or the IP address in a textual representation. We do not want to perform reverse DNS
+ * lookups on this address.
+ */
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ String getHostnameOrIP() {
+ if (peerHostname != null) {
+ return peerHostname;
+ }
+
+ InetAddress peerAddress = getInetAddress();
+ if (peerAddress != null) {
+ return Platform.getOriginalHostNameFromInetAddress(peerAddress);
+ }
+
+ return null;
+ }
+
+ /**
+ * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
+ */
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ void setSoWriteTimeout(int writeTimeoutMilliseconds) throws SocketException {
+ throw new SocketException("Method setSoWriteTimeout() is not supported.");
+ }
+
+ /**
+ * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
+ */
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ int getSoWriteTimeout() throws SocketException {
+ return 0;
+ }
+
+ /**
+ * Set the handshake timeout on this socket. This timeout is specified in
+ * milliseconds and will be used only during the handshake process.
+ */
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketException {
+ throw new SocketException("Method setHandshakeTimeout() is not supported.");
+ }
+
+ final void checkOpen() throws SocketException {
+ if (isClosed()) {
+ throw new SocketException("Socket is closed");
+ }
+ }
+
+ final PeerInfoProvider peerInfoProvider() {
+ return peerInfoProvider;
+ }
+
+ /**
+ * Called by {@link #notifyHandshakeCompletedListeners()} to get the currently active session.
+ * Unlike {@link #getSession()}, this method must not block.
+ */
+ abstract SSLSession getActiveSession();
+
+ abstract void setApplicationProtocolSelector(ApplicationProtocolSelectorAdapter selector);
+
+ final void notifyHandshakeCompletedListeners() {
+ List<HandshakeCompletedListener> listenersCopy = new ArrayList<>(listeners);
+ if (!listenersCopy.isEmpty()) {
+ // notify the listeners
+ HandshakeCompletedEvent event = new HandshakeCompletedEvent(this, getActiveSession());
+ for (HandshakeCompletedListener listener : listenersCopy) {
+ try {
+ listener.handshakeCompleted(event);
+ } catch (RuntimeException e) {
+ // The RI runs the handlers in a separate thread,
+ // which we do not. But we try to preserve their
+ // behavior of logging a problem and not killing
+ // the handshaking thread just because a listener
+ // has a problem.
+ Thread thread = Thread.currentThread();
+ thread.getUncaughtExceptionHandler().uncaughtException(thread, e);
+ }
+ }
+ }
+ }
+
+ private boolean isDelegating() {
+ // Checking for null to handle the case of calling virtual methods in the super class
+ // constructor.
+ return socket != null && socket != this;
+ }
+ /* @Override */
+ @SuppressWarnings("MissingOverride") // For compilation with Java 6.
+ public abstract SSLSession getHandshakeSession();
+
+ /**
+ * This method enables session ticket support.
+ *
+ * @param useSessionTickets True to enable session tickets
+ */
+ @android.compat.annotation.
+ UnsupportedAppUsage(maxTargetSdk = dalvik.annotation.compat.VersionCodes.Q,
+ publicAlternatives = "Use {@link android.net.ssl.SSLSockets#setUseSessionTickets}.")
+ abstract void
+ setUseSessionTickets(boolean useSessionTickets);
+
+ /**
+ * Enables/disables TLS Channel ID for this server socket.
+ *
+ * <p>This method needs to be invoked before the handshake starts.
+ *
+ * @throws IllegalStateException if this is a client socket or if the handshake has already
+ * started.
+ */
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ abstract void setChannelIdEnabled(boolean enabled);
+
+ /**
+ * Gets the TLS Channel ID for this server socket. Channel ID is only available once the
+ * handshake completes.
+ *
+ * @return channel ID or {@code null} if not available.
+ *
+ * @throws IllegalStateException if this is a client socket or if the handshake has not yet
+ * completed.
+ * @throws SSLException if channel ID is available but could not be obtained.
+ */
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ abstract byte[] getChannelId() throws SSLException;
+
+ /**
+ * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client socket.
+ *
+ * <p>This method needs to be invoked before the handshake starts.
+ *
+ * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables
+ * TLS Channel ID). The private key must be an Elliptic Curve (EC) key based on the NIST
+ * P-256 curve (aka SECG secp256r1 or ANSI X9.62 prime256v1).
+ *
+ * @throws IllegalStateException if this is a server socket or if the handshake has already
+ * started.
+ */
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ abstract void setChannelIdPrivateKey(PrivateKey privateKey);
+
+ /**
+ * Returns null always for backward compatibility.
+ * @deprecated NPN is not supported
+ */
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ @Deprecated
+ byte[] getNpnSelectedProtocol() {
+ return null;
+ }
+
+ /**
+ * This method does nothing and is kept for backward compatibility.
+ * @deprecated NPN is not supported
+ */
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ @Deprecated
+ void setNpnProtocols(byte[] npnProtocols) {}
+
+ /**
+ * Returns the protocol agreed upon by client and server, or {@code null} if
+ * no protocol was agreed upon.
+ *
+ * @deprecated use {@link #getApplicationProtocol()} instead.
+ */
+ @android.compat.annotation.
+ UnsupportedAppUsage(maxTargetSdk = dalvik.annotation.compat.VersionCodes.Q,
+ publicAlternatives = "Use {@code javax.net.ssl.SSLSocket#getApplicationProtocol()}.")
+ @Deprecated
+ abstract byte[]
+ getAlpnSelectedProtocol();
+
+ /**
+ * Sets the list of ALPN protocols. This method internally converts the protocols to their
+ * wire-format form.
+ *
+ * @param alpnProtocols the list of ALPN protocols
+ * @deprecated use {@link #setApplicationProtocols(String[])} instead.
+ */
+ @android.compat.annotation.
+ UnsupportedAppUsage(maxTargetSdk = dalvik.annotation.compat.VersionCodes.Q,
+ publicAlternatives =
+ "Use {@code javax.net.ssl.SSLParameters#setApplicationProtocols(java.lang.String[])}.")
+ @Deprecated
+ abstract void
+ setAlpnProtocols(String[] alpnProtocols);
+
+ /**
+ * Alternate version of {@link #setAlpnProtocols(String[])} that directly sets the list of
+ * ALPN in the wire-format form used by BoringSSL (length-prefixed 8-bit strings).
+ * Requires that all strings be encoded with US-ASCII.
+ *
+ * @param alpnProtocols the encoded form of the ALPN protocol list
+ * @deprecated Use {@link #setApplicationProtocols(String[])} instead.
+ */
+ @android.compat.annotation.
+ UnsupportedAppUsage(maxTargetSdk = dalvik.annotation.compat.VersionCodes.Q,
+ publicAlternatives =
+ "Use {@code javax.net.ssl.SSLParameters#setApplicationProtocols(java.lang.String[])}.")
+ @Deprecated
+ abstract void
+ setAlpnProtocols(byte[] alpnProtocols);
+
+ /**
+ * Sets the list of ALPN protocols.
+ *
+ * @param protocols the list of ALPN protocols
+ */
+ @android.compat.annotation.
+ UnsupportedAppUsage(maxTargetSdk = dalvik.annotation.compat.VersionCodes.Q,
+ publicAlternatives =
+ "Use {@code javax.net.ssl.SSLParameters#setApplicationProtocols(java.lang.String[])}.")
+ @SuppressWarnings("MissingOverride") // For compiling pre Java 9.
+ abstract void
+ setApplicationProtocols(String[] protocols);
+
+ /**
+ * Returns the list of supported ALPN protocols.
+ */
+ @android.compat.annotation.
+ UnsupportedAppUsage(maxTargetSdk = dalvik.annotation.compat.VersionCodes.Q,
+ publicAlternatives =
+ "Use {@code javax.net.ssl.SSLParameters#getApplicationProtocols()}.")
+ @SuppressWarnings("MissingOverride") // For compiling pre Java 9.
+ abstract String[]
+ getApplicationProtocols();
+
+ @SuppressWarnings("MissingOverride") // For compiling pre Java 9.
+ public abstract String getApplicationProtocol();
+
+ @SuppressWarnings("MissingOverride") // For compiling pre Java 9.
+ public abstract String getHandshakeApplicationProtocol();
+
+ /**
+ * Sets an application-provided ALPN protocol selector. If provided, this will override
+ * the list of protocols set by {@link #setApplicationProtocols(String[])}.
+ */
+ abstract void setApplicationProtocolSelector(ApplicationProtocolSelector selector);
+
+ /**
+ * Returns the tls-unique channel binding value for this connection, per RFC 5929. This
+ * will return {@code null} if there is no such value available, such as if the handshake
+ * has not yet completed or this connection is closed.
+ */
+ abstract byte[] getTlsUnique();
+
+ /**
+ * Exports a value derived from the TLS master secret as described in RFC 5705.
+ *
+ * @param label the label to use in calculating the exported value. This must be
+ * an ASCII-only string.
+ * @param context the application-specific context value to use in calculating the
+ * exported value. This may be {@code null} to use no application context, which is
+ * treated differently than an empty byte array.
+ * @param length the number of bytes of keying material to return.
+ * @return a value of the specified length, or {@code null} if the handshake has not yet
+ * completed or the connection has been closed.
+ * @throws SSLException if the value could not be exported.
+ */
+ abstract byte[] exportKeyingMaterial(String label, byte[] context, int length)
+ throws SSLException;
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/AbstractSessionContext.java b/repackaged/common/src/main/java/com/android/org/conscrypt/AbstractSessionContext.java
new file mode 100644
index 0000000..6469d95
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/AbstractSessionContext.java
@@ -0,0 +1,304 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+
+/**
+ * Supports SSL session caches.
+ */
+abstract class AbstractSessionContext implements SSLSessionContext {
+
+ /**
+ * Maximum lifetime of a session (in seconds) after which it's considered invalid and should not
+ * be used to for new connections.
+ */
+ private static final int DEFAULT_SESSION_TIMEOUT_SECONDS = 8 * 60 * 60;
+
+ private volatile int maximumSize;
+ private volatile int timeout = DEFAULT_SESSION_TIMEOUT_SECONDS;
+
+ final long sslCtxNativePointer = NativeCrypto.SSL_CTX_new();
+
+ private final Map<ByteArray, NativeSslSession> sessions =
+ new LinkedHashMap<ByteArray, NativeSslSession>() {
+ @Override
+ protected boolean removeEldestEntry(
+ Map.Entry<ByteArray, NativeSslSession> eldest) {
+ // NOTE: does not take into account any session that may have become
+ // invalid.
+ if (maximumSize > 0 && size() > maximumSize) {
+ // Let the subclass know.
+ onBeforeRemoveSession(eldest.getValue());
+ return true;
+ }
+ return false;
+ }
+ };
+
+ /**
+ * Constructs a new session context.
+ *
+ * @param maximumSize of cache
+ */
+ AbstractSessionContext(int maximumSize) {
+ this.maximumSize = maximumSize;
+ }
+
+ /**
+ * This method is provided for API-compatibility only, not intended for use. No guarantees
+ * are made WRT performance.
+ */
+ @Override
+ public final Enumeration<byte[]> getIds() {
+ // Make a copy of the IDs.
+ final Iterator<NativeSslSession> iter;
+ synchronized (sessions) {
+ iter = Arrays.asList(sessions.values().toArray(new NativeSslSession[0])).iterator();
+ }
+ return new Enumeration<byte[]>() {
+ private NativeSslSession next;
+
+ @Override
+ public boolean hasMoreElements() {
+ if (next != null) {
+ return true;
+ }
+ while (iter.hasNext()) {
+ NativeSslSession session = iter.next();
+ if (session.isValid()) {
+ next = session;
+ return true;
+ }
+ }
+ next = null;
+ return false;
+ }
+
+ @Override
+ public byte[] nextElement() {
+ if (hasMoreElements()) {
+ byte[] id = next.getId();
+ next = null;
+ return id;
+ }
+ throw new NoSuchElementException();
+ }
+ };
+ }
+
+ /**
+ * This is provided for API-compatibility only, not intended for use. No guarantees are
+ * made WRT performance or the validity of the returned session.
+ */
+ @Override
+ public final SSLSession getSession(byte[] sessionId) {
+ if (sessionId == null) {
+ throw new NullPointerException("sessionId");
+ }
+ ByteArray key = new ByteArray(sessionId);
+ NativeSslSession session;
+ synchronized (sessions) {
+ session = sessions.get(key);
+ }
+ if (session != null && session.isValid()) {
+ return session.toSSLSession();
+ }
+ return null;
+ }
+
+ @Override
+ public final int getSessionCacheSize() {
+ return maximumSize;
+ }
+
+ @Override
+ public final int getSessionTimeout() {
+ return timeout;
+ }
+
+ @Override
+ public final void setSessionTimeout(int seconds) throws IllegalArgumentException {
+ if (seconds < 0) {
+ throw new IllegalArgumentException("seconds < 0");
+ }
+
+ synchronized (sessions) {
+ // Set the timeout on this context.
+ timeout = seconds;
+ // setSessionTimeout(0) is defined to remove the timeout, but passing 0
+ // to SSL_CTX_set_timeout in BoringSSL sets it to the default timeout instead.
+ // Pass INT_MAX seconds (68 years), since that's equivalent for practical purposes.
+ if (seconds > 0) {
+ NativeCrypto.SSL_CTX_set_timeout(sslCtxNativePointer, this, seconds);
+ } else {
+ NativeCrypto.SSL_CTX_set_timeout(sslCtxNativePointer, this, Integer.MAX_VALUE);
+ }
+
+ Iterator<NativeSslSession> i = sessions.values().iterator();
+ while (i.hasNext()) {
+ NativeSslSession session = i.next();
+ // SSLSession's know their context and consult the
+ // timeout as part of their validity condition.
+ if (!session.isValid()) {
+ // Let the subclass know.
+ onBeforeRemoveSession(session);
+ i.remove();
+ }
+ }
+ }
+ }
+
+ @Override
+ public final void setSessionCacheSize(int size) throws IllegalArgumentException {
+ if (size < 0) {
+ throw new IllegalArgumentException("size < 0");
+ }
+
+ int oldMaximum = maximumSize;
+ maximumSize = size;
+
+ // Trim cache to size if necessary.
+ if (size < oldMaximum) {
+ trimToSize();
+ }
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ protected void finalize() throws Throwable {
+ try {
+ NativeCrypto.SSL_CTX_free(sslCtxNativePointer, this);
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * Adds the given session to the cache.
+ */
+ final void cacheSession(NativeSslSession session) {
+ byte[] id = session.getId();
+ if (id == null || id.length == 0) {
+ return;
+ }
+
+ synchronized (sessions) {
+ ByteArray key = new ByteArray(id);
+ if (sessions.containsKey(key)) {
+ removeSession(sessions.get(key));
+ }
+ // Let the subclass know.
+ onBeforeAddSession(session);
+
+ sessions.put(key, session);
+ }
+ }
+
+ /**
+ * Removes the given session from the cache.
+ */
+ final void removeSession(NativeSslSession session) {
+ byte[] id = session.getId();
+ if (id == null || id.length == 0) {
+ return;
+ }
+
+ onBeforeRemoveSession(session);
+
+ ByteArray key = new ByteArray(id);
+ synchronized (sessions) {
+ sessions.remove(key);
+ }
+ }
+
+ /**
+ * Called for server sessions only. Retrieves the session by its ID. Overridden by
+ * {@link ServerSessionContext} to
+ */
+ final NativeSslSession getSessionFromCache(byte[] sessionId) {
+ if (sessionId == null) {
+ return null;
+ }
+
+ // First, look in the in-memory cache.
+ NativeSslSession session;
+ synchronized (sessions) {
+ session = sessions.get(new ByteArray(sessionId));
+ }
+ if (session != null && session.isValid()) {
+ if (session.isSingleUse()) {
+ removeSession(session);
+ }
+ return session;
+ }
+
+ // Look in persistent cache. We don't currently delete sessions from the persistent
+ // cache, so we may find a multi-use (aka TLS 1.2) session after having received and
+ // then used up one or more single-use (aka TLS 1.3) sessions.
+ return getSessionFromPersistentCache(sessionId);
+ }
+
+ /**
+ * Called when the given session is about to be added. Used by {@link ClientSessionContext} to
+ * update its host-and-port based cache.
+ *
+ * <p>Visible for extension only, not intended to be called directly.
+ */
+ abstract void onBeforeAddSession(NativeSslSession session);
+
+ /**
+ * Called when a session is about to be removed. Used by {@link ClientSessionContext}
+ * to update its host-and-port based cache.
+ *
+ * <p>Visible for extension only, not intended to be called directly.
+ */
+ abstract void onBeforeRemoveSession(NativeSslSession session);
+
+ /**
+ * Called for server sessions only. Retrieves the session by ID from the persistent cache.
+ *
+ * <p>Visible for extension only, not intended to be called directly.
+ */
+ abstract NativeSslSession getSessionFromPersistentCache(byte[] sessionId);
+
+ /**
+ * Makes sure cache size is < maximumSize.
+ */
+ private void trimToSize() {
+ synchronized (sessions) {
+ int size = sessions.size();
+ if (size > maximumSize) {
+ int removals = size - maximumSize;
+ Iterator<NativeSslSession> i = sessions.values().iterator();
+ while (removals-- > 0) {
+ NativeSslSession session = i.next();
+ onBeforeRemoveSession(session);
+ i.remove();
+ }
+ }
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ActiveSession.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ActiveSession.java
new file mode 100644
index 0000000..3ad5950
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ActiveSession.java
@@ -0,0 +1,345 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.Preconditions.checkNotNull;
+
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.List;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSessionContext;
+
+/**
+ * A session that is dedicated a single connection and operates directly on the underlying
+ * {@code SSL}.
+ */
+final class ActiveSession implements ConscryptSession {
+ private final NativeSsl ssl;
+ private final AbstractSessionContext sessionContext;
+ private byte[] id;
+ private long creationTime;
+ private String protocol;
+ private String applicationProtocol;
+ private String peerHost;
+ private int peerPort = -1;
+ private long lastAccessedTime = 0;
+ @SuppressWarnings("deprecation")
+ private volatile javax.security.cert.X509Certificate[] peerCertificateChain;
+ private X509Certificate[] localCertificates;
+ private X509Certificate[] peerCertificates;
+ private byte[] peerCertificateOcspData;
+ private byte[] peerTlsSctData;
+
+ ActiveSession(NativeSsl ssl, AbstractSessionContext sessionContext) {
+ this.ssl = checkNotNull(ssl, "ssl");
+ this.sessionContext = checkNotNull(sessionContext, "sessionContext");
+ }
+
+ @Override
+ public byte[] getId() {
+ if (id == null) {
+ synchronized (ssl) {
+ id = ssl.getSessionId();
+ }
+ }
+ return id != null ? id.clone() : EmptyArray.BYTE;
+ }
+
+ @Override
+ public SSLSessionContext getSessionContext() {
+ return isValid() ? sessionContext : null;
+ }
+
+ @Override
+ public long getCreationTime() {
+ if (creationTime == 0) {
+ synchronized (ssl) {
+ creationTime = ssl.getTime();
+ }
+ }
+ return creationTime;
+ }
+
+ /**
+ * Returns the last time this SSL session was accessed. Accessing
+ * here is to mean that a new connection with the same SSL context data was
+ * established.
+ *
+ * @return the session's last access time in milliseconds since the epoch
+ */
+ // TODO(nathanmittler): Does lastAccessedTime need to account for session reuse?
+ @Override
+ public long getLastAccessedTime() {
+ return lastAccessedTime == 0 ? getCreationTime() : lastAccessedTime;
+ }
+
+ void setLastAccessedTime(long accessTimeMillis) {
+ lastAccessedTime = accessTimeMillis;
+ }
+
+ /**
+ * Returns the OCSP stapled response. Returns a copy of the internal arrays.
+ *
+ * The method signature matches
+ * <a
+ * href="http://download.java.net/java/jdk9/docs/api/javax/net/ssl/ExtendedSSLSession.html#getStatusResponses--">Java
+ * 9</a>.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc6066">RFC 6066</a>
+ * @see <a href="https://tools.ietf.org/html/rfc6961">RFC 6961</a>
+ */
+ @Override
+ public List<byte[]> getStatusResponses() {
+ if (peerCertificateOcspData == null) {
+ return Collections.emptyList();
+ }
+
+ return Collections.singletonList(peerCertificateOcspData.clone());
+ }
+
+ /**
+ * Returns the signed certificate timestamp (SCT) received from the peer. Returns a
+ * copy of the internal array.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc6962">RFC 6962</a>
+ */
+ @Override
+ public byte[] getPeerSignedCertificateTimestamp() {
+ if (peerTlsSctData == null) {
+ return null;
+ }
+ return peerTlsSctData.clone();
+ }
+
+ @Override
+ public String getRequestedServerName() {
+ synchronized (ssl) {
+ return ssl.getRequestedServerName();
+ }
+ }
+
+ @Override
+ public void invalidate() {
+ synchronized (ssl) {
+ ssl.setTimeout(0L);
+ }
+ }
+
+ @Override
+ public boolean isValid() {
+ synchronized (ssl) {
+ long creationTimeMillis = ssl.getTime();
+ long timeoutMillis = ssl.getTimeout();
+ return (System.currentTimeMillis() - timeoutMillis) < creationTimeMillis;
+ }
+ }
+
+ @Override
+ public void putValue(String name, Object value) {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ExternalSession.");
+ }
+
+ @Override
+ public Object getValue(String name) {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ExternalSession.");
+ }
+
+ @Override
+ public void removeValue(String name) {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ExternalSession.");
+ }
+
+ @Override
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ExternalSession.");
+ }
+
+ @Override
+ public X509Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ checkPeerCertificatesPresent();
+ return peerCertificates.clone();
+ }
+
+ @Override
+ public Certificate[] getLocalCertificates() {
+ // Local certificates never change, so set them locally as soon as they're available
+ if (localCertificates == null) {
+ synchronized (ssl) {
+ localCertificates = ssl.getLocalCertificates();
+ }
+ }
+ return localCertificates == null ? null : localCertificates.clone();
+ }
+
+ /**
+ * Returns the certificate(s) of the peer in this SSL session
+ * used in the handshaking phase of the connection.
+ * Please notice hat this method is superseded by
+ * <code>getPeerCertificates()</code>.
+ * @return an array of X509 certificates (the peer's one first and then
+ * eventually that of the certification authority) or null if no
+ * certificate were used during the SSL connection.
+ * @throws SSLPeerUnverifiedException if either a non-X.509 certificate
+ * was used (i.e. Kerberos certificates) or the peer could not
+ * be verified.
+ */
+ @Override
+ @SuppressWarnings("deprecation") // Public API
+ public javax.security.cert.X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ if (!Platform.isJavaxCertificateSupported()) {
+ throw new UnsupportedOperationException("Use getPeerCertificates() instead");
+ }
+
+ checkPeerCertificatesPresent();
+ // TODO(nathanmittler): Should we clone?
+ javax.security.cert.X509Certificate[] result = peerCertificateChain;
+ if (result == null) {
+ // single-check idiom
+ peerCertificateChain = result = SSLUtils.toCertificateChain(peerCertificates);
+ }
+ return result;
+ }
+
+ @Override
+ public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+ checkPeerCertificatesPresent();
+ return peerCertificates[0].getSubjectX500Principal();
+ }
+
+ @Override
+ public Principal getLocalPrincipal() {
+ X509Certificate[] certs = (X509Certificate[]) getLocalCertificates();
+ if (certs != null && certs.length > 0) {
+ return certs[0].getSubjectX500Principal();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public String getCipherSuite() {
+ // Always get the Cipher from the SSL directly since it may have changed during a
+ // renegotiation.
+ String cipher;
+ synchronized (ssl) {
+ cipher = ssl.getCipherSuite();
+ }
+ return cipher == null ? SSLNullSession.INVALID_CIPHER : cipher;
+ }
+
+ @Override
+ public String getProtocol() {
+ String protocol = this.protocol;
+ if (protocol == null) {
+ synchronized (ssl) {
+ protocol = ssl.getVersion();
+ }
+ this.protocol = protocol;
+ }
+ return protocol;
+ }
+
+ @Override
+ public String getPeerHost() {
+ return peerHost;
+ }
+
+ @Override
+ public int getPeerPort() {
+ return peerPort;
+ }
+
+ @Override
+ public int getPacketBufferSize() {
+ return NativeConstants.SSL3_RT_MAX_PACKET_SIZE;
+ }
+
+ @Override
+ public int getApplicationBufferSize() {
+ return NativeConstants.SSL3_RT_MAX_PLAIN_LENGTH;
+ }
+
+ @Override
+ public String getApplicationProtocol() {
+ String applicationProtocol = this.applicationProtocol;
+ if (applicationProtocol == null) {
+ synchronized (ssl) {
+ applicationProtocol = SSLUtils.toProtocolString(ssl.getApplicationProtocol());
+ }
+ this.applicationProtocol = applicationProtocol;
+ }
+ return applicationProtocol;
+ }
+
+ /**
+ * Configures the peer information once it has been received by the handshake.
+ */
+ void onPeerCertificatesReceived(
+ String peerHost, int peerPort, X509Certificate[] peerCertificates) {
+ configurePeer(peerHost, peerPort, peerCertificates);
+ }
+
+ private void configurePeer(String peerHost, int peerPort, X509Certificate[] peerCertificates) {
+ this.peerHost = peerHost;
+ this.peerPort = peerPort;
+ this.peerCertificates = peerCertificates;
+ synchronized (ssl) {
+ this.peerCertificateOcspData = ssl.getPeerCertificateOcspData();
+ this.peerTlsSctData = ssl.getPeerTlsSctData();
+ }
+ }
+
+ /**
+ * Updates the cached peer certificate after the handshake has completed
+ * (or entered False Start).
+ */
+ void onPeerCertificateAvailable(String peerHost, int peerPort) throws CertificateException {
+ synchronized (ssl) {
+ id = null;
+ if (localCertificates == null) {
+ this.localCertificates = ssl.getLocalCertificates();
+ }
+ if (this.peerCertificates == null) {
+ // When resuming a session, the cert_verify_callback (which calls
+ // onPeerCertificatesReceived) isn't called by BoringSSL during the handshake
+ // because it presumes the certs were verified in the previous connection on that
+ // session, leaving us without the peer certificates. If that happens, fetch them
+ // explicitly.
+ configurePeer(peerHost, peerPort, ssl.getPeerCertificates());
+ }
+ }
+ }
+
+ /**
+ * Throw SSLPeerUnverifiedException on null or empty peerCertificates array
+ */
+ private void checkPeerCertificatesPresent() throws SSLPeerUnverifiedException {
+ if (peerCertificates == null || peerCertificates.length == 0) {
+ throw new SSLPeerUnverifiedException("No peer certificates");
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/AddressUtils.java b/repackaged/common/src/main/java/com/android/org/conscrypt/AddressUtils.java
new file mode 100644
index 0000000..bdd7c97
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/AddressUtils.java
@@ -0,0 +1,62 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2014 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.util.regex.Pattern;
+
+/**
+ * Utilities to check whether IP addresses meet some criteria.
+ */
+final class AddressUtils {
+ /*
+ * Regex that matches valid IPv4 and IPv6 addresses.
+ */
+ private static final String IP_PATTERN =
+ "^(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9]))|"
+ + "(?i:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:)))(?:%.+)?$";
+
+ private static Pattern ipPattern;
+
+ private AddressUtils() {}
+
+ /**
+ * Returns true when the supplied hostname is valid for SNI purposes.
+ */
+ static boolean isValidSniHostname(String sniHostname) {
+ if (sniHostname == null) {
+ return false;
+ }
+
+ // Must be a FQDN that does not have a trailing dot.
+ return (sniHostname.equalsIgnoreCase("localhost") || sniHostname.indexOf('.') != -1)
+ && !isLiteralIpAddress(sniHostname) && !sniHostname.endsWith(".")
+ && sniHostname.indexOf('\0') == -1;
+ }
+
+ /**
+ * Returns true if the supplied hostname is an literal IP address.
+ */
+ static boolean isLiteralIpAddress(String hostname) {
+ /* This is here for backwards compatibility for pre-Honeycomb devices. */
+ Pattern ipPattern = AddressUtils.ipPattern;
+ if (ipPattern == null) {
+ AddressUtils.ipPattern = ipPattern = Pattern.compile(IP_PATTERN);
+ }
+ return ipPattern.matcher(hostname).matches();
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/AllocatedBuffer.java b/repackaged/common/src/main/java/com/android/org/conscrypt/AllocatedBuffer.java
new file mode 100644
index 0000000..cc1bc07
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/AllocatedBuffer.java
@@ -0,0 +1,88 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/*
+ * Copyright 2013 The Netty Project
+ *
+ * The Netty Project licenses this file to you 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.
+ */
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.Preconditions.checkNotNull;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A buffer that was allocated by a {@link BufferAllocator}.
+ * @hide This class is not part of the Android public SDK API
+ */
+@ExperimentalApi
+public abstract class AllocatedBuffer {
+ /**
+ * Returns the {@link ByteBuffer} that backs this buffer.
+ */
+ public abstract ByteBuffer nioBuffer();
+
+ /**
+ * Returns the current instance for backward compatibility.
+ *
+ * @deprecated this method is not used
+ */
+ @Deprecated
+ public AllocatedBuffer retain() {
+ // Do nothing.
+ return this;
+ }
+
+ /**
+ * Returns the delegate {@link ByteBuffer} for reuse or garbage collection.
+ *
+ * @return this {@link AllocatedBuffer} instance
+ */
+ public abstract AllocatedBuffer release();
+
+ /**
+ * Creates a new {@link AllocatedBuffer} that is backed by the given {@link ByteBuffer}.
+ */
+ public static AllocatedBuffer wrap(final ByteBuffer buffer) {
+ checkNotNull(buffer, "buffer");
+
+ return new AllocatedBuffer() {
+
+ @Override
+ public ByteBuffer nioBuffer() {
+ return buffer;
+ }
+
+ @Override
+ public AllocatedBuffer release() {
+ // Do nothing.
+ return this;
+ }
+ };
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ApplicationProtocolSelector.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ApplicationProtocolSelector.java
new file mode 100644
index 0000000..6ac4713
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ApplicationProtocolSelector.java
@@ -0,0 +1,58 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.util.List;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLSocket;
+
+/**
+ * Server-side selector for the ALPN protocol. This is a backward-compatibility shim for Java 9's
+ * new {@code setHandshakeApplicationProtocolSelector} API, which takes a {@code BiFunction}
+ * (available in Java 8+). This interface is provided to support protocol selection in Java < 8.
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class ApplicationProtocolSelector {
+ /**
+ * Selects the appropriate ALPN protocol.
+ *
+ * @param engine the server-side engine
+ * @param protocols The list of client-supplied protocols
+ * @return The function's result is an application protocol name, or {@code null} to indicate
+ * that none of the advertised names are acceptable. If the return value is an empty
+ * {@link String} then application protocol indications will not be used. If the return value
+ * is {@code null} (no value chosen) or is a value that was not advertised by the peer, a
+ * "no_application_protocol" alert will be sent to the peer and the connection will be
+ * terminated.
+ */
+ public abstract String selectApplicationProtocol(SSLEngine engine, List<String> protocols);
+
+ /**
+ * Selects the appropriate ALPN protocol.
+ *
+ * @param socket the server-side socket
+ * @param protocols The list of client-supplied protocols
+ * @return The function's result is an application protocol name, or {@code null} to indicate
+ * that none of the advertised names are acceptable. If the return value is an empty
+ * {@link String} then application protocol indications will not be used. If the return value
+ * is {@code null} (no value chosen) or is a value that was not advertised by the peer, a
+ * "no_application_protocol" alert will be sent to the peer and the connection will be
+ * terminated.
+ */
+ public abstract String selectApplicationProtocol(SSLSocket socket, List<String> protocols);
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ApplicationProtocolSelectorAdapter.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ApplicationProtocolSelectorAdapter.java
new file mode 100644
index 0000000..64f5dce
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ApplicationProtocolSelectorAdapter.java
@@ -0,0 +1,89 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+import java.util.List;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLSocket;
+
+/**
+ * An adapter to bridge between the native code and the {@link ApplicationProtocolSelector} API.
+ */
+final class ApplicationProtocolSelectorAdapter {
+ private static final int NO_PROTOCOL_SELECTED = -1;
+
+ private final SSLEngine engine;
+ private final SSLSocket socket;
+ private final ApplicationProtocolSelector selector;
+
+ ApplicationProtocolSelectorAdapter(SSLEngine engine, ApplicationProtocolSelector selector) {
+ this.engine = checkNotNull(engine, "engine");
+ this.socket = null;
+ this.selector = checkNotNull(selector, "selector");
+ }
+
+ ApplicationProtocolSelectorAdapter(SSLSocket socket, ApplicationProtocolSelector selector) {
+ this.engine = null;
+ this.socket = checkNotNull(socket, "socket");
+ this.selector = checkNotNull(selector, "selector");
+ }
+
+ /**
+ * Performs the ALPN protocol selection from the given list of length-delimited peer protocols.
+ * @param encodedProtocols the peer protocols in length-delimited form.
+ * @return If successful, returns the offset into the {@code lenghPrefixedList} array of the
+ * selected protocol (i.e. points to the length prefix). Otherwise, returns
+ * {@link #NO_PROTOCOL_SELECTED}.
+ */
+ int selectApplicationProtocol(byte[] encodedProtocols) {
+ if (encodedProtocols == null || encodedProtocols.length == 0) {
+ return NO_PROTOCOL_SELECTED;
+ }
+
+ // Decode the protocols.
+ List<String> protocols = Arrays.asList(SSLUtils.decodeProtocols(encodedProtocols));
+
+ // Select the protocol.
+ final String selected;
+ if (engine != null ) {
+ selected = selector.selectApplicationProtocol(engine, protocols);
+ } else {
+ selected = selector.selectApplicationProtocol(socket, protocols);
+ }
+ if (selected == null || selected.isEmpty()) {
+ return NO_PROTOCOL_SELECTED;
+ }
+
+ int offset = 0;
+ for (String protocol : protocols) {
+ if (selected.equals(protocol)) {
+ // Found the selected protocol. Return the index position of the beginning of
+ // the protocol.
+ return offset;
+ }
+
+ // Add 1 byte for the length prefix.
+ offset += 1 + protocol.length();
+ }
+
+ return NO_PROTOCOL_SELECTED;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ArrayUtils.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ArrayUtils.java
new file mode 100644
index 0000000..49a06c0
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ArrayUtils.java
@@ -0,0 +1,36 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2014 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.
+ */
+
+package com.android.org.conscrypt;
+
+/**
+ * Compatibility utility for Arrays.
+ */
+final class ArrayUtils {
+ private ArrayUtils() {}
+
+ /**
+ * Checks that the range described by {@code offset} and {@code count}
+ * doesn't exceed {@code arrayLength}.
+ */
+ static void checkOffsetAndCount(int arrayLength, int offset, int count) {
+ if ((offset | count) < 0 || offset > arrayLength || arrayLength - offset < count) {
+ throw new ArrayIndexOutOfBoundsException("length=" + arrayLength + "; regionStart="
+ + offset + "; regionLength=" + count);
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/BufferAllocator.java b/repackaged/common/src/main/java/com/android/org/conscrypt/BufferAllocator.java
new file mode 100644
index 0000000..6dc1e75
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/BufferAllocator.java
@@ -0,0 +1,46 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.android.org.conscrypt;
+
+import java.nio.ByteBuffer;
+
+/**
+ * An object responsible for allocation of buffers. This is an extension point to enable buffer
+ * pooling within an application.
+ * @hide This class is not part of the Android public SDK API
+ */
+@ExperimentalApi
+public abstract class BufferAllocator {
+ private static final BufferAllocator UNPOOLED = new BufferAllocator() {
+ @Override
+ public AllocatedBuffer allocateDirectBuffer(int capacity) {
+ return AllocatedBuffer.wrap(ByteBuffer.allocateDirect(capacity));
+ }
+ };
+
+ /**
+ * Returns an unpooled buffer allocator, which will create a new buffer for each request.
+ */
+ public static BufferAllocator unpooled() {
+ return UNPOOLED;
+ }
+
+ /**
+ * Allocates a direct (i.e. non-heap) buffer with the given capacity.
+ */
+ public abstract AllocatedBuffer allocateDirectBuffer(int capacity);
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/BufferUtils.java b/repackaged/common/src/main/java/com/android/org/conscrypt/BufferUtils.java
new file mode 100644
index 0000000..8861531
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/BufferUtils.java
@@ -0,0 +1,140 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2021 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static java.lang.Math.min;
+import static com.android.org.conscrypt.Preconditions.checkArgument;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Utility methods for dealing with arrays of ByteBuffers.
+ *
+ * @hide This class is not part of the Android public SDK API
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class BufferUtils {
+ private BufferUtils() {}
+
+ /**
+ * Throws {@link IllegalArgumentException} if any of the buffers in the array are null.
+ */
+ public static void checkNotNull(ByteBuffer[] buffers) {
+ for (ByteBuffer buffer : buffers) {
+ if (buffer == null) {
+ throw new IllegalArgumentException("Null buffer in array");
+ }
+ }
+ }
+
+ /**
+ * Returns the total number of bytes remaining in the buffer array.
+ */
+ public static long remaining(ByteBuffer[] buffers) {
+ long size = 0;
+ for (ByteBuffer buffer : buffers) {
+ size += buffer.remaining();
+ }
+ return size;
+ }
+
+ /**
+ * Marks {@code toConsume} bytes of data as consumed from the buffer array.
+ *
+ * @throws IllegalArgumentException if there are fewer than {@code toConsume} bytes remaining
+ */
+ public static void consume(ByteBuffer[] sourceBuffers, int toConsume) {
+ for (ByteBuffer sourceBuffer : sourceBuffers) {
+ int amount = min(sourceBuffer.remaining(), toConsume);
+ if (amount > 0) {
+ sourceBuffer.position(sourceBuffer.position() + amount);
+ toConsume -= amount;
+ if (toConsume == 0) {
+ break;
+ }
+ }
+ }
+ if (toConsume > 0) {
+ throw new IllegalArgumentException("toConsume > data size");
+ }
+ }
+
+ /**
+ * Looks for a buffer in the buffer array which EITHER is larger than {@code minSize} AND
+ * has no preceding non-empty buffers OR is the only non-empty buffer in the array.
+ */
+ public static ByteBuffer getBufferLargerThan(ByteBuffer[] buffers, int minSize) {
+ int length = buffers.length;
+ for (int i = 0; i < length; i++) {
+ ByteBuffer buffer = buffers[i];
+ int remaining = buffer.remaining();
+ if (remaining > 0) {
+ if (remaining >= minSize) {
+ return buffer;
+ }
+ for (int j = i + 1; j < length; j++) {
+ if (buffers[j].remaining() > 0) {
+ return null;
+ }
+ }
+ return buffer;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Copies up to {@code maxAmount} bytes from a buffer array to {@code destination}.
+ * The copied data is <b>not</b> marked as consumed from the source buffers, on the
+ * assumption the copy will be passed to some method which will consume between 0 and
+ * {@code maxAmount} bytes which can then be reflected in the source array using the
+ * {@code consume()} method.
+ *
+ */
+ public static ByteBuffer copyNoConsume(
+ ByteBuffer[] buffers, ByteBuffer destination, int maxAmount) {
+ checkArgument(destination.remaining() >= maxAmount, "Destination buffer too small");
+ int needed = maxAmount;
+ for (ByteBuffer buffer : buffers) {
+ int remaining = buffer.remaining();
+ if (remaining > 0) {
+ // If this buffer can fit completely then copy it all, otherwise temporarily
+ // adjust its limit to fill so as to the output buffer completely
+ int oldPosition = buffer.position();
+ if (remaining <= needed) {
+ destination.put(buffer);
+ needed -= remaining;
+ } else {
+ int oldLimit = buffer.limit();
+ buffer.limit(buffer.position() + needed);
+ destination.put(buffer);
+ buffer.limit(oldLimit);
+ needed = 0;
+ }
+ // Restore the buffer's position, the data won't get marked as consumed until
+ // outputBuffer has been successfully consumed.
+ buffer.position(oldPosition);
+ if (needed == 0) {
+ break;
+ }
+ }
+ }
+ destination.flip();
+ return destination;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ByteArray.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ByteArray.java
new file mode 100644
index 0000000..6bd104d
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ByteArray.java
@@ -0,0 +1,50 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2011 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.util.Arrays;
+
+/**
+ * Byte array wrapper for hashtable use. Implements equals() and hashCode().
+ */
+final class ByteArray {
+ private final byte[] bytes;
+ private final int hashCode;
+
+ ByteArray(byte[] bytes) {
+ this.bytes = bytes;
+ this.hashCode = Arrays.hashCode(bytes);
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof ByteArray)) {
+ return false;
+ }
+ ByteArray lhs = (ByteArray) o;
+ if (hashCode != lhs.hashCode) {
+ return false;
+ }
+ return Arrays.equals(bytes, lhs.bytes);
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/CertBlocklist.java b/repackaged/common/src/main/java/com/android/org/conscrypt/CertBlocklist.java
new file mode 100644
index 0000000..14454d2
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/CertBlocklist.java
@@ -0,0 +1,38 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.math.BigInteger;
+import java.security.PublicKey;
+
+/**
+ * A set of certificates that are blacklisted from trust.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface CertBlocklist {
+
+ /**
+ * Returns whether the given public key is in the blacklist.
+ */
+ boolean isPublicKeyBlockListed(PublicKey publicKey);
+
+ /**
+ * Returns whether the given serial number is in the blacklist.
+ */
+ boolean isSerialNumberBlockListed(BigInteger serial);
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/CertPinManager.java b/repackaged/common/src/main/java/com/android/org/conscrypt/CertPinManager.java
new file mode 100644
index 0000000..50a36da
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/CertPinManager.java
@@ -0,0 +1,38 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.List;
+
+/**
+ * Interface for classes that implement certificate pinning for use in {@link TrustManagerImpl}.
+ * @hide This class is not part of the Android public SDK API
+ */
+@libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+@Internal
+public interface CertPinManager {
+ /**
+ * Given a {@code hostname} and a {@code chain} this verifies that the
+ * certificate chain includes pinned certificates if pinning is requested
+ * for {@code hostname}.
+ */
+ void checkChainPinning(String hostname, List<X509Certificate> chain)
+ throws CertificateException;
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/CertificatePriorityComparator.java b/repackaged/common/src/main/java/com/android/org/conscrypt/CertificatePriorityComparator.java
new file mode 100644
index 0000000..defb37e
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/CertificatePriorityComparator.java
@@ -0,0 +1,171 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2016 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.
+ */
+package com.android.org.conscrypt;
+
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * {@link Comparator} for prioritizing certificates in path building.
+ *
+ * <p>
+ * The sort order is as follows:
+ * <ol>
+ * <li>Self-issued certificates first.</li>
+ * <li>Strength of certificates descending (EC before RSA, key size descending, signature
+ * algorithm strength descending).</li>
+ * <li>notAfter date descending.</li>
+ * <li>notBefore date descending.</li>
+ * </ol>
+ * </p>
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class CertificatePriorityComparator implements Comparator<X509Certificate> {
+
+ /**
+ * Map of signature algorithm OIDs to priorities. OIDs with a lower priority will be sorted
+ * before those with higher.
+ */
+ private static final Map<String, Integer> ALGORITHM_OID_PRIORITY_MAP;
+
+ /*
+ * Priorities of digest algorithms. Lower is better.
+ */
+ private static final Integer PRIORITY_MD5 = 6;
+ private static final Integer PRIORITY_SHA1 = 5;
+ private static final Integer PRIORITY_SHA224 = 4;
+ private static final Integer PRIORITY_SHA256 = 3;
+ private static final Integer PRIORITY_SHA384 = 2;
+ private static final Integer PRIORITY_SHA512 = 1;
+ private static final Integer PRIORITY_UNKNOWN = -1;
+ static {
+ ALGORITHM_OID_PRIORITY_MAP = new HashMap<String, Integer>();
+ // RSA oids
+ ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.113549.1.1.13", PRIORITY_SHA512);
+ ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.113549.1.1.12", PRIORITY_SHA384);
+ ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.113549.1.1.11", PRIORITY_SHA256);
+ ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.113549.1.1.14", PRIORITY_SHA224);
+ ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.113549.1.1.5", PRIORITY_SHA1);
+ ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.113549.1.1.4", PRIORITY_MD5);
+ // ECDSA oids
+ ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.10045.4.3.4", PRIORITY_SHA512);
+ ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.10045.4.3.3", PRIORITY_SHA384);
+ ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.10045.4.3.2", PRIORITY_SHA256);
+ ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.10045.4.3.1", PRIORITY_SHA224);
+ ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.10045.4.1", PRIORITY_SHA1);
+ }
+
+ @Override
+ @SuppressWarnings("JdkObsolete") // Certificate uses Date
+ public int compare(X509Certificate lhs, X509Certificate rhs) {
+ int result;
+ boolean lhsSelfSigned = lhs.getSubjectDN().equals(lhs.getIssuerDN());
+ boolean rhsSelfSigned = rhs.getSubjectDN().equals(rhs.getIssuerDN());
+ // Self-issued before not self-issued to avoid trying bridge certs first.
+ if (lhsSelfSigned != rhsSelfSigned) {
+ return rhsSelfSigned ? 1 : -1;
+ }
+ // Strength descending.
+ result = compareStrength(rhs, lhs);
+ if (result != 0) {
+ return result;
+ }
+ // notAfter descending.
+ Date lhsNotAfter = lhs.getNotAfter();
+ Date rhsNotAfter = rhs.getNotAfter();
+ result = rhsNotAfter.compareTo(lhsNotAfter);
+ if (result != 0) {
+ return result;
+ }
+ // notBefore descending.
+ Date lhsNotBefore = lhs.getNotBefore();
+ Date rhsNotBefore = rhs.getNotBefore();
+ return rhsNotBefore.compareTo(lhsNotBefore);
+ }
+
+ private int compareStrength(X509Certificate lhs, X509Certificate rhs) {
+ int result;
+ PublicKey lhsPublicKey = lhs.getPublicKey();
+ PublicKey rhsPublicKey = rhs.getPublicKey();
+ result = compareKeyAlgorithm(lhsPublicKey, rhsPublicKey);
+ if (result != 0) {
+ return result;
+ }
+ result = compareKeySize(lhsPublicKey, rhsPublicKey);
+ if (result != 0) {
+ return result;
+ }
+ return compareSignatureAlgorithm(lhs, rhs);
+ }
+
+ private int compareKeyAlgorithm(PublicKey lhs, PublicKey rhs) {
+ String lhsAlgorithm = lhs.getAlgorithm();
+ String rhsAlgorithm = rhs.getAlgorithm();
+
+ if (lhsAlgorithm.equalsIgnoreCase(rhsAlgorithm)) {
+ return 0;
+ }
+
+ // Prefer EC to RSA.
+ if ("EC".equalsIgnoreCase(lhsAlgorithm)) {
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+
+ private int compareKeySize(PublicKey lhs, PublicKey rhs) {
+ String lhsAlgorithm = lhs.getAlgorithm();
+ String rhsAlgorithm = rhs.getAlgorithm();
+ if (!lhsAlgorithm.equalsIgnoreCase(rhsAlgorithm)) {
+ throw new IllegalArgumentException("Keys are not of the same type");
+ }
+ int lhsSize = getKeySize(lhs);
+ int rhsSize = getKeySize(rhs);
+ return lhsSize - rhsSize;
+ }
+
+ private int getKeySize(PublicKey pkey) {
+ if (pkey instanceof ECPublicKey) {
+ return ((ECPublicKey) pkey).getParams().getCurve().getField().getFieldSize();
+ } else if (pkey instanceof RSAPublicKey) {
+ return ((RSAPublicKey) pkey).getModulus().bitLength();
+ } else {
+ throw new IllegalArgumentException(
+ "Unsupported public key type: " + pkey.getClass().getName());
+ }
+ }
+
+ private int compareSignatureAlgorithm(X509Certificate lhs, X509Certificate rhs) {
+ Integer lhsPriority = ALGORITHM_OID_PRIORITY_MAP.get(lhs.getSigAlgOID());
+ Integer rhsPriority = ALGORITHM_OID_PRIORITY_MAP.get(rhs.getSigAlgOID());
+ if (lhsPriority == null) {
+ lhsPriority = PRIORITY_UNKNOWN;
+ }
+ if (rhsPriority == null) {
+ rhsPriority = PRIORITY_UNKNOWN;
+ }
+ return rhsPriority - lhsPriority;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ChainStrengthAnalyzer.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ChainStrengthAnalyzer.java
new file mode 100644
index 0000000..e34f8c5
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ChainStrengthAnalyzer.java
@@ -0,0 +1,116 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.List;
+
+/**
+ * Analyzes the cryptographic strength of a chain of X.509 certificates.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class ChainStrengthAnalyzer {
+
+ private static final int MIN_RSA_MODULUS_LEN_BITS = 1024;
+
+ private static final int MIN_EC_FIELD_SIZE_BITS = 160;
+
+ private static final int MIN_DSA_P_LEN_BITS = 1024;
+ private static final int MIN_DSA_Q_LEN_BITS = 160;
+
+ private static final String[] SIGNATURE_ALGORITHM_OID_BLACKLIST = {
+ "1.2.840.113549.1.1.2", // md2WithRSAEncryption
+ "1.2.840.113549.1.1.3", // md4WithRSAEncryption
+ "1.2.840.113549.1.1.4", // md5WithRSAEncryption
+ "1.2.840.113549.1.1.5", // sha1WithRSAEncryption
+ "1.2.840.10040.4.3", //dsa-with-sha1
+ "1.2.840.10045.4.1", //ecdsa-with-sha1
+ };
+
+ public static final void check(X509Certificate[] chain) throws CertificateException {
+ for (X509Certificate cert : chain) {
+ try {
+ checkCert(cert);
+ } catch (CertificateException e) {
+ throw new CertificateException("Unacceptable certificate: "
+ + cert.getSubjectX500Principal(), e);
+ }
+ }
+ }
+
+ public static final void check(List<X509Certificate> chain) throws CertificateException {
+ for (X509Certificate cert : chain) {
+ try {
+ checkCert(cert);
+ } catch (CertificateException e) {
+ throw new CertificateException("Unacceptable certificate: "
+ + cert.getSubjectX500Principal(), e);
+ }
+ }
+ }
+
+ public static final void checkCert(X509Certificate cert) throws CertificateException {
+ checkKeyLength(cert);
+ checkSignatureAlgorithm(cert);
+ }
+
+ private static void checkKeyLength(X509Certificate cert) throws CertificateException {
+ Object pubkey = cert.getPublicKey();
+ if (pubkey instanceof RSAPublicKey) {
+ int modulusLength = ((RSAPublicKey) pubkey).getModulus().bitLength();
+ if (modulusLength < MIN_RSA_MODULUS_LEN_BITS) {
+ throw new CertificateException(
+ "RSA modulus is < " + MIN_RSA_MODULUS_LEN_BITS + " bits");
+ }
+ } else if (pubkey instanceof ECPublicKey) {
+ int fieldSizeBits =
+ ((ECPublicKey) pubkey).getParams().getCurve().getField().getFieldSize();
+ if (fieldSizeBits < MIN_EC_FIELD_SIZE_BITS) {
+ throw new CertificateException(
+ "EC key field size is < " + MIN_EC_FIELD_SIZE_BITS + " bits");
+ }
+ } else if (pubkey instanceof DSAPublicKey) {
+ int pLength = ((DSAPublicKey) pubkey).getParams().getP().bitLength();
+ int qLength = ((DSAPublicKey) pubkey).getParams().getQ().bitLength();
+ if ((pLength < MIN_DSA_P_LEN_BITS) || (qLength < MIN_DSA_Q_LEN_BITS)) {
+ throw new CertificateException(
+ "DSA key length is < (" + MIN_DSA_P_LEN_BITS + ", " + MIN_DSA_Q_LEN_BITS
+ + ") bits");
+ }
+ } else {
+ // Unknown keys will be of type X509PublicKey.
+ throw new CertificateException("Rejecting unknown key class " + pubkey.getClass().getName());
+ }
+ }
+
+ private static void checkSignatureAlgorithm(
+ X509Certificate cert) throws CertificateException {
+ String oid = cert.getSigAlgOID();
+ for (String blacklisted : SIGNATURE_ALGORITHM_OID_BLACKLIST) {
+ if (oid.equals(blacklisted)) {
+ throw new CertificateException("Signature uses an insecure hash function: " + oid);
+ }
+ }
+ }
+}
+
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ClientSessionContext.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ClientSessionContext.java
new file mode 100644
index 0000000..c4fa3a7
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ClientSessionContext.java
@@ -0,0 +1,251 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.net.ssl.SSLContext;
+
+/**
+ * Caches client sessions. Indexes by host and port. Users are typically
+ * looking to reuse any session for a given host and port.
+ * @hide This class is not part of the Android public SDK API
+ */
+@libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+@Internal
+public final class ClientSessionContext extends AbstractSessionContext {
+ /**
+ * Sessions indexed by host and port. Protect from concurrent
+ * access by holding a lock on sessionsByHostAndPort.
+ *
+ * Invariant: Each list includes either exactly one multi-use session or one
+ * or more single-use sessions. The types of sessions are never mixed, and adding
+ * a session of one kind will remove all sessions of the other kind.
+ */
+ @SuppressWarnings("serial")
+ private final Map<HostAndPort, List<NativeSslSession>> sessionsByHostAndPort = new HashMap<HostAndPort, List<NativeSslSession>>();
+
+ private SSLClientSessionCache persistentCache;
+
+ ClientSessionContext() {
+ super(10);
+ }
+
+ /**
+ * Applications should not use this method. Instead use {@link
+ * Conscrypt#setClientSessionCache(SSLContext, SSLClientSessionCache)}.
+ */
+ @android.compat.annotation.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public void setPersistentCache(SSLClientSessionCache persistentCache) {
+ this.persistentCache = persistentCache;
+ }
+
+ /**
+ * Gets the suitable session reference from the session cache container.
+ */
+ synchronized NativeSslSession getCachedSession(String hostName, int port,
+ SSLParametersImpl sslParameters) {
+ if (hostName == null) {
+ return null;
+ }
+
+ NativeSslSession session = getSession(hostName, port);
+ if (session == null) {
+ return null;
+ }
+
+ String protocol = session.getProtocol();
+ boolean protocolFound = false;
+ for (String enabledProtocol : sslParameters.enabledProtocols) {
+ if (protocol.equals(enabledProtocol)) {
+ protocolFound = true;
+ break;
+ }
+ }
+ if (!protocolFound) {
+ return null;
+ }
+
+ String cipherSuite = session.getCipherSuite();
+ boolean cipherSuiteFound = false;
+ for (String enabledCipherSuite : sslParameters.getEnabledCipherSuites()) {
+ if (cipherSuite.equals(enabledCipherSuite)) {
+ cipherSuiteFound = true;
+ break;
+ }
+ }
+ if (!cipherSuiteFound) {
+ return null;
+ }
+
+ if (session.isSingleUse()) {
+ removeSession(session);
+ }
+ return session;
+ }
+
+ int size() {
+ int size = 0;
+ synchronized (sessionsByHostAndPort) {
+ for (List<NativeSslSession> sessions : sessionsByHostAndPort.values()) {
+ size += sessions.size();
+ }
+ }
+ return size;
+ }
+
+ /**
+ * Finds a cached session for the given host name and port.
+ *
+ * @param host of server
+ * @param port of server
+ * @return cached session or null if none found
+ */
+ @android.compat.annotation.UnsupportedAppUsage
+ private NativeSslSession getSession(String host, int port) {
+ if (host == null) {
+ return null;
+ }
+
+ HostAndPort key = new HostAndPort(host, port);
+ NativeSslSession session = null;
+ synchronized (sessionsByHostAndPort) {
+ List<NativeSslSession> sessions = sessionsByHostAndPort.get(key);
+ if (sessions != null && sessions.size() > 0) {
+ session = sessions.get(0);
+ }
+ }
+ if (session != null && session.isValid()) {
+ return session;
+ }
+
+ // Look in persistent cache. We don't currently delete sessions from the persistent
+ // cache, so we may find a multi-use (aka TLS 1.2) session after having received and
+ // then used up one or more single-use (aka TLS 1.3) sessions.
+ if (persistentCache != null) {
+ byte[] data = persistentCache.getSessionData(host, port);
+ if (data != null) {
+ session = NativeSslSession.newInstance(this, data, host, port);
+ if (session != null && session.isValid()) {
+ putSession(key, session);
+ return session;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private void putSession(HostAndPort key, NativeSslSession session) {
+ synchronized (sessionsByHostAndPort) {
+ List<NativeSslSession> sessions = sessionsByHostAndPort.get(key);
+ if (sessions == null) {
+ sessions = new ArrayList<NativeSslSession>();
+ sessionsByHostAndPort.put(key, sessions);
+ }
+ // To maintain the invariant that single- and multi-use sessions aren't
+ // mixed, check what the current list contains and remove those sessions if
+ // they're of the other type.
+ if (sessions.size() > 0 && sessions.get(0).isSingleUse() != session.isSingleUse()) {
+ while (!sessions.isEmpty()) {
+ removeSession(sessions.get(0));
+ }
+ // The last removeSession() call will have removed the list from
+ // the map, so put it back.
+ sessionsByHostAndPort.put(key, sessions);
+ }
+ sessions.add(session);
+ }
+ }
+
+ private void removeSession(HostAndPort key, NativeSslSession session) {
+ synchronized (sessionsByHostAndPort) {
+ List<NativeSslSession> sessions = sessionsByHostAndPort.get(key);
+ if (sessions != null) {
+ sessions.remove(session);
+ if (sessions.isEmpty()) {
+ sessionsByHostAndPort.remove(key);
+ }
+ }
+ }
+ }
+
+ @Override
+ void onBeforeAddSession(NativeSslSession session) {
+ String host = session.getPeerHost();
+ int port = session.getPeerPort();
+ if (host == null) {
+ return;
+ }
+
+ HostAndPort key = new HostAndPort(host, port);
+ putSession(key, session);
+
+ // TODO: Do this in a background thread.
+ if (persistentCache != null && !session.isSingleUse()) {
+ byte[] data = session.toBytes();
+ if (data != null) {
+ persistentCache.putSessionData(session.toSSLSession(), data);
+ }
+ }
+ }
+
+ @Override
+ void onBeforeRemoveSession(NativeSslSession session) {
+ String host = session.getPeerHost();
+ if (host == null) {
+ return;
+ }
+ int port = session.getPeerPort();
+ HostAndPort hostAndPortKey = new HostAndPort(host, port);
+ removeSession(hostAndPortKey, session);
+ }
+
+ @Override
+ NativeSslSession getSessionFromPersistentCache(byte[] sessionId) {
+ // Not implemented for clients.
+ return null;
+ }
+
+ private static final class HostAndPort {
+ final String host;
+ final int port;
+
+ HostAndPort(String host, int port) {
+ this.host = host;
+ this.port = port;
+ }
+
+ @Override
+ public int hashCode() {
+ return host.hashCode() * 31 + port;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof HostAndPort)) {
+ return false;
+ }
+ HostAndPort lhs = (HostAndPort) o;
+ return host.equals(lhs.host) && port == lhs.port;
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/Conscrypt.java b/repackaged/common/src/main/java/com/android/org/conscrypt/Conscrypt.java
new file mode 100644
index 0000000..ba51136
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/Conscrypt.java
@@ -0,0 +1,824 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.android.org.conscrypt;
+
+import com.android.org.conscrypt.io.IoUtils;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.security.KeyManagementException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.cert.X509Certificate;
+import java.util.Properties;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLContextSpi;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * Core API for creating and configuring all Conscrypt types.
+ * @hide This class is not part of the Android public SDK API
+ */
+@libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+@SuppressWarnings("unused")
+public final class Conscrypt {
+ private Conscrypt() {}
+
+ /**
+ * Returns {@code true} if the Conscrypt native library has been successfully loaded.
+ */
+ public static boolean isAvailable() {
+ try {
+ checkAvailability();
+ return true;
+ } catch (Throwable e) {
+ return false;
+ }
+ }
+
+ /**
+ * Return {@code true} if BoringSSL has been built in FIPS mode.
+ */
+ public static boolean isBoringSslFIPSBuild() {
+ try {
+ return NativeCrypto.usesBoringSsl_FIPS_mode();
+ } catch (Throwable e) {
+ return false;
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class Version {
+ private final int major;
+ private final int minor;
+ private final int patch;
+
+ private Version(int major, int minor, int patch) {
+ this.major = major;
+ this.minor = minor;
+ this.patch = patch;
+ }
+
+ public int major() { return major; }
+ public int minor() { return minor; }
+ public int patch() { return patch; }
+ }
+
+ private static final Version VERSION;
+
+ static {
+ int major = -1;
+ int minor = -1;
+ int patch = -1;
+ InputStream stream = null;
+ try {
+ stream = Conscrypt.class.getResourceAsStream("conscrypt.properties");
+ if (stream != null) {
+ Properties props = new Properties();
+ props.load(stream);
+ major = Integer.parseInt(props.getProperty("com.android.org.conscrypt.version.major", "-1"));
+ minor = Integer.parseInt(props.getProperty("com.android.org.conscrypt.version.minor", "-1"));
+ patch = Integer.parseInt(props.getProperty("com.android.org.conscrypt.version.patch", "-1"));
+ }
+ } catch (IOException e) {
+ // TODO(prb): This should probably be fatal or have some fallback behaviour
+ } finally {
+ IoUtils.closeQuietly(stream);
+ }
+ if ((major >= 0) && (minor >= 0) && (patch >= 0)) {
+ VERSION = new Version(major, minor, patch);
+ } else {
+ VERSION = null;
+ }
+ }
+
+ /**
+ * Returns the version of this distribution of Conscrypt. If version information is
+ * unavailable, returns {@code null}.
+ */
+ public static Version version() {
+ return VERSION;
+ }
+
+ /**
+ * Checks that the Conscrypt support is available for the system.
+ *
+ * @throws UnsatisfiedLinkError if unavailable
+ */
+ public static void checkAvailability() {
+ NativeCrypto.checkAvailability();
+ }
+
+ /**
+ * Indicates whether the given {@link Provider} was created by this distribution of Conscrypt.
+ */
+ public static boolean isConscrypt(Provider provider) {
+ return provider instanceof OpenSSLProvider;
+ }
+
+ /**
+ * Constructs a new {@link Provider} with the default name.
+ */
+ public static Provider newProvider() {
+ checkAvailability();
+ return new OpenSSLProvider();
+ }
+
+ /**
+ * Constructs a new {@link Provider} with the given name.
+ *
+ * @deprecated Use {@link #newProviderBuilder()} instead.
+ */
+ @Deprecated
+ public static Provider newProvider(String providerName) {
+ checkAvailability();
+ return newProviderBuilder().setName(providerName).build();
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class ProviderBuilder {
+ private String name = Platform.getDefaultProviderName();
+ private boolean provideTrustManager = Platform.provideTrustManagerByDefault();
+ private String defaultTlsProtocol = NativeCrypto.SUPPORTED_PROTOCOL_TLSV1_3;
+
+ private ProviderBuilder() {}
+
+ /**
+ * Sets the name of the Provider to be built.
+ */
+ public ProviderBuilder setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * Causes the returned provider to provide an implementation of
+ * {@link javax.net.ssl.TrustManagerFactory}.
+ * @deprecated Use provideTrustManager(true)
+ */
+ @Deprecated
+ public ProviderBuilder provideTrustManager() {
+ return provideTrustManager(true);
+ }
+
+ /**
+ * Specifies whether the returned provider will provide an implementation of
+ * {@link javax.net.ssl.TrustManagerFactory}.
+ */
+ public ProviderBuilder provideTrustManager(boolean provide) {
+ this.provideTrustManager = provide;
+ return this;
+ }
+
+ /**
+ * Specifies what the default TLS protocol should be for SSLContext identifiers
+ * {@code TLS}, {@code SSL}, and {@code Default}.
+ */
+ public ProviderBuilder defaultTlsProtocol(String defaultTlsProtocol) {
+ this.defaultTlsProtocol = defaultTlsProtocol;
+ return this;
+ }
+
+ public Provider build() {
+ return new OpenSSLProvider(name, provideTrustManager, defaultTlsProtocol);
+ }
+ }
+
+ public static ProviderBuilder newProviderBuilder() {
+ return new ProviderBuilder();
+ }
+
+ /**
+ * Returns the maximum length (in bytes) of an encrypted packet.
+ */
+ public static int maxEncryptedPacketLength() {
+ return NativeConstants.SSL3_RT_MAX_PACKET_SIZE;
+ }
+
+ /**
+ * Gets the default X.509 trust manager.
+ */
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ @ExperimentalApi
+ public static X509TrustManager getDefaultX509TrustManager() throws KeyManagementException {
+ checkAvailability();
+ return SSLParametersImpl.getDefaultX509TrustManager();
+ }
+
+ /**
+ * Indicates whether the given {@link SSLContext} was created by this distribution of Conscrypt.
+ */
+ public static boolean isConscrypt(SSLContext context) {
+ return context.getProvider() instanceof OpenSSLProvider;
+ }
+
+ /**
+ * Constructs a new instance of the preferred {@link SSLContextSpi}.
+ */
+ public static SSLContextSpi newPreferredSSLContextSpi() {
+ checkAvailability();
+ return OpenSSLContextImpl.getPreferred();
+ }
+
+ /**
+ * Sets the client-side persistent cache to be used by the context.
+ */
+ public static void setClientSessionCache(SSLContext context, SSLClientSessionCache cache) {
+ SSLSessionContext clientContext = context.getClientSessionContext();
+ if (!(clientContext instanceof ClientSessionContext)) {
+ throw new IllegalArgumentException(
+ "Not a conscrypt client context: " + clientContext.getClass().getName());
+ }
+ ((ClientSessionContext) clientContext).setPersistentCache(cache);
+ }
+
+ /**
+ * Sets the server-side persistent cache to be used by the context.
+ */
+ public static void setServerSessionCache(SSLContext context, SSLServerSessionCache cache) {
+ SSLSessionContext serverContext = context.getServerSessionContext();
+ if (!(serverContext instanceof ServerSessionContext)) {
+ throw new IllegalArgumentException(
+ "Not a conscrypt client context: " + serverContext.getClass().getName());
+ }
+ ((ServerSessionContext) serverContext).setPersistentCache(cache);
+ }
+
+ /**
+ * Indicates whether the given {@link SSLSocketFactory} was created by this distribution of
+ * Conscrypt.
+ */
+ public static boolean isConscrypt(SSLSocketFactory factory) {
+ return factory instanceof OpenSSLSocketFactoryImpl;
+ }
+
+ private static OpenSSLSocketFactoryImpl toConscrypt(SSLSocketFactory factory) {
+ if (!isConscrypt(factory)) {
+ throw new IllegalArgumentException(
+ "Not a conscrypt socket factory: " + factory.getClass().getName());
+ }
+ return (OpenSSLSocketFactoryImpl) factory;
+ }
+
+ /**
+ * Configures the default socket to be created for all socket factory instances.
+ */
+ @ExperimentalApi
+ public static void setUseEngineSocketByDefault(boolean useEngineSocket) {
+ OpenSSLSocketFactoryImpl.setUseEngineSocketByDefault(useEngineSocket);
+ OpenSSLServerSocketFactoryImpl.setUseEngineSocketByDefault(useEngineSocket);
+ }
+
+ /**
+ * Configures the socket to be created for the given socket factory instance.
+ */
+ @ExperimentalApi
+ public static void setUseEngineSocket(SSLSocketFactory factory, boolean useEngineSocket) {
+ toConscrypt(factory).setUseEngineSocket(useEngineSocket);
+ }
+
+ /**
+ * Indicates whether the given {@link SSLServerSocketFactory} was created by this distribution
+ * of Conscrypt.
+ */
+ public static boolean isConscrypt(SSLServerSocketFactory factory) {
+ return factory instanceof OpenSSLServerSocketFactoryImpl;
+ }
+
+ private static OpenSSLServerSocketFactoryImpl toConscrypt(SSLServerSocketFactory factory) {
+ if (!isConscrypt(factory)) {
+ throw new IllegalArgumentException(
+ "Not a conscrypt server socket factory: " + factory.getClass().getName());
+ }
+ return (OpenSSLServerSocketFactoryImpl) factory;
+ }
+
+ /**
+ * Configures the socket to be created for the given server socket factory instance.
+ */
+ @ExperimentalApi
+ public static void setUseEngineSocket(SSLServerSocketFactory factory, boolean useEngineSocket) {
+ toConscrypt(factory).setUseEngineSocket(useEngineSocket);
+ }
+
+ /**
+ * Indicates whether the given {@link SSLSocket} was created by this distribution of Conscrypt.
+ */
+ public static boolean isConscrypt(SSLSocket socket) {
+ return socket instanceof AbstractConscryptSocket;
+ }
+
+ private static AbstractConscryptSocket toConscrypt(SSLSocket socket) {
+ if (!isConscrypt(socket)) {
+ throw new IllegalArgumentException(
+ "Not a conscrypt socket: " + socket.getClass().getName());
+ }
+ return (AbstractConscryptSocket) socket;
+ }
+
+ /**
+ * This method enables Server Name Indication (SNI) and overrides the hostname supplied
+ * during socket creation. If the hostname is not a valid SNI hostname, the SNI extension
+ * will be omitted from the handshake.
+ *
+ * @param socket the socket
+ * @param hostname the desired SNI hostname, or null to disable
+ */
+ public static void setHostname(SSLSocket socket, String hostname) {
+ toConscrypt(socket).setHostname(hostname);
+ }
+
+ /**
+ * Returns either the hostname supplied during socket creation or via
+ * {@link #setHostname(SSLSocket, String)}. No DNS resolution is attempted before
+ * returning the hostname.
+ */
+ public static String getHostname(SSLSocket socket) {
+ return toConscrypt(socket).getHostname();
+ }
+
+ /**
+ * This method attempts to create a textual representation of the peer host or IP. Does
+ * not perform a reverse DNS lookup. This is typically used during session creation.
+ */
+ public static String getHostnameOrIP(SSLSocket socket) {
+ return toConscrypt(socket).getHostnameOrIP();
+ }
+
+ /**
+ * This method enables session ticket support.
+ *
+ * @param socket the socket
+ * @param useSessionTickets True to enable session tickets
+ */
+ public static void setUseSessionTickets(SSLSocket socket, boolean useSessionTickets) {
+ toConscrypt(socket).setUseSessionTickets(useSessionTickets);
+ }
+
+ /**
+ * Enables/disables TLS Channel ID for the given server-side socket.
+ *
+ * <p>This method needs to be invoked before the handshake starts.
+ *
+ * @param socket the socket
+ * @param enabled Whether to enable channel ID.
+ * @throws IllegalStateException if this is a client socket or if the handshake has already
+ * started.
+ */
+ public static void setChannelIdEnabled(SSLSocket socket, boolean enabled) {
+ toConscrypt(socket).setChannelIdEnabled(enabled);
+ }
+
+ /**
+ * Gets the TLS Channel ID for the given server-side socket. Channel ID is only available
+ * once the handshake completes.
+ *
+ * @param socket the socket
+ * @return channel ID or {@code null} if not available.
+ * @throws IllegalStateException if this is a client socket or if the handshake has not yet
+ * completed.
+ * @throws SSLException if channel ID is available but could not be obtained.
+ */
+ public static byte[] getChannelId(SSLSocket socket) throws SSLException {
+ return toConscrypt(socket).getChannelId();
+ }
+
+ /**
+ * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client socket.
+ *
+ * <p>This method needs to be invoked before the handshake starts.
+ *
+ * @param socket the socket
+ * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key
+ * (disables TLS Channel ID).
+ * The private key must be an Elliptic Curve (EC) key based on the NIST P-256 curve (aka
+ * SECG secp256r1 or ANSI
+ * X9.62 prime256v1).
+ * @throws IllegalStateException if this is a server socket or if the handshake has already
+ * started.
+ */
+ public static void setChannelIdPrivateKey(SSLSocket socket, PrivateKey privateKey) {
+ toConscrypt(socket).setChannelIdPrivateKey(privateKey);
+ }
+
+ /**
+ * Returns the ALPN protocol agreed upon by client and server.
+ *
+ * @param socket the socket
+ * @return the selected protocol or {@code null} if no protocol was agreed upon.
+ */
+ public static String getApplicationProtocol(SSLSocket socket) {
+ return toConscrypt(socket).getApplicationProtocol();
+ }
+
+ /**
+ * Sets an application-provided ALPN protocol selector. If provided, this will override
+ * the list of protocols set by {@link #setApplicationProtocols(SSLSocket, String[])}.
+ *
+ * @param socket the socket
+ * @param selector the ALPN protocol selector
+ */
+ public static void setApplicationProtocolSelector(SSLSocket socket,
+ ApplicationProtocolSelector selector) {
+ toConscrypt(socket).setApplicationProtocolSelector(selector);
+ }
+
+ /**
+ * Sets the application-layer protocols (ALPN) in prioritization order.
+ *
+ * @param socket the socket being configured
+ * @param protocols the protocols in descending order of preference. If empty, no protocol
+ * indications will be used. This array will be copied.
+ * @throws IllegalArgumentException - if protocols is null, or if any element in a non-empty
+ * array is null or an empty (zero-length) string
+ */
+ public static void setApplicationProtocols(SSLSocket socket, String[] protocols) {
+ toConscrypt(socket).setApplicationProtocols(protocols);
+ }
+
+ /**
+ * Gets the application-layer protocols (ALPN) in prioritization order.
+ *
+ * @param socket the socket
+ * @return the protocols in descending order of preference, or an empty array if protocol
+ * indications are not being used. Always returns a new array.
+ */
+ public static String[] getApplicationProtocols(SSLSocket socket) {
+ return toConscrypt(socket).getApplicationProtocols();
+ }
+
+ /**
+ * Returns the tls-unique channel binding value for this connection, per RFC 5929. This
+ * will return {@code null} if there is no such value available, such as if the handshake
+ * has not yet completed or this connection is closed.
+ */
+ public static byte[] getTlsUnique(SSLSocket socket) {
+ return toConscrypt(socket).getTlsUnique();
+ }
+
+ /**
+ * Exports a value derived from the TLS master secret as described in RFC 5705.
+ *
+ * @param label the label to use in calculating the exported value. This must be
+ * an ASCII-only string.
+ * @param context the application-specific context value to use in calculating the
+ * exported value. This may be {@code null} to use no application context, which is
+ * treated differently than an empty byte array.
+ * @param length the number of bytes of keying material to return.
+ * @return a value of the specified length, or {@code null} if the handshake has not yet
+ * completed or the connection has been closed.
+ * @throws SSLException if the value could not be exported.
+ */
+ public static byte[] exportKeyingMaterial(SSLSocket socket, String label, byte[] context,
+ int length) throws SSLException {
+ return toConscrypt(socket).exportKeyingMaterial(label, context, length);
+ }
+
+ /**
+ * Indicates whether the given {@link SSLEngine} was created by this distribution of Conscrypt.
+ */
+ public static boolean isConscrypt(SSLEngine engine) {
+ return engine instanceof AbstractConscryptEngine;
+ }
+
+ private static AbstractConscryptEngine toConscrypt(SSLEngine engine) {
+ if (!isConscrypt(engine)) {
+ throw new IllegalArgumentException(
+ "Not a conscrypt engine: " + engine.getClass().getName());
+ }
+ return (AbstractConscryptEngine) engine;
+ }
+
+ /**
+ * Provides the given engine with the provided bufferAllocator.
+ * @throws IllegalArgumentException if the provided engine is not a Conscrypt engine.
+ * @throws IllegalStateException if the provided engine has already begun its handshake.
+ */
+ @ExperimentalApi
+ public static void setBufferAllocator(SSLEngine engine, BufferAllocator bufferAllocator) {
+ toConscrypt(engine).setBufferAllocator(bufferAllocator);
+ }
+
+ /**
+ * Provides the given socket with the provided bufferAllocator. If the given socket is a
+ * Conscrypt socket but does not use buffer allocators, this method does nothing.
+ * @throws IllegalArgumentException if the provided socket is not a Conscrypt socket.
+ * @throws IllegalStateException if the provided socket has already begun its handshake.
+ */
+ @ExperimentalApi
+ public static void setBufferAllocator(SSLSocket socket, BufferAllocator bufferAllocator) {
+ AbstractConscryptSocket s = toConscrypt(socket);
+ if (s instanceof ConscryptEngineSocket) {
+ ((ConscryptEngineSocket) s).setBufferAllocator(bufferAllocator);
+ }
+ }
+
+ /**
+ * Configures the default {@link BufferAllocator} to be used by all future
+ * {@link SSLEngine} instances from this provider.
+ */
+ @ExperimentalApi
+ public static void setDefaultBufferAllocator(BufferAllocator bufferAllocator) {
+ ConscryptEngine.setDefaultBufferAllocator(bufferAllocator);
+ }
+
+ /**
+ * This method enables Server Name Indication (SNI) and overrides the hostname supplied
+ * during engine creation.
+ *
+ * @param engine the engine
+ * @param hostname the desired SNI hostname, or {@code null} to disable
+ */
+ public static void setHostname(SSLEngine engine, String hostname) {
+ toConscrypt(engine).setHostname(hostname);
+ }
+
+ /**
+ * Returns either the hostname supplied during socket creation or via
+ * {@link #setHostname(SSLEngine, String)}. No DNS resolution is attempted before
+ * returning the hostname.
+ */
+ public static String getHostname(SSLEngine engine) {
+ return toConscrypt(engine).getHostname();
+ }
+
+ /**
+ * Returns the maximum overhead, in bytes, of sealing a record with SSL.
+ */
+ public static int maxSealOverhead(SSLEngine engine) {
+ return toConscrypt(engine).maxSealOverhead();
+ }
+
+ /**
+ * Sets a listener on the given engine for completion of the TLS handshake
+ */
+ public static void setHandshakeListener(SSLEngine engine, HandshakeListener handshakeListener) {
+ toConscrypt(engine).setHandshakeListener(handshakeListener);
+ }
+
+ /**
+ * Enables/disables TLS Channel ID for the given server-side engine.
+ *
+ * <p>This method needs to be invoked before the handshake starts.
+ *
+ * @param engine the engine
+ * @param enabled Whether to enable channel ID.
+ * @throws IllegalStateException if this is a client engine or if the handshake has already
+ * started.
+ */
+ public static void setChannelIdEnabled(SSLEngine engine, boolean enabled) {
+ toConscrypt(engine).setChannelIdEnabled(enabled);
+ }
+
+ /**
+ * Gets the TLS Channel ID for the given server-side engine. Channel ID is only available
+ * once the handshake completes.
+ *
+ * @param engine the engine
+ * @return channel ID or {@code null} if not available.
+ * @throws IllegalStateException if this is a client engine or if the handshake has not yet
+ * completed.
+ * @throws SSLException if channel ID is available but could not be obtained.
+ */
+ public static byte[] getChannelId(SSLEngine engine) throws SSLException {
+ return toConscrypt(engine).getChannelId();
+ }
+
+ /**
+ * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client engine.
+ *
+ * <p>This method needs to be invoked before the handshake starts.
+ *
+ * @param engine the engine
+ * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key
+ * (disables TLS Channel ID).
+ * The private key must be an Elliptic Curve (EC) key based on the NIST P-256 curve (aka
+ * SECG secp256r1 or ANSI X9.62 prime256v1).
+ * @throws IllegalStateException if this is a server engine or if the handshake has already
+ * started.
+ */
+ public static void setChannelIdPrivateKey(SSLEngine engine, PrivateKey privateKey) {
+ toConscrypt(engine).setChannelIdPrivateKey(privateKey);
+ }
+
+ /**
+ * Extended unwrap method for multiple source and destination buffers.
+ *
+ * @param engine the target engine for the unwrap
+ * @param srcs the source buffers
+ * @param dsts the destination buffers
+ * @return the result of the unwrap operation
+ * @throws SSLException thrown if an SSL error occurred
+ */
+ public static SSLEngineResult unwrap(SSLEngine engine, final ByteBuffer[] srcs,
+ final ByteBuffer[] dsts) throws SSLException {
+ return toConscrypt(engine).unwrap(srcs, dsts);
+ }
+
+ /**
+ * Exteneded unwrap method for multiple source and destination buffers.
+ *
+ * @param engine the target engine for the unwrap.
+ * @param srcs the source buffers
+ * @param srcsOffset the offset in the {@code srcs} array of the first source buffer
+ * @param srcsLength the number of source buffers starting at {@code srcsOffset}
+ * @param dsts the destination buffers
+ * @param dstsOffset the offset in the {@code dsts} array of the first destination buffer
+ * @param dstsLength the number of destination buffers starting at {@code dstsOffset}
+ * @return the result of the unwrap operation
+ * @throws SSLException thrown if an SSL error occurred
+ */
+ public static SSLEngineResult unwrap(SSLEngine engine, final ByteBuffer[] srcs, int srcsOffset,
+ final int srcsLength, final ByteBuffer[] dsts, final int dstsOffset,
+ final int dstsLength) throws SSLException {
+ return toConscrypt(engine).unwrap(
+ srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
+ }
+
+ /**
+ * This method enables session ticket support.
+ *
+ * @param engine the engine
+ * @param useSessionTickets True to enable session tickets
+ */
+ public static void setUseSessionTickets(SSLEngine engine, boolean useSessionTickets) {
+ toConscrypt(engine).setUseSessionTickets(useSessionTickets);
+ }
+
+ /**
+ * Sets the application-layer protocols (ALPN) in prioritization order.
+ *
+ * @param engine the engine being configured
+ * @param protocols the protocols in descending order of preference. If empty, no protocol
+ * indications will be used. This array will be copied.
+ * @throws IllegalArgumentException - if protocols is null, or if any element in a non-empty
+ * array is null or an empty (zero-length) string
+ */
+ public static void setApplicationProtocols(SSLEngine engine, String[] protocols) {
+ toConscrypt(engine).setApplicationProtocols(protocols);
+ }
+
+ /**
+ * Gets the application-layer protocols (ALPN) in prioritization order.
+ *
+ * @param engine the engine
+ * @return the protocols in descending order of preference, or an empty array if protocol
+ * indications are not being used. Always returns a new array.
+ */
+ public static String[] getApplicationProtocols(SSLEngine engine) {
+ return toConscrypt(engine).getApplicationProtocols();
+ }
+
+ /**
+ * Sets an application-provided ALPN protocol selector. If provided, this will override
+ * the list of protocols set by {@link #setApplicationProtocols(SSLEngine, String[])}.
+ *
+ * @param engine the engine
+ * @param selector the ALPN protocol selector
+ */
+ public static void setApplicationProtocolSelector(SSLEngine engine,
+ ApplicationProtocolSelector selector) {
+ toConscrypt(engine).setApplicationProtocolSelector(selector);
+ }
+
+ /**
+ * Returns the ALPN protocol agreed upon by client and server.
+ *
+ * @param engine the engine
+ * @return the selected protocol or {@code null} if no protocol was agreed upon.
+ */
+ public static String getApplicationProtocol(SSLEngine engine) {
+ return toConscrypt(engine).getApplicationProtocol();
+ }
+
+ /**
+ * Returns the tls-unique channel binding value for this connection, per RFC 5929. This
+ * will return {@code null} if there is no such value available, such as if the handshake
+ * has not yet completed or this connection is closed.
+ */
+ public static byte[] getTlsUnique(SSLEngine engine) {
+ return toConscrypt(engine).getTlsUnique();
+ }
+
+ /**
+ * Exports a value derived from the TLS master secret as described in RFC 5705.
+ *
+ * @param label the label to use in calculating the exported value. This must be
+ * an ASCII-only string.
+ * @param context the application-specific context value to use in calculating the
+ * exported value. This may be {@code null} to use no application context, which is
+ * treated differently than an empty byte array.
+ * @param length the number of bytes of keying material to return.
+ * @return a value of the specified length, or {@code null} if the handshake has not yet
+ * completed or the connection has been closed.
+ * @throws SSLException if the value could not be exported.
+ */
+ public static byte[] exportKeyingMaterial(SSLEngine engine, String label, byte[] context,
+ int length) throws SSLException {
+ return toConscrypt(engine).exportKeyingMaterial(label, context, length);
+ }
+
+ /**
+ * Indicates whether the given {@link TrustManager} was created by this distribution of
+ * Conscrypt.
+ */
+ public static boolean isConscrypt(TrustManager trustManager) {
+ return trustManager instanceof TrustManagerImpl;
+ }
+
+ private static TrustManagerImpl toConscrypt(TrustManager trustManager) {
+ if (!isConscrypt(trustManager)) {
+ throw new IllegalArgumentException(
+ "Not a Conscrypt trust manager: " + trustManager.getClass().getName());
+ }
+ return (TrustManagerImpl) trustManager;
+ }
+
+ /**
+ * Set the default hostname verifier that will be used for HTTPS endpoint identification by
+ * Conscrypt trust managers. If {@code null} (the default), endpoint identification will use
+ * the default hostname verifier set in
+ * {@link HttpsURLConnection#setDefaultHostnameVerifier(javax.net.ssl.HostnameVerifier)}.
+ */
+ public synchronized static void setDefaultHostnameVerifier(ConscryptHostnameVerifier verifier) {
+ TrustManagerImpl.setDefaultHostnameVerifier(verifier);
+ }
+
+ /**
+ * Returns the currently-set default hostname verifier for Conscrypt trust managers.
+ *
+ * @see #setDefaultHostnameVerifier(ConscryptHostnameVerifier)
+ */
+ public synchronized static ConscryptHostnameVerifier getDefaultHostnameVerifier(
+ TrustManager trustManager) {
+ return TrustManagerImpl.getDefaultHostnameVerifier();
+ }
+
+ /**
+ * Set the hostname verifier that will be used for HTTPS endpoint identification by the
+ * given trust manager. If {@code null} (the default), endpoint identification will use the
+ * default hostname verifier set in {@link
+ * #setDefaultHostnameVerifier(ConscryptHostnameVerifier)}.
+ *
+ * @throws IllegalArgumentException if the provided trust manager is not a Conscrypt trust
+ * manager per {@link #isConscrypt(TrustManager)}
+ */
+ public static void setHostnameVerifier(
+ TrustManager trustManager, ConscryptHostnameVerifier verifier) {
+ toConscrypt(trustManager).setHostnameVerifier(verifier);
+ }
+
+ /**
+ * Returns the currently-set hostname verifier for the given trust manager.
+ *
+ * @throws IllegalArgumentException if the provided trust manager is not a Conscrypt trust
+ * manager per {@link #isConscrypt(TrustManager)}
+ *
+ * @see #setHostnameVerifier(TrustManager, ConscryptHostnameVerifier)
+ */
+ public static ConscryptHostnameVerifier getHostnameVerifier(TrustManager trustManager) {
+ return toConscrypt(trustManager).getHostnameVerifier();
+ }
+
+ /**
+ * Wraps the HttpsURLConnection.HostnameVerifier into a ConscryptHostnameVerifier
+ */
+ public static ConscryptHostnameVerifier wrapHostnameVerifier(final HostnameVerifier verifier) {
+ return new ConscryptHostnameVerifier() {
+ @Override
+ public boolean verify(
+ X509Certificate[] certificates, String hostname, SSLSession session) {
+ return verifier.verify(hostname, session);
+ }
+ };
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptCertStore.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptCertStore.java
new file mode 100644
index 0000000..213f28a
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptCertStore.java
@@ -0,0 +1,43 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.cert.X509Certificate;
+import java.util.Set;
+
+/**
+ * A certificate store that supports additional operations that are used in
+ * TrustManagerImpl. This is primarily implemented by the cert store on the
+ * Android platform.
+ * @hide This class is not part of the Android public SDK API
+ */
+@libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+@Internal
+public interface ConscryptCertStore {
+ /**
+ * Returns a stored CA certificate with the same name and public key as the
+ * provided {@link X509Certificate}.
+ */
+ X509Certificate getTrustAnchor(X509Certificate c);
+
+ /**
+ * Returns all CA certificates with the public key that was used to sign the
+ * provided {@link X509Certificate}.
+ */
+ Set<X509Certificate> findAllIssuers(X509Certificate c);
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptEngine.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptEngine.java
new file mode 100644
index 0000000..4e4bd62
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptEngine.java
@@ -0,0 +1,1838 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2013 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.
+ */
+
+/*
+ * Copyright 2016 The Netty Project
+ *
+ * The Netty Project licenses this file to you 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.NativeConstants.SSL3_RT_HEADER_LENGTH;
+import static com.android.org.conscrypt.NativeConstants.SSL3_RT_MAX_PACKET_SIZE;
+import static com.android.org.conscrypt.NativeConstants.SSL3_RT_MAX_PLAIN_LENGTH;
+import static com.android.org.conscrypt.NativeConstants.SSL_CB_HANDSHAKE_DONE;
+import static com.android.org.conscrypt.NativeConstants.SSL_CB_HANDSHAKE_START;
+import static com.android.org.conscrypt.NativeConstants.SSL_ERROR_WANT_READ;
+import static com.android.org.conscrypt.NativeConstants.SSL_ERROR_WANT_WRITE;
+import static com.android.org.conscrypt.NativeConstants.SSL_ERROR_ZERO_RETURN;
+import static com.android.org.conscrypt.Preconditions.checkArgument;
+import static com.android.org.conscrypt.Preconditions.checkNotNull;
+import static com.android.org.conscrypt.Preconditions.checkPositionIndexes;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_CLOSED;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_CLOSED_INBOUND;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_CLOSED_OUTBOUND;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_HANDSHAKE_COMPLETED;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_HANDSHAKE_STARTED;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_MODE_SET;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_NEW;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_READY;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_READY_HANDSHAKE_CUT_THROUGH;
+import static com.android.org.conscrypt.SSLUtils.calculateOutNetBufSize;
+import static com.android.org.conscrypt.SSLUtils.toSSLHandshakeException;
+import static java.lang.Math.max;
+import static java.lang.Math.min;
+import static javax.net.ssl.SSLEngineResult.HandshakeStatus.FINISHED;
+import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
+import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_WRAP;
+import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
+import static javax.net.ssl.SSLEngineResult.Status.BUFFER_OVERFLOW;
+import static javax.net.ssl.SSLEngineResult.Status.BUFFER_UNDERFLOW;
+import static javax.net.ssl.SSLEngineResult.Status.CLOSED;
+import static javax.net.ssl.SSLEngineResult.Status.OK;
+
+import com.android.org.conscrypt.NativeRef.SSL_SESSION;
+import com.android.org.conscrypt.NativeSsl.BioWrapper;
+import com.android.org.conscrypt.SSLParametersImpl.AliasChooser;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.ECKey;
+import java.security.spec.ECParameterSpec;
+import java.util.Arrays;
+import javax.crypto.SecretKey;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLEngineResult.Status;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * Implements the {@link SSLEngine} API using OpenSSL's non-blocking interfaces.
+ */
+final class ConscryptEngine extends AbstractConscryptEngine implements NativeCrypto.SSLHandshakeCallbacks,
+ SSLParametersImpl.AliasChooser,
+ SSLParametersImpl.PSKCallbacks {
+ private static final SSLEngineResult NEED_UNWRAP_OK =
+ new SSLEngineResult(OK, NEED_UNWRAP, 0, 0);
+ private static final SSLEngineResult NEED_UNWRAP_CLOSED =
+ new SSLEngineResult(CLOSED, NEED_UNWRAP, 0, 0);
+ private static final SSLEngineResult NEED_WRAP_OK = new SSLEngineResult(OK, NEED_WRAP, 0, 0);
+ private static final SSLEngineResult NEED_WRAP_CLOSED =
+ new SSLEngineResult(CLOSED, NEED_WRAP, 0, 0);
+ private static final SSLEngineResult CLOSED_NOT_HANDSHAKING =
+ new SSLEngineResult(CLOSED, NOT_HANDSHAKING, 0, 0);
+
+ private static BufferAllocator defaultBufferAllocator = null;
+
+ private final SSLParametersImpl sslParameters;
+ private BufferAllocator bufferAllocator = defaultBufferAllocator;
+
+ /**
+ * A lazy-created direct buffer used as a bridge between heap buffers provided by the
+ * application and JNI. This avoids the overhead of calling JNI with heap buffers.
+ * Used only when no {@link #bufferAllocator} has been provided.
+ */
+ private ByteBuffer lazyDirectBuffer;
+
+ /**
+ * Hostname used with the TLS extension SNI hostname.
+ */
+ private String peerHostname;
+
+ // @GuardedBy("ssl");
+ private int state = STATE_NEW;
+ private boolean handshakeFinished;
+
+ /**
+ * Wrapper around the underlying SSL object.
+ */
+ private final NativeSsl ssl;
+
+ /**
+ * The BIO used for reading/writing encrypted bytes.
+ */
+ // @GuardedBy("ssl");
+ private final BioWrapper networkBio;
+
+ /**
+ * Set during startHandshake.
+ */
+ private ActiveSession activeSession;
+
+ /**
+ * A snapshot of the active session when the engine was closed.
+ */
+ private SessionSnapshot closedSession;
+
+ /**
+ * The session object exposed externally from this class.
+ */
+ private final SSLSession externalSession =
+ Platform.wrapSSLSession(new ExternalSession(new ExternalSession.Provider() {
+ @Override
+ public ConscryptSession provideSession() {
+ return ConscryptEngine.this.provideSession();
+ }
+ }));
+
+ /**
+ * Private key for the TLS Channel ID extension. This field is client-side only. Set during
+ * startHandshake.
+ */
+ private OpenSSLKey channelIdPrivateKey;
+
+ private int maxSealOverhead;
+
+ private HandshakeListener handshakeListener;
+
+ private final ByteBuffer[] singleSrcBuffer = new ByteBuffer[1];
+ private final ByteBuffer[] singleDstBuffer = new ByteBuffer[1];
+ private final PeerInfoProvider peerInfoProvider;
+
+ ConscryptEngine(SSLParametersImpl sslParameters) {
+ this.sslParameters = sslParameters;
+ peerInfoProvider = PeerInfoProvider.nullProvider();
+ this.ssl = newSsl(sslParameters, this, this);
+ this.networkBio = ssl.newBio();
+ }
+
+ ConscryptEngine(String host, int port, SSLParametersImpl sslParameters) {
+ this.sslParameters = sslParameters;
+ this.peerInfoProvider = PeerInfoProvider.forHostAndPort(host, port);
+ this.ssl = newSsl(sslParameters, this, this);
+ this.networkBio = ssl.newBio();
+ }
+
+ ConscryptEngine(SSLParametersImpl sslParameters, PeerInfoProvider peerInfoProvider,
+ AliasChooser aliasChooser) {
+ this.sslParameters = sslParameters;
+ this.peerInfoProvider = checkNotNull(peerInfoProvider, "peerInfoProvider");
+ this.ssl = newSsl(sslParameters, this, aliasChooser);
+ this.networkBio = ssl.newBio();
+ }
+
+ private static NativeSsl newSsl(
+ SSLParametersImpl sslParameters, ConscryptEngine engine, AliasChooser aliasChooser) {
+ try {
+ return NativeSsl.newInstance(sslParameters, engine, aliasChooser, engine);
+ } catch (SSLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Configures the default {@link BufferAllocator} to be used by all future
+ * {@link SSLEngine} and {@link ConscryptEngineSocket} instances from this provider.
+ */
+ static void setDefaultBufferAllocator(BufferAllocator bufferAllocator) {
+ defaultBufferAllocator = bufferAllocator;
+ }
+
+ /**
+ * Returns the default {@link BufferAllocator}, which may be {@code null} if no default
+ * has been explicitly set.
+ */
+ static BufferAllocator getDefaultBufferAllocator() {
+ return defaultBufferAllocator;
+ }
+
+ @Override
+ void setBufferAllocator(BufferAllocator bufferAllocator) {
+ synchronized (ssl) {
+ if (isHandshakeStarted()) {
+ throw new IllegalStateException(
+ "Could not set buffer allocator after the initial handshake has begun.");
+ }
+ this.bufferAllocator = bufferAllocator;
+ }
+ }
+
+ /**
+ * Returns the maximum overhead, in bytes, of sealing a record with SSL.
+ */
+ @Override
+ int maxSealOverhead() {
+ return maxSealOverhead;
+ }
+
+ /**
+ * Enables/disables TLS Channel ID for this server engine.
+ *
+ * <p>This method needs to be invoked before the handshake starts.
+ *
+ * @throws IllegalStateException if this is a client engine or if the handshake has already
+ * started.
+ */
+ @Override
+ void setChannelIdEnabled(boolean enabled) {
+ synchronized (ssl) {
+ if (getUseClientMode()) {
+ throw new IllegalStateException("Not allowed in client mode");
+ }
+ if (isHandshakeStarted()) {
+ throw new IllegalStateException(
+ "Could not enable/disable Channel ID after the initial handshake has begun.");
+ }
+ sslParameters.channelIdEnabled = enabled;
+ }
+ }
+
+ /**
+ * Gets the TLS Channel ID for this server engine. Channel ID is only available once the
+ * handshake completes.
+ *
+ * @return channel ID or {@code null} if not available.
+ *
+ * @throws IllegalStateException if this is a client engine or if the handshake has not yet
+ * completed.
+ * @throws SSLException if channel ID is available but could not be obtained.
+ */
+ @Override
+ byte[] getChannelId() throws SSLException {
+ synchronized (ssl) {
+ if (getUseClientMode()) {
+ throw new IllegalStateException("Not allowed in client mode");
+ }
+
+ if (isHandshakeStarted()) {
+ throw new IllegalStateException(
+ "Channel ID is only available after handshake completes");
+ }
+ return ssl.getTlsChannelId();
+ }
+ }
+
+ /**
+ * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client engine.
+ *
+ * <p>This method needs to be invoked before the handshake starts.
+ *
+ * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables
+ * TLS Channel ID). The private key must be an Elliptic Curve (EC) key based on the NIST
+ * P-256 curve (aka SECG secp256r1 or ANSI X9.62 prime256v1).
+ *
+ * @throws IllegalStateException if this is a server engine or if the handshake has already
+ * started.
+ */
+ @Override
+ void setChannelIdPrivateKey(PrivateKey privateKey) {
+ if (!getUseClientMode()) {
+ throw new IllegalStateException("Not allowed in server mode");
+ }
+
+ synchronized (ssl) {
+ if (isHandshakeStarted()) {
+ throw new IllegalStateException("Could not change Channel ID private key "
+ + "after the initial handshake has begun.");
+ }
+
+ if (privateKey == null) {
+ sslParameters.channelIdEnabled = false;
+ channelIdPrivateKey = null;
+ return;
+ }
+
+ sslParameters.channelIdEnabled = true;
+ try {
+ ECParameterSpec ecParams = null;
+ if (privateKey instanceof ECKey) {
+ ecParams = ((ECKey) privateKey).getParams();
+ }
+ if (ecParams == null) {
+ // Assume this is a P-256 key, as specified in the contract of this method.
+ ecParams =
+ OpenSSLECGroupContext.getCurveByName("prime256v1").getECParameterSpec();
+ }
+ channelIdPrivateKey =
+ OpenSSLKey.fromECPrivateKeyForTLSStackOnly(privateKey, ecParams);
+ } catch (InvalidKeyException e) {
+ // Will have error in startHandshake
+ }
+ }
+ }
+
+ /**
+ * Sets the listener for the completion of the TLS handshake.
+ */
+ @Override
+ void setHandshakeListener(HandshakeListener handshakeListener) {
+ synchronized (ssl) {
+ if (isHandshakeStarted()) {
+ throw new IllegalStateException(
+ "Handshake listener must be set before starting the handshake.");
+ }
+ this.handshakeListener = handshakeListener;
+ }
+ }
+
+ private boolean isHandshakeStarted() {
+ switch (state) {
+ case STATE_NEW:
+ case STATE_MODE_SET:
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ /**
+ * This method enables Server Name Indication (SNI) and overrides the {@link PeerInfoProvider}
+ * supplied during engine creation. If the hostname is not a valid SNI hostname, the SNI
+ * extension will be omitted from the handshake.
+ */
+ @Override
+ void setHostname(String hostname) {
+ sslParameters.setUseSni(hostname != null);
+ this.peerHostname = hostname;
+ }
+
+ /**
+ * Returns the hostname from {@link #setHostname(String)} or supplied by the
+ * {@link PeerInfoProvider} upon creation. No DNS resolution is attempted before
+ * returning the hostname.
+ */
+ @Override
+ String getHostname() {
+ return peerHostname != null ? peerHostname : peerInfoProvider.getHostname();
+ }
+
+ @Override
+ public String getPeerHost() {
+ return peerHostname != null ? peerHostname : peerInfoProvider.getHostnameOrIP();
+ }
+
+ @Override
+ public int getPeerPort() {
+ return peerInfoProvider.getPort();
+ }
+
+ @Override
+ public void beginHandshake() throws SSLException {
+ synchronized (ssl) {
+ beginHandshakeInternal();
+ }
+ }
+
+ private void beginHandshakeInternal() throws SSLException {
+ switch (state) {
+ case STATE_NEW: {
+ throw new IllegalStateException("Client/server mode must be set before handshake");
+ }
+ case STATE_MODE_SET: {
+ // We know what mode to handshake in but have not started the handshake, proceed
+ break;
+ }
+ case STATE_CLOSED_INBOUND:
+ case STATE_CLOSED_OUTBOUND:
+ case STATE_CLOSED:
+ throw new SSLHandshakeException("Engine has already been closed");
+ default:
+ // We've already started the handshake, just return
+ return;
+ }
+
+ transitionTo(STATE_HANDSHAKE_STARTED);
+
+ boolean releaseResources = true;
+ try {
+ // Prepare the SSL object for the handshake.
+ ssl.initialize(getHostname(), channelIdPrivateKey);
+
+ // For clients, offer to resume a previously cached session to avoid the
+ // full TLS handshake.
+ if (getUseClientMode()) {
+ NativeSslSession cachedSession = clientSessionContext().getCachedSession(
+ getHostname(), getPeerPort(), sslParameters);
+ if (cachedSession != null) {
+ cachedSession.offerToResume(ssl);
+ }
+ }
+
+ maxSealOverhead = ssl.getMaxSealOverhead();
+ handshake();
+ releaseResources = false;
+ } catch (IOException e) {
+ // Write CCS errors to EventLog
+ String message = e.getMessage();
+ // Must match error reason string of SSL_R_UNEXPECTED_CCS (in ssl/ssl_err.c)
+ if (message.contains("unexpected CCS")) {
+ String logMessage = String.format("ssl_unexpected_ccs: host=%s", getPeerHost());
+ Platform.logEvent(logMessage);
+ }
+ closeAll();
+ throw SSLUtils.toSSLHandshakeException(e);
+ } finally {
+ if (releaseResources) {
+ closeAndFreeResources();
+ }
+ }
+ }
+
+ @Override
+ public void closeInbound() {
+ synchronized (ssl) {
+ if (state == STATE_CLOSED || state == STATE_CLOSED_INBOUND) {
+ return;
+ }
+ if (isHandshakeStarted()) {
+ if (state == STATE_CLOSED_OUTBOUND) {
+ transitionTo(STATE_CLOSED);
+ } else {
+ transitionTo(STATE_CLOSED_INBOUND);
+ }
+ freeIfDone();
+ } else {
+ // Never started the handshake. Just close now.
+ closeAndFreeResources();
+ }
+ }
+ }
+
+ @Override
+ public void closeOutbound() {
+ synchronized (ssl) {
+ if (state == STATE_CLOSED || state == STATE_CLOSED_OUTBOUND) {
+ return;
+ }
+ if (isHandshakeStarted()) {
+ if (state == STATE_CLOSED_INBOUND) {
+ transitionTo(STATE_CLOSED);
+ } else {
+ transitionTo(STATE_CLOSED_OUTBOUND);
+ }
+ sendSSLShutdown();
+ freeIfDone();
+ } else {
+ // Never started the handshake. Just close now.
+ closeAndFreeResources();
+ }
+ }
+ }
+
+ @Override
+ public Runnable getDelegatedTask() {
+ // This implementation doesn't use any delegated tasks.
+ return null;
+ }
+
+ @Override
+ public String[] getEnabledCipherSuites() {
+ return sslParameters.getEnabledCipherSuites();
+ }
+
+ @Override
+ public String[] getEnabledProtocols() {
+ return sslParameters.getEnabledProtocols();
+ }
+
+ @Override
+ public boolean getEnableSessionCreation() {
+ return sslParameters.getEnableSessionCreation();
+ }
+
+ @Override
+ public SSLParameters getSSLParameters() {
+ SSLParameters params = super.getSSLParameters();
+ Platform.getSSLParameters(params, sslParameters, this);
+ return params;
+ }
+
+ @Override
+ public void setSSLParameters(SSLParameters p) {
+ super.setSSLParameters(p);
+ Platform.setSSLParameters(p, sslParameters, this);
+ }
+
+ @Override
+ public HandshakeStatus getHandshakeStatus() {
+ synchronized (ssl) {
+ return getHandshakeStatusInternal();
+ }
+ }
+
+ private HandshakeStatus getHandshakeStatusInternal() {
+ if (handshakeFinished) {
+ return HandshakeStatus.NOT_HANDSHAKING;
+ }
+ switch (state) {
+ case STATE_HANDSHAKE_STARTED:
+ return pendingStatus(pendingOutboundEncryptedBytes());
+ case STATE_HANDSHAKE_COMPLETED:
+ return HandshakeStatus.NEED_WRAP;
+ case STATE_NEW:
+ case STATE_MODE_SET:
+ case STATE_CLOSED:
+ case STATE_CLOSED_INBOUND:
+ case STATE_CLOSED_OUTBOUND:
+ case STATE_READY:
+ case STATE_READY_HANDSHAKE_CUT_THROUGH:
+ return HandshakeStatus.NOT_HANDSHAKING;
+ default:
+ break;
+ }
+ throw new IllegalStateException("Unexpected engine state: " + state);
+ }
+
+ int pendingOutboundEncryptedBytes() {
+ return networkBio.getPendingWrittenBytes();
+ }
+
+ private int pendingInboundCleartextBytes() {
+ return ssl.getPendingReadableBytes();
+ }
+
+ private static SSLEngineResult.HandshakeStatus pendingStatus(int pendingOutboundBytes) {
+ // Depending on if there is something left in the BIO we need to WRAP or UNWRAP
+ return pendingOutboundBytes > 0 ? NEED_WRAP : NEED_UNWRAP;
+ }
+
+ @Override
+ public boolean getNeedClientAuth() {
+ return sslParameters.getNeedClientAuth();
+ }
+
+ /**
+ * Work-around to allow this method to be called on older versions of Android.
+ */
+ @Override
+ SSLSession handshakeSession() {
+ synchronized (ssl) {
+ if (state == STATE_HANDSHAKE_STARTED) {
+ return Platform.wrapSSLSession(new ExternalSession(new ExternalSession.Provider() {
+ @Override
+ public ConscryptSession provideSession() {
+ return ConscryptEngine.this.provideHandshakeSession();
+ }
+ }));
+ }
+ return null;
+ }
+ }
+
+ @Override
+ public SSLSession getSession() {
+ return externalSession;
+ }
+
+ private ConscryptSession provideSession() {
+ synchronized (ssl) {
+ if (state == STATE_CLOSED) {
+ return closedSession != null ? closedSession : SSLNullSession.getNullSession();
+ }
+ if (state < STATE_HANDSHAKE_COMPLETED) {
+ // Return an invalid session with invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
+ return SSLNullSession.getNullSession();
+ }
+ return activeSession;
+ }
+ }
+
+ private ConscryptSession provideHandshakeSession() {
+ synchronized (ssl) {
+ return state == STATE_HANDSHAKE_STARTED ? activeSession
+ : SSLNullSession.getNullSession();
+ }
+ }
+
+ // After handshake has started, provide active session otherwise a null session,
+ // for code which needs to read session attributes without triggering the handshake.
+ private ConscryptSession provideAfterHandshakeSession() {
+ return (state < STATE_HANDSHAKE_STARTED) ? SSLNullSession.getNullSession()
+ : provideSession();
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return NativeCrypto.getSupportedCipherSuites();
+ }
+
+ @Override
+ public String[] getSupportedProtocols() {
+ return NativeCrypto.getSupportedProtocols();
+ }
+
+ @Override
+ public boolean getUseClientMode() {
+ return sslParameters.getUseClientMode();
+ }
+
+ @Override
+ public boolean getWantClientAuth() {
+ return sslParameters.getWantClientAuth();
+ }
+
+ @Override
+ public boolean isInboundDone() {
+ synchronized (ssl) {
+ return (state == STATE_CLOSED || state == STATE_CLOSED_INBOUND
+ || ssl.wasShutdownReceived())
+ && (pendingInboundCleartextBytes() == 0);
+ }
+ }
+
+ @Override
+ public boolean isOutboundDone() {
+ synchronized (ssl) {
+ return (state == STATE_CLOSED || state == STATE_CLOSED_OUTBOUND
+ || ssl.wasShutdownSent())
+ && (pendingOutboundEncryptedBytes() == 0);
+ }
+ }
+
+ @Override
+ public void setEnabledCipherSuites(String[] suites) {
+ sslParameters.setEnabledCipherSuites(suites);
+ }
+
+ @Override
+ public void setEnabledProtocols(String[] protocols) {
+ sslParameters.setEnabledProtocols(protocols);
+ }
+
+ @Override
+ public void setEnableSessionCreation(boolean flag) {
+ sslParameters.setEnableSessionCreation(flag);
+ }
+
+ @Override
+ public void setNeedClientAuth(boolean need) {
+ sslParameters.setNeedClientAuth(need);
+ }
+
+ @Override
+ public void setUseClientMode(boolean mode) {
+ synchronized (ssl) {
+ if (isHandshakeStarted()) {
+ throw new IllegalArgumentException(
+ "Can not change mode after handshake: state == " + state);
+ }
+ transitionTo(STATE_MODE_SET);
+ sslParameters.setUseClientMode(mode);
+ }
+ }
+
+ @Override
+ public void setWantClientAuth(boolean want) {
+ sslParameters.setWantClientAuth(want);
+ }
+
+ @Override
+ public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
+ synchronized (ssl) {
+ try {
+ return unwrap(singleSrcBuffer(src), singleDstBuffer(dst));
+ } finally {
+ resetSingleSrcBuffer();
+ resetSingleDstBuffer();
+ }
+ }
+ }
+
+ @Override
+ public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts) throws SSLException {
+ synchronized (ssl) {
+ try {
+ return unwrap(singleSrcBuffer(src), dsts);
+ } finally {
+ resetSingleSrcBuffer();
+ }
+ }
+ }
+
+ @Override
+ public SSLEngineResult unwrap(final ByteBuffer src, final ByteBuffer[] dsts, final int offset,
+ final int length) throws SSLException {
+ synchronized (ssl) {
+ try {
+ return unwrap(singleSrcBuffer(src), 0, 1, dsts, offset, length);
+ } finally {
+ resetSingleSrcBuffer();
+ }
+ }
+ }
+
+ @Override
+ SSLEngineResult unwrap(final ByteBuffer[] srcs, final ByteBuffer[] dsts) throws SSLException {
+ checkArgument(srcs != null, "srcs is null");
+ checkArgument(dsts != null, "dsts is null");
+ return unwrap(srcs, 0, srcs.length, dsts, 0, dsts.length);
+ }
+
+ @Override
+ SSLEngineResult unwrap(final ByteBuffer[] srcs, int srcsOffset, final int srcsLength,
+ final ByteBuffer[] dsts, final int dstsOffset, final int dstsLength)
+ throws SSLException {
+ checkArgument(srcs != null, "srcs is null");
+ checkArgument(dsts != null, "dsts is null");
+ checkPositionIndexes(srcsOffset, srcsOffset + srcsLength, srcs.length);
+ checkPositionIndexes(dstsOffset, dstsOffset + dstsLength, dsts.length);
+
+ // Determine the output capacity.
+ final int dstLength = calcDstsLength(dsts, dstsOffset, dstsLength);
+ final int endOffset = dstsOffset + dstsLength;
+
+ final int srcsEndOffset = srcsOffset + srcsLength;
+ final long srcLength = calcSrcsLength(srcs, srcsOffset, srcsEndOffset);
+
+ synchronized (ssl) {
+ switch (state) {
+ case STATE_MODE_SET:
+ // Begin the handshake implicitly.
+ beginHandshakeInternal();
+ break;
+ case STATE_CLOSED_INBOUND:
+ case STATE_CLOSED:
+ freeIfDone();
+ // If the inbound direction is closed. we can't send anymore.
+ return new SSLEngineResult(Status.CLOSED, getHandshakeStatusInternal(), 0, 0);
+ case STATE_NEW:
+ throw new IllegalStateException(
+ "Client/server mode must be set before calling unwrap");
+ default:
+ break;
+ }
+
+ HandshakeStatus handshakeStatus = HandshakeStatus.NOT_HANDSHAKING;
+ if (!handshakeFinished) {
+ handshakeStatus = handshake();
+ if (handshakeStatus == NEED_WRAP) {
+ return NEED_WRAP_OK;
+ }
+ if (state == STATE_CLOSED) {
+ return NEED_WRAP_CLOSED;
+ }
+ // NEED_UNWRAP - just fall through to perform the unwrap.
+ }
+
+ // Consume any source data. Skip this if there are unread cleartext data.
+ boolean noCleartextDataAvailable = pendingInboundCleartextBytes() <= 0;
+ int lenRemaining = 0;
+ if (srcLength > 0 && noCleartextDataAvailable) {
+ if (srcLength < SSL3_RT_HEADER_LENGTH) {
+ // Need to be able to read a full TLS header.
+ return new SSLEngineResult(BUFFER_UNDERFLOW, getHandshakeStatus(), 0, 0);
+ }
+
+ int packetLength = SSLUtils.getEncryptedPacketLength(srcs, srcsOffset);
+ if (packetLength < 0) {
+ throw new SSLException("Unable to parse TLS packet header");
+ }
+
+ if (srcLength < packetLength) {
+ // We either have not enough data to read the packet header or not enough for
+ // reading the whole packet.
+ return new SSLEngineResult(BUFFER_UNDERFLOW, getHandshakeStatus(), 0, 0);
+ }
+
+ // Limit the amount of data to be read to a single packet.
+ lenRemaining = packetLength;
+ } else if (noCleartextDataAvailable) {
+ // No pending data and nothing provided as input. Need more data.
+ return new SSLEngineResult(BUFFER_UNDERFLOW, getHandshakeStatus(), 0, 0);
+ }
+
+ // Write all of the encrypted source data to the networkBio
+ int bytesConsumed = 0;
+ if (lenRemaining > 0 && srcsOffset < srcsEndOffset) {
+ do {
+ ByteBuffer src = srcs[srcsOffset];
+ int remaining = src.remaining();
+ if (remaining == 0) {
+ // We must skip empty buffers as BIO_write will return 0 if asked to
+ // write something with length 0.
+ srcsOffset++;
+ continue;
+ }
+ // Write the source encrypted data to the networkBio.
+ int written = writeEncryptedData(src, min(lenRemaining, remaining));
+ if (written > 0) {
+ bytesConsumed += written;
+ lenRemaining -= written;
+ if (lenRemaining == 0) {
+ // A whole packet has been consumed.
+ break;
+ }
+
+ if (written == remaining) {
+ srcsOffset++;
+ } else {
+ // We were not able to write everything into the BIO so break the
+ // write loop as otherwise we will produce an error on the next
+ // write attempt, which will trigger a SSL.clearError() later.
+ break;
+ }
+ } else {
+ // BIO_write returned a negative or zero number, this means we could not
+ // complete the write operation and should retry later.
+ // We ignore BIO_* errors here as we use in memory BIO anyway and will
+ // do another SSL_* call later on in which we will produce an exception
+ // in case of an error
+ NativeCrypto.SSL_clear_error();
+ break;
+ }
+ } while (srcsOffset < srcsEndOffset);
+ }
+
+ // Now read any available plaintext data.
+ int bytesProduced = 0;
+ try {
+ if (dstLength > 0) {
+ // Write decrypted data to dsts buffers
+ for (int idx = dstsOffset; idx < endOffset; ++idx) {
+ ByteBuffer dst = dsts[idx];
+ if (!dst.hasRemaining()) {
+ continue;
+ }
+
+ int bytesRead = readPlaintextData(dst);
+ if (bytesRead > 0) {
+ bytesProduced += bytesRead;
+ if (dst.hasRemaining()) {
+ // We haven't filled this buffer fully, break out of the loop
+ // and determine the correct response status below.
+ break;
+ }
+ } else {
+ switch (bytesRead) {
+ case -SSL_ERROR_WANT_READ:
+ case -SSL_ERROR_WANT_WRITE: {
+ return newResult(bytesConsumed, bytesProduced, handshakeStatus);
+ }
+ case -SSL_ERROR_ZERO_RETURN: {
+ // We received a close_notify from the peer, so mark the
+ // inbound direction as closed and shut down the SSL object
+ closeAll();
+ return new SSLEngineResult(Status.CLOSED,
+ pendingOutboundEncryptedBytes() > 0
+ ? NEED_WRAP : NOT_HANDSHAKING,
+ bytesConsumed, bytesProduced);
+ }
+ default: {
+ // Should never get here.
+ closeAll();
+ throw newSslExceptionWithMessage("SSL_read");
+ }
+ }
+ }
+ }
+ } else {
+ // If the capacity of all destination buffers is 0 we need to trigger a SSL_read
+ // anyway to ensure everything is flushed in the BIO pair and so we can detect
+ // it in the pendingInboundCleartextBytes() call.
+ ssl.forceRead();
+ }
+ } catch (InterruptedIOException e) {
+ return newResult(bytesConsumed, bytesProduced, handshakeStatus);
+ } catch (IOException e) {
+ // Shut down the SSL and rethrow the exception. Users will need to drain any alerts
+ // from the SSL before closing.
+ closeAll();
+ throw convertException(e);
+ }
+
+ // There won't be any application data until we're done handshaking.
+ // We first check handshakeFinished to eliminate the overhead of extra JNI call if
+ // possible.
+ int pendingCleartextBytes = handshakeFinished ? pendingInboundCleartextBytes() : 0;
+ if (pendingCleartextBytes > 0) {
+ // We filled all buffers but there is still some data pending in the BIO buffer,
+ // return BUFFER_OVERFLOW.
+ return new SSLEngineResult(BUFFER_OVERFLOW,
+ mayFinishHandshake(handshakeStatus == FINISHED
+ ? handshakeStatus
+ : getHandshakeStatusInternal()),
+ bytesConsumed, bytesProduced);
+ }
+
+ return newResult(bytesConsumed, bytesProduced, handshakeStatus);
+ }
+ }
+
+ private static int calcDstsLength(ByteBuffer[] dsts, int dstsOffset, int dstsLength) {
+ int capacity = 0;
+ for (int i = 0; i < dsts.length; i++) {
+ ByteBuffer dst = dsts[i];
+ checkArgument(dst != null, "dsts[%d] is null", i);
+ if (dst.isReadOnly()) {
+ throw new ReadOnlyBufferException();
+ }
+ if (i >= dstsOffset && i < dstsOffset + dstsLength) {
+ capacity += dst.remaining();
+ }
+ }
+ return capacity;
+ }
+
+ private static long calcSrcsLength(ByteBuffer[] srcs, int srcsOffset, int srcsEndOffset) {
+ long len = 0;
+ for (int i = srcsOffset; i < srcsEndOffset; i++) {
+ ByteBuffer src = srcs[i];
+ if (src == null) {
+ throw new IllegalArgumentException("srcs[" + i + "] is null");
+ }
+ len += src.remaining();
+ }
+ return len;
+ }
+
+ private SSLEngineResult.HandshakeStatus handshake() throws SSLException {
+ try {
+ // Only actually perform the handshake if we haven't already just completed it
+ // via BIO operations.
+ try {
+ int ssl_error_code = ssl.doHandshake();
+ switch (ssl_error_code) {
+ case SSL_ERROR_WANT_READ:
+ return pendingStatus(pendingOutboundEncryptedBytes());
+ case SSL_ERROR_WANT_WRITE: {
+ return NEED_WRAP;
+ }
+ default: {
+ // SSL_ERROR_NONE.
+ }
+ }
+ } catch (IOException e) {
+ // Shut down the SSL and rethrow the exception. Users will need to drain any alerts
+ // from the SSL before closing.
+ closeAll();
+ throw e;
+ }
+
+ // The handshake has completed successfully...
+
+ // Update the session from the current state of the SSL object.
+ activeSession.onPeerCertificateAvailable(getPeerHost(), getPeerPort());
+
+ finishHandshake();
+ return FINISHED;
+ } catch (Exception e) {
+ throw toSSLHandshakeException(e);
+ }
+ }
+
+ private void finishHandshake() throws SSLException {
+ handshakeFinished = true;
+ // Notify the listener, if provided.
+ if (handshakeListener != null) {
+ handshakeListener.onHandshakeFinished();
+ }
+ }
+
+ /**
+ * Write plaintext data to the OpenSSL internal BIO
+ *
+ * Calling this function with src.remaining == 0 is undefined.
+ */
+ private int writePlaintextData(final ByteBuffer src, int len) throws SSLException {
+ try {
+ final int pos = src.position();
+ final int sslWrote;
+ if (src.isDirect()) {
+ sslWrote = writePlaintextDataDirect(src, pos, len);
+ } else {
+ sslWrote = writePlaintextDataHeap(src, pos, len);
+ }
+ if (sslWrote > 0) {
+ src.position(pos + sslWrote);
+ }
+ return sslWrote;
+ } catch (Exception e) {
+ throw convertException(e);
+ }
+ }
+
+ private int writePlaintextDataDirect(ByteBuffer src, int pos, int len) throws IOException {
+ return ssl.writeDirectByteBuffer(directByteBufferAddress(src, pos), len);
+ }
+
+ private int writePlaintextDataHeap(ByteBuffer src, int pos, int len) throws IOException {
+ AllocatedBuffer allocatedBuffer = null;
+ try {
+ final ByteBuffer buffer;
+ if (bufferAllocator != null) {
+ allocatedBuffer = bufferAllocator.allocateDirectBuffer(len);
+ buffer = allocatedBuffer.nioBuffer();
+ } else {
+ // We don't have a buffer allocator, but we don't want to send a heap
+ // buffer to JNI. So lazy-create a direct buffer that we will use from now
+ // on to copy plaintext data.
+ buffer = getOrCreateLazyDirectBuffer();
+ }
+
+ // Copy the data to the direct buffer.
+ int limit = src.limit();
+ int bytesToWrite = min(len, buffer.remaining());
+ src.limit(pos + bytesToWrite);
+ buffer.put(src);
+ buffer.flip();
+ // Restore the original position and limit.
+ src.limit(limit);
+ src.position(pos);
+
+ return writePlaintextDataDirect(buffer, 0, bytesToWrite);
+ } finally {
+ if (allocatedBuffer != null) {
+ // Release the buffer back to the pool.
+ allocatedBuffer.release();
+ }
+ }
+ }
+
+ /**
+ * Read plaintext data from the OpenSSL internal BIO
+ */
+ private int readPlaintextData(final ByteBuffer dst) throws IOException {
+ try {
+ final int pos = dst.position();
+ final int limit = dst.limit();
+ final int len = min(SSL3_RT_MAX_PACKET_SIZE, limit - pos);
+ if (dst.isDirect()) {
+ int bytesRead = readPlaintextDataDirect(dst, pos, len);
+ if (bytesRead > 0) {
+ dst.position(pos + bytesRead);
+ }
+ return bytesRead;
+ }
+
+ // The heap method updates the dst position automatically.
+ return readPlaintextDataHeap(dst, len);
+ } catch (CertificateException e) {
+ throw convertException(e);
+ }
+ }
+
+ private int readPlaintextDataDirect(ByteBuffer dst, int pos, int len)
+ throws IOException, CertificateException {
+ return ssl.readDirectByteBuffer(directByteBufferAddress(dst, pos), len);
+ }
+
+ private int readPlaintextDataHeap(ByteBuffer dst, int len)
+ throws IOException, CertificateException {
+ AllocatedBuffer allocatedBuffer = null;
+ try {
+ final ByteBuffer buffer;
+ if (bufferAllocator != null) {
+ allocatedBuffer = bufferAllocator.allocateDirectBuffer(len);
+ buffer = allocatedBuffer.nioBuffer();
+ } else {
+ // We don't have a buffer allocator, but we don't want to send a heap
+ // buffer to JNI. So lazy-create a direct buffer that we will use from now
+ // on to copy plaintext data.
+ buffer = getOrCreateLazyDirectBuffer();
+ }
+
+ // Read the data to the direct buffer.
+ int bytesToRead = min(len, buffer.remaining());
+ int bytesRead = readPlaintextDataDirect(buffer, 0, bytesToRead);
+ if (bytesRead > 0) {
+ // Copy the data to the heap buffer.
+ buffer.position(bytesRead);
+ buffer.flip();
+ dst.put(buffer);
+ }
+
+ return bytesRead;
+ } finally {
+ if (allocatedBuffer != null) {
+ // Release the buffer back to the pool.
+ allocatedBuffer.release();
+ }
+ }
+ }
+
+ private SSLException convertException(Throwable e) {
+ if (e instanceof SSLHandshakeException || !handshakeFinished) {
+ return SSLUtils.toSSLHandshakeException(e);
+ }
+ return SSLUtils.toSSLException(e);
+ }
+
+ /**
+ * Write encrypted data to the OpenSSL network BIO.
+ */
+ private int writeEncryptedData(final ByteBuffer src, int len) throws SSLException {
+ try {
+ final int pos = src.position();
+ final int bytesWritten;
+ if (src.isDirect()) {
+ bytesWritten = writeEncryptedDataDirect(src, pos, len);
+ } else {
+ bytesWritten = writeEncryptedDataHeap(src, pos, len);
+ }
+
+ if (bytesWritten > 0) {
+ src.position(pos + bytesWritten);
+ }
+
+ return bytesWritten;
+ } catch (IOException e) {
+ closeAll();
+ throw new SSLException(e);
+ }
+ }
+
+ private int writeEncryptedDataDirect(ByteBuffer src, int pos, int len) throws IOException {
+ return networkBio.writeDirectByteBuffer(directByteBufferAddress(src, pos), len);
+ }
+
+ private int writeEncryptedDataHeap(ByteBuffer src, int pos, int len) throws IOException {
+ AllocatedBuffer allocatedBuffer = null;
+ try {
+ final ByteBuffer buffer;
+ if (bufferAllocator != null) {
+ allocatedBuffer = bufferAllocator.allocateDirectBuffer(len);
+ buffer = allocatedBuffer.nioBuffer();
+ } else {
+ // We don't have a buffer allocator, but we don't want to send a heap
+ // buffer to JNI. So lazy-create a direct buffer that we will use from now
+ // on to copy encrypted packets.
+ buffer = getOrCreateLazyDirectBuffer();
+ }
+
+ int limit = src.limit();
+ int bytesToCopy = min(min(limit - pos, len), buffer.remaining());
+ src.limit(pos + bytesToCopy);
+ buffer.put(src);
+ // Restore the original limit.
+ src.limit(limit);
+
+ // Reset the original position on the source buffer.
+ src.position(pos);
+
+ int bytesWritten = writeEncryptedDataDirect(buffer, 0, bytesToCopy);
+
+ // Restore the original position.
+ src.position(pos);
+
+ return bytesWritten;
+ } finally {
+ if (allocatedBuffer != null) {
+ // Release the buffer back to the pool.
+ allocatedBuffer.release();
+ }
+ }
+ }
+
+ private ByteBuffer getOrCreateLazyDirectBuffer() {
+ if (lazyDirectBuffer == null) {
+ lazyDirectBuffer = ByteBuffer.allocateDirect(
+ max(SSL3_RT_MAX_PLAIN_LENGTH, SSL3_RT_MAX_PACKET_SIZE));
+ }
+ lazyDirectBuffer.clear();
+ return lazyDirectBuffer;
+ }
+
+ private long directByteBufferAddress(ByteBuffer directBuffer, int pos) {
+ return NativeCrypto.getDirectBufferAddress(directBuffer) + pos;
+ }
+
+ private SSLEngineResult readPendingBytesFromBIO(ByteBuffer dst, int bytesConsumed,
+ int bytesProduced, SSLEngineResult.HandshakeStatus status) throws SSLException {
+ try {
+ // Check to see if the engine wrote data into the network BIO
+ int pendingNet = pendingOutboundEncryptedBytes();
+ if (pendingNet > 0) {
+ // Do we have enough room in dst to write encrypted data?
+ int capacity = dst.remaining();
+ if (capacity < pendingNet) {
+ return new SSLEngineResult(BUFFER_OVERFLOW,
+ mayFinishHandshake(
+ status == FINISHED ? status : getHandshakeStatus(pendingNet)),
+ bytesConsumed, bytesProduced);
+ }
+
+ // Write the pending data from the network BIO into the dst buffer
+ int produced = readEncryptedData(dst, pendingNet);
+
+ if (produced <= 0) {
+ // We ignore BIO_* errors here as we use in memory BIO anyway and will do
+ // another SSL_* call later on in which we will produce an exception in
+ // case of an error
+ NativeCrypto.SSL_clear_error();
+ } else {
+ bytesProduced += produced;
+ pendingNet -= produced;
+ }
+
+ return new SSLEngineResult(getEngineStatus(),
+ mayFinishHandshake(
+ status == FINISHED ? status : getHandshakeStatus(pendingNet)),
+ bytesConsumed, bytesProduced);
+ }
+ return null;
+ } catch (Exception e) {
+ throw convertException(e);
+ }
+ }
+
+ /**
+ * Read encrypted data from the OpenSSL network BIO
+ */
+ private int readEncryptedData(final ByteBuffer dst, final int pending) throws SSLException {
+ try {
+ int bytesRead = 0;
+ final int pos = dst.position();
+ if (dst.remaining() >= pending) {
+ final int limit = dst.limit();
+ final int len = min(pending, limit - pos);
+ if (dst.isDirect()) {
+ bytesRead = readEncryptedDataDirect(dst, pos, len);
+ // Need to update the position on the dst buffer.
+ if (bytesRead > 0) {
+ dst.position(pos + bytesRead);
+ }
+ } else {
+ // The heap method will update the position on the dst buffer automatically.
+ bytesRead = readEncryptedDataHeap(dst, len);
+ }
+ }
+
+ return bytesRead;
+ } catch (Exception e) {
+ throw convertException(e);
+ }
+ }
+
+ private int readEncryptedDataDirect(ByteBuffer dst, int pos, int len) throws IOException {
+ return networkBio.readDirectByteBuffer(directByteBufferAddress(dst, pos), len);
+ }
+
+ private int readEncryptedDataHeap(ByteBuffer dst, int len) throws IOException {
+ AllocatedBuffer allocatedBuffer = null;
+ try {
+ final ByteBuffer buffer;
+ if (bufferAllocator != null) {
+ allocatedBuffer = bufferAllocator.allocateDirectBuffer(len);
+ buffer = allocatedBuffer.nioBuffer();
+ } else {
+ // We don't have a buffer allocator, but we don't want to send a heap
+ // buffer to JNI. So lazy-create a direct buffer that we will use from now
+ // on to copy encrypted packets.
+ buffer = getOrCreateLazyDirectBuffer();
+ }
+
+ int bytesToRead = min(len, buffer.remaining());
+ int bytesRead = readEncryptedDataDirect(buffer, 0, bytesToRead);
+ if (bytesRead > 0) {
+ buffer.position(bytesRead);
+ buffer.flip();
+ dst.put(buffer);
+ }
+
+ return bytesRead;
+ } finally {
+ if (allocatedBuffer != null) {
+ // Release the buffer back to the pool.
+ allocatedBuffer.release();
+ }
+ }
+ }
+
+ private SSLEngineResult.HandshakeStatus mayFinishHandshake(
+ SSLEngineResult.HandshakeStatus status) throws SSLException {
+ if (!handshakeFinished && status == NOT_HANDSHAKING) {
+ // If the status was NOT_HANDSHAKING and we not finished the handshake we need to call
+ // SSL_do_handshake() again
+ return handshake();
+ }
+ return status;
+ }
+
+ private SSLEngineResult.HandshakeStatus getHandshakeStatus(int pending) {
+ // Check if we are in the initial handshake phase or shutdown phase
+ return !handshakeFinished ? pendingStatus(pending) : NOT_HANDSHAKING;
+ }
+
+ private SSLEngineResult.Status getEngineStatus() {
+ switch (state) {
+ case STATE_CLOSED_INBOUND:
+ case STATE_CLOSED_OUTBOUND:
+ case STATE_CLOSED:
+ return CLOSED;
+ default:
+ return OK;
+ }
+ }
+
+ private void closeAll() {
+ closeOutbound();
+ closeInbound();
+ }
+
+ private void freeIfDone() {
+ if (isInboundDone() && isOutboundDone()) {
+ closeAndFreeResources();
+ }
+ }
+
+ private SSLException newSslExceptionWithMessage(String err) {
+ if (!handshakeFinished) {
+ return new SSLException(err);
+ }
+ return new SSLHandshakeException(err);
+ }
+
+ private SSLEngineResult newResult(int bytesConsumed, int bytesProduced,
+ SSLEngineResult.HandshakeStatus status) throws SSLException {
+ return new SSLEngineResult(getEngineStatus(),
+ mayFinishHandshake(status == FINISHED ? status : getHandshakeStatusInternal()),
+ bytesConsumed, bytesProduced);
+ }
+
+ @Override
+ public SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
+ synchronized (ssl) {
+ try {
+ return wrap(singleSrcBuffer(src), dst);
+ } finally {
+ resetSingleSrcBuffer();
+ }
+ }
+ }
+
+ @Override
+ public SSLEngineResult wrap(ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer dst)
+ throws SSLException {
+ checkArgument(srcs != null, "srcs is null");
+ checkArgument(dst != null, "dst is null");
+ checkPositionIndexes(srcsOffset, srcsOffset + srcsLength, srcs.length);
+ if (dst.isReadOnly()) {
+ throw new ReadOnlyBufferException();
+ }
+
+ if ((srcsOffset != 0) || (srcsLength != srcs.length)) {
+ srcs = Arrays.copyOfRange(srcs, srcsOffset, srcsOffset + srcsLength);
+ }
+ BufferUtils.checkNotNull(srcs);
+
+ synchronized (ssl) {
+ switch (state) {
+ case STATE_MODE_SET:
+ // Begin the handshake implicitly.
+ beginHandshakeInternal();
+ break;
+ case STATE_CLOSED_OUTBOUND:
+ case STATE_CLOSED:
+ // We may have pending encrypted bytes from a close_notify alert, so
+ // try to read them out
+ SSLEngineResult pendingNetResult =
+ readPendingBytesFromBIO(dst, 0, 0, HandshakeStatus.NOT_HANDSHAKING);
+ if (pendingNetResult != null) {
+ freeIfDone();
+ return pendingNetResult;
+ }
+ return new SSLEngineResult(Status.CLOSED, getHandshakeStatusInternal(), 0, 0);
+ case STATE_NEW:
+ throw new IllegalStateException(
+ "Client/server mode must be set before calling wrap");
+ default:
+ break;
+ }
+
+ // If we haven't completed the handshake yet, just let the caller know.
+ HandshakeStatus handshakeStatus = HandshakeStatus.NOT_HANDSHAKING;
+ // Prepare OpenSSL to work in server mode and receive handshake
+ if (!handshakeFinished) {
+ handshakeStatus = handshake();
+ if (handshakeStatus == NEED_UNWRAP) {
+ return NEED_UNWRAP_OK;
+ }
+
+ if (state == STATE_CLOSED) {
+ return NEED_UNWRAP_CLOSED;
+ }
+ // NEED_WRAP - just fall through to perform the wrap.
+ }
+
+ int dataLength = (int) min(BufferUtils.remaining(srcs), SSL3_RT_MAX_PLAIN_LENGTH);
+ if (dst.remaining() < calculateOutNetBufSize(dataLength)) {
+ return new SSLEngineResult(
+ Status.BUFFER_OVERFLOW, getHandshakeStatusInternal(), 0, 0);
+ }
+
+ int bytesProduced = 0;
+ int bytesConsumed = 0;
+ if (dataLength > 0) {
+ // Try and find a single buffer to send, e.g. the first non-empty buffer has
+ // more than enough data remaining to fill a TLS record. Otherwise copy as much
+ // data as possible from the source buffers to fill a record. Note the we can't
+ // mark the data as consumed until we see how much the TLS layer actually consumes.
+ boolean isCopy = false;
+ ByteBuffer outputBuffer =
+ BufferUtils.getBufferLargerThan(srcs, SSL3_RT_MAX_PLAIN_LENGTH);
+ if (outputBuffer == null) {
+ // The buffer by getOrCreateLazyDirectBuffer() is also used by
+ // writePlainTextDataHeap(), but by filling it here the write path will go via
+ // writePlainTextDataDirect() and the cost will be approximately the same,
+ // especially if compacting multiple non-direct buffers into a single
+ // direct one.
+ // TODO(): use bufferAllocator if set.
+ // https://github.com/google/conscrypt/issues/974
+ outputBuffer = BufferUtils.copyNoConsume(
+ srcs, getOrCreateLazyDirectBuffer(), SSL3_RT_MAX_PLAIN_LENGTH);
+ isCopy = true;
+ }
+ final SSLEngineResult pendingNetResult;
+ // Write plaintext application data to the SSL engine
+ int result = writePlaintextData(
+ outputBuffer, min(SSL3_RT_MAX_PLAIN_LENGTH, outputBuffer.remaining()));
+ if (result > 0) {
+ bytesConsumed = result;
+ if (isCopy) {
+ // Data was a copy, so mark it as consumed in the original buffers.
+ BufferUtils.consume(srcs, bytesConsumed);
+ }
+
+ pendingNetResult = readPendingBytesFromBIO(
+ dst, bytesConsumed, bytesProduced, handshakeStatus);
+ if (pendingNetResult != null) {
+ if (pendingNetResult.getStatus() != OK) {
+ return pendingNetResult;
+ }
+ bytesProduced = pendingNetResult.bytesProduced();
+ }
+ } else {
+ int sslError = ssl.getError(result);
+ switch (sslError) {
+ case SSL_ERROR_ZERO_RETURN:
+ // This means the connection was shutdown correctly, close inbound
+ // and outbound
+ closeAll();
+ pendingNetResult = readPendingBytesFromBIO(
+ dst, bytesConsumed, bytesProduced, handshakeStatus);
+ return pendingNetResult != null ? pendingNetResult
+ : CLOSED_NOT_HANDSHAKING;
+ case SSL_ERROR_WANT_READ:
+ // If there is no pending data to read from BIO we should go back to
+ // event loop and try
+ // to read more data [1]. It is also possible that event loop will
+ // detect the socket
+ // has been closed. [1]
+ // https://www.openssl.org/docs/manmaster/man3/SSL_write.html
+ pendingNetResult = readPendingBytesFromBIO(
+ dst, bytesConsumed, bytesProduced, handshakeStatus);
+ return pendingNetResult != null
+ ? pendingNetResult
+ : new SSLEngineResult(getEngineStatus(), NEED_UNWRAP,
+ bytesConsumed, bytesProduced);
+ case SSL_ERROR_WANT_WRITE:
+ // SSL_ERROR_WANT_WRITE typically means that the underlying
+ // transport is not writable
+ // and we should set the "want write" flag on the selector and try
+ // again when the
+ // underlying transport is writable [1]. However we are not directly
+ // writing to the
+ // underlying transport and instead writing to a BIO buffer. The
+ // OpenSsl documentation
+ // says we should do the following [1]:
+ //
+ // "When using a buffering BIO, like a BIO pair, data must be
+ // written into or retrieved
+ // out of the BIO before being able to continue."
+ //
+ // So we attempt to drain the BIO buffer below, but if there is no
+ // data this condition
+ // is undefined and we assume their is a fatal error with the
+ // openssl engine and close.
+ // [1] https://www.openssl.org/docs/manmaster/man3/SSL_write.html
+ pendingNetResult = readPendingBytesFromBIO(
+ dst, bytesConsumed, bytesProduced, handshakeStatus);
+ return pendingNetResult != null ? pendingNetResult : NEED_WRAP_CLOSED;
+ default:
+ // Everything else is considered as error
+ closeAll();
+ throw newSslExceptionWithMessage("SSL_write: error " + sslError);
+ }
+ }
+ }
+
+ // We need to check if pendingWrittenBytesInBIO was checked yet, as we may not have
+ // checked if the srcs was empty, or only contained empty buffers.
+ if (bytesConsumed == 0) {
+ SSLEngineResult pendingNetResult =
+ readPendingBytesFromBIO(dst, 0, bytesProduced, handshakeStatus);
+ if (pendingNetResult != null) {
+ return pendingNetResult;
+ }
+ }
+ return newResult(bytesConsumed, bytesProduced, handshakeStatus);
+ }
+ }
+
+ @Override
+ public int clientPSKKeyRequested(String identityHint, byte[] identity, byte[] key) {
+ return ssl.clientPSKKeyRequested(identityHint, identity, key);
+ }
+
+ @Override
+ public int serverPSKKeyRequested(String identityHint, String identity, byte[] key) {
+ return ssl.serverPSKKeyRequested(identityHint, identity, key);
+ }
+
+ @Override
+ public void onSSLStateChange(int type, int val) {
+ synchronized (ssl) {
+ switch (type) {
+ case SSL_CB_HANDSHAKE_START: {
+ // For clients, this will allow the NEED_UNWRAP status to be
+ // returned.
+ transitionTo(STATE_HANDSHAKE_STARTED);
+ break;
+ }
+ case SSL_CB_HANDSHAKE_DONE: {
+ if (state != STATE_HANDSHAKE_STARTED
+ && state != STATE_READY_HANDSHAKE_CUT_THROUGH) {
+ throw new IllegalStateException(
+ "Completed handshake while in mode " + state);
+ }
+ transitionTo(STATE_HANDSHAKE_COMPLETED);
+ break;
+ }
+ default:
+ // Ignore
+ }
+ }
+ }
+
+ @Override
+ public void serverCertificateRequested() throws IOException {
+ synchronized (ssl) {
+ ssl.configureServerCertificate();
+ }
+ }
+
+ @Override
+ public void onNewSessionEstablished(long sslSessionNativePtr) {
+ try {
+ // Increment the reference count to "take ownership" of the session resource.
+ NativeCrypto.SSL_SESSION_up_ref(sslSessionNativePtr);
+
+ // Create a native reference which will release the SSL_SESSION in its finalizer.
+ // This constructor will only throw if the native pointer passed in is NULL, which
+ // BoringSSL guarantees will not happen.
+ NativeRef.SSL_SESSION ref = new SSL_SESSION(sslSessionNativePtr);
+
+ NativeSslSession nativeSession = NativeSslSession.newInstance(ref, activeSession);
+
+ // Cache the newly established session.
+ AbstractSessionContext ctx = sessionContext();
+ ctx.cacheSession(nativeSession);
+ } catch (Exception ignored) {
+ // Ignore.
+ }
+ }
+
+ @Override
+ public long serverSessionRequested(byte[] id) {
+ // TODO(nathanmittler): Implement server-side caching for TLS < 1.3
+ return 0;
+ }
+
+ @Override
+ public void verifyCertificateChain(byte[][] certChain, String authMethod)
+ throws CertificateException {
+ try {
+ if (certChain == null || certChain.length == 0) {
+ throw new CertificateException("Peer sent no certificate");
+ }
+ X509Certificate[] peerCertChain = SSLUtils.decodeX509CertificateChain(certChain);
+
+ X509TrustManager x509tm = sslParameters.getX509TrustManager();
+ if (x509tm == null) {
+ throw new CertificateException("No X.509 TrustManager");
+ }
+
+ // Update the peer information on the session.
+ activeSession.onPeerCertificatesReceived(getPeerHost(), getPeerPort(), peerCertChain);
+
+ if (getUseClientMode()) {
+ Platform.checkServerTrusted(x509tm, peerCertChain, authMethod, this);
+ } else {
+ String authType = peerCertChain[0].getPublicKey().getAlgorithm();
+ Platform.checkClientTrusted(x509tm, peerCertChain, authType, this);
+ }
+ } catch (CertificateException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new CertificateException(e);
+ }
+ }
+
+ @Override
+ public void clientCertificateRequested(byte[] keyTypeBytes, int[] signatureAlgs,
+ byte[][] asn1DerEncodedPrincipals)
+ throws CertificateEncodingException, SSLException {
+ ssl.chooseClientCertificate(keyTypeBytes, signatureAlgs, asn1DerEncodedPrincipals);
+ }
+
+ private void sendSSLShutdown() {
+ try {
+ ssl.shutdown();
+ } catch (IOException ignored) {
+ // TODO: The RI ignores close failures in SSLSocket, but need to
+ // investigate whether it does for SSLEngine.
+ }
+ }
+
+ private void closeAndFreeResources() {
+ transitionTo(STATE_CLOSED);
+ if (ssl != null) {
+ ssl.close();
+ }
+ if (networkBio != null) {
+ networkBio.close();
+ }
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ protected void finalize() throws Throwable {
+ try {
+ closeAndFreeResources();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ @Override
+ public String chooseServerAlias(X509KeyManager keyManager, String keyType) {
+ if (keyManager instanceof X509ExtendedKeyManager) {
+ X509ExtendedKeyManager ekm = (X509ExtendedKeyManager) keyManager;
+ return ekm.chooseEngineServerAlias(keyType, null, this);
+ } else {
+ return keyManager.chooseServerAlias(keyType, null, null);
+ }
+ }
+
+ @Override
+ public String chooseClientAlias(
+ X509KeyManager keyManager, X500Principal[] issuers, String[] keyTypes) {
+ if (keyManager instanceof X509ExtendedKeyManager) {
+ X509ExtendedKeyManager ekm = (X509ExtendedKeyManager) keyManager;
+ return ekm.chooseEngineClientAlias(keyTypes, issuers, this);
+ } else {
+ return keyManager.chooseClientAlias(keyTypes, issuers, null);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
+ public String chooseServerPSKIdentityHint(PSKKeyManager keyManager) {
+ return keyManager.chooseServerKeyIdentityHint(this);
+ }
+
+ @Override
+ @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
+ public String chooseClientPSKIdentity(PSKKeyManager keyManager, String identityHint) {
+ return keyManager.chooseClientKeyIdentity(identityHint, this);
+ }
+
+ @Override
+ @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
+ public SecretKey getPSKKey(PSKKeyManager keyManager, String identityHint, String identity) {
+ return keyManager.getKey(identityHint, identity, this);
+ }
+
+ /**
+ * This method enables session ticket support.
+ *
+ * @param useSessionTickets True to enable session tickets
+ */
+ @Override
+ void setUseSessionTickets(boolean useSessionTickets) {
+ sslParameters.setUseSessionTickets(useSessionTickets);
+ }
+
+ @Override
+ String[] getApplicationProtocols() {
+ return sslParameters.getApplicationProtocols();
+ }
+
+ @Override
+ void setApplicationProtocols(String[] protocols) {
+ sslParameters.setApplicationProtocols(protocols);
+ }
+
+ @Override
+ void setApplicationProtocolSelector(ApplicationProtocolSelector selector) {
+ setApplicationProtocolSelector(
+ selector == null ? null : new ApplicationProtocolSelectorAdapter(this, selector));
+ }
+
+ @Override
+ byte[] getTlsUnique() {
+ return ssl.getTlsUnique();
+ }
+
+ @Override
+ byte[] exportKeyingMaterial(String label, byte[] context, int length) throws SSLException {
+ synchronized (ssl) {
+ if (state < STATE_HANDSHAKE_COMPLETED || state == STATE_CLOSED) {
+ return null;
+ }
+ }
+ return ssl.exportKeyingMaterial(label, context, length);
+ }
+
+ void setApplicationProtocolSelector(ApplicationProtocolSelectorAdapter adapter) {
+ sslParameters.setApplicationProtocolSelector(adapter);
+ }
+
+ @Override
+ public int selectApplicationProtocol(byte[] protocols) {
+ ApplicationProtocolSelectorAdapter adapter = sslParameters.getApplicationProtocolSelector();
+ if (adapter == null) {
+ return NativeConstants.SSL_TLSEXT_ERR_NOACK;
+ }
+ return adapter.selectApplicationProtocol(protocols);
+ }
+
+ @Override
+ public String getApplicationProtocol() {
+ return provideAfterHandshakeSession().getApplicationProtocol();
+ }
+
+ @Override
+ public String getHandshakeApplicationProtocol() {
+ synchronized (ssl) {
+ return state >= STATE_HANDSHAKE_STARTED ? getApplicationProtocol() : null;
+ }
+ }
+
+ private ByteBuffer[] singleSrcBuffer(ByteBuffer src) {
+ singleSrcBuffer[0] = src;
+ return singleSrcBuffer;
+ }
+
+ private void resetSingleSrcBuffer() {
+ singleSrcBuffer[0] = null;
+ }
+
+ private ByteBuffer[] singleDstBuffer(ByteBuffer src) {
+ singleDstBuffer[0] = src;
+ return singleDstBuffer;
+ }
+
+ private void resetSingleDstBuffer() {
+ singleDstBuffer[0] = null;
+ }
+
+ private ClientSessionContext clientSessionContext() {
+ return sslParameters.getClientSessionContext();
+ }
+
+ private AbstractSessionContext sessionContext() {
+ return sslParameters.getSessionContext();
+ }
+
+ private void transitionTo(int newState) {
+ switch (newState) {
+ case STATE_HANDSHAKE_STARTED: {
+ handshakeFinished = false;
+ activeSession = new ActiveSession(ssl, sslParameters.getSessionContext());
+ break;
+ }
+ case STATE_CLOSED: {
+ if (!ssl.isClosed() && state >= STATE_HANDSHAKE_STARTED && state < STATE_CLOSED) {
+ closedSession = new SessionSnapshot(activeSession);
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ // Update the state
+ this.state = newState;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptEngineSocket.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptEngineSocket.java
new file mode 100644
index 0000000..9d87c8e
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptEngineSocket.java
@@ -0,0 +1,995 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2016 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_CLOSED;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_HANDSHAKE_COMPLETED;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_HANDSHAKE_STARTED;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_NEW;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_READY;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_READY_HANDSHAKE_CUT_THROUGH;
+import static javax.net.ssl.SSLEngineResult.Status.CLOSED;
+import static javax.net.ssl.SSLEngineResult.Status.OK;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.security.PrivateKey;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.X509ExtendedTrustManager;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * Implements crypto handling by delegating to {@link ConscryptEngine}.
+ */
+class ConscryptEngineSocket extends OpenSSLSocketImpl implements SSLParametersImpl.AliasChooser {
+ private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);
+
+ private final ConscryptEngine engine;
+ private final Object stateLock = new Object();
+ private final Object handshakeLock = new Object();
+
+ private SSLOutputStream out;
+ private SSLInputStream in;
+
+ private long handshakeStartedMillis = 0;
+
+ private BufferAllocator bufferAllocator = ConscryptEngine.getDefaultBufferAllocator();
+
+ // @GuardedBy("stateLock");
+ private int state = STATE_NEW;
+
+ // The constructors should not be called except from the Platform class, because we may
+ // want to construct a subclass instead.
+ ConscryptEngineSocket(SSLParametersImpl sslParameters) throws IOException {
+ engine = newEngine(sslParameters, this);
+ }
+
+ ConscryptEngineSocket(String hostname, int port, SSLParametersImpl sslParameters)
+ throws IOException {
+ super(hostname, port);
+ engine = newEngine(sslParameters, this);
+ }
+
+ ConscryptEngineSocket(InetAddress address, int port, SSLParametersImpl sslParameters)
+ throws IOException {
+ super(address, port);
+ engine = newEngine(sslParameters, this);
+ }
+
+ ConscryptEngineSocket(String hostname, int port, InetAddress clientAddress, int clientPort,
+ SSLParametersImpl sslParameters) throws IOException {
+ super(hostname, port, clientAddress, clientPort);
+ engine = newEngine(sslParameters, this);
+ }
+
+ ConscryptEngineSocket(InetAddress address, int port, InetAddress clientAddress, int clientPort,
+ SSLParametersImpl sslParameters) throws IOException {
+ super(address, port, clientAddress, clientPort);
+ engine = newEngine(sslParameters, this);
+ }
+
+ ConscryptEngineSocket(Socket socket, String hostname, int port, boolean autoClose,
+ SSLParametersImpl sslParameters) throws IOException {
+ super(socket, hostname, port, autoClose);
+ engine = newEngine(sslParameters, this);
+ }
+
+ private static ConscryptEngine newEngine(
+ SSLParametersImpl sslParameters, final ConscryptEngineSocket socket) {
+ SSLParametersImpl modifiedParams;
+ if (Platform.supportsX509ExtendedTrustManager()) {
+ modifiedParams = sslParameters.cloneWithTrustManager(
+ getDelegatingTrustManager(sslParameters.getX509TrustManager(), socket));
+ } else {
+ modifiedParams = sslParameters;
+ }
+ ConscryptEngine engine =
+ new ConscryptEngine(modifiedParams, socket.peerInfoProvider(), socket);
+
+ // When the handshake completes, notify any listeners.
+ engine.setHandshakeListener(new HandshakeListener() {
+ /**
+ * Protected by {@code stateLock}
+ */
+ @Override
+ public void onHandshakeFinished() {
+ // Just call the outer class method.
+ socket.onEngineHandshakeFinished();
+ }
+ });
+
+ // Transition the engine state to MODE_SET
+ engine.setUseClientMode(sslParameters.getUseClientMode());
+ return engine;
+ }
+
+ // Returns a trust manager that delegates to the given trust manager, but maps SSLEngine
+ // references to the given ConscryptEngineSocket. Our internal engine will call
+ // the SSLEngine-receiving methods, but our callers expect the SSLSocket-receiving
+ // methods to get called.
+ private static X509TrustManager getDelegatingTrustManager(
+ final X509TrustManager delegate, final ConscryptEngineSocket socket) {
+ if (delegate instanceof X509ExtendedTrustManager) {
+ final X509ExtendedTrustManager extendedDelegate = (X509ExtendedTrustManager) delegate;
+ return new X509ExtendedTrustManager() {
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s,
+ Socket socket) throws CertificateException {
+ throw new AssertionError("Should not be called");
+ }
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s,
+ Socket socket) throws CertificateException {
+ throw new AssertionError("Should not be called");
+ }
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s,
+ SSLEngine sslEngine) throws CertificateException {
+ extendedDelegate.checkClientTrusted(x509Certificates, s, socket);
+ }
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s,
+ SSLEngine sslEngine) throws CertificateException {
+ extendedDelegate.checkServerTrusted(x509Certificates, s, socket);
+ }
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s)
+ throws CertificateException {
+ extendedDelegate.checkClientTrusted(x509Certificates, s);
+ }
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s)
+ throws CertificateException {
+ extendedDelegate.checkServerTrusted(x509Certificates, s);
+ }
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return extendedDelegate.getAcceptedIssuers();
+ }
+ };
+ }
+ return delegate;
+ }
+
+ @Override
+ public final SSLParameters getSSLParameters() {
+ return engine.getSSLParameters();
+ }
+
+ @Override
+ public final void setSSLParameters(SSLParameters sslParameters) {
+ engine.setSSLParameters(sslParameters);
+ }
+
+ @Override
+ public final void startHandshake() throws IOException {
+ checkOpen();
+
+ try {
+ synchronized (handshakeLock) {
+ // Only lock stateLock when we begin the handshake. This is done so that we don't
+ // hold the stateLock when we invoke the handshake completion listeners.
+ synchronized (stateLock) {
+ // Initialize the handshake if we haven't already.
+ if (state == STATE_NEW) {
+ transitionTo(STATE_HANDSHAKE_STARTED);
+ engine.beginHandshake();
+ createInputStream();
+ createOutputStream();
+ } else {
+ // We've either started the handshake already or have been closed.
+ // Do nothing in both cases.
+ //
+ // NOTE: BoringSSL does not support initiating renegotiation, so we always
+ // ignore addition handshake calls.
+ return;
+ }
+ }
+ doHandshake();
+ }
+ } catch (IOException e) {
+ close();
+ throw e;
+ } catch (Exception e) {
+ close();
+ // Convert anything else to a handshake exception.
+ throw SSLUtils.toSSLHandshakeException(e);
+ }
+ }
+
+ private void doHandshake() throws IOException {
+ try {
+ boolean finished = false;
+ while (!finished) {
+ switch (engine.getHandshakeStatus()) {
+ case NEED_UNWRAP:
+ if (in.processDataFromSocket(EmptyArray.BYTE, 0, 0) < 0) {
+ // Can't complete the handshake due to EOF.
+ close();
+ throw SSLUtils.toSSLHandshakeException(
+ new EOFException("connection closed"));
+ }
+ break;
+ case NEED_WRAP: {
+ out.writeInternal(EMPTY_BUFFER);
+ // Always flush handshake frames immediately.
+ out.flushInternal();
+ break;
+ }
+ case NEED_TASK: {
+ // Should never get here, since our engine never provides tasks.
+ close();
+ throw new IllegalStateException("Engine tasks are unsupported");
+ }
+ case NOT_HANDSHAKING:
+ case FINISHED: {
+ // Handshake is complete.
+ finished = true;
+ break;
+ }
+ default: {
+ throw new IllegalStateException(
+ "Unknown handshake status: " + engine.getHandshakeStatus());
+ }
+ }
+ }
+ if (isState(STATE_HANDSHAKE_COMPLETED)) {
+ // STATE_READY_HANDSHAKE_CUT_THROUGH will wake up any waiting threads which can
+ // race with the listeners, but that's OK.
+ transitionTo(STATE_READY_HANDSHAKE_CUT_THROUGH);
+ notifyHandshakeCompletedListeners();
+ transitionTo(STATE_READY);
+ }
+ } catch (SSLException e) {
+ drainOutgoingQueue();
+ close();
+ throw e;
+ } catch (IOException e) {
+ close();
+ throw e;
+ } catch (Exception e) {
+ close();
+ // Convert anything else to a handshake exception.
+ throw SSLUtils.toSSLHandshakeException(e);
+ }
+ }
+
+ private boolean isState(int desiredState) {
+ synchronized (stateLock) {
+ return state == desiredState;
+ }
+ }
+
+ private int transitionTo(int newState) {
+ synchronized (stateLock) {
+ if (state == newState) {
+ return state;
+ }
+
+ int previousState = state;
+ boolean notify = false;
+ switch (newState) {
+ case STATE_HANDSHAKE_STARTED:
+ handshakeStartedMillis = Platform.getMillisSinceBoot();
+ break;
+
+ case STATE_READY_HANDSHAKE_CUT_THROUGH:
+ if (handshakeStartedMillis > 0) {
+ Platform.countTlsHandshake(true, engine.getSession().getProtocol(),
+ engine.getSession().getCipherSuite(),
+ Platform.getMillisSinceBoot() - handshakeStartedMillis);
+ handshakeStartedMillis = 0;
+ }
+ notify = true;
+ break;
+
+ case STATE_READY:
+ notify = true;
+ break;
+
+ case STATE_CLOSED:
+ if (handshakeStartedMillis > 0) {
+ // Handshake was in progress and so must have failed.
+ Platform.countTlsHandshake(false, "TLS_PROTO_FAILED", "TLS_CIPHER_FAILED",
+ Platform.getMillisSinceBoot() - handshakeStartedMillis);
+ handshakeStartedMillis = 0;
+ }
+ notify = true;
+ break;
+
+ default:
+ break;
+ }
+
+ state = newState;
+ if (notify) {
+ stateLock.notifyAll();
+ }
+ return previousState;
+ }
+ }
+
+ @Override
+ public final InputStream getInputStream() throws IOException {
+ checkOpen();
+ return createInputStream();
+ }
+
+ private SSLInputStream createInputStream() {
+ synchronized (stateLock) {
+ if (in == null) {
+ in = new SSLInputStream();
+ }
+ }
+ return in;
+ }
+
+ @Override
+ public final OutputStream getOutputStream() throws IOException {
+ checkOpen();
+ return createOutputStream();
+ }
+
+ private SSLOutputStream createOutputStream() {
+ synchronized (stateLock) {
+ if (out == null) {
+ out = new SSLOutputStream();
+ }
+ }
+ return out;
+ }
+
+ @Override
+ public final SSLSession getHandshakeSession() {
+ return engine.handshakeSession();
+ }
+
+ @Override
+ public final SSLSession getSession() {
+ if (isConnected()) {
+ try {
+ waitForHandshake();
+ } catch (IOException e) {
+ // Fall through
+ }
+ }
+ return engine.getSession();
+ }
+
+ @Override
+ final SSLSession getActiveSession() {
+ return engine.getSession();
+ }
+
+ @Override
+ public final boolean getEnableSessionCreation() {
+ return engine.getEnableSessionCreation();
+ }
+
+ @Override
+ public final void setEnableSessionCreation(boolean flag) {
+ engine.setEnableSessionCreation(flag);
+ }
+
+ @Override
+ public final String[] getSupportedCipherSuites() {
+ return engine.getSupportedCipherSuites();
+ }
+
+ @Override
+ public final String[] getEnabledCipherSuites() {
+ return engine.getEnabledCipherSuites();
+ }
+
+ @Override
+ public final void setEnabledCipherSuites(String[] suites) {
+ engine.setEnabledCipherSuites(suites);
+ }
+
+ @Override
+ public final String[] getSupportedProtocols() {
+ return engine.getSupportedProtocols();
+ }
+
+ @Override
+ public final String[] getEnabledProtocols() {
+ return engine.getEnabledProtocols();
+ }
+
+ @Override
+ public final void setEnabledProtocols(String[] protocols) {
+ engine.setEnabledProtocols(protocols);
+ }
+
+ /**
+ * This method enables Server Name Indication. If the hostname is not a valid SNI hostname,
+ * the SNI extension will be omitted from the handshake.
+ *
+ * @param hostname the desired SNI hostname, or null to disable
+ */
+ @android.compat.annotation.
+ UnsupportedAppUsage(maxTargetSdk = dalvik.annotation.compat.VersionCodes.Q,
+ publicAlternatives = "Use {@code javax.net.ssl.SSLParameters#setServerNames}.")
+ @Override
+ public final void
+ setHostname(String hostname) {
+ engine.setHostname(hostname);
+ super.setHostname(hostname);
+ }
+
+ @android.compat.annotation.
+ UnsupportedAppUsage(maxTargetSdk = dalvik.annotation.compat.VersionCodes.Q,
+ publicAlternatives = "Use {@link android.net.ssl.SSLSockets#setUseSessionTickets}.")
+ @Override
+ public final void
+ setUseSessionTickets(boolean useSessionTickets) {
+ engine.setUseSessionTickets(useSessionTickets);
+ }
+
+ @Override
+ public final void setChannelIdEnabled(boolean enabled) {
+ engine.setChannelIdEnabled(enabled);
+ }
+
+ @Override
+ public final byte[] getChannelId() throws SSLException {
+ return engine.getChannelId();
+ }
+
+ @Override
+ public final void setChannelIdPrivateKey(PrivateKey privateKey) {
+ engine.setChannelIdPrivateKey(privateKey);
+ }
+
+ @Override
+ byte[] getTlsUnique() {
+ return engine.getTlsUnique();
+ }
+
+ @Override
+ byte[] exportKeyingMaterial(String label, byte[] context, int length) throws SSLException {
+ return engine.exportKeyingMaterial(label, context, length);
+ }
+
+ @Override
+ public final boolean getUseClientMode() {
+ return engine.getUseClientMode();
+ }
+
+ @Override
+ public final void setUseClientMode(boolean mode) {
+ engine.setUseClientMode(mode);
+ }
+
+ @Override
+ public final boolean getWantClientAuth() {
+ return engine.getWantClientAuth();
+ }
+
+ @Override
+ public final boolean getNeedClientAuth() {
+ return engine.getNeedClientAuth();
+ }
+
+ @Override
+ public final void setNeedClientAuth(boolean need) {
+ engine.setNeedClientAuth(need);
+ }
+
+ @Override
+ public final void setWantClientAuth(boolean want) {
+ engine.setWantClientAuth(want);
+ }
+
+ @Override
+ @SuppressWarnings("UnsynchronizedOverridesSynchronized")
+ public final void close() throws IOException {
+ // TODO: Close SSL sockets using a background thread so they close gracefully.
+
+ if (stateLock == null) {
+ // Constructor failed, e.g. superclass constructor called close()
+ return;
+ }
+
+ int previousState = transitionTo(STATE_CLOSED);
+ if (previousState == STATE_CLOSED) {
+ return;
+ }
+ try {
+ // Close the engine.
+ engine.closeInbound();
+ engine.closeOutbound();
+
+ // Closing the outbound direction of a connected engine will trigger a TLS close
+ // notify, which we should try and send.
+ // If we don't, then closeOutbound won't be able to free resources because there are
+ // bytes queued for transmission so drain the queue those and call closeOutbound a
+ // second time.
+ if (previousState >= STATE_HANDSHAKE_STARTED) {
+ drainOutgoingQueue();
+ engine.closeOutbound();
+ }
+ } finally {
+ // In case of an exception thrown while closing the engine, we still need to close the
+ // underlying socket and release any resources the input stream is holding.
+ try {
+ super.close();
+ } finally {
+ if (in != null) {
+ in.release();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketException {
+ // Not supported but ignored rather than throwing for compatibility: b/146041327
+ }
+
+ @Override
+ final void setApplicationProtocols(String[] protocols) {
+ engine.setApplicationProtocols(protocols);
+ }
+
+ @Override
+ final String[] getApplicationProtocols() {
+ return engine.getApplicationProtocols();
+ }
+
+ @Override
+ public final String getApplicationProtocol() {
+ return engine.getApplicationProtocol();
+ }
+
+ @Override
+ public final String getHandshakeApplicationProtocol() {
+ return engine.getHandshakeApplicationProtocol();
+ }
+
+ @Override
+ public final void setApplicationProtocolSelector(ApplicationProtocolSelector selector) {
+ setApplicationProtocolSelector(
+ selector == null ? null : new ApplicationProtocolSelectorAdapter(this, selector));
+ }
+
+ @Override
+ final void setApplicationProtocolSelector(ApplicationProtocolSelectorAdapter selector) {
+ engine.setApplicationProtocolSelector(selector);
+ }
+
+ void setBufferAllocator(BufferAllocator bufferAllocator) {
+ engine.setBufferAllocator(bufferAllocator);
+ this.bufferAllocator = bufferAllocator;
+ }
+
+ private void onEngineHandshakeFinished() {
+ // Don't do anything here except change state. This method will be called from
+ // e.g. wrap() which is non re-entrant so we can't call anything that might do
+ // IO until after it exits, e.g. in doHandshake().
+ if (isState(STATE_HANDSHAKE_STARTED)) {
+ transitionTo(STATE_HANDSHAKE_COMPLETED);
+ }
+ }
+
+ /**
+ * Waits for the handshake to complete.
+ */
+ private void waitForHandshake() throws IOException {
+ startHandshake();
+
+ synchronized (stateLock) {
+ while (state != STATE_READY
+ // Waiting threads are allowed to compete with handshake listeners for access.
+ && state != STATE_READY_HANDSHAKE_CUT_THROUGH && state != STATE_CLOSED) {
+ try {
+ stateLock.wait();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new IOException("Interrupted waiting for handshake", e);
+ }
+ }
+
+ if (state == STATE_CLOSED) {
+ throw new SocketException("Socket is closed");
+ }
+ }
+ }
+
+ private void drainOutgoingQueue() {
+ try {
+ while (engine.pendingOutboundEncryptedBytes() > 0) {
+ out.writeInternal(EMPTY_BUFFER);
+ // Always flush handshake frames immediately.
+ out.flushInternal();
+ }
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+
+ private OutputStream getUnderlyingOutputStream() throws IOException {
+ return super.getOutputStream();
+ }
+
+ private InputStream getUnderlyingInputStream() throws IOException {
+ return super.getInputStream();
+ }
+
+ @Override
+ public final String chooseServerAlias(X509KeyManager keyManager, String keyType) {
+ return keyManager.chooseServerAlias(keyType, null, this);
+ }
+
+ @Override
+ public final String chooseClientAlias(
+ X509KeyManager keyManager, X500Principal[] issuers, String[] keyTypes) {
+ return keyManager.chooseClientAlias(keyTypes, issuers, this);
+ }
+
+ /**
+ * Wrap bytes written to the underlying socket.
+ */
+ private final class SSLOutputStream extends OutputStream {
+ private final Object writeLock = new Object();
+ private final ByteBuffer target;
+ private final int targetArrayOffset;
+ private OutputStream socketOutputStream;
+
+ SSLOutputStream() {
+ target = ByteBuffer.allocate(engine.getSession().getPacketBufferSize());
+ targetArrayOffset = target.arrayOffset();
+ }
+
+ @Override
+ public void close() throws IOException {
+ ConscryptEngineSocket.this.close();
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ waitForHandshake();
+ synchronized (writeLock) {
+ write(new byte[] {(byte) b});
+ }
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ waitForHandshake();
+ synchronized (writeLock) {
+ writeInternal(ByteBuffer.wrap(b));
+ }
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ waitForHandshake();
+ synchronized (writeLock) {
+ writeInternal(ByteBuffer.wrap(b, off, len));
+ }
+ }
+
+ private void writeInternal(ByteBuffer buffer) throws IOException {
+ Platform.blockGuardOnNetwork();
+ checkOpen();
+ init();
+
+ // Need to loop through at least once to enable handshaking where no application
+ // bytes are processed.
+ int len = buffer.remaining();
+ SSLEngineResult engineResult;
+ do {
+ target.clear();
+ engineResult = engine.wrap(buffer, target);
+ if (engineResult.getStatus() != OK && engineResult.getStatus() != CLOSED) {
+ throw new SSLException("Unexpected engine result " + engineResult.getStatus());
+ }
+ if (target.position() != engineResult.bytesProduced()) {
+ throw new SSLException("Engine bytesProduced " + engineResult.bytesProduced()
+ + " does not match bytes written " + target.position());
+ }
+ len -= engineResult.bytesConsumed();
+ if (len != buffer.remaining()) {
+ throw new SSLException("Engine did not read the correct number of bytes");
+ }
+ if (engineResult.getStatus() == CLOSED && engineResult.bytesProduced() == 0) {
+ if (len > 0) {
+ throw new SocketException("Socket closed");
+ }
+ break;
+ }
+
+ target.flip();
+
+ // Write the data to the socket.
+ writeToSocket();
+ } while (len > 0);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ waitForHandshake();
+ synchronized (writeLock) {
+ flushInternal();
+ }
+ }
+
+ private void flushInternal() throws IOException {
+ checkOpen();
+ init();
+ socketOutputStream.flush();
+ }
+
+ private void init() throws IOException {
+ if (socketOutputStream == null) {
+ socketOutputStream = getUnderlyingOutputStream();
+ }
+ }
+
+ private void writeToSocket() throws IOException {
+ // Write the data to the socket.
+ socketOutputStream.write(target.array(), targetArrayOffset, target.limit());
+ }
+ }
+
+ /**
+ * Unwrap bytes read from the underlying socket.
+ */
+ private final class SSLInputStream extends InputStream {
+ private final Object readLock = new Object();
+ private final byte[] singleByte = new byte[1];
+ private final ByteBuffer fromEngine;
+ private final ByteBuffer fromSocket;
+ private final int fromSocketArrayOffset;
+ private final AllocatedBuffer allocatedBuffer;
+ private InputStream socketInputStream;
+
+ SSLInputStream() {
+ if (bufferAllocator != null) {
+ allocatedBuffer = bufferAllocator.allocateDirectBuffer(
+ engine.getSession().getApplicationBufferSize());
+ fromEngine = allocatedBuffer.nioBuffer();
+ } else {
+ allocatedBuffer = null;
+ fromEngine = ByteBuffer.allocateDirect(engine.getSession().getApplicationBufferSize());
+ }
+ // Initially fromEngine.remaining() == 0.
+ fromEngine.flip();
+ fromSocket = ByteBuffer.allocate(engine.getSession().getPacketBufferSize());
+ fromSocketArrayOffset = fromSocket.arrayOffset();
+ }
+
+ @Override
+ public void close() throws IOException {
+ ConscryptEngineSocket.this.close();
+ }
+
+ void release() {
+ synchronized (readLock) {
+ if (allocatedBuffer != null) {
+ allocatedBuffer.release();
+ }
+ }
+ }
+
+ @Override
+ public int read() throws IOException {
+ waitForHandshake();
+ synchronized (readLock) {
+ // Handle returning of -1 if EOF is reached.
+ int count = read(singleByte, 0, 1);
+ if (count == -1) {
+ // Handle EOF.
+ return -1;
+ }
+ if (count != 1) {
+ throw new SSLException("read incorrect number of bytes " + count);
+ }
+ return singleByte[0] & 0xff;
+ }
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ waitForHandshake();
+ synchronized (readLock) {
+ return read(b, 0, b.length);
+ }
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ waitForHandshake();
+ synchronized (readLock) {
+ return readUntilDataAvailable(b, off, len);
+ }
+ }
+
+ @Override
+ public int available() throws IOException {
+ waitForHandshake();
+ synchronized (readLock) {
+ init();
+ return fromEngine.remaining();
+ }
+ }
+
+ private boolean isHandshaking(HandshakeStatus status) {
+ switch(status) {
+ case NEED_TASK:
+ case NEED_WRAP:
+ case NEED_UNWRAP:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private int readUntilDataAvailable(byte[] b, int off, int len) throws IOException {
+ int count;
+ do {
+ count = processDataFromSocket(b, off, len);
+ } while (count == 0);
+ return count;
+ }
+
+ // Returns any decrypted data from the engine. If no data is currently present in the
+ // engine's output buffer, reads from the input socket until the engine has processed
+ // at least one TLS record, then returns any data in the output buffer or 0 if no
+ // data is available. This is used both during handshaking (in which case, the records
+ // will produce no data and this method will return 0) and by the InputStream read()
+ // methods that expect records to produce application data.
+ private int processDataFromSocket(byte[] b, int off, int len) throws IOException {
+ Platform.blockGuardOnNetwork();
+ checkOpen();
+
+ // Make sure the input stream has been created.
+ init();
+
+ for (;;) {
+ // Serve any remaining data from the engine first.
+ if (fromEngine.remaining() > 0) {
+ int readFromEngine = Math.min(fromEngine.remaining(), len);
+ fromEngine.get(b, off, readFromEngine);
+ return readFromEngine;
+ }
+
+ // Try to unwrap any data already in the socket buffer.
+ boolean needMoreDataFromSocket = true;
+
+ // Unwrap the unencrypted bytes into the engine buffer.
+ fromSocket.flip();
+ fromEngine.clear();
+
+ boolean engineHandshaking = isHandshaking(engine.getHandshakeStatus());
+ SSLEngineResult engineResult = engine.unwrap(fromSocket, fromEngine);
+
+ // Shift any remaining data to the beginning of the buffer so that
+ // we can accommodate the next full packet. After this is called,
+ // limit will be restored to capacity and position will point just
+ // past the end of the data.
+ fromSocket.compact();
+ fromEngine.flip();
+
+ switch (engineResult.getStatus()) {
+ case BUFFER_UNDERFLOW: {
+ if (engineResult.bytesProduced() == 0) {
+ // Need to read more data from the socket.
+ break;
+ }
+ // Also serve the data that was produced.
+ needMoreDataFromSocket = false;
+ break;
+ }
+ case OK: {
+ // We processed the entire packet successfully...
+
+ if (!engineHandshaking && isHandshaking(engineResult.getHandshakeStatus())
+ && isHandshakeFinished()) {
+ // The received packet is the beginning of a renegotiation handshake.
+ // Perform another handshake.
+ renegotiate();
+ return 0;
+ }
+
+ needMoreDataFromSocket = false;
+ break;
+ }
+ case CLOSED: {
+ // EOF
+ return -1;
+ }
+ default: {
+ // Anything else is an error.
+ throw new SSLException(
+ "Unexpected engine result " + engineResult.getStatus());
+ }
+ }
+
+ if (!needMoreDataFromSocket && engineResult.bytesProduced() == 0) {
+ // Read successfully, but produced no data. Possibly part of a
+ // handshake.
+ return 0;
+ }
+
+ // Read more data from the socket.
+ if (needMoreDataFromSocket && readFromSocket() == -1) {
+ // Failed to read the next encrypted packet before reaching EOF.
+ return -1;
+ }
+
+ // Continue the loop and return the data from the engine buffer.
+ }
+ }
+
+ private boolean isHandshakeFinished() {
+ synchronized (stateLock) {
+ return state > STATE_HANDSHAKE_STARTED;
+ }
+ }
+
+ /**
+ * Processes a renegotiation received from the remote peer.
+ */
+ private void renegotiate() throws IOException {
+ synchronized (handshakeLock) {
+ doHandshake();
+ }
+ }
+
+ private void init() throws IOException {
+ if (socketInputStream == null) {
+ socketInputStream = getUnderlyingInputStream();
+ }
+ }
+
+ private int readFromSocket() throws IOException {
+ try {
+ // Read directly to the underlying array and increment the buffer position if
+ // appropriate.
+ int pos = fromSocket.position();
+ int lim = fromSocket.limit();
+ int read = socketInputStream.read(
+ fromSocket.array(), fromSocketArrayOffset + pos, lim - pos);
+
+ if (read > 0) {
+ fromSocket.position(pos + read);
+ }
+ return read;
+ } catch (EOFException e) {
+ return -1;
+ }
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptFileDescriptorSocket.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptFileDescriptorSocket.java
new file mode 100644
index 0000000..1724e48
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptFileDescriptorSocket.java
@@ -0,0 +1,1239 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_CLOSED;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_HANDSHAKE_COMPLETED;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_HANDSHAKE_STARTED;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_NEW;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_READY;
+import static com.android.org.conscrypt.SSLUtils.EngineStates.STATE_READY_HANDSHAKE_CUT_THROUGH;
+
+import com.android.org.conscrypt.ExternalSession.Provider;
+import com.android.org.conscrypt.NativeRef.SSL_SESSION;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.ECKey;
+import java.security.spec.ECParameterSpec;
+import javax.crypto.SecretKey;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLProtocolException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * Implementation of the class OpenSSLSocketImpl based on OpenSSL.
+ * <p>
+ * Extensions to SSLSocket include:
+ * <ul>
+ * <li>handshake timeout
+ * <li>session tickets
+ * <li>Server Name Indication
+ * </ul>
+ */
+class ConscryptFileDescriptorSocket extends OpenSSLSocketImpl
+ implements NativeCrypto.SSLHandshakeCallbacks, SSLParametersImpl.PSKCallbacks,
+ SSLParametersImpl.AliasChooser {
+ private static final boolean DBG_STATE = false;
+
+ // @GuardedBy("ssl");
+ private int state = STATE_NEW;
+
+ /**
+ * Wrapper around the underlying SSL object.
+ */
+ private final NativeSsl ssl;
+
+ /**
+ * Protected by synchronizing on ssl. Starts as null, set by
+ * getInputStream.
+ */
+ // @GuardedBy("ssl");
+ private SSLInputStream is;
+
+ /**
+ * Protected by synchronizing on ssl. Starts as null, set by
+ * getInputStream.
+ */
+ // @GuardedBy("ssl");
+ private SSLOutputStream os;
+
+ private final SSLParametersImpl sslParameters;
+
+ /*
+ * A CloseGuard object on Android. On other platforms, this is nothing.
+ */
+ private final Object guard = Platform.closeGuardGet();
+
+ /**
+ * Private key for the TLS Channel ID extension. This field is client-side
+ * only. Set during startHandshake.
+ */
+ private OpenSSLKey channelIdPrivateKey;
+
+ private final ActiveSession activeSession;
+ /**
+ * A snapshot of the active session when the engine was closed.
+ */
+ private SessionSnapshot closedSession;
+ /**
+ * The session object exposed externally from this class.
+ */
+ private final SSLSession externalSession =
+ Platform.wrapSSLSession(new ExternalSession(new ExternalSession.Provider() {
+ @Override
+ public ConscryptSession provideSession() {
+ return ConscryptFileDescriptorSocket.this.provideSession();
+ }
+ }));
+
+ private int writeTimeoutMilliseconds = 0;
+ private int handshakeTimeoutMilliseconds = -1; // -1 = same as timeout; 0 = infinite
+
+ private long handshakeStartedMillis = 0;
+
+ // The constructors should not be called except from the Platform class, because we may
+ // want to construct a subclass instead.
+ ConscryptFileDescriptorSocket(SSLParametersImpl sslParameters) throws IOException {
+ this.sslParameters = sslParameters;
+ this.ssl = newSsl(sslParameters, this);
+ activeSession = new ActiveSession(ssl, sslParameters.getSessionContext());
+ }
+
+ ConscryptFileDescriptorSocket(String hostname, int port, SSLParametersImpl sslParameters)
+ throws IOException {
+ super(hostname, port);
+ this.sslParameters = sslParameters;
+ this.ssl = newSsl(sslParameters, this);
+ activeSession = new ActiveSession(ssl, sslParameters.getSessionContext());
+ }
+
+ ConscryptFileDescriptorSocket(InetAddress address, int port, SSLParametersImpl sslParameters)
+ throws IOException {
+ super(address, port);
+ this.sslParameters = sslParameters;
+ this.ssl = newSsl(sslParameters, this);
+ activeSession = new ActiveSession(ssl, sslParameters.getSessionContext());
+ }
+
+ ConscryptFileDescriptorSocket(String hostname, int port, InetAddress clientAddress,
+ int clientPort, SSLParametersImpl sslParameters) throws IOException {
+ super(hostname, port, clientAddress, clientPort);
+ this.sslParameters = sslParameters;
+ this.ssl = newSsl(sslParameters, this);
+ activeSession = new ActiveSession(ssl, sslParameters.getSessionContext());
+ }
+
+ ConscryptFileDescriptorSocket(InetAddress address, int port, InetAddress clientAddress,
+ int clientPort, SSLParametersImpl sslParameters) throws IOException {
+ super(address, port, clientAddress, clientPort);
+ this.sslParameters = sslParameters;
+ this.ssl = newSsl(sslParameters, this);
+ activeSession = new ActiveSession(ssl, sslParameters.getSessionContext());
+ }
+
+ ConscryptFileDescriptorSocket(Socket socket, String hostname, int port, boolean autoClose,
+ SSLParametersImpl sslParameters) throws IOException {
+ super(socket, hostname, port, autoClose);
+ this.sslParameters = sslParameters;
+ this.ssl = newSsl(sslParameters, this);
+ activeSession = new ActiveSession(ssl, sslParameters.getSessionContext());
+ }
+
+ private static NativeSsl newSsl(SSLParametersImpl sslParameters,
+ ConscryptFileDescriptorSocket engine) throws SSLException {
+ return NativeSsl.newInstance(sslParameters, engine, engine, engine);
+ }
+
+ /**
+ * Starts a TLS/SSL handshake on this connection using some native methods
+ * from the OpenSSL library. It can negotiate new encryption keys, change
+ * cipher suites, or initiate a new session. The certificate chain is
+ * verified if the correspondent property in java.Security is set. All
+ * listeners are notified at the end of the TLS/SSL handshake.
+ */
+ @Override
+ public final void startHandshake() throws IOException {
+ checkOpen();
+ synchronized (ssl) {
+ if (state == STATE_NEW) {
+ transitionTo(STATE_HANDSHAKE_STARTED);
+ } else {
+ // We've either started the handshake already or have been closed.
+ // Do nothing in both cases.
+ return;
+ }
+ }
+
+ boolean releaseResources = true;
+ try {
+ Platform.closeGuardOpen(guard, "close");
+
+ // Prepare the SSL object for the handshake.
+ ssl.initialize(getHostname(), channelIdPrivateKey);
+
+ // For clients, offer to resume a previously cached session to avoid the
+ // full TLS handshake.
+ if (getUseClientMode()) {
+ NativeSslSession cachedSession = clientSessionContext().getCachedSession(
+ getHostnameOrIP(), getPort(), sslParameters);
+ if (cachedSession != null) {
+ cachedSession.offerToResume(ssl);
+ }
+ }
+
+ // Temporarily use a different timeout for the handshake process
+ int savedReadTimeoutMilliseconds = getSoTimeout();
+ int savedWriteTimeoutMilliseconds = getSoWriteTimeout();
+ if (handshakeTimeoutMilliseconds >= 0) {
+ setSoTimeout(handshakeTimeoutMilliseconds);
+ setSoWriteTimeout(handshakeTimeoutMilliseconds);
+ }
+
+ synchronized (ssl) {
+ if (state == STATE_CLOSED) {
+ return;
+ }
+ }
+
+ try {
+ ssl.doHandshake(Platform.getFileDescriptor(socket), getSoTimeout());
+
+ // Update the session from the current state of the SSL object.
+ activeSession.onPeerCertificateAvailable(getHostnameOrIP(), getPort());
+ } catch (CertificateException e) {
+ SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage());
+ wrapper.initCause(e);
+ throw wrapper;
+ } catch (SSLException e) {
+ // Swallow this exception if it's thrown as the result of an interruption.
+ //
+ // TODO: SSL_read and SSL_write return -1 when interrupted, but SSL_do_handshake
+ // will throw the last sslError that it saw before sslSelect, usually SSL_WANT_READ
+ // (or WANT_WRITE). Catching that exception here doesn't seem much worse than
+ // changing the native code to return a "special" native pointer value when that
+ // happens.
+ synchronized (ssl) {
+ if (state == STATE_CLOSED) {
+ return;
+ }
+ }
+
+ // Write CCS errors to EventLog
+ String message = e.getMessage();
+ // Must match error string of SSL_R_UNEXPECTED_CCS
+ if (message.contains("unexpected CCS")) {
+ String logMessage =
+ String.format("ssl_unexpected_ccs: host=%s", getHostnameOrIP());
+ Platform.logEvent(logMessage);
+ }
+
+ throw e;
+ }
+
+ synchronized (ssl) {
+ if (state == STATE_CLOSED) {
+ return;
+ }
+ }
+
+ // Restore the original timeout now that the handshake is complete
+ if (handshakeTimeoutMilliseconds >= 0) {
+ setSoTimeout(savedReadTimeoutMilliseconds);
+ setSoWriteTimeout(savedWriteTimeoutMilliseconds);
+ }
+
+ synchronized (ssl) {
+ releaseResources = (state == STATE_CLOSED);
+
+ if (state == STATE_HANDSHAKE_STARTED) {
+ transitionTo(STATE_READY_HANDSHAKE_CUT_THROUGH);
+ } else {
+ transitionTo(STATE_READY);
+ }
+
+ if (!releaseResources) {
+ // Unblock threads that are waiting for our state to transition
+ // into STATE_READY or STATE_READY_HANDSHAKE_CUT_THROUGH.
+ ssl.notifyAll();
+ }
+ }
+ } catch (SSLProtocolException e) {
+ throw(SSLHandshakeException) new SSLHandshakeException("Handshake failed").initCause(e);
+ } finally {
+ // on exceptional exit, treat the socket as closed
+ if (releaseResources) {
+ synchronized (ssl) {
+ // Mark the socket as closed since we might have reached this as
+ // a result on an exception thrown by the handshake process.
+ //
+ // The state will already be set to closed if we reach this as a result of
+ // an early return or an interruption due to a concurrent call to close().
+ transitionTo(STATE_CLOSED);
+ ssl.notifyAll();
+ }
+
+ try {
+ shutdownAndFreeSslNative();
+ } catch (IOException ignored) {
+ // Ignored.
+ }
+ }
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb
+ public final void clientCertificateRequested(byte[] keyTypeBytes, int[] signatureAlgs,
+ byte[][] asn1DerEncodedPrincipals)
+ throws CertificateEncodingException, SSLException {
+ ssl.chooseClientCertificate(keyTypeBytes, signatureAlgs, asn1DerEncodedPrincipals);
+ }
+
+ @Override
+ @SuppressWarnings("unused") // used by native psk_client_callback
+ public final int clientPSKKeyRequested(String identityHint, byte[] identity, byte[] key) {
+ return ssl.clientPSKKeyRequested(identityHint, identity, key);
+ }
+
+ @Override
+ @SuppressWarnings("unused") // used by native psk_server_callback
+ public final int serverPSKKeyRequested(String identityHint, String identity, byte[] key) {
+ return ssl.serverPSKKeyRequested(identityHint, identity, key);
+ }
+
+ @Override
+ @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / info_callback
+ public final void onSSLStateChange(int type, int val) {
+ if (type != NativeConstants.SSL_CB_HANDSHAKE_DONE) {
+ // We only care about successful completion.
+ return;
+ }
+
+ // First, update the state.
+ synchronized (ssl) {
+ if (state == STATE_CLOSED) {
+ // Someone called "close" but the handshake hasn't been interrupted yet.
+ return;
+ }
+
+ // Now that we've fixed up our state, we can tell waiting threads that
+ // we're ready.
+ transitionTo(STATE_READY);
+ }
+
+ // Let listeners know we are finally done
+ notifyHandshakeCompletedListeners();
+
+ synchronized (ssl) {
+ // Notify all threads waiting for the handshake to complete.
+ ssl.notifyAll();
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / new_session_callback
+ public final void onNewSessionEstablished(long sslSessionNativePtr) {
+ try {
+ // Increment the reference count to "take ownership" of the session resource.
+ NativeCrypto.SSL_SESSION_up_ref(sslSessionNativePtr);
+
+ // Create a native reference which will release the SSL_SESSION in its finalizer.
+ // This constructor will only throw if the native pointer passed in is NULL, which
+ // BoringSSL guarantees will not happen.
+ NativeRef.SSL_SESSION ref = new SSL_SESSION(sslSessionNativePtr);
+
+ NativeSslSession nativeSession = NativeSslSession.newInstance(ref, activeSession);
+
+ // Cache the newly established session.
+ AbstractSessionContext ctx = sessionContext();
+ ctx.cacheSession(nativeSession);
+ } catch (Exception ignored) {
+ // Ignore.
+ }
+ }
+
+ @Override
+ public final long serverSessionRequested(byte[] id) {
+ // TODO(nathanmittler): Implement server-side caching for TLS < 1.3
+ return 0;
+ }
+
+ @Override
+ public final void serverCertificateRequested() throws IOException {
+ synchronized (ssl) {
+ ssl.configureServerCertificate();
+ }
+ }
+
+ @Override
+ public final void verifyCertificateChain(byte[][] certChain, String authMethod)
+ throws CertificateException {
+ try {
+ if (certChain == null || certChain.length == 0) {
+ throw new CertificateException("Peer sent no certificate");
+ }
+ X509Certificate[] peerCertChain = SSLUtils.decodeX509CertificateChain(certChain);
+
+ X509TrustManager x509tm = sslParameters.getX509TrustManager();
+ if (x509tm == null) {
+ throw new CertificateException("No X.509 TrustManager");
+ }
+ // Update the peer information on the session.
+ activeSession.onPeerCertificatesReceived(getHostnameOrIP(), getPort(), peerCertChain);
+
+ if (getUseClientMode()) {
+ Platform.checkServerTrusted(x509tm, peerCertChain, authMethod, this);
+ } else {
+ String authType = peerCertChain[0].getPublicKey().getAlgorithm();
+ Platform.checkClientTrusted(x509tm, peerCertChain, authType, this);
+ }
+ } catch (CertificateException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new CertificateException(e);
+ }
+ }
+
+ @Override
+ public final InputStream getInputStream() throws IOException {
+ checkOpen();
+
+ InputStream returnVal;
+ synchronized (ssl) {
+ if (state == STATE_CLOSED) {
+ throw new SocketException("Socket is closed.");
+ }
+
+ if (is == null) {
+ is = new SSLInputStream();
+ }
+
+ returnVal = is;
+ }
+
+ // Block waiting for a handshake without a lock held. It's possible that the socket
+ // is closed at this point. If that happens, we'll still return the input stream but
+ // all reads on it will throw.
+ waitForHandshake();
+ return returnVal;
+ }
+
+ @Override
+ public final OutputStream getOutputStream() throws IOException {
+ checkOpen();
+
+ OutputStream returnVal;
+ synchronized (ssl) {
+ if (state == STATE_CLOSED) {
+ throw new SocketException("Socket is closed.");
+ }
+
+ if (os == null) {
+ os = new SSLOutputStream();
+ }
+
+ returnVal = os;
+ }
+
+ // Block waiting for a handshake without a lock held. It's possible that the socket
+ // is closed at this point. If that happens, we'll still return the output stream but
+ // all writes on it will throw.
+ waitForHandshake();
+ return returnVal;
+ }
+
+ private void assertReadableOrWriteableState() {
+ if (state == STATE_READY || state == STATE_READY_HANDSHAKE_CUT_THROUGH) {
+ return;
+ }
+
+ throw new AssertionError("Invalid state: " + state);
+ }
+
+ private void waitForHandshake() throws IOException {
+ startHandshake();
+
+ synchronized (ssl) {
+ while (state != STATE_READY &&
+ state != STATE_READY_HANDSHAKE_CUT_THROUGH &&
+ state != STATE_CLOSED) {
+ try {
+ ssl.wait();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new IOException("Interrupted waiting for handshake", e);
+ }
+ }
+
+ if (state == STATE_CLOSED) {
+ throw new SocketException("Socket is closed");
+ }
+ }
+ }
+
+ /**
+ * This inner class provides input data stream functionality
+ * for the OpenSSL native implementation. It is used to
+ * read data received via SSL protocol.
+ */
+ private class SSLInputStream extends InputStream {
+ /**
+ * OpenSSL only lets one thread read at a time, so this is used to
+ * make sure we serialize callers of SSL_read. Thread is already
+ * expected to have completed handshaking.
+ */
+ private final Object readLock = new Object();
+
+ SSLInputStream() {
+ }
+
+ /**
+ * Reads one byte. If there is no data in the underlying buffer,
+ * this operation can block until the data will be
+ * available.
+ */
+ @Override
+ public int read() throws IOException {
+ byte[] buffer = new byte[1];
+ int result = read(buffer, 0, 1);
+ return (result != -1) ? buffer[0] & 0xff : -1;
+ }
+
+ /**
+ * Method acts as described in spec for superclass.
+ * @see java.io.InputStream#read(byte[],int,int)
+ */
+ @Override
+ public int read(byte[] buf, int offset, int byteCount) throws IOException {
+ Platform.blockGuardOnNetwork();
+
+ checkOpen();
+ ArrayUtils.checkOffsetAndCount(buf.length, offset, byteCount);
+ if (byteCount == 0) {
+ return 0;
+ }
+
+ synchronized (readLock) {
+ synchronized (ssl) {
+ if (state == STATE_CLOSED) {
+ throw new SocketException("socket is closed");
+ }
+
+ if (DBG_STATE) {
+ assertReadableOrWriteableState();
+ }
+ }
+
+ int ret = ssl.read(
+ Platform.getFileDescriptor(socket), buf, offset, byteCount, getSoTimeout());
+ if (ret == -1) {
+ synchronized (ssl) {
+ if (state == STATE_CLOSED) {
+ throw new SocketException("socket is closed");
+ }
+ }
+ }
+ return ret;
+ }
+ }
+
+ @Override
+ public int available() {
+ return ssl.getPendingReadableBytes();
+ }
+
+ void awaitPendingOps() {
+ if (DBG_STATE) {
+ synchronized (ssl) {
+ if (state != STATE_CLOSED) {
+ throw new AssertionError("State is: " + state);
+ }
+ }
+ }
+
+ synchronized (readLock) {}
+ }
+ }
+
+ /**
+ * This inner class provides output data stream functionality
+ * for the OpenSSL native implementation. It is used to
+ * write data according to the encryption parameters given in SSL context.
+ */
+ private class SSLOutputStream extends OutputStream {
+ /**
+ * OpenSSL only lets one thread write at a time, so this is used
+ * to make sure we serialize callers of SSL_write. Thread is
+ * already expected to have completed handshaking.
+ */
+ private final Object writeLock = new Object();
+
+ SSLOutputStream() {
+ }
+
+ /**
+ * Method acts as described in spec for superclass.
+ * @see java.io.OutputStream#write(int)
+ */
+ @Override
+ public void write(int oneByte) throws IOException {
+ byte[] buffer = new byte[1];
+ buffer[0] = (byte) (oneByte & 0xff);
+ write(buffer);
+ }
+
+ /**
+ * Method acts as described in spec for superclass.
+ * @see java.io.OutputStream#write(byte[],int,int)
+ */
+ @Override
+ public void write(byte[] buf, int offset, int byteCount) throws IOException {
+ Platform.blockGuardOnNetwork();
+ checkOpen();
+ ArrayUtils.checkOffsetAndCount(buf.length, offset, byteCount);
+ if (byteCount == 0) {
+ return;
+ }
+
+ synchronized (writeLock) {
+ synchronized (ssl) {
+ if (state == STATE_CLOSED) {
+ throw new SocketException("socket is closed");
+ }
+
+ if (DBG_STATE) {
+ assertReadableOrWriteableState();
+ }
+ }
+
+ ssl.write(Platform.getFileDescriptor(socket), buf, offset, byteCount,
+ writeTimeoutMilliseconds);
+
+ synchronized (ssl) {
+ if (state == STATE_CLOSED) {
+ throw new SocketException("socket is closed");
+ }
+ }
+ }
+ }
+
+ void awaitPendingOps() {
+ if (DBG_STATE) {
+ synchronized (ssl) {
+ if (state != STATE_CLOSED) {
+ throw new AssertionError("State is: " + state);
+ }
+ }
+ }
+
+ synchronized (writeLock) {}
+ }
+ }
+
+ @Override
+ public final SSLSession getSession() {
+ return externalSession;
+ }
+
+ private ConscryptSession provideSession() {
+ boolean handshakeCompleted = false;
+ synchronized (ssl) {
+ if (state == STATE_CLOSED) {
+ return closedSession != null ? closedSession : SSLNullSession.getNullSession();
+ }
+
+ try {
+ handshakeCompleted = state >= STATE_READY;
+ if (!handshakeCompleted && isConnected()) {
+ waitForHandshake();
+ handshakeCompleted = true;
+ }
+ } catch (IOException e) {
+ // Fall through.
+ }
+ }
+
+ if (!handshakeCompleted) {
+ // return an invalid session with
+ // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
+ return SSLNullSession.getNullSession();
+ }
+
+ return activeSession;
+ }
+
+ // After handshake has started, provide active session otherwise a null session,
+ // for code which needs to read session attributes without triggering the handshake.
+ private ConscryptSession provideAfterHandshakeSession() {
+ return (state < STATE_HANDSHAKE_STARTED) ? SSLNullSession.getNullSession()
+ : provideSession();
+ }
+
+ // If handshake is in progress, provide active session otherwise a null session.
+ private ConscryptSession provideHandshakeSession() {
+ synchronized (ssl) {
+ return state >= STATE_HANDSHAKE_STARTED && state < STATE_READY ? activeSession
+ : SSLNullSession.getNullSession();
+ }
+ }
+
+ @Override
+ final SSLSession getActiveSession() {
+ return activeSession;
+ }
+
+ @Override
+ public final SSLSession getHandshakeSession() {
+ synchronized (ssl) {
+ if (state >= STATE_HANDSHAKE_STARTED && state < STATE_READY) {
+ return Platform.wrapSSLSession(new ExternalSession(new ExternalSession.Provider() {
+ @Override
+ public ConscryptSession provideSession() {
+ return ConscryptFileDescriptorSocket.this.provideHandshakeSession();
+ }
+ }));
+ }
+ return null;
+ }
+ }
+
+ @Override
+ public final boolean getEnableSessionCreation() {
+ return sslParameters.getEnableSessionCreation();
+ }
+
+ @Override
+ public final void setEnableSessionCreation(boolean flag) {
+ sslParameters.setEnableSessionCreation(flag);
+ }
+
+ @Override
+ public final String[] getSupportedCipherSuites() {
+ return NativeCrypto.getSupportedCipherSuites();
+ }
+
+ @Override
+ public final String[] getEnabledCipherSuites() {
+ return sslParameters.getEnabledCipherSuites();
+ }
+
+ @Override
+ public final void setEnabledCipherSuites(String[] suites) {
+ sslParameters.setEnabledCipherSuites(suites);
+ }
+
+ @Override
+ public final String[] getSupportedProtocols() {
+ return NativeCrypto.getSupportedProtocols();
+ }
+
+ @Override
+ public final String[] getEnabledProtocols() {
+ return sslParameters.getEnabledProtocols();
+ }
+
+ @Override
+ public final void setEnabledProtocols(String[] protocols) {
+ sslParameters.setEnabledProtocols(protocols);
+ }
+
+ /**
+ * This method enables session ticket support.
+ *
+ * @param useSessionTickets True to enable session tickets
+ */
+ @android.compat.annotation.
+ UnsupportedAppUsage(maxTargetSdk = dalvik.annotation.compat.VersionCodes.Q,
+ publicAlternatives = "Use {@link android.net.ssl.SSLSockets#setUseSessionTickets}.")
+ @Override
+ public final void
+ setUseSessionTickets(boolean useSessionTickets) {
+ sslParameters.setUseSessionTickets(useSessionTickets);
+ }
+
+ /**
+ * This method enables Server Name Indication. If the hostname is not a valid SNI hostname,
+ * the SNI extension will be omitted from the handshake.
+ *
+ * @param hostname the desired SNI hostname, or null to disable
+ */
+ @android.compat.annotation.
+ UnsupportedAppUsage(maxTargetSdk = dalvik.annotation.compat.VersionCodes.Q,
+ publicAlternatives = "Use {@code javax.net.ssl.SSLParameters#setServerNames}.")
+ @Override
+ public final void
+ setHostname(String hostname) {
+ sslParameters.setUseSni(hostname != null);
+ super.setHostname(hostname);
+ }
+
+ /**
+ * Enables/disables TLS Channel ID for this server socket.
+ *
+ * <p>This method needs to be invoked before the handshake starts.
+ *
+ * @throws IllegalStateException if this is a client socket or if the handshake has already
+ * started.
+ */
+ @Override
+ public final void setChannelIdEnabled(boolean enabled) {
+ if (getUseClientMode()) {
+ throw new IllegalStateException("Client mode");
+ }
+
+ synchronized (ssl) {
+ if (state != STATE_NEW) {
+ throw new IllegalStateException(
+ "Could not enable/disable Channel ID after the initial handshake has"
+ + " begun.");
+ }
+ }
+ sslParameters.channelIdEnabled = enabled;
+ }
+
+ /**
+ * Gets the TLS Channel ID for this server socket. Channel ID is only available once the
+ * handshake completes.
+ *
+ * @return channel ID or {@code null} if not available.
+ *
+ * @throws IllegalStateException if this is a client socket or if the handshake has not yet
+ * completed.
+ * @throws SSLException if channel ID is available but could not be obtained.
+ */
+ @Override
+ public final byte[] getChannelId() throws SSLException {
+ if (getUseClientMode()) {
+ throw new IllegalStateException("Client mode");
+ }
+
+ synchronized (ssl) {
+ if (state != STATE_READY) {
+ throw new IllegalStateException(
+ "Channel ID is only available after handshake completes");
+ }
+ }
+ return ssl.getTlsChannelId();
+ }
+
+ /**
+ * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client socket.
+ *
+ * <p>This method needs to be invoked before the handshake starts.
+ *
+ * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables
+ * TLS Channel ID). The private key must be an Elliptic Curve (EC) key based on the NIST
+ * P-256 curve (aka SECG secp256r1 or ANSI X9.62 prime256v1).
+ *
+ * @throws IllegalStateException if this is a server socket or if the handshake has already
+ * started.
+ */
+ @Override
+ public final void setChannelIdPrivateKey(PrivateKey privateKey) {
+ if (!getUseClientMode()) {
+ throw new IllegalStateException("Server mode");
+ }
+
+ synchronized (ssl) {
+ if (state != STATE_NEW) {
+ throw new IllegalStateException(
+ "Could not change Channel ID private key after the initial handshake has"
+ + " begun.");
+ }
+ }
+
+ if (privateKey == null) {
+ sslParameters.channelIdEnabled = false;
+ channelIdPrivateKey = null;
+ } else {
+ sslParameters.channelIdEnabled = true;
+ try {
+ ECParameterSpec ecParams = null;
+ if (privateKey instanceof ECKey) {
+ ecParams = ((ECKey) privateKey).getParams();
+ }
+ if (ecParams == null) {
+ // Assume this is a P-256 key, as specified in the contract of this method.
+ ecParams =
+ OpenSSLECGroupContext.getCurveByName("prime256v1").getECParameterSpec();
+ }
+ channelIdPrivateKey =
+ OpenSSLKey.fromECPrivateKeyForTLSStackOnly(privateKey, ecParams);
+ } catch (InvalidKeyException e) {
+ // Will have error in startHandshake
+ }
+ }
+ }
+
+ @Override
+ byte[] getTlsUnique() {
+ return ssl.getTlsUnique();
+ }
+
+ @Override
+ byte[] exportKeyingMaterial(String label, byte[] context, int length) throws SSLException {
+ synchronized (ssl) {
+ if (state < STATE_HANDSHAKE_COMPLETED || state == STATE_CLOSED) {
+ return null;
+ }
+ }
+ return ssl.exportKeyingMaterial(label, context, length);
+ }
+
+ @Override
+ public final boolean getUseClientMode() {
+ return sslParameters.getUseClientMode();
+ }
+
+ @Override
+ public final void setUseClientMode(boolean mode) {
+ synchronized (ssl) {
+ if (state != STATE_NEW) {
+ throw new IllegalArgumentException(
+ "Could not change the mode after the initial handshake has begun.");
+ }
+ }
+ sslParameters.setUseClientMode(mode);
+ }
+
+ @Override
+ public final boolean getWantClientAuth() {
+ return sslParameters.getWantClientAuth();
+ }
+
+ @Override
+ public final boolean getNeedClientAuth() {
+ return sslParameters.getNeedClientAuth();
+ }
+
+ @Override
+ public final void setNeedClientAuth(boolean need) {
+ sslParameters.setNeedClientAuth(need);
+ }
+
+ @Override
+ public final void setWantClientAuth(boolean want) {
+ sslParameters.setWantClientAuth(want);
+ }
+
+ /**
+ * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
+ */
+ @Override
+ public final void setSoWriteTimeout(int writeTimeoutMilliseconds) throws SocketException {
+ this.writeTimeoutMilliseconds = writeTimeoutMilliseconds;
+
+ Platform.setSocketWriteTimeout(this, writeTimeoutMilliseconds);
+ }
+
+ /**
+ * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
+ */
+ @Override
+ public final int getSoWriteTimeout() {
+ return writeTimeoutMilliseconds;
+ }
+
+ /**
+ * Set the handshake timeout on this socket. This timeout is specified in
+ * milliseconds and will be used only during the handshake process.
+ */
+ @Override
+ public final void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketException {
+ this.handshakeTimeoutMilliseconds = handshakeTimeoutMilliseconds;
+ }
+
+ @Override
+ @SuppressWarnings("UnsynchronizedOverridesSynchronized")
+ public final void close() throws IOException {
+ // TODO: Close SSL sockets using a background thread so they close gracefully.
+
+ SSLInputStream sslInputStream;
+ SSLOutputStream sslOutputStream;
+
+ if (ssl == null) {
+ // close() has been called before we've initialized the socket, so just
+ // return.
+ return;
+ }
+
+ synchronized (ssl) {
+ if (state == STATE_CLOSED) {
+ // close() has already been called, so do nothing and return.
+ return;
+ }
+
+ int oldState = state;
+ transitionTo(STATE_CLOSED);
+
+ if (oldState == STATE_NEW) {
+ // The handshake hasn't been started yet, so there's no OpenSSL related
+ // state to clean up. We still need to close the underlying socket if
+ // we're wrapping it and were asked to autoClose.
+ free();
+ closeUnderlyingSocket();
+
+ ssl.notifyAll();
+ return;
+ }
+
+ if (oldState != STATE_READY && oldState != STATE_READY_HANDSHAKE_CUT_THROUGH) {
+ // If we're in these states, we still haven't returned from startHandshake.
+ // We call SSL_interrupt so that we can interrupt SSL_do_handshake and then
+ // set the state to STATE_CLOSED. startHandshake will handle all cleanup
+ // after SSL_do_handshake returns, so we don't have anything to do here.
+ ssl.interrupt();
+
+ ssl.notifyAll();
+ return;
+ }
+
+ ssl.notifyAll();
+ // We've already returned from startHandshake, so we potentially have
+ // input and output streams to clean up.
+ sslInputStream = is;
+ sslOutputStream = os;
+ }
+
+ // Don't bother interrupting unless we have something to interrupt.
+ if (sslInputStream != null || sslOutputStream != null) {
+ ssl.interrupt();
+ }
+
+ // Wait for the input and output streams to finish any reads they have in
+ // progress. If there are no reads in progress at this point, future reads will
+ // throw because state == STATE_CLOSED
+ if (sslInputStream != null) {
+ sslInputStream.awaitPendingOps();
+ }
+ if (sslOutputStream != null) {
+ sslOutputStream.awaitPendingOps();
+ }
+
+ shutdownAndFreeSslNative();
+ }
+
+ private void shutdownAndFreeSslNative() throws IOException {
+ try {
+ Platform.blockGuardOnNetwork();
+ ssl.shutdown(Platform.getFileDescriptor(socket));
+ } catch (IOException ignored) {
+ /*
+ * Note that although close() can throw
+ * IOException, the RI does not throw if there
+ * is problem sending a "close notify" which
+ * can happen if the underlying socket is closed.
+ */
+ } finally {
+ free();
+ closeUnderlyingSocket();
+ }
+ }
+
+ private void closeUnderlyingSocket() throws IOException {
+ super.close();
+ }
+
+ private void free() {
+ if (!ssl.isClosed()) {
+ ssl.close();
+ Platform.closeGuardClose(guard);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ protected final void finalize() throws Throwable {
+ try {
+ /*
+ * Just worry about our own state. Notably we do not try and
+ * close anything. The SocketImpl, either our own
+ * PlainSocketImpl, or the Socket we are wrapping, will do
+ * that. This might mean we do not properly SSL_shutdown, but
+ * if you want to do that, properly close the socket yourself.
+ *
+ * The reason why we don't try to SSL_shutdown, is that there
+ * can be a race between finalizers where the PlainSocketImpl
+ * finalizer runs first and closes the socket. However, in the
+ * meanwhile, the underlying file descriptor could be reused
+ * for another purpose. If we call SSL_shutdown, the
+ * underlying socket BIOs still have the old file descriptor
+ * and will write the close notify to some unsuspecting
+ * reader.
+ */
+ if (guard != null) {
+ Platform.closeGuardWarnIfOpen(guard);
+ }
+ if (ssl != null) {
+ synchronized (ssl) {
+ transitionTo(STATE_CLOSED);
+ }
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+ @Override
+ public final void setApplicationProtocolSelector(ApplicationProtocolSelector selector) {
+ setApplicationProtocolSelector(
+ selector == null ? null : new ApplicationProtocolSelectorAdapter(this, selector));
+ }
+
+ @Override
+ final void setApplicationProtocolSelector(ApplicationProtocolSelectorAdapter selector) {
+ sslParameters.setApplicationProtocolSelector(selector);
+ }
+
+ @Override
+ public int selectApplicationProtocol(byte[] protocols) {
+ ApplicationProtocolSelectorAdapter adapter = sslParameters.getApplicationProtocolSelector();
+ if (adapter == null) {
+ return NativeConstants.SSL_TLSEXT_ERR_NOACK;
+ }
+ return adapter.selectApplicationProtocol(protocols);
+ }
+
+ @Override
+ final void setApplicationProtocols(String[] protocols) {
+ sslParameters.setApplicationProtocols(protocols);
+ }
+
+ @Override
+ final String[] getApplicationProtocols() {
+ return sslParameters.getApplicationProtocols();
+ }
+
+ @Override
+ public final String getApplicationProtocol() {
+ return provideAfterHandshakeSession().getApplicationProtocol();
+ }
+
+ @Override
+ public final String getHandshakeApplicationProtocol() {
+ synchronized (ssl) {
+ return state >= STATE_HANDSHAKE_STARTED && state < STATE_READY
+ ? getApplicationProtocol() : null;
+ }
+ }
+
+ @Override
+ public final SSLParameters getSSLParameters() {
+ SSLParameters params = super.getSSLParameters();
+ Platform.getSSLParameters(params, sslParameters, this);
+ return params;
+ }
+
+ @Override
+ public final void setSSLParameters(SSLParameters p) {
+ super.setSSLParameters(p);
+ Platform.setSSLParameters(p, sslParameters, this);
+ }
+
+ @Override
+ @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
+ public final String chooseServerPSKIdentityHint(PSKKeyManager keyManager) {
+ return keyManager.chooseServerKeyIdentityHint(this);
+ }
+
+ @Override
+ @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
+ public final String chooseClientPSKIdentity(PSKKeyManager keyManager, String identityHint) {
+ return keyManager.chooseClientKeyIdentity(identityHint, this);
+ }
+
+ @Override
+ @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
+ public final SecretKey getPSKKey(PSKKeyManager keyManager, String identityHint, String identity) {
+ return keyManager.getKey(identityHint, identity, this);
+ }
+
+ @Override
+ public final String chooseServerAlias(X509KeyManager keyManager, String keyType) {
+ return keyManager.chooseServerAlias(keyType, null, this);
+ }
+
+ @Override
+ public final String chooseClientAlias(
+ X509KeyManager keyManager, X500Principal[] issuers, String[] keyTypes) {
+ return keyManager.chooseClientAlias(keyTypes, issuers, this);
+ }
+
+ private ClientSessionContext clientSessionContext() {
+ return sslParameters.getClientSessionContext();
+ }
+
+ private AbstractSessionContext sessionContext() {
+ return sslParameters.getSessionContext();
+ }
+
+ // All calls synchronized on this.ssl.
+ private void transitionTo(int newState) {
+ if (state == newState) {
+ return;
+ }
+
+ switch (newState) {
+ case STATE_HANDSHAKE_STARTED:
+ handshakeStartedMillis = Platform.getMillisSinceBoot();
+ break;
+
+ case STATE_READY:
+ if (handshakeStartedMillis != 0) {
+ Platform.countTlsHandshake(true, activeSession.getProtocol(),
+ activeSession.getCipherSuite(),
+ Platform.getMillisSinceBoot() - handshakeStartedMillis);
+ handshakeStartedMillis = 0;
+ }
+ break;
+
+ case STATE_CLOSED: {
+ if (handshakeStartedMillis != 0) {
+ // Handshake was in progress so must have failed.
+ Platform.countTlsHandshake(false, "TLS_PROTO_FAILED", "TLS_CIPHER_FAILED",
+ Platform.getMillisSinceBoot() - handshakeStartedMillis);
+ handshakeStartedMillis = 0;
+ }
+ if (!ssl.isClosed() && state >= STATE_HANDSHAKE_STARTED && state < STATE_CLOSED) {
+ closedSession = new SessionSnapshot(activeSession);
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ // Update the state
+ this.state = newState;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptHostnameVerifier.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptHostnameVerifier.java
new file mode 100644
index 0000000..05784bc
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptHostnameVerifier.java
@@ -0,0 +1,36 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2019 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.cert.X509Certificate;
+import javax.net.ssl.SSLSession;
+
+/**
+ * This interface is used to implement hostname verification in Conscrypt. Unlike with
+ * {@link javax.net.ssl.HostnameVerifier}, the hostname verifier is called whenever hostname
+ * verification is needed, without any use of default rules.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ConscryptHostnameVerifier {
+
+ /**
+ * Returns whether the given hostname is allowable given the peer's authentication information
+ * from the given session.
+ */
+ boolean verify(X509Certificate[] certs, String hostname, SSLSession session);
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptServerSocket.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptServerSocket.java
new file mode 100644
index 0000000..c667e8b
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptServerSocket.java
@@ -0,0 +1,190 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2007 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import javax.net.ssl.SSLServerSocket;
+
+/**
+ * BoringSSL-based implementation of server sockets.
+ */
+final class ConscryptServerSocket extends SSLServerSocket {
+ private final SSLParametersImpl sslParameters;
+ private boolean channelIdEnabled;
+ private boolean useEngineSocket;
+
+ ConscryptServerSocket(SSLParametersImpl sslParameters) throws IOException {
+ this.sslParameters = sslParameters;
+ }
+
+ ConscryptServerSocket(int port, SSLParametersImpl sslParameters)
+ throws IOException {
+ super(port);
+ this.sslParameters = sslParameters;
+ }
+
+ ConscryptServerSocket(int port, int backlog, SSLParametersImpl sslParameters)
+ throws IOException {
+ super(port, backlog);
+ this.sslParameters = sslParameters;
+ }
+
+ ConscryptServerSocket(int port,
+ int backlog,
+ InetAddress iAddress,
+ SSLParametersImpl sslParameters)
+ throws IOException {
+ super(port, backlog, iAddress);
+ this.sslParameters = sslParameters;
+ }
+
+ /**
+ * Configures the socket to be created for this instance.
+ */
+ ConscryptServerSocket setUseEngineSocket(boolean useEngineSocket) {
+ this.useEngineSocket = useEngineSocket;
+ return this;
+ }
+
+ @Override
+ public boolean getEnableSessionCreation() {
+ return sslParameters.getEnableSessionCreation();
+ }
+
+ @Override
+ public void setEnableSessionCreation(boolean flag) {
+ sslParameters.setEnableSessionCreation(flag);
+ }
+
+ /**
+ * The names of the protocols' versions that may be used on this SSL
+ * connection.
+ * @return an array of protocols names
+ */
+ @Override
+ public String[] getSupportedProtocols() {
+ return NativeCrypto.getSupportedProtocols();
+ }
+
+ /**
+ * The names of the protocols' versions that in use on this SSL connection.
+ *
+ * @return an array of protocols names
+ */
+ @Override
+ public String[] getEnabledProtocols() {
+ return sslParameters.getEnabledProtocols();
+ }
+
+ /**
+ * This method enables the protocols' versions listed by
+ * getSupportedProtocols().
+ *
+ * @param protocols names of all the protocols to enable.
+ *
+ * @throws IllegalArgumentException when one or more of the names in the
+ * array are not supported, or when the array is null.
+ */
+ @Override
+ public void setEnabledProtocols(String[] protocols) {
+ sslParameters.setEnabledProtocols(protocols);
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return NativeCrypto.getSupportedCipherSuites();
+ }
+
+ @Override
+ public String[] getEnabledCipherSuites() {
+ return sslParameters.getEnabledCipherSuites();
+ }
+
+ /**
+ * Enables/disables the TLS Channel ID extension for this server socket.
+ */
+ void setChannelIdEnabled(boolean enabled) {
+ channelIdEnabled = enabled;
+ }
+
+ /**
+ * Checks whether the TLS Channel ID extension is enabled for this server socket.
+ */
+ boolean isChannelIdEnabled() {
+ return channelIdEnabled;
+ }
+
+ /**
+ * This method enables the cipher suites listed by
+ * getSupportedCipherSuites().
+ *
+ * @param suites the names of all the cipher suites to enable
+ * @throws IllegalArgumentException when one or more of the ciphers in array
+ * suites are not supported, or when the array is null.
+ */
+ @Override
+ public void setEnabledCipherSuites(String[] suites) {
+ sslParameters.setEnabledCipherSuites(suites);
+ }
+
+ @Override
+ public boolean getWantClientAuth() {
+ return sslParameters.getWantClientAuth();
+ }
+
+ @Override
+ public void setWantClientAuth(boolean want) {
+ sslParameters.setWantClientAuth(want);
+ }
+
+ @Override
+ public boolean getNeedClientAuth() {
+ return sslParameters.getNeedClientAuth();
+ }
+
+ @Override
+ public void setNeedClientAuth(boolean need) {
+ sslParameters.setNeedClientAuth(need);
+ }
+
+ @Override
+ public void setUseClientMode(boolean mode) {
+ sslParameters.setUseClientMode(mode);
+ }
+
+ @Override
+ public boolean getUseClientMode() {
+ return sslParameters.getUseClientMode();
+ }
+
+ @Override
+ public Socket accept() throws IOException {
+ final AbstractConscryptSocket socket;
+ if (useEngineSocket) {
+ socket = Platform.createEngineSocket(sslParameters);
+ } else {
+ socket = Platform.createFileDescriptorSocket(sslParameters);
+ }
+
+ socket.setChannelIdEnabled(channelIdEnabled);
+ implAccept(socket);
+ return socket;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptSession.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptSession.java
new file mode 100644
index 0000000..5e241d9
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptSession.java
@@ -0,0 +1,58 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.cert.X509Certificate;
+import java.util.List;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+
+/**
+ * Extends the default interface for {@link SSLSession} to provide additional properties exposed
+ * by Conscrypt.
+ */
+interface ConscryptSession extends SSLSession {
+
+ String getRequestedServerName();
+
+ /**
+ * Returns the OCSP stapled response. Returns a copy of the internal arrays.
+ *
+ * The method signature matches
+ * <a
+ * href="http://download.java.net/java/jdk9/docs/api/javax/net/ssl/ExtendedSSLSession.html#getStatusResponses--">Java
+ * 9</a>.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc6066">RFC 6066</a>
+ * @see <a href="https://tools.ietf.org/html/rfc6961">RFC 6961</a>
+ */
+ List<byte[]> getStatusResponses();
+
+ /**
+ * Returns the signed certificate timestamp (SCT) received from the peer. Returns a
+ * copy of the internal array.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc6962">RFC 6962</a>
+ */
+ byte[] getPeerSignedCertificateTimestamp();
+
+ @Override
+ X509Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException;
+
+ String getApplicationProtocol();
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/CryptoUpcalls.java b/repackaged/common/src/main/java/com/android/org/conscrypt/CryptoUpcalls.java
new file mode 100644
index 0000000..7e2a4e9
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/CryptoUpcalls.java
@@ -0,0 +1,230 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2014 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.Security;
+import java.security.Signature;
+import java.util.ArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+
+/**
+ * Provides a place where NativeCrypto can call back up to do Java language
+ * calls to work on delegated key types from native code. Delegated keys are
+ * usually backed by hardware so we don't have access directly to the private
+ * key material. If it were a key where we can get to the private key, we
+ * would not ever call into this class.
+ */
+final class CryptoUpcalls {
+ private static final Logger logger = Logger.getLogger(CryptoUpcalls.class.getName());
+
+ private CryptoUpcalls() {}
+
+ /**
+ * Finds providers that are not us that provide the requested algorithms.
+ */
+ private static ArrayList<Provider> getExternalProviders(String algorithm) {
+ ArrayList<Provider> providers = new ArrayList<Provider>(1);
+ for (Provider p : Security.getProviders(algorithm)) {
+ if (!Conscrypt.isConscrypt(p)) {
+ providers.add(p);
+ }
+ }
+ if (providers.isEmpty()) {
+ logger.warning("Could not find external provider for algorithm: " + algorithm);
+ }
+ return providers;
+ }
+
+ static byte[] ecSignDigestWithPrivateKey(PrivateKey javaKey, byte[] message) {
+ // Hint: Algorithm names come from:
+ // http://docs.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html
+ String keyAlgorithm = javaKey.getAlgorithm();
+ if (!"EC".equals(keyAlgorithm)) {
+ throw new RuntimeException("Unexpected key type: " + javaKey.toString());
+ }
+
+ return signDigestWithPrivateKey(javaKey, message, "NONEwithECDSA");
+ }
+
+ private static byte[] signDigestWithPrivateKey(PrivateKey javaKey, byte[] message,
+ String algorithm) {
+ Signature signature;
+
+ // Since this is a delegated key, we cannot handle providing a signature using this key.
+ // Otherwise we wouldn't end up in this class in the first place. The first step is to
+ // try to get the most preferred provider as long as it isn't us.
+ try {
+ signature = Signature.getInstance(algorithm);
+ signature.initSign(javaKey);
+
+ // Ignore it if it points back to us.
+ if (Conscrypt.isConscrypt(signature.getProvider())) {
+ signature = null;
+ }
+ } catch (NoSuchAlgorithmException e) {
+ logger.warning("Unsupported signature algorithm: " + algorithm);
+ return null;
+ } catch (InvalidKeyException e) {
+ logger.warning("Preferred provider doesn't support key:");
+ e.printStackTrace();
+ signature = null;
+ }
+
+ // If the preferred provider was us, fall back to trying to find the
+ // first not-us provider that initializes correctly.
+ if (signature == null) {
+ ArrayList<Provider> providers = getExternalProviders("Signature." + algorithm);
+ RuntimeException savedRuntimeException = null;
+ for (Provider p : providers) {
+ try {
+ signature = Signature.getInstance(algorithm, p);
+ signature.initSign(javaKey);
+ break;
+ } catch (NoSuchAlgorithmException | InvalidKeyException e) {
+ signature = null;
+ } catch (RuntimeException e) {
+ signature = null;
+ if (savedRuntimeException == null) {
+ savedRuntimeException = e;
+ }
+ }
+ }
+ if (signature == null) {
+ if (savedRuntimeException != null) {
+ throw savedRuntimeException;
+ }
+ logger.warning("Could not find provider for algorithm: " + algorithm);
+ return null;
+ }
+ }
+
+ // Sign the message.
+ try {
+ signature.update(message);
+ return signature.sign();
+ } catch (Exception e) {
+ logger.log(Level.WARNING,
+ "Exception while signing message with " + javaKey.getAlgorithm()
+ + " private key:",
+ e);
+ return null;
+ }
+ }
+
+ static byte[] rsaSignDigestWithPrivateKey(PrivateKey javaKey, int openSSLPadding,
+ byte[] message) {
+ // An RSA cipher + ENCRYPT_MODE produces a standard RSA signature
+ return rsaOpWithPrivateKey(javaKey, openSSLPadding, Cipher.ENCRYPT_MODE, message);
+ }
+
+ static byte[] rsaDecryptWithPrivateKey(PrivateKey javaKey, int openSSLPadding, byte[] input) {
+ return rsaOpWithPrivateKey(javaKey, openSSLPadding, Cipher.DECRYPT_MODE, input);
+ }
+
+ private static byte[] rsaOpWithPrivateKey(PrivateKey javaKey, int openSSLPadding,
+ int cipherMode, byte[] input) {
+ String keyAlgorithm = javaKey.getAlgorithm();
+ if (!"RSA".equals(keyAlgorithm)) {
+ logger.warning("Unexpected key type: " + keyAlgorithm);
+ return null;
+ }
+
+ String jcaPadding;
+ switch (openSSLPadding) {
+ case NativeConstants.RSA_PKCS1_PADDING:
+ // Since we're using this with a private key, this will produce RSASSA-PKCS1-v1_5
+ // (signature) padding rather than RSAES-PKCS1-v1_5 (encryption) padding
+ jcaPadding = "PKCS1Padding";
+ break;
+ case NativeConstants.RSA_NO_PADDING:
+ jcaPadding = "NoPadding";
+ break;
+ case NativeConstants.RSA_PKCS1_OAEP_PADDING:
+ jcaPadding = "OAEPPadding";
+ break;
+ default:
+ logger.warning("Unsupported OpenSSL/BoringSSL padding: " + openSSLPadding);
+ return null;
+ }
+
+ String transformation = "RSA/ECB/" + jcaPadding;
+ Cipher c = null;
+
+ // Since this is a delegated key, we cannot handle providing a cipher using this key.
+ // Otherwise we wouldn't end up in this class in the first place. The first step is to
+ // try to get the most preferred provider as long as it isn't us.
+ try {
+ c = Cipher.getInstance(transformation);
+ c.init(cipherMode, javaKey);
+
+ // Ignore it if it points back to us.
+ if (Conscrypt.isConscrypt(c.getProvider())) {
+ c = null;
+ }
+ } catch (NoSuchAlgorithmException e) {
+ logger.warning("Unsupported cipher algorithm: " + transformation);
+ return null;
+ } catch (NoSuchPaddingException e) {
+ logger.warning("Unsupported cipher algorithm: " + transformation);
+ return null;
+ } catch (InvalidKeyException e) {
+ logger.log(Level.WARNING, "Preferred provider doesn't support key:", e);
+ c = null;
+ }
+
+ // If the preferred provider was us, fall back to trying to find the
+ // first not-us provider that initializes correctly.
+ if (c == null) {
+ ArrayList<Provider> providers = getExternalProviders("Cipher." + transformation);
+ for (Provider p : providers) {
+ try {
+ c = Cipher.getInstance(transformation, p);
+ c.init(cipherMode, javaKey);
+ break;
+ } catch (NoSuchAlgorithmException e) {
+ c = null;
+ } catch (InvalidKeyException e) {
+ c = null;
+ } catch (NoSuchPaddingException e) {
+ c = null;
+ }
+ }
+ if (c == null) {
+ logger.warning("Could not find provider for algorithm: " + transformation);
+ return null;
+ }
+ }
+
+ try {
+ return c.doFinal(input);
+ } catch (Exception e) {
+ logger.log(Level.WARNING,
+ "Exception while decrypting message with " + javaKey.getAlgorithm()
+ + " private key using " + transformation + ":",
+ e);
+ return null;
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/DESEDESecretKeyFactory.java b/repackaged/common/src/main/java/com/android/org/conscrypt/DESEDESecretKeyFactory.java
new file mode 100644
index 0000000..4dc3a6a
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/DESEDESecretKeyFactory.java
@@ -0,0 +1,100 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.InvalidKeyException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactorySpi;
+import javax.crypto.spec.DESedeKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * An implementation of {@link javax.crypto.SecretKeyFactory} for use with DESEDE keys. This
+ * class supports {@link SecretKeySpec} and {@link DESedeKeySpec} for key specs.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class DESEDESecretKeyFactory extends SecretKeyFactorySpi {
+
+ public DESEDESecretKeyFactory() {}
+
+ @Override
+ protected SecretKey engineGenerateSecret(KeySpec keySpec) throws InvalidKeySpecException {
+ if (keySpec == null) {
+ throw new InvalidKeySpecException("Null KeySpec");
+ }
+ if (keySpec instanceof SecretKeySpec) {
+ SecretKeySpec key = (SecretKeySpec) keySpec;
+ try {
+ if (!DESedeKeySpec.isParityAdjusted(key.getEncoded(), 0)) {
+ throw new InvalidKeySpecException(
+ "SecretKeySpec is not a parity-adjusted DESEDE key");
+ }
+ } catch (InvalidKeyException e) {
+ throw new InvalidKeySpecException(e);
+ }
+ return key;
+ } else if (keySpec instanceof DESedeKeySpec) {
+ DESedeKeySpec desKeySpec = (DESedeKeySpec) keySpec;
+ return new SecretKeySpec(desKeySpec.getKey(), "DESEDE");
+ } else {
+ throw new InvalidKeySpecException(
+ "Unsupported KeySpec class: " + keySpec.getClass().getName());
+ }
+ }
+
+ @Override
+ protected KeySpec engineGetKeySpec(SecretKey secretKey,
+ @SuppressWarnings("rawtypes") Class aClass) throws InvalidKeySpecException {
+ if (secretKey == null) {
+ throw new InvalidKeySpecException("Null SecretKey");
+ }
+ if (aClass == SecretKeySpec.class) {
+ try {
+ if (!DESedeKeySpec.isParityAdjusted(secretKey.getEncoded(), 0)) {
+ throw new InvalidKeySpecException("SecretKey is not a parity-adjusted DESEDE key");
+ }
+ } catch (InvalidKeyException e) {
+ throw new InvalidKeySpecException(e);
+ }
+ if (secretKey instanceof SecretKeySpec) {
+ return (KeySpec) secretKey;
+ } else {
+ return new SecretKeySpec(secretKey.getEncoded(), "DESEDE");
+ }
+ } else if (aClass == DESedeKeySpec.class) {
+ try {
+ return new DESedeKeySpec(secretKey.getEncoded());
+ } catch (InvalidKeyException e) {
+ throw new InvalidKeySpecException(e);
+ }
+ } else {
+ throw new InvalidKeySpecException("Unsupported KeySpec class: " + aClass);
+ }
+ }
+
+ @Override
+ protected SecretKey engineTranslateKey(SecretKey secretKey) throws InvalidKeyException {
+ if (secretKey == null) {
+ throw new InvalidKeyException("Null SecretKey");
+ }
+ return new SecretKeySpec(secretKey.getEncoded(), secretKey.getAlgorithm());
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/DefaultSSLContextImpl.java b/repackaged/common/src/main/java/com/android/org/conscrypt/DefaultSSLContextImpl.java
new file mode 100644
index 0000000..41ca363
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/DefaultSSLContextImpl.java
@@ -0,0 +1,148 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+
+/**
+ * Support class for this package.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class DefaultSSLContextImpl extends OpenSSLContextImpl {
+ /**
+ * Accessed by SSLContextImpl(DefaultSSLContextImpl) holding the
+ * DefaultSSLContextImpl.class monitor
+ */
+ private static KeyManager[] KEY_MANAGERS;
+
+ /**
+ * Accessed by SSLContextImpl(DefaultSSLContextImpl) holding the
+ * DefaultSSLContextImpl.class monitor
+ */
+ private static TrustManager[] TRUST_MANAGERS;
+
+ /**
+ * DefaultSSLContextImpl delegates the work to the super class since there
+ * is no way to put a synchronized around both the call to super and the
+ * rest of this constructor to guarantee that we don't have races in
+ * creating the state shared between all default SSLContexts.
+ */
+ private DefaultSSLContextImpl(String[] protocols) throws GeneralSecurityException, IOException {
+ super(protocols, true);
+ }
+
+ // TODO javax.net.ssl.keyStoreProvider system property
+ KeyManager[] getKeyManagers() throws GeneralSecurityException, IOException {
+ if (KEY_MANAGERS != null) {
+ return KEY_MANAGERS;
+ }
+ // find KeyStore, KeyManagers
+ String keystore = System.getProperty("javax.net.ssl.keyStore");
+ if (keystore == null) {
+ return null;
+ }
+ String keystorepwd = System.getProperty("javax.net.ssl.keyStorePassword");
+ char[] pwd = (keystorepwd == null) ? null : keystorepwd.toCharArray();
+
+ KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ InputStream is = null;
+ try {
+ is = new BufferedInputStream(new FileInputStream(keystore));
+ ks.load(is, pwd);
+ } finally {
+ if (is != null) {
+ is.close();
+ }
+ }
+
+ String kmfAlg = KeyManagerFactory.getDefaultAlgorithm();
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(kmfAlg);
+ kmf.init(ks, pwd);
+ KEY_MANAGERS = kmf.getKeyManagers();
+ return KEY_MANAGERS;
+ }
+
+ // TODO javax.net.ssl.trustStoreProvider system property
+ TrustManager[] getTrustManagers() throws GeneralSecurityException, IOException {
+ if (TRUST_MANAGERS != null) {
+ return TRUST_MANAGERS;
+ }
+
+ // find TrustStore, TrustManagers
+ String keystore = System.getProperty("javax.net.ssl.trustStore");
+ if (keystore == null) {
+ return null;
+ }
+ String keystorepwd = System.getProperty("javax.net.ssl.trustStorePassword");
+ char[] pwd = (keystorepwd == null) ? null : keystorepwd.toCharArray();
+
+ // TODO Defaults: jssecacerts; cacerts
+ KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ InputStream is = null;
+ try {
+ is = new BufferedInputStream(new FileInputStream(keystore));
+ ks.load(is, pwd);
+ } finally {
+ if (is != null) {
+ is.close();
+ }
+ }
+ String tmfAlg = TrustManagerFactory.getDefaultAlgorithm();
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlg);
+ tmf.init(ks);
+ TRUST_MANAGERS = tmf.getTrustManagers();
+ return TRUST_MANAGERS;
+ }
+
+ @Override
+ public void engineInit(KeyManager[] kms, TrustManager[] tms,
+ SecureRandom sr) throws KeyManagementException {
+ throw new KeyManagementException("Do not init() the default SSLContext ");
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public final static class TLSv13 extends DefaultSSLContextImpl {
+ public TLSv13() throws GeneralSecurityException, IOException {
+ super(NativeCrypto.TLSV13_PROTOCOLS);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public final static class TLSv12 extends DefaultSSLContextImpl {
+ public TLSv12() throws GeneralSecurityException, IOException {
+ super(NativeCrypto.TLSV12_PROTOCOLS);
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/DuckTypedPSKKeyManager.java b/repackaged/common/src/main/java/com/android/org/conscrypt/DuckTypedPSKKeyManager.java
new file mode 100644
index 0000000..7c6eccf
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/DuckTypedPSKKeyManager.java
@@ -0,0 +1,138 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2014 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.lang.reflect.Method;
+import java.net.Socket;
+import javax.crypto.SecretKey;
+import javax.net.ssl.SSLEngine;
+
+/**
+ * Reflection-based {@link PSKKeyManager} adaptor for objects which expose all the methods of the
+ * {@code PSKKeyManager} interface but do not implement the interface.
+ *
+ * <p>This is expected to be useful on platforms where there are multiple instances of the
+ * {@code PSKKeyManager} interface.
+ *
+ * Visible for testing only.
+ *
+ * @deprecated This abstraction is deprecated because it does not work with TLS 1.3.
+ */
+@Deprecated
+final class DuckTypedPSKKeyManager implements PSKKeyManager {
+
+ private final Object mDelegate;
+
+ private DuckTypedPSKKeyManager(Object delegate) {
+ mDelegate = delegate;
+ }
+
+ /**
+ * Gets an instance of {@code DuckTypedPSKKeyManager} which delegates all invocations of methods
+ * of the {@link PSKKeyManager} interface to the same methods of the provided object.
+ *
+ * @throws NoSuchMethodException if {@code obj} does not implement a method of the
+ * {@code PSKKeyManager} interface.
+ */
+ static DuckTypedPSKKeyManager getInstance(Object obj) throws NoSuchMethodException {
+ Class<?> sourceClass = obj.getClass();
+ for (Method targetMethod : PSKKeyManager.class.getMethods()) {
+ if (targetMethod.isSynthetic()) {
+ continue;
+ }
+ // Check that obj exposes the target method (same name and parameter types)
+ Method sourceMethod =
+ sourceClass.getMethod(targetMethod.getName(), targetMethod.getParameterTypes());
+ // Check that the return type of obj's method matches the target method.
+ Class<?> sourceReturnType = sourceMethod.getReturnType();
+ Class<?> targetReturnType = targetMethod.getReturnType();
+ if (!targetReturnType.isAssignableFrom(sourceReturnType)) {
+ throw new NoSuchMethodException(sourceMethod + " return value (" + sourceReturnType
+ + ") incompatible with target return value (" + targetReturnType + ")");
+ }
+ }
+
+ return new DuckTypedPSKKeyManager(obj);
+ }
+
+ @Override
+ public String chooseServerKeyIdentityHint(Socket socket) {
+ try {
+ return (String) mDelegate.getClass()
+ .getMethod("chooseServerKeyIdentityHint", Socket.class)
+ .invoke(mDelegate, socket);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to invoke chooseServerKeyIdentityHint", e);
+ }
+ }
+
+ @Override
+ public String chooseServerKeyIdentityHint(SSLEngine engine) {
+ try {
+ return (String) mDelegate.getClass()
+ .getMethod("chooseServerKeyIdentityHint", SSLEngine.class)
+ .invoke(mDelegate, engine);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to invoke chooseServerKeyIdentityHint", e);
+ }
+ }
+
+ @Override
+ public String chooseClientKeyIdentity(String identityHint, Socket socket) {
+ try {
+ return (String) mDelegate.getClass()
+ .getMethod("chooseClientKeyIdentity", String.class, Socket.class)
+ .invoke(mDelegate, identityHint, socket);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to invoke chooseClientKeyIdentity", e);
+ }
+ }
+
+ @Override
+ public String chooseClientKeyIdentity(String identityHint, SSLEngine engine) {
+ try {
+ return (String) mDelegate.getClass()
+ .getMethod("chooseClientKeyIdentity", String.class, SSLEngine.class)
+ .invoke(mDelegate, identityHint, engine);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to invoke chooseClientKeyIdentity", e);
+ }
+ }
+
+ @Override
+ public SecretKey getKey(String identityHint, String identity, Socket socket) {
+ try {
+ return (SecretKey) mDelegate.getClass()
+ .getMethod("getKey", String.class, String.class, Socket.class)
+ .invoke(mDelegate, identityHint, identity, socket);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to invoke getKey", e);
+ }
+ }
+
+ @Override
+ public SecretKey getKey(String identityHint, String identity, SSLEngine engine) {
+ try {
+ return (SecretKey) mDelegate.getClass()
+ .getMethod("getKey", String.class, String.class, SSLEngine.class)
+ .invoke(mDelegate, identityHint, identity, engine);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to invoke getKey", e);
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ECParameters.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ECParameters.java
new file mode 100644
index 0000000..ad87258
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ECParameters.java
@@ -0,0 +1,115 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.IOException;
+import java.security.AlgorithmParametersSpi;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+/**
+ * AlgorithmParameters implementation for elliptic curves. The only supported encoding format is
+ * ASN.1, as specified in RFC 3279, section 2.3.5. However, only named curves are supported.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class ECParameters extends AlgorithmParametersSpi {
+
+ private OpenSSLECGroupContext curve;
+
+ public ECParameters() {}
+
+ @Override
+ protected void engineInit(AlgorithmParameterSpec algorithmParameterSpec)
+ throws InvalidParameterSpecException {
+ if (algorithmParameterSpec instanceof ECGenParameterSpec) {
+ String newCurveName = ((ECGenParameterSpec) algorithmParameterSpec).getName();
+ OpenSSLECGroupContext newCurve = OpenSSLECGroupContext.getCurveByName(newCurveName);
+ if (newCurve == null) {
+ throw new InvalidParameterSpecException("Unknown EC curve name: " + newCurveName);
+ }
+ this.curve = newCurve;
+ } else if (algorithmParameterSpec instanceof ECParameterSpec) {
+ ECParameterSpec ecParamSpec = (ECParameterSpec) algorithmParameterSpec;
+ try {
+ OpenSSLECGroupContext newCurve = OpenSSLECGroupContext.getInstance(ecParamSpec);
+ if (newCurve == null) {
+ throw new InvalidParameterSpecException("Unknown EC curve: " + ecParamSpec);
+ }
+ this.curve = newCurve;
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new InvalidParameterSpecException(e.getMessage());
+ }
+ } else {
+ throw new InvalidParameterSpecException(
+ "Only ECParameterSpec and ECGenParameterSpec are supported");
+ }
+ }
+
+ @Override
+ protected void engineInit(byte[] bytes) throws IOException {
+ long ref = NativeCrypto.EC_KEY_parse_curve_name(bytes);
+ if (ref == 0) {
+ throw new IOException("Error reading ASN.1 encoding");
+ }
+ this.curve = new OpenSSLECGroupContext(new NativeRef.EC_GROUP(ref));
+ }
+
+ @Override
+ protected void engineInit(byte[] bytes, String format) throws IOException {
+ if (format == null || format.equals("ASN.1")) {
+ engineInit(bytes);
+ } else {
+ throw new IOException("Unsupported format: " + format);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected <T extends AlgorithmParameterSpec> T engineGetParameterSpec(Class<T> aClass)
+ throws InvalidParameterSpecException {
+ if (aClass == ECParameterSpec.class) {
+ return (T) curve.getECParameterSpec();
+ } else if (aClass == ECGenParameterSpec.class) {
+ return (T) new ECGenParameterSpec(curve.getCurveName());
+ } else {
+ throw new InvalidParameterSpecException("Unsupported class: " + aClass);
+ }
+ }
+
+ @Override
+ protected byte[] engineGetEncoded() throws IOException {
+ return NativeCrypto.EC_KEY_marshal_curve_name(curve.getNativeRef());
+ }
+
+ @Override
+ protected byte[] engineGetEncoded(String format) throws IOException {
+ if (format == null || format.equals("ASN.1")) {
+ return engineGetEncoded();
+ }
+ throw new IOException("Unsupported format: " + format);
+ }
+
+ @Override
+ protected String engineToString() {
+ return "Conscrypt EC AlgorithmParameters";
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/EmptyArray.java b/repackaged/common/src/main/java/com/android/org/conscrypt/EmptyArray.java
new file mode 100644
index 0000000..a36d337
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/EmptyArray.java
@@ -0,0 +1,36 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+// Copied from libcore.util.EmptyArray
+
+package com.android.org.conscrypt;
+
+final class EmptyArray {
+ private EmptyArray() {}
+
+ static final boolean[] BOOLEAN = new boolean[0];
+ static final byte[] BYTE = new byte[0];
+ static final char[] CHAR = new char[0];
+ static final double[] DOUBLE = new double[0];
+ static final int[] INT = new int[0];
+
+ static final Class<?>[] CLASS = new Class<?>[ 0 ];
+ static final Object[] OBJECT = new Object[0];
+ static final String[] STRING = new String[0];
+ static final Throwable[] THROWABLE = new Throwable[0];
+ static final StackTraceElement[] STACK_TRACE_ELEMENT = new StackTraceElement[0];
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/EvpMdRef.java b/repackaged/common/src/main/java/com/android/org/conscrypt/EvpMdRef.java
new file mode 100644
index 0000000..fd62130
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/EvpMdRef.java
@@ -0,0 +1,159 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2016 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.NoSuchAlgorithmException;
+import java.util.Locale;
+
+/**
+ * Utility class to convert between BoringSSL- and JCE-style message digest identifiers.
+ */
+final class EvpMdRef {
+ static final String MGF1_ALGORITHM_NAME = "MGF1";
+ static final String MGF1_OID = "1.2.840.113549.1.1.8";
+
+ /**
+ * Returns the canonical JCA digest algorithm name for the provided digest
+ * algorithm name or {@code null} if the digest algorithm is not known.
+ */
+ static String getJcaDigestAlgorithmStandardName(String algorithm) {
+ String algorithmUpper = algorithm.toUpperCase(Locale.US);
+ if (SHA256.JCA_NAME.equals(algorithmUpper) || SHA256.OID.equals(algorithmUpper)) {
+ return SHA256.JCA_NAME;
+ } else if (SHA512.JCA_NAME.equals(algorithmUpper) || SHA512.OID.equals(algorithmUpper)) {
+ return SHA512.JCA_NAME;
+ } else if (SHA1.JCA_NAME.equals(algorithmUpper) || SHA1.OID.equals(algorithmUpper)) {
+ return SHA1.JCA_NAME;
+ } else if (SHA384.JCA_NAME.equals(algorithmUpper) || SHA384.OID.equals(algorithmUpper)) {
+ return SHA384.JCA_NAME;
+ } else if (SHA224.JCA_NAME.equals(algorithmUpper) || SHA224.OID.equals(algorithmUpper)) {
+ return SHA224.JCA_NAME;
+ } else {
+ return null;
+ }
+ }
+
+ static long getEVP_MDByJcaDigestAlgorithmStandardName(String algorithm)
+ throws NoSuchAlgorithmException {
+ String algorithmUpper = algorithm.toUpperCase(Locale.US);
+ if (SHA256.JCA_NAME.equals(algorithmUpper)) {
+ return EvpMdRef.SHA256.EVP_MD;
+ } else if (SHA512.JCA_NAME.equals(algorithmUpper)) {
+ return EvpMdRef.SHA512.EVP_MD;
+ } else if (SHA1.JCA_NAME.equals(algorithmUpper)) {
+ return EvpMdRef.SHA1.EVP_MD;
+ } else if (SHA384.JCA_NAME.equals(algorithmUpper)) {
+ return EvpMdRef.SHA384.EVP_MD;
+ } else if (SHA224.JCA_NAME.equals(algorithmUpper)) {
+ return EvpMdRef.SHA224.EVP_MD;
+ } else {
+ throw new NoSuchAlgorithmException("Unsupported algorithm: " + algorithm);
+ }
+ }
+
+ static int getDigestSizeBytesByJcaDigestAlgorithmStandardName(String algorithm)
+ throws NoSuchAlgorithmException {
+ String algorithmUpper = algorithm.toUpperCase(Locale.US);
+ if (SHA256.JCA_NAME.equals(algorithmUpper)) {
+ return EvpMdRef.SHA256.SIZE_BYTES;
+ } else if (SHA512.JCA_NAME.equals(algorithmUpper)) {
+ return EvpMdRef.SHA512.SIZE_BYTES;
+ } else if (SHA1.JCA_NAME.equals(algorithmUpper)) {
+ return EvpMdRef.SHA1.SIZE_BYTES;
+ } else if (SHA384.JCA_NAME.equals(algorithmUpper)) {
+ return EvpMdRef.SHA384.SIZE_BYTES;
+ } else if (SHA224.JCA_NAME.equals(algorithmUpper)) {
+ return EvpMdRef.SHA224.SIZE_BYTES;
+ } else {
+ throw new NoSuchAlgorithmException("Unsupported algorithm: " + algorithm);
+ }
+ }
+
+ static String getJcaDigestAlgorithmStandardNameFromEVP_MD(long evpMdRef) {
+ if (evpMdRef == MD5.EVP_MD) {
+ return MD5.JCA_NAME;
+ } else if (evpMdRef == SHA1.EVP_MD) {
+ return SHA1.JCA_NAME;
+ } else if (evpMdRef == SHA224.EVP_MD) {
+ return SHA224.JCA_NAME;
+ } else if (evpMdRef == SHA256.EVP_MD) {
+ return SHA256.JCA_NAME;
+ } else if (evpMdRef == SHA384.EVP_MD) {
+ return SHA384.JCA_NAME;
+ } else if (evpMdRef == SHA512.EVP_MD) {
+ return SHA512.JCA_NAME;
+ } else {
+ throw new IllegalArgumentException("Unknown EVP_MD reference");
+ }
+ }
+
+ static final class MD5 {
+ static final String JCA_NAME = "MD5";
+ static final String OID = "1.2.840.113549.2.5";
+ static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("md5");
+ static final int SIZE_BYTES = NativeCrypto.EVP_MD_size(EVP_MD);
+
+ private MD5() {}
+ }
+
+ static final class SHA1 {
+ static final String JCA_NAME = "SHA-1";
+ static final String OID = "1.3.14.3.2.26";
+ static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha1");
+ static final int SIZE_BYTES = NativeCrypto.EVP_MD_size(EVP_MD);
+ private SHA1() {}
+ }
+
+ static final class SHA224 {
+ static final String JCA_NAME = "SHA-224";
+ static final String OID = "2.16.840.1.101.3.4.2.4";
+ static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha224");
+ static final int SIZE_BYTES = NativeCrypto.EVP_MD_size(EVP_MD);
+
+ private SHA224() {}
+ }
+
+ static final class SHA256 {
+ static final String JCA_NAME = "SHA-256";
+ static final String OID = "2.16.840.1.101.3.4.2.1";
+ static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha256");
+ static final int SIZE_BYTES = NativeCrypto.EVP_MD_size(EVP_MD);
+
+ private SHA256() {}
+ }
+
+ static final class SHA384 {
+ static final String JCA_NAME = "SHA-384";
+ static final String OID = "2.16.840.1.101.3.4.2.2";
+ static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha384");
+ static final int SIZE_BYTES = NativeCrypto.EVP_MD_size(EVP_MD);
+
+ private SHA384() {}
+ }
+
+ static final class SHA512 {
+ static final String JCA_NAME = "SHA-512";
+ static final String OID = "2.16.840.1.101.3.4.2.3";
+ static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha512");
+ static final int SIZE_BYTES = NativeCrypto.EVP_MD_size(EVP_MD);
+
+ private SHA512() {}
+ }
+
+ private EvpMdRef() {}
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ExperimentalApi.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ExperimentalApi.java
new file mode 100644
index 0000000..b768463
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ExperimentalApi.java
@@ -0,0 +1,53 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.android.org.conscrypt;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates a public API that can change at any time, and has no guarantee of API stability and
+ * backward-compatibility.
+ *
+ * <p>Usage guidelines:
+ * <ol>
+ * <li>This annotation is used only on public API. Internal interfaces should not use it.</li>
+ * <li>This annotation should only be added to new APIs. Adding it to an existing API is
+ * considered API-breaking.</li>
+ * <li>Removing this annotation from an API gives it stable status.</li>
+ * </ol>
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+@Retention(RetentionPolicy.SOURCE)
+@Target({
+ ElementType.ANNOTATION_TYPE,
+ ElementType.CONSTRUCTOR,
+ ElementType.FIELD,
+ ElementType.METHOD,
+ ElementType.PACKAGE,
+ ElementType.TYPE})
+@Documented
+public @interface ExperimentalApi {
+ /**
+ * Context information such as links to discussion thread, tracking issue etc.
+ */
+ String value() default "";
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ExternalSession.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ExternalSession.java
new file mode 100644
index 0000000..8dffbb3
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ExternalSession.java
@@ -0,0 +1,220 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.util.HashMap;
+import java.util.List;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionBindingEvent;
+import javax.net.ssl.SSLSessionBindingListener;
+import javax.net.ssl.SSLSessionContext;
+
+/**
+ * An externalized view of the underlying {@link SSLSession} used within a
+ * socket/engine. This class provides the caller with a consistent session
+ * handle which will continue to be usable regardless of internal changes
+ * to the connection. It does this by delegating calls to the <b>current</b>
+ * internal session, which is provided by the session {@code Provider}
+ * (i.e. the socket or engine that owns the session). This allows the provider
+ * to switch implementations (for instance, using a JNI implementation to
+ * access live values while the connection is open and a set of final values
+ * when the connection is closed), even if the caller stores a reference to
+ * the session object.
+ *
+ * <p>This class implements the {@link SSLSession} value API itself, rather
+ * than delegating to the provided session, to ensure the caller has a consistent
+ * value map, regardless of which internal session is currently being used by the
+ * socket/engine. This class will never call the value API methods on the
+ * underlying sessions, so they need not be implemented.
+ */
+final class ExternalSession implements ConscryptSession {
+ // Use an initial capacity of 2 to keep it small in the average case.
+ private final HashMap<String, Object> values = new HashMap<>(2);
+ private final Provider provider;
+
+ public ExternalSession(Provider provider) {
+ this.provider = provider;
+ }
+
+ @Override
+ public String getRequestedServerName() {
+ return provider.provideSession().getRequestedServerName();
+ }
+
+ @Override
+ public List<byte[]> getStatusResponses() {
+ return provider.provideSession().getStatusResponses();
+ }
+
+ @Override
+ public byte[] getPeerSignedCertificateTimestamp() {
+ return provider.provideSession().getPeerSignedCertificateTimestamp();
+ }
+
+ @Override
+ public byte[] getId() {
+ return provider.provideSession().getId();
+ }
+
+ @Override
+ public SSLSessionContext getSessionContext() {
+ return provider.provideSession().getSessionContext();
+ }
+
+ @Override
+ public long getCreationTime() {
+ return provider.provideSession().getCreationTime();
+ }
+
+ @Override
+ public long getLastAccessedTime() {
+ return provider.provideSession().getLastAccessedTime();
+ }
+
+ @Override
+ public void invalidate() {
+ provider.provideSession().invalidate();
+ }
+
+ @Override
+ public boolean isValid() {
+ return provider.provideSession().isValid();
+ }
+
+ @Override
+ public java.security.cert.X509Certificate[] getPeerCertificates()
+ throws SSLPeerUnverifiedException {
+ return provider.provideSession().getPeerCertificates();
+ }
+
+ @Override
+ public Certificate[] getLocalCertificates() {
+ return provider.provideSession().getLocalCertificates();
+ }
+
+ @Override
+ @SuppressWarnings("deprecation") // Public API
+ public javax.security.cert.X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ return provider.provideSession().getPeerCertificateChain();
+ }
+
+ @Override
+ public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+ return provider.provideSession().getPeerPrincipal();
+ }
+
+ @Override
+ public Principal getLocalPrincipal() {
+ return provider.provideSession().getLocalPrincipal();
+ }
+
+ @Override
+ public String getCipherSuite() {
+ return provider.provideSession().getCipherSuite();
+ }
+
+ @Override
+ public String getProtocol() {
+ return provider.provideSession().getProtocol();
+ }
+
+ @Override
+ public String getPeerHost() {
+ return provider.provideSession().getPeerHost();
+ }
+
+ @Override
+ public int getPeerPort() {
+ return provider.provideSession().getPeerPort();
+ }
+
+ @Override
+ public int getPacketBufferSize() {
+ return provider.provideSession().getPacketBufferSize();
+ }
+
+ @Override
+ public int getApplicationBufferSize() {
+ return provider.provideSession().getApplicationBufferSize();
+ }
+
+ @Override
+ public String getApplicationProtocol() {
+ return provider.provideSession().getApplicationProtocol();
+ }
+
+ @Override
+ public Object getValue(String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("name == null");
+ }
+ return values.get(name);
+ }
+
+ @Override
+ public String[] getValueNames() {
+ return values.keySet().toArray(new String[0]);
+ }
+
+ @Override
+ public void putValue(String name, Object value) {
+ putValue(this, name, value);
+ }
+
+ void putValue(SSLSession session, String name, Object value) {
+ if (name == null || value == null) {
+ throw new IllegalArgumentException("name == null || value == null");
+ }
+ Object old = values.put(name, value);
+ if (value instanceof SSLSessionBindingListener) {
+ ((SSLSessionBindingListener) value)
+ .valueBound(new SSLSessionBindingEvent(session, name));
+ }
+ if (old instanceof SSLSessionBindingListener) {
+ ((SSLSessionBindingListener) old)
+ .valueUnbound(new SSLSessionBindingEvent(session, name));
+ }
+ }
+
+ @Override
+ public void removeValue(String name) {
+ removeValue(this, name);
+ }
+
+ void removeValue(SSLSession session, String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("name == null");
+ }
+ Object old = values.remove(name);
+ if (old instanceof SSLSessionBindingListener) {
+ SSLSessionBindingListener listener = (SSLSessionBindingListener) old;
+ listener.valueUnbound(new SSLSessionBindingEvent(session, name));
+ }
+ }
+
+ /**
+ * The provider of the current delegate session.
+ */
+ interface Provider {
+ ConscryptSession provideSession();
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/FileClientSessionCache.java b/repackaged/common/src/main/java/com/android/org/conscrypt/FileClientSessionCache.java
new file mode 100644
index 0000000..248eee1
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/FileClientSessionCache.java
@@ -0,0 +1,382 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt;
+
+import com.android.org.conscrypt.io.IoUtils;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.net.ssl.SSLSession;
+
+/**
+ * File-based cache implementation. Only one process should access the
+ * underlying directory at a time.
+ * @hide This class is not part of the Android public SDK API
+ */
+@libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+@Internal
+public final class FileClientSessionCache {
+ private static final Logger logger = Logger.getLogger(FileClientSessionCache.class.getName());
+
+ public static final int MAX_SIZE = 12; // ~72k
+
+ private FileClientSessionCache() {}
+
+ /**
+ * This cache creates one file per SSL session using "host.port" for
+ * the file name. Files are created or replaced when session data is put
+ * in the cache (see {@link #putSessionData}). Files are read on
+ * cache hits, but not on cache misses.
+ *
+ * <p>When the number of session files exceeds MAX_SIZE, we delete the
+ * least-recently-used file. We don't current persist the last access time,
+ * so the ordering actually ends up being least-recently-modified in some
+ * cases and even just "not accessed in this process" if the filesystem
+ * doesn't track last modified times.
+ */
+ static class Impl implements SSLClientSessionCache {
+ /** Directory to store session files in. */
+ final File directory;
+
+ /**
+ * Map of name -> File. Keeps track of the order files were accessed in.
+ */
+ Map<String, File> accessOrder = newAccessOrder();
+
+ /** The number of files on disk. */
+ int size;
+
+ /**
+ * The initial set of files. We use this to defer adding information
+ * about all files to accessOrder until necessary.
+ */
+ String[] initialFiles;
+
+ /**
+ * Constructs a new cache backed by the given directory.
+ */
+ Impl(File directory) throws IOException {
+ boolean exists = directory.exists();
+ if (exists && !directory.isDirectory()) {
+ throw new IOException(directory + " exists but is not a directory.");
+ }
+
+ if (exists) {
+ // Read and sort initial list of files. We defer adding
+ // information about these files to accessOrder until necessary
+ // (see indexFiles()). Sorting the list enables us to detect
+ // cache misses in getSessionData().
+ // Note: Sorting an array here was faster than creating a
+ // HashSet on Dalvik.
+ initialFiles = directory.list();
+ if (initialFiles == null) {
+ // File.list() will return null in error cases without throwing IOException
+ // http://b/3363561
+ throw new IOException(directory + " exists but cannot list contents.");
+ }
+ Arrays.sort(initialFiles);
+ size = initialFiles.length;
+ } else {
+ // Create directory.
+ if (!directory.mkdirs()) {
+ throw new IOException("Creation of " + directory + " directory failed.");
+ }
+ size = 0;
+ }
+
+ this.directory = directory;
+ }
+
+ /**
+ * Creates a new access-ordered linked hash map.
+ */
+ private static Map<String, File> newAccessOrder() {
+ return new LinkedHashMap<String, File>(MAX_SIZE, 0.75f, true /* access order */);
+ }
+
+ /**
+ * Gets the file name for the given host and port.
+ */
+ private static String fileName(String host, int port) {
+ if (host == null) {
+ throw new NullPointerException("host == null");
+ }
+ return host + "." + port;
+ }
+
+ @android.compat.annotation.UnsupportedAppUsage
+ @Override
+ public synchronized byte[] getSessionData(String host, int port) {
+ /*
+ * Note: This method is only called when the in-memory cache
+ * in SSLSessionContext misses, so it would be unnecessarily
+ * redundant for this cache to store data in memory.
+ */
+
+ String name = fileName(host, port);
+ File file = accessOrder.get(name);
+
+ if (file == null) {
+ // File wasn't in access order. Check initialFiles...
+ if (initialFiles == null) {
+ // All files are in accessOrder, so it doesn't exist.
+ return null;
+ }
+
+ // Look in initialFiles.
+ if (Arrays.binarySearch(initialFiles, name) < 0) {
+ // Not found.
+ return null;
+ }
+
+ // The file is on disk but not in accessOrder yet.
+ file = new File(directory, name);
+ accessOrder.put(name, file);
+ }
+
+ FileInputStream in;
+ try {
+ in = new FileInputStream(file);
+ } catch (FileNotFoundException e) {
+ logReadError(host, file, e);
+ return null;
+ }
+ try {
+ int size = (int) file.length();
+ byte[] data = new byte[size];
+ new DataInputStream(in).readFully(data);
+ return data;
+ } catch (IOException e) {
+ logReadError(host, file, e);
+ return null;
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
+ }
+
+ static void logReadError(String host, File file, Throwable t) {
+ logger.log(Level.WARNING,
+ "FileClientSessionCache: Error reading session data for " + host + " from "
+ + file + ".",
+ t);
+ }
+
+ @Override
+ public synchronized void putSessionData(SSLSession session, byte[] sessionData) {
+ String host = session.getPeerHost();
+ if (sessionData == null) {
+ throw new NullPointerException("sessionData == null");
+ }
+
+ String name = fileName(host, session.getPeerPort());
+ File file = new File(directory, name);
+
+ // Used to keep track of whether or not we're expanding the cache.
+ boolean existedBefore = file.exists();
+
+ FileOutputStream out;
+ try {
+ out = new FileOutputStream(file);
+ } catch (FileNotFoundException e) {
+ // We can't write to the file.
+ logWriteError(host, file, e);
+ return;
+ }
+
+ // If we expanded the cache (by creating a new file)...
+ if (!existedBefore) {
+ size++;
+
+ // Delete an old file if necessary.
+ makeRoom();
+ }
+
+ boolean writeSuccessful = false;
+ try {
+ out.write(sessionData);
+ writeSuccessful = true;
+ } catch (IOException e) {
+ logWriteError(host, file, e);
+ } finally {
+ boolean closeSuccessful = false;
+ try {
+ out.close();
+ closeSuccessful = true;
+ } catch (IOException e) {
+ logWriteError(host, file, e);
+ } finally {
+ if (!writeSuccessful || !closeSuccessful) {
+ // Storage failed. Clean up.
+ delete(file);
+ } else {
+ // Success!
+ accessOrder.put(name, file);
+ }
+ }
+ }
+ }
+
+ /**
+ * Deletes old files if necessary.
+ */
+ private void makeRoom() {
+ if (size <= MAX_SIZE) {
+ return;
+ }
+
+ indexFiles();
+
+ // Delete LRUed files.
+ int removals = size - MAX_SIZE;
+ Iterator<File> i = accessOrder.values().iterator();
+ do {
+ delete(i.next());
+ i.remove();
+ } while (--removals > 0);
+ }
+
+ /**
+ * Lazily updates accessOrder to know about all files as opposed to
+ * just the files accessed since this process started.
+ */
+ private void indexFiles() {
+ String[] initialFiles = this.initialFiles;
+ if (initialFiles != null) {
+ this.initialFiles = null;
+
+ // Files on disk only, sorted by last modified time.
+ // TODO: Use last access time.
+ Set<CacheFile> diskOnly = new TreeSet<CacheFile>();
+ for (String name : initialFiles) {
+ // If the file hasn't been accessed in this process...
+ if (!accessOrder.containsKey(name)) {
+ diskOnly.add(new CacheFile(directory, name));
+ }
+ }
+
+ if (!diskOnly.isEmpty()) {
+ // Add files not accessed in this process to the beginning
+ // of accessOrder.
+ Map<String, File> newOrder = newAccessOrder();
+ for (CacheFile cacheFile : diskOnly) {
+ newOrder.put(cacheFile.name, cacheFile);
+ }
+ newOrder.putAll(accessOrder);
+
+ this.accessOrder = newOrder;
+ }
+ }
+ }
+
+ @SuppressWarnings("ThrowableInstanceNeverThrown")
+ private void delete(File file) {
+ if (!file.delete()) {
+ Exception e =
+ new IOException("FileClientSessionCache: Failed to delete " + file + ".");
+ logger.log(Level.WARNING, e.getMessage(), e);
+ }
+ size--;
+ }
+
+ static void logWriteError(String host, File file, Throwable t) {
+ logger.log(Level.WARNING,
+ "FileClientSessionCache: Error writing session data for " + host + " to " + file
+ + ".",
+ t);
+ }
+ }
+
+ /**
+ * Maps directories to the cache instances that are backed by those
+ * directories. We synchronize access using the cache instance, so it's
+ * important that everyone shares the same instance.
+ */
+ static final Map<File, FileClientSessionCache.Impl> caches =
+ new HashMap<File, FileClientSessionCache.Impl>();
+
+ /**
+ * Returns a cache backed by the given directory. Creates the directory
+ * (including parent directories) if necessary. This cache should have
+ * exclusive access to the given directory.
+ *
+ * @param directory to store files in
+ * @return a cache backed by the given directory
+ * @throws IOException if the file exists and is not a directory or if
+ * creating the directories fails
+ */
+ @android.compat.annotation.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public static synchronized SSLClientSessionCache usingDirectory(File directory)
+ throws IOException {
+ FileClientSessionCache.Impl cache = caches.get(directory);
+ if (cache == null) {
+ cache = new FileClientSessionCache.Impl(directory);
+ caches.put(directory, cache);
+ }
+ return cache;
+ }
+
+ /** For testing. */
+ static synchronized void reset() {
+ caches.clear();
+ }
+
+ /** A file containing a piece of cached data. */
+ @SuppressWarnings("serial")
+ static class CacheFile extends File {
+ final String name;
+
+ CacheFile(File dir, String name) {
+ super(dir, name);
+ this.name = name;
+ }
+
+ long lastModified = -1;
+
+ @Override
+ public long lastModified() {
+ long lastModified = this.lastModified;
+ if (lastModified == -1) {
+ lastModified = this.lastModified = super.lastModified();
+ }
+ return lastModified;
+ }
+
+ @Override
+ public int compareTo(File another) {
+ // Sort by last modified time.
+ long result = lastModified() - another.lastModified();
+ if (result == 0) {
+ return super.compareTo(another);
+ }
+ return result < 0 ? -1 : 1;
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/GCMParameters.java b/repackaged/common/src/main/java/com/android/org/conscrypt/GCMParameters.java
new file mode 100644
index 0000000..db36acc
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/GCMParameters.java
@@ -0,0 +1,154 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2015 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.IOException;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+/**
+ * GCM parameters used during an ciphering operation with {@link OpenSSLCipher}.
+ * This class is used internally for backward compatibility with Android versions
+ * that did not have the {@code GCMParameterSpec} class, in addition to being the
+ * implementation of the GCM AlgorithmParameters implementation.
+ * <p>
+ * The only supported encoding format is ASN.1, as specified in RFC 5084 section 3.2.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class GCMParameters extends AlgorithmParametersSpi {
+
+ // The default value (in bits) for TLEN in the GCM ASN.1 module
+ private static final int DEFAULT_TLEN = 96;
+
+ /** The tag length in bits. */
+ private int tLen;
+
+ /** Actually the nonce value for the GCM operation. */
+ private byte[] iv;
+
+ public GCMParameters() { }
+
+ GCMParameters(int tLen, byte[] iv) {
+ this.tLen = tLen;
+ this.iv = iv;
+ }
+
+ /**
+ * Returns the tag length in bits.
+ */
+ int getTLen() {
+ return tLen;
+ }
+
+ /**
+ * Returns a non-cloned version of the IV.
+ */
+ byte[] getIV() {
+ return iv;
+ }
+
+ @Override
+ protected void engineInit(AlgorithmParameterSpec algorithmParameterSpec)
+ throws InvalidParameterSpecException {
+ GCMParameters params = Platform.fromGCMParameterSpec(algorithmParameterSpec);
+ if (params == null) {
+ throw new InvalidParameterSpecException("Only GCMParameterSpec is supported");
+ }
+ this.tLen = params.tLen;
+ this.iv = params.iv;
+ }
+
+ @Override
+ protected void engineInit(byte[] bytes) throws IOException {
+ long readRef = 0;
+ long seqRef = 0;
+ try {
+ readRef = NativeCrypto.asn1_read_init(bytes);
+ seqRef = NativeCrypto.asn1_read_sequence(readRef);
+ byte[] newIv = NativeCrypto.asn1_read_octetstring(seqRef);
+ int newTlen = DEFAULT_TLEN;
+ if (!NativeCrypto.asn1_read_is_empty(seqRef)) {
+ newTlen = 8 * (int) NativeCrypto.asn1_read_uint64(seqRef);
+ }
+ if (!NativeCrypto.asn1_read_is_empty(seqRef)
+ || !NativeCrypto.asn1_read_is_empty(readRef)) {
+ throw new IOException("Error reading ASN.1 encoding");
+ }
+ this.iv = newIv;
+ this.tLen = newTlen;
+ } finally {
+ NativeCrypto.asn1_read_free(seqRef);
+ NativeCrypto.asn1_read_free(readRef);
+ }
+ }
+
+ @Override
+ protected void engineInit(byte[] bytes, String format) throws IOException {
+ if ((format == null) || format.equals("ASN.1")) {
+ engineInit(bytes);
+ } else {
+ throw new IOException("Unsupported format: " + format);
+ }
+ }
+
+ @Override
+ protected <T extends AlgorithmParameterSpec> T engineGetParameterSpec(Class<T> aClass)
+ throws InvalidParameterSpecException {
+ if ((aClass != null) && aClass.getName().equals("javax.crypto.spec.GCMParameterSpec")) {
+ return aClass.cast(Platform.toGCMParameterSpec(tLen, iv));
+ } else {
+ throw new InvalidParameterSpecException("Unsupported class: " + aClass);
+ }
+ }
+
+ @Override
+ protected byte[] engineGetEncoded() throws IOException {
+ long cbbRef = 0;
+ long seqRef = 0;
+ try {
+ cbbRef = NativeCrypto.asn1_write_init();
+ seqRef = NativeCrypto.asn1_write_sequence(cbbRef);
+ NativeCrypto.asn1_write_octetstring(seqRef, this.iv);
+ if (this.tLen != DEFAULT_TLEN) {
+ NativeCrypto.asn1_write_uint64(seqRef, this.tLen / 8);
+ }
+ return NativeCrypto.asn1_write_finish(cbbRef);
+ } catch (IOException e) {
+ NativeCrypto.asn1_write_cleanup(cbbRef);
+ throw e;
+ } finally {
+ NativeCrypto.asn1_write_free(seqRef);
+ NativeCrypto.asn1_write_free(cbbRef);
+ }
+ }
+
+ @Override
+ protected byte[] engineGetEncoded(String format) throws IOException {
+ if ((format == null) || format.equals("ASN.1")) {
+ return engineGetEncoded();
+ }
+ throw new IOException("Unsupported format: " + format);
+ }
+
+ @Override
+ protected String engineToString() {
+ return "Conscrypt GCM AlgorithmParameters";
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/HandshakeListener.java b/repackaged/common/src/main/java/com/android/org/conscrypt/HandshakeListener.java
new file mode 100644
index 0000000..72d7767
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/HandshakeListener.java
@@ -0,0 +1,33 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import javax.net.ssl.SSLException;
+
+/**
+ * Similar in concept to {@link javax.net.ssl.HandshakeCompletedListener}, but used for listening directly
+ * to the engine. Allows the caller to be notified immediately upon completion of the TLS handshake.
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class HandshakeListener {
+
+ /**
+ * Called by the engine when the TLS handshake has completed.
+ */
+ public abstract void onHandshakeFinished() throws SSLException;
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/Internal.java b/repackaged/common/src/main/java/com/android/org/conscrypt/Internal.java
new file mode 100644
index 0000000..cd87a86
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/Internal.java
@@ -0,0 +1,37 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates a program element (class, method, package etc) which is internal to Conscrypt, not part
+ * of
+ * the public API, and should not be used by users of Conscrypt.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD,
+ ElementType.METHOD, ElementType.PACKAGE, ElementType.TYPE})
+@Documented
+public @interface Internal {}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/IvParameters.java b/repackaged/common/src/main/java/com/android/org/conscrypt/IvParameters.java
new file mode 100644
index 0000000..0e8931d
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/IvParameters.java
@@ -0,0 +1,132 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.IOException;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import javax.crypto.spec.IvParameterSpec;
+
+/**
+ * An implementation of {@link java.security.AlgorithmParameters} that contains only an IV. The
+ * supported encoding formats are ASN.1 (primary) and RAW.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class IvParameters extends AlgorithmParametersSpi {
+ private byte[] iv;
+
+ public IvParameters() {}
+
+ @Override
+ protected void engineInit(AlgorithmParameterSpec algorithmParameterSpec)
+ throws InvalidParameterSpecException {
+ if (!(algorithmParameterSpec instanceof IvParameterSpec)) {
+ throw new InvalidParameterSpecException("Only IvParameterSpec is supported");
+ }
+ iv = ((IvParameterSpec) algorithmParameterSpec).getIV().clone();
+ }
+
+ @Override
+ protected void engineInit(byte[] bytes) throws IOException {
+ long readRef = 0;
+ try {
+ readRef = NativeCrypto.asn1_read_init(bytes);
+ byte[] newIv = NativeCrypto.asn1_read_octetstring(readRef);
+ if (!NativeCrypto.asn1_read_is_empty(readRef)) {
+ throw new IOException("Error reading ASN.1 encoding");
+ }
+ this.iv = newIv;
+ } finally {
+ NativeCrypto.asn1_read_free(readRef);
+ }
+ }
+
+ @Override
+ protected void engineInit(byte[] bytes, String format) throws IOException {
+ if (format == null || format.equals("ASN.1")) {
+ engineInit(bytes);
+ } else if (format.equals("RAW")) {
+ iv = bytes.clone();
+ } else {
+ throw new IOException("Unsupported format: " + format);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected <T extends AlgorithmParameterSpec> T engineGetParameterSpec(Class<T> aClass)
+ throws InvalidParameterSpecException {
+ if (aClass != IvParameterSpec.class) {
+ throw new InvalidParameterSpecException(
+ "Incompatible AlgorithmParametersSpec class: " + aClass);
+ }
+ return (T) new IvParameterSpec(iv);
+ }
+
+ @Override
+ protected byte[] engineGetEncoded() throws IOException {
+ long cbbRef = 0;
+ try {
+ cbbRef = NativeCrypto.asn1_write_init();
+ NativeCrypto.asn1_write_octetstring(cbbRef, this.iv);
+ return NativeCrypto.asn1_write_finish(cbbRef);
+ } catch (IOException e) {
+ NativeCrypto.asn1_write_cleanup(cbbRef);
+ throw e;
+ } finally {
+ NativeCrypto.asn1_write_free(cbbRef);
+ }
+ }
+
+ @Override
+ protected byte[] engineGetEncoded(String format) throws IOException {
+ if (format == null || format.equals("ASN.1")) {
+ return engineGetEncoded();
+ } else if (format.equals("RAW")) {
+ return iv.clone();
+ } else {
+ throw new IOException("Unsupported format: " + format);
+ }
+ }
+
+ @Override
+ protected String engineToString() {
+ return "Conscrypt IV AlgorithmParameters";
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class AES extends IvParameters {
+ public AES() {}
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class DESEDE extends IvParameters {
+ public DESEDE() {}
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class ChaCha20 extends IvParameters {
+ public ChaCha20() {}
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/Java7ExtendedSSLSession.java b/repackaged/common/src/main/java/com/android/org/conscrypt/Java7ExtendedSSLSession.java
new file mode 100644
index 0000000..1a49e37
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/Java7ExtendedSSLSession.java
@@ -0,0 +1,187 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+package com.android.org.conscrypt;
+
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.util.List;
+import javax.net.ssl.ExtendedSSLSession;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSessionContext;
+
+/**
+ * This is an adapter that wraps the active session with {@link ExtendedSSLSession}, if running
+ * on Java 7+.
+ */
+class Java7ExtendedSSLSession extends ExtendedSSLSession implements ConscryptSession {
+ // TODO: use BoringSSL API to actually fetch the real data
+ private static final String[] LOCAL_SUPPORTED_SIGNATURE_ALGORITHMS = new String[] {
+ "SHA512withRSA", "SHA512withECDSA", "SHA384withRSA", "SHA384withECDSA", "SHA256withRSA",
+ "SHA256withECDSA", "SHA224withRSA", "SHA224withECDSA", "SHA1withRSA", "SHA1withECDSA",
+ };
+ // TODO: use BoringSSL API to actually fetch the real data
+ private static final String[] PEER_SUPPORTED_SIGNATURE_ALGORITHMS =
+ new String[] {"SHA1withRSA", "SHA1withECDSA"};
+ protected final ExternalSession delegate;
+
+ Java7ExtendedSSLSession(ExternalSession delegate) {
+ this.delegate = delegate;
+ }
+
+ /* @Override */
+ @SuppressWarnings("MissingOverride") // For Android backward-compatibility.
+ public final String[] getLocalSupportedSignatureAlgorithms() {
+ return LOCAL_SUPPORTED_SIGNATURE_ALGORITHMS.clone();
+ }
+
+ /* @Override */
+ @SuppressWarnings("MissingOverride") // For Android backward-compatibility.
+ public final String[] getPeerSupportedSignatureAlgorithms() {
+ return PEER_SUPPORTED_SIGNATURE_ALGORITHMS.clone();
+ }
+
+ @Override
+ public final String getRequestedServerName() {
+ return delegate.getRequestedServerName();
+ }
+
+ /**
+ * Provides forward-compatibility with Java 9.
+ */
+ @Override
+ public final List<byte[]> getStatusResponses() {
+ return delegate.getStatusResponses();
+ }
+
+ @Override
+ public final byte[] getPeerSignedCertificateTimestamp() {
+ return delegate.getPeerSignedCertificateTimestamp();
+ }
+
+ @Override
+ public final byte[] getId() {
+ return delegate.getId();
+ }
+
+ @Override
+ public final SSLSessionContext getSessionContext() {
+ return delegate.getSessionContext();
+ }
+
+ @Override
+ public final long getCreationTime() {
+ return delegate.getCreationTime();
+ }
+
+ @Override
+ public final long getLastAccessedTime() {
+ return delegate.getLastAccessedTime();
+ }
+
+ @Override
+ public final void invalidate() {
+ delegate.invalidate();
+ }
+
+ @Override
+ public final boolean isValid() {
+ return delegate.isValid();
+ }
+
+ @Override
+ public final void putValue(String s, Object o) {
+ delegate.putValue(this, s, o);
+ }
+
+ @Override
+ public final Object getValue(String s) {
+ return delegate.getValue(s);
+ }
+
+ @Override
+ public final void removeValue(String s) {
+ delegate.removeValue(this, s);
+ }
+
+ @Override
+ public final String[] getValueNames() {
+ return delegate.getValueNames();
+ }
+
+ @Override
+ public java.security.cert.X509Certificate[] getPeerCertificates()
+ throws SSLPeerUnverifiedException {
+ return delegate.getPeerCertificates();
+ }
+
+ @Override
+ public final Certificate[] getLocalCertificates() {
+ return delegate.getLocalCertificates();
+ }
+
+ @Override
+ @SuppressWarnings("deprecation") // Public API
+ public final javax.security.cert.X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ return delegate.getPeerCertificateChain();
+ }
+
+ @Override
+ public final Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+ return delegate.getPeerPrincipal();
+ }
+
+ @Override
+ public final Principal getLocalPrincipal() {
+ return delegate.getLocalPrincipal();
+ }
+
+ @Override
+ public final String getCipherSuite() {
+ return delegate.getCipherSuite();
+ }
+
+ @Override
+ public final String getProtocol() {
+ return delegate.getProtocol();
+ }
+
+ @Override
+ public final String getPeerHost() {
+ return delegate.getPeerHost();
+ }
+
+ @Override
+ public final int getPeerPort() {
+ return delegate.getPeerPort();
+ }
+
+ @Override
+ public final int getPacketBufferSize() {
+ return delegate.getPacketBufferSize();
+ }
+
+ @Override
+ public final int getApplicationBufferSize() {
+ return delegate.getApplicationBufferSize();
+ }
+
+ @Override
+ public String getApplicationProtocol() {
+ return delegate.getApplicationProtocol();
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/Java8EngineSocket.java b/repackaged/common/src/main/java/com/android/org/conscrypt/Java8EngineSocket.java
new file mode 100644
index 0000000..b1c852b
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/Java8EngineSocket.java
@@ -0,0 +1,93 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.util.List;
+import java.util.function.BiFunction;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLSocket;
+
+/**
+ * A version of ConscryptEngineSocket that includes the new Java 9 (and potentially later
+ * patches of 8) {@code setHandshakeApplicationProtocolSelector} API (which requires Java 8 for
+ * compilation, due to the use of {@link BiFunction}).
+ */
+final class Java8EngineSocket extends ConscryptEngineSocket {
+ private BiFunction<SSLSocket, List<String>, String> selector;
+
+ Java8EngineSocket(SSLParametersImpl sslParameters) throws IOException {
+ super(sslParameters);
+ }
+
+ Java8EngineSocket(String hostname, int port, SSLParametersImpl sslParameters)
+ throws IOException {
+ super(hostname, port, sslParameters);
+ }
+
+ Java8EngineSocket(InetAddress address, int port, SSLParametersImpl sslParameters)
+ throws IOException {
+ super(address, port, sslParameters);
+ }
+
+ Java8EngineSocket(String hostname, int port, InetAddress clientAddress, int clientPort,
+ SSLParametersImpl sslParameters) throws IOException {
+ super(hostname, port, clientAddress, clientPort, sslParameters);
+ }
+
+ Java8EngineSocket(InetAddress address, int port, InetAddress clientAddress, int clientPort,
+ SSLParametersImpl sslParameters) throws IOException {
+ super(address, port, clientAddress, clientPort, sslParameters);
+ }
+
+ Java8EngineSocket(Socket socket, String hostname, int port, boolean autoClose,
+ SSLParametersImpl sslParameters) throws IOException {
+ super(socket, hostname, port, autoClose, sslParameters);
+ }
+
+ /* @Override */
+ @SuppressWarnings("MissingOverride") // For compilation with Java < 9.
+ public void setHandshakeApplicationProtocolSelector(
+ final BiFunction<SSLSocket, List<String>, String> selector) {
+ this.selector = selector;
+ setApplicationProtocolSelector(toApplicationProtocolSelector(selector));
+ }
+
+ /* @Override */
+ @SuppressWarnings("MissingOverride") // For compilation with Java < 9.
+ public BiFunction<SSLSocket, List<String>, String> getHandshakeApplicationProtocolSelector() {
+ return selector;
+ }
+
+ private static ApplicationProtocolSelector toApplicationProtocolSelector(
+ final BiFunction<SSLSocket, List<String>, String> selector) {
+ return selector == null ? null : new ApplicationProtocolSelector() {
+ @Override
+ public String selectApplicationProtocol(SSLEngine socket, List<String> protocols) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String selectApplicationProtocol(SSLSocket socket, List<String> protocols) {
+ return selector.apply(socket, protocols);
+ }
+ };
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/Java8EngineWrapper.java b/repackaged/common/src/main/java/com/android/org/conscrypt/Java8EngineWrapper.java
new file mode 100644
index 0000000..6462219
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/Java8EngineWrapper.java
@@ -0,0 +1,342 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.Preconditions.checkNotNull;
+
+import java.nio.ByteBuffer;
+import java.security.PrivateKey;
+import java.util.List;
+import java.util.function.BiFunction;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+
+/**
+ * A wrapper around {@link ConscryptEngine} that adapts to the new Java 9 (and potentially later
+ * patches of 8) {@code setHandshakeApplicationProtocolSelector} API (which requires Java 8 for
+ * compilation, due to the use of {@link BiFunction}).
+ */
+final class Java8EngineWrapper extends AbstractConscryptEngine {
+ private final ConscryptEngine delegate;
+ private BiFunction<SSLEngine, List<String>, String> selector;
+
+ Java8EngineWrapper(ConscryptEngine delegate) {
+ this.delegate = checkNotNull(delegate, "delegate");
+ }
+
+ static SSLEngine getDelegate(SSLEngine engine) {
+ if (engine instanceof Java8EngineWrapper) {
+ return ((Java8EngineWrapper) engine).delegate;
+ }
+ return engine;
+ }
+
+ @Override
+ public SSLEngineResult wrap(ByteBuffer[] byteBuffers, ByteBuffer byteBuffer)
+ throws SSLException {
+ return delegate.wrap(byteBuffers, byteBuffer);
+ }
+
+ @Override
+ public SSLParameters getSSLParameters() {
+ return delegate.getSSLParameters();
+ }
+
+ @Override
+ public void setSSLParameters(SSLParameters sslParameters) {
+ delegate.setSSLParameters(sslParameters);
+ }
+
+ @Override
+ void setBufferAllocator(BufferAllocator bufferAllocator) {
+ delegate.setBufferAllocator(bufferAllocator);
+ }
+
+ @Override
+ int maxSealOverhead() {
+ return delegate.maxSealOverhead();
+ }
+
+ @Override
+ void setChannelIdEnabled(boolean enabled) {
+ delegate.setChannelIdEnabled(enabled);
+ }
+
+ @Override
+ byte[] getChannelId() throws SSLException {
+ return delegate.getChannelId();
+ }
+
+ @Override
+ void setChannelIdPrivateKey(PrivateKey privateKey) {
+ delegate.setChannelIdPrivateKey(privateKey);
+ }
+
+ @Override
+ void setHandshakeListener(HandshakeListener handshakeListener) {
+ delegate.setHandshakeListener(handshakeListener);
+ }
+
+ @Override
+ void setHostname(String hostname) {
+ delegate.setHostname(hostname);
+ }
+
+ @Override
+ String getHostname() {
+ return delegate.getHostname();
+ }
+
+ @Override
+ public String getPeerHost() {
+ return delegate.getPeerHost();
+ }
+
+ @Override
+ public int getPeerPort() {
+ return delegate.getPeerPort();
+ }
+
+ @Override
+ public void beginHandshake() throws SSLException {
+ delegate.beginHandshake();
+ }
+
+ @Override
+ public void closeInbound() throws SSLException {
+ delegate.closeInbound();
+ }
+
+ @Override
+ public void closeOutbound() {
+ delegate.closeOutbound();
+ }
+
+ @Override
+ public Runnable getDelegatedTask() {
+ return delegate.getDelegatedTask();
+ }
+
+ @Override
+ public String[] getEnabledCipherSuites() {
+ return delegate.getEnabledCipherSuites();
+ }
+
+ @Override
+ public String[] getEnabledProtocols() {
+ return delegate.getEnabledProtocols();
+ }
+
+ @Override
+ public boolean getEnableSessionCreation() {
+ return delegate.getEnableSessionCreation();
+ }
+
+ @Override
+ public HandshakeStatus getHandshakeStatus() {
+ return delegate.getHandshakeStatus();
+ }
+
+ @Override
+ public boolean getNeedClientAuth() {
+ return delegate.getNeedClientAuth();
+ }
+
+ @Override
+ SSLSession handshakeSession() {
+ return delegate.handshakeSession();
+ }
+
+ @Override
+ public SSLSession getSession() {
+ return delegate.getSession();
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return delegate.getSupportedCipherSuites();
+ }
+
+ @Override
+ public String[] getSupportedProtocols() {
+ return delegate.getSupportedProtocols();
+ }
+
+ @Override
+ public boolean getUseClientMode() {
+ return delegate.getUseClientMode();
+ }
+
+ @Override
+ public boolean getWantClientAuth() {
+ return delegate.getWantClientAuth();
+ }
+
+ @Override
+ public boolean isInboundDone() {
+ return delegate.isInboundDone();
+ }
+
+ @Override
+ public boolean isOutboundDone() {
+ return delegate.isOutboundDone();
+ }
+
+ @Override
+ public void setEnabledCipherSuites(String[] suites) {
+ delegate.setEnabledCipherSuites(suites);
+ }
+
+ @Override
+ public void setEnabledProtocols(String[] protocols) {
+ delegate.setEnabledProtocols(protocols);
+ }
+
+ @Override
+ public void setEnableSessionCreation(boolean flag) {
+ delegate.setEnableSessionCreation(flag);
+ }
+
+ @Override
+ public void setNeedClientAuth(boolean need) {
+ delegate.setNeedClientAuth(need);
+ }
+
+ @Override
+ public void setUseClientMode(boolean mode) {
+ delegate.setUseClientMode(mode);
+ }
+
+ @Override
+ public void setWantClientAuth(boolean want) {
+ delegate.setWantClientAuth(want);
+ }
+
+ @Override
+ public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
+ return delegate.unwrap(src, dst);
+ }
+
+ @Override
+ public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts) throws SSLException {
+ return delegate.unwrap(src, dsts);
+ }
+
+ @Override
+ public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts, int offset, int length)
+ throws SSLException {
+ return delegate.unwrap(src, dsts, offset, length);
+ }
+
+ @Override
+ SSLEngineResult unwrap(ByteBuffer[] srcs, ByteBuffer[] dsts) throws SSLException {
+ return delegate.unwrap(srcs, dsts);
+ }
+
+ @Override
+ SSLEngineResult unwrap(ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer[] dsts,
+ int dstsOffset, int dstsLength) throws SSLException {
+ return delegate.unwrap(srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
+ }
+
+ @Override
+ public SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
+ return delegate.wrap(src, dst);
+ }
+
+ @Override
+ public SSLEngineResult wrap(ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer dst)
+ throws SSLException {
+ return delegate.wrap(srcs, srcsOffset, srcsLength, dst);
+ }
+
+ @Override
+ void setUseSessionTickets(boolean useSessionTickets) {
+ delegate.setUseSessionTickets(useSessionTickets);
+ }
+
+ @Override
+ void setApplicationProtocols(String[] protocols) {
+ delegate.setApplicationProtocols(protocols);
+ }
+
+ @Override
+ String[] getApplicationProtocols() {
+ return delegate.getApplicationProtocols();
+ }
+
+ @Override
+ public String getApplicationProtocol() {
+ return delegate.getApplicationProtocol();
+ }
+
+ @Override
+ void setApplicationProtocolSelector(ApplicationProtocolSelector selector) {
+ delegate.setApplicationProtocolSelector(
+ selector == null ? null : new ApplicationProtocolSelectorAdapter(this, selector));
+ }
+
+ @Override
+ byte[] getTlsUnique() {
+ return delegate.getTlsUnique();
+ }
+
+ @Override
+ byte[] exportKeyingMaterial(String label, byte[] context, int length) throws SSLException {
+ return delegate.exportKeyingMaterial(label, context, length);
+ }
+
+ @Override
+ public String getHandshakeApplicationProtocol() {
+ return delegate.getHandshakeApplicationProtocol();
+ }
+
+ /* @Override */
+ @SuppressWarnings("MissingOverride") // For compilation with Java < 9.
+ public void setHandshakeApplicationProtocolSelector(
+ final BiFunction<SSLEngine, List<String>, String> selector) {
+ this.selector = selector;
+ setApplicationProtocolSelector(toApplicationProtocolSelector(selector));
+ }
+
+ /* @Override */
+ @SuppressWarnings("MissingOverride") // For compilation with Java < 9.
+ public BiFunction<SSLEngine, List<String>, String> getHandshakeApplicationProtocolSelector() {
+ return selector;
+ }
+
+ private static ApplicationProtocolSelector toApplicationProtocolSelector(
+ final BiFunction<SSLEngine, List<String>, String> selector) {
+ return selector == null ? null : new ApplicationProtocolSelector() {
+ @Override
+ public String selectApplicationProtocol(SSLEngine engine, List<String> protocols) {
+ return selector.apply(engine, protocols);
+ }
+
+ @Override
+ public String selectApplicationProtocol(SSLSocket socket, List<String> protocols) {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/Java8ExtendedSSLSession.java b/repackaged/common/src/main/java/com/android/org/conscrypt/Java8ExtendedSSLSession.java
new file mode 100644
index 0000000..f57a35f
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/Java8ExtendedSSLSession.java
@@ -0,0 +1,44 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.util.Collections;
+import java.util.List;
+import javax.net.ssl.ExtendedSSLSession;
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIServerName;
+
+/**
+ * This is an adapter that wraps the active session with {@link ExtendedSSLSession}, if running
+ * on Java 8+.
+ */
+class Java8ExtendedSSLSession extends Java7ExtendedSSLSession {
+ public Java8ExtendedSSLSession(ExternalSession delegate) {
+ super(delegate);
+ }
+
+ @Override
+ public final List<SNIServerName> getRequestedServerNames() {
+ String requestedServerName = delegate.getRequestedServerName();
+ if (requestedServerName == null) {
+ return Collections.emptyList();
+ }
+
+ return Collections.singletonList((SNIServerName) new SNIHostName(requestedServerName));
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/Java8FileDescriptorSocket.java b/repackaged/common/src/main/java/com/android/org/conscrypt/Java8FileDescriptorSocket.java
new file mode 100644
index 0000000..2d9f3bc
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/Java8FileDescriptorSocket.java
@@ -0,0 +1,93 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.util.List;
+import java.util.function.BiFunction;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLSocket;
+
+/**
+ * A version of ConscryptFileDescriptorSocket that includes the new Java 9 (and potentially later
+ * patches of 8) {@code setHandshakeApplicationProtocolSelector} API (which requires Java 8 for
+ * compilation, due to the use of {@link BiFunction}).
+ */
+final class Java8FileDescriptorSocket extends ConscryptFileDescriptorSocket {
+ private BiFunction<SSLSocket, List<String>, String> selector;
+
+ Java8FileDescriptorSocket(SSLParametersImpl sslParameters) throws IOException {
+ super(sslParameters);
+ }
+
+ Java8FileDescriptorSocket(String hostname, int port, SSLParametersImpl sslParameters)
+ throws IOException {
+ super(hostname, port, sslParameters);
+ }
+
+ Java8FileDescriptorSocket(InetAddress address, int port, SSLParametersImpl sslParameters)
+ throws IOException {
+ super(address, port, sslParameters);
+ }
+
+ Java8FileDescriptorSocket(String hostname, int port, InetAddress clientAddress, int clientPort,
+ SSLParametersImpl sslParameters) throws IOException {
+ super(hostname, port, clientAddress, clientPort, sslParameters);
+ }
+
+ Java8FileDescriptorSocket(InetAddress address, int port, InetAddress clientAddress, int clientPort,
+ SSLParametersImpl sslParameters) throws IOException {
+ super(address, port, clientAddress, clientPort, sslParameters);
+ }
+
+ Java8FileDescriptorSocket(Socket socket, String hostname, int port, boolean autoClose,
+ SSLParametersImpl sslParameters) throws IOException {
+ super(socket, hostname, port, autoClose, sslParameters);
+ }
+
+ /* @Override */
+ @SuppressWarnings("MissingOverride") // For compilation with Java < 9.
+ public void setHandshakeApplicationProtocolSelector(
+ final BiFunction<SSLSocket, List<String>, String> selector) {
+ this.selector = selector;
+ setApplicationProtocolSelector(toApplicationProtocolSelector(selector));
+ }
+
+ /* @Override */
+ @SuppressWarnings("MissingOverride") // For compilation with Java < 9.
+ public BiFunction<SSLSocket, List<String>, String> getHandshakeApplicationProtocolSelector() {
+ return selector;
+ }
+
+ private static ApplicationProtocolSelector toApplicationProtocolSelector(
+ final BiFunction<SSLSocket, List<String>, String> selector) {
+ return selector == null ? null : new ApplicationProtocolSelector() {
+ @Override
+ public String selectApplicationProtocol(SSLEngine socket, List<String> protocols) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String selectApplicationProtocol(SSLSocket socket, List<String> protocols) {
+ return selector.apply(socket, protocols);
+ }
+ };
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/KeyGeneratorImpl.java b/repackaged/common/src/main/java/com/android/org/conscrypt/KeyGeneratorImpl.java
new file mode 100644
index 0000000..50dc15a
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/KeyGeneratorImpl.java
@@ -0,0 +1,224 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.android.org.conscrypt;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import javax.crypto.KeyGeneratorSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.DESedeKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * An implementation of {@link javax.crypto.KeyGenerator} suitable for use with other Conscrypt
+ * algorithms.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public abstract class KeyGeneratorImpl extends KeyGeneratorSpi {
+ private final String algorithm;
+ protected SecureRandom secureRandom;
+ private int keySizeBits;
+
+ private KeyGeneratorImpl(String algorithm, int defaultKeySizeBits) {
+ this.algorithm = algorithm;
+ this.keySizeBits = defaultKeySizeBits;
+ }
+
+ protected void checkKeySize(int keySize) {
+ if (keySize <= 0) {
+ throw new InvalidParameterException("Key size must be positive");
+ }
+ }
+
+ @Override
+ protected void engineInit(SecureRandom secureRandom) {
+ this.secureRandom = secureRandom;
+ }
+
+ @Override
+ protected void engineInit(AlgorithmParameterSpec params, SecureRandom secureRandom)
+ throws InvalidAlgorithmParameterException {
+ if (params == null) {
+ throw new InvalidAlgorithmParameterException("No params provided");
+ } else {
+ throw new InvalidAlgorithmParameterException(
+ "Unknown param type: " + params.getClass().getName());
+ }
+ }
+
+ @Override
+ protected void engineInit(int keySize, SecureRandom secureRandom) {
+ checkKeySize(keySize);
+ this.keySizeBits = keySize;
+ this.secureRandom = secureRandom;
+ }
+
+ protected byte[] doKeyGeneration(int keyBytes) {
+ byte[] keyData = new byte[keyBytes];
+ secureRandom.nextBytes(keyData);
+ return keyData;
+ }
+
+ @Override
+ protected SecretKey engineGenerateKey() {
+ if (secureRandom == null) {
+ secureRandom = new SecureRandom();
+ }
+
+ return new SecretKeySpec(doKeyGeneration((keySizeBits + 7) / 8), algorithm);
+ }
+
+ // For HMAC, RFC 2104 recommends using the hash's output length as the key length
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class HmacMD5 extends KeyGeneratorImpl {
+ public HmacMD5() {
+ super("HmacMD5", 128);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class HmacSHA1 extends KeyGeneratorImpl {
+ public HmacSHA1() {
+ super("HmacSHA1", 160);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class HmacSHA224 extends KeyGeneratorImpl {
+ public HmacSHA224() {
+ super("HmacSHA224", 224);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class HmacSHA256 extends KeyGeneratorImpl {
+ public HmacSHA256() {
+ super("HmacSHA256", 256);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class HmacSHA384 extends KeyGeneratorImpl {
+ public HmacSHA384() {
+ super("HmacSHA384", 384);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class HmacSHA512 extends KeyGeneratorImpl {
+ public HmacSHA512() {
+ super("HmacSHA512", 512);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class DESEDE extends KeyGeneratorImpl {
+ public DESEDE() {
+ super("DESEDE", 192);
+ }
+
+ @Override
+ protected void checkKeySize(int keySize) {
+ if ((keySize != 112) && (keySize != 168)) {
+ throw new InvalidParameterException("Key size must be either 112 or 168 bits");
+ }
+ }
+
+ @Override
+ protected byte[] doKeyGeneration(int keyBytes) {
+ byte[] keyData = new byte[DESedeKeySpec.DES_EDE_KEY_LEN];
+ secureRandom.nextBytes(keyData);
+ // Set the parity bit for each byte
+ for (int i = 0; i < keyData.length; i++) {
+ if (Integer.bitCount(keyData[i]) % 2 == 0) {
+ keyData[i] = (byte) (keyData[i] ^ 1);
+ }
+ }
+ if (keyBytes == 14) {
+ // The user requested an A-B-A key
+ System.arraycopy(keyData, 0, keyData, 16, 8);
+ }
+ return keyData;
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class AES extends KeyGeneratorImpl {
+ public AES() {
+ super("AES", 128);
+ }
+
+ @Override
+ protected void checkKeySize(int keySize) {
+ if ((keySize != 128) && (keySize != 192) && (keySize != 256)) {
+ throw new InvalidParameterException(
+ "Key size must be either 128, 192, or 256 bits");
+ }
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class ChaCha20 extends KeyGeneratorImpl {
+ public ChaCha20() {
+ super("ChaCha20", 256);
+ }
+
+ @Override
+ protected void checkKeySize(int keySize) {
+ if (keySize != 256) {
+ throw new InvalidParameterException("Key size must be 256 bits");
+ }
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class ARC4 extends KeyGeneratorImpl {
+ public ARC4() {
+ super("ARC4", 128);
+ }
+
+ @Override
+ protected void checkKeySize(int keySize) {
+ if (keySize < 40 || 2048 < keySize) {
+ throw new InvalidParameterException("Key size must be between 40 and 2048 bits");
+ }
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/KeyManagerFactoryImpl.java b/repackaged/common/src/main/java/com/android/org/conscrypt/KeyManagerFactoryImpl.java
new file mode 100644
index 0000000..1551e41
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/KeyManagerFactoryImpl.java
@@ -0,0 +1,122 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package com.android.org.conscrypt;
+
+import com.android.org.conscrypt.io.IoUtils;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactorySpi;
+import javax.net.ssl.ManagerFactoryParameters;
+
+/**
+ * KeyManagerFactory implementation.
+ * @see KeyManagerFactorySpi
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class KeyManagerFactoryImpl extends KeyManagerFactorySpi {
+
+ // source of key material
+ private KeyStore keyStore;
+
+ //password
+ private char[] pwd;
+
+ /**
+ * @see KeyManagerFactorySpi#engineInit(KeyStore ks, char[] password)
+ */
+ @Override
+ protected void engineInit(KeyStore ks, char[] password)
+ throws KeyStoreException, NoSuchAlgorithmException,
+ UnrecoverableKeyException {
+ if (ks != null) {
+ keyStore = ks;
+ if (password != null) {
+ pwd = password.clone();
+ } else {
+ pwd = EmptyArray.CHAR;
+ }
+ } else {
+ keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ String keyStoreName = System.getProperty("javax.net.ssl.keyStore");
+ String keyStorePwd = null;
+ if (keyStoreName == null || keyStoreName.equalsIgnoreCase("NONE") || keyStoreName.isEmpty()) {
+ try {
+ keyStore.load(null, null);
+ } catch (IOException e) {
+ throw new KeyStoreException(e);
+ } catch (CertificateException e) {
+ throw new KeyStoreException(e);
+ }
+ } else {
+ keyStorePwd = System.getProperty("javax.net.ssl.keyStorePassword");
+ if (keyStorePwd == null) {
+ pwd = EmptyArray.CHAR;
+ } else {
+ pwd = keyStorePwd.toCharArray();
+ }
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(new File(keyStoreName));
+ keyStore.load(fis, pwd);
+ } catch (FileNotFoundException e) {
+ throw new KeyStoreException(e);
+ } catch (IOException e) {
+ throw new KeyStoreException(e);
+ } catch (CertificateException e) {
+ throw new KeyStoreException(e);
+ } finally {
+ IoUtils.closeQuietly(fis);
+ }
+ }
+
+ }
+
+ }
+
+ /**
+ * @see KeyManagerFactorySpi#engineInit(ManagerFactoryParameters spec)
+ */
+ @Override
+ protected void engineInit(ManagerFactoryParameters spec)
+ throws InvalidAlgorithmParameterException {
+ throw new InvalidAlgorithmParameterException(
+ "ManagerFactoryParameters not supported");
+
+ }
+
+ /**
+ * @see KeyManagerFactorySpi#engineGetKeyManagers()
+ */
+ @Override
+ protected KeyManager[] engineGetKeyManagers() {
+ if (keyStore == null) {
+ throw new IllegalStateException("KeyManagerFactory is not initialized");
+ }
+ return new KeyManager[] { new KeyManagerImpl(keyStore, pwd) };
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/KeyManagerImpl.java b/repackaged/common/src/main/java/com/android/org/conscrypt/KeyManagerImpl.java
new file mode 100644
index 0000000..e85392c
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/KeyManagerImpl.java
@@ -0,0 +1,230 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package com.android.org.conscrypt;
+
+import java.net.Socket;
+import java.security.KeyStore;
+import java.security.KeyStore.PrivateKeyEntry;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.UnrecoverableEntryException;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * KeyManager implementation.
+ *
+ * This implementation uses hashed key store information. It works faster than retrieving all of the
+ * data from the key store. Any key store changes, that happen after key manager was created, have
+ * no effect. The implementation does not use peer information (host, port) that may be obtained
+ * from socket or engine.
+ *
+ * @see javax.net.ssl.KeyManager
+ */
+class KeyManagerImpl extends X509ExtendedKeyManager {
+
+ // hashed key store information
+ private final HashMap<String, PrivateKeyEntry> hash;
+
+ /**
+ * Creates Key manager
+ */
+ @SuppressWarnings("JdkObsolete") // KeyStore#aliases is the only way of enumerating all entries
+ KeyManagerImpl(KeyStore keyStore, char[] pwd) {
+ this.hash = new HashMap<>();
+ final Enumeration<String> aliases;
+ try {
+ aliases = keyStore.aliases();
+ } catch (KeyStoreException e) {
+ return;
+ }
+ while (aliases.hasMoreElements()) {
+ final String alias = aliases.nextElement();
+ try {
+ if (keyStore.entryInstanceOf(alias, PrivateKeyEntry.class)) {
+ PrivateKeyEntry entry;
+ try {
+ entry = (PrivateKeyEntry) keyStore.getEntry(
+ alias, new KeyStore.PasswordProtection(pwd));
+ } catch (UnsupportedOperationException e) {
+ // If the KeyStore doesn't support getEntry(), as Android Keystore
+ // doesn't, fall back to reading the two values separately.
+ PrivateKey key = (PrivateKey) keyStore.getKey(alias, pwd);
+ Certificate[] certs = keyStore.getCertificateChain(alias);
+ entry = new PrivateKeyEntry(key, certs);
+ }
+ hash.put(alias, entry);
+ }
+ } catch (KeyStoreException | UnrecoverableEntryException
+ | NoSuchAlgorithmException ignored) {
+ // Ignored.
+ }
+ }
+ }
+
+ @Override
+ public String chooseClientAlias(String[] keyTypes, Principal[] issuers, Socket socket) {
+ final String[] al = chooseAlias(keyTypes, issuers);
+ return (al == null ? null : al[0]);
+ }
+
+ @Override
+ public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
+ final String[] al = chooseAlias(new String[] { keyType }, issuers);
+ return (al == null ? null : al[0]);
+ }
+
+ @Override
+ public X509Certificate[] getCertificateChain(String alias) {
+ if (alias == null) {
+ return null;
+ }
+ if (hash.containsKey(alias)) {
+ Certificate[] certs = hash.get(alias).getCertificateChain();
+ if (certs[0] instanceof X509Certificate) {
+ X509Certificate[] xcerts = new X509Certificate[certs.length];
+ for (int i = 0; i < certs.length; i++) {
+ xcerts[i] = (X509Certificate) certs[i];
+ }
+ return xcerts;
+ }
+ }
+ return null;
+
+ }
+
+ @Override
+ public String[] getClientAliases(String keyType, Principal[] issuers) {
+ return chooseAlias(new String[] { keyType }, issuers);
+ }
+
+ @Override
+ public String[] getServerAliases(String keyType, Principal[] issuers) {
+ return chooseAlias(new String[] { keyType }, issuers);
+ }
+
+ @Override
+ public PrivateKey getPrivateKey(String alias) {
+ if (alias == null) {
+ return null;
+ }
+ if (hash.containsKey(alias)) {
+ return hash.get(alias).getPrivateKey();
+ }
+ return null;
+ }
+
+ @Override
+ public String chooseEngineClientAlias(String[] keyTypes, Principal[] issuers, SSLEngine engine) {
+ final String[] al = chooseAlias(keyTypes, issuers);
+ return (al == null ? null : al[0]);
+ }
+
+ @Override
+ public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) {
+ final String[] al = chooseAlias(new String[] { keyType }, issuers);
+ return (al == null ? null : al[0]);
+ }
+
+ private String[] chooseAlias(String[] keyTypes, Principal[] issuers) {
+ if (keyTypes == null || keyTypes.length == 0) {
+ return null;
+ }
+ List<Principal> issuersList = (issuers == null) ? null : Arrays.asList(issuers);
+ ArrayList<String> found = new ArrayList<>();
+ for (final Map.Entry<String, PrivateKeyEntry> entry : hash.entrySet()) {
+ final String alias = entry.getKey();
+ final Certificate[] chain = entry.getValue().getCertificateChain();
+ final Certificate cert = chain[0];
+ final String certKeyAlg = cert.getPublicKey().getAlgorithm();
+ final String certSigAlg = (cert instanceof X509Certificate
+ ? ((X509Certificate) cert).getSigAlgName().toUpperCase(Locale.US)
+ : null);
+ for (String keyAlgorithm : keyTypes) {
+ if (keyAlgorithm == null) {
+ continue;
+ }
+ final String sigAlgorithm;
+ // handle cases like EC_EC and EC_RSA
+ int index = keyAlgorithm.indexOf('_');
+ if (index == -1) {
+ sigAlgorithm = null;
+ } else {
+ sigAlgorithm = keyAlgorithm.substring(index + 1);
+ keyAlgorithm = keyAlgorithm.substring(0, index);
+ }
+ // key algorithm does not match
+ if (!certKeyAlg.equals(keyAlgorithm)) {
+ continue;
+ }
+ /*
+ * TODO find a more reliable test for signature
+ * algorithm. Unfortunately value varies with
+ * provider. For example for "EC" it could be
+ * "SHA1WithECDSA" or simply "ECDSA".
+ */
+ // sig algorithm does not match
+ if (sigAlgorithm != null && certSigAlg != null
+ && !certSigAlg.contains(sigAlgorithm)) {
+ continue;
+ }
+ // no issuers to match, just add to return list and continue
+ if (issuers == null || issuers.length == 0) {
+ found.add(alias);
+ continue;
+ }
+ // check that a certificate in the chain was issued by one of the specified issuers
+ for (Certificate certFromChain : chain) {
+ if (!(certFromChain instanceof X509Certificate)) {
+ // skip non-X509Certificates
+ continue;
+ }
+ X509Certificate xcertFromChain = (X509Certificate) certFromChain;
+ /*
+ * Note use of X500Principal from
+ * getIssuerX500Principal as opposed to Principal
+ * from getIssuerDN. Principal.equals test does
+ * not work in the case where
+ * xcertFromChain.getIssuerDN is a bouncycastle
+ * org.bouncycastle.jce.X509Principal.
+ */
+ X500Principal issuerFromChain = xcertFromChain.getIssuerX500Principal();
+ if (issuersList.contains(issuerFromChain)) {
+ found.add(alias);
+ }
+ }
+ }
+ }
+ if (!found.isEmpty()) {
+ return found.toArray(new String[0]);
+ }
+ return null;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/NativeCrypto.java b/repackaged/common/src/main/java/com/android/org/conscrypt/NativeCrypto.java
new file mode 100644
index 0000000..41ebb1a
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/NativeCrypto.java
@@ -0,0 +1,1505 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2008 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.
+ */
+
+package com.android.org.conscrypt;
+
+import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.SocketTimeoutException;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateParsingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.ShortBufferException;
+import javax.net.ssl.SSLException;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * Provides the Java side of our JNI glue for OpenSSL.
+ * <p>
+ * Note: Many methods in this class take a reference to a Java object that holds a
+ * native pointer in the form of a long in addition to the long itself and don't use
+ * the Java object in the native implementation. This is to prevent the Java object
+ * from becoming eligible for GC while the native method is executing. See
+ * <a href="https://github.com/google/error-prone/blob/master/docs/bugpattern/UnsafeFinalization.md">this</a>
+ * for more details.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class NativeCrypto {
+ // --- OpenSSL library initialization --------------------------------------
+ private static final UnsatisfiedLinkError loadError;
+ static {
+ UnsatisfiedLinkError error = null;
+ try {
+ NativeCryptoJni.init();
+ clinit();
+ } catch (UnsatisfiedLinkError t) {
+ // Don't rethrow the error, so that we can later on interrogate the
+ // value of loadError.
+ error = t;
+ }
+ loadError = error;
+ }
+
+ private native static void clinit();
+
+ /**
+ * Checks to see whether or not the native library was successfully loaded. If not, throws
+ * the {@link UnsatisfiedLinkError} that was encountered while attempting to load the library.
+ */
+ static void checkAvailability() {
+ if (loadError != null) {
+ throw loadError;
+ }
+ }
+
+ // --- DSA/RSA public/private key handling functions -----------------------
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native long EVP_PKEY_new_RSA(byte[] n, byte[] e, byte[] d, byte[] p, byte[] q,
+ byte[] dmp1, byte[] dmq1, byte[] iqmp);
+
+ static native int EVP_PKEY_type(NativeRef.EVP_PKEY pkey);
+
+ static native String EVP_PKEY_print_public(NativeRef.EVP_PKEY pkeyRef);
+
+ static native String EVP_PKEY_print_params(NativeRef.EVP_PKEY pkeyRef);
+
+ @android.compat.annotation.UnsupportedAppUsage static native void EVP_PKEY_free(long pkey);
+
+ static native int EVP_PKEY_cmp(NativeRef.EVP_PKEY pkey1, NativeRef.EVP_PKEY pkey2);
+
+ static native byte[] EVP_marshal_private_key(NativeRef.EVP_PKEY pkey);
+
+ static native long EVP_parse_private_key(byte[] data) throws ParsingException;
+
+ static native byte[] EVP_marshal_public_key(NativeRef.EVP_PKEY pkey);
+
+ static native long EVP_parse_public_key(byte[] data) throws ParsingException;
+
+ static native long PEM_read_bio_PUBKEY(long bioCtx);
+
+ static native long PEM_read_bio_PrivateKey(long bioCtx);
+
+ static native long getRSAPrivateKeyWrapper(PrivateKey key, byte[] modulus);
+
+ static native long getECPrivateKeyWrapper(PrivateKey key, NativeRef.EC_GROUP ecGroupRef);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native long RSA_generate_key_ex(int modulusBits, byte[] publicExponent);
+
+ static native int RSA_size(NativeRef.EVP_PKEY pkey);
+
+ static native int RSA_private_encrypt(
+ int flen, byte[] from, byte[] to, NativeRef.EVP_PKEY pkey, int padding);
+
+ static native int RSA_public_decrypt(int flen, byte[] from, byte[] to, NativeRef.EVP_PKEY pkey,
+ int padding) throws BadPaddingException, SignatureException;
+
+ static native int RSA_public_encrypt(
+ int flen, byte[] from, byte[] to, NativeRef.EVP_PKEY pkey, int padding);
+
+ static native int RSA_private_decrypt(int flen, byte[] from, byte[] to, NativeRef.EVP_PKEY pkey,
+ int padding) throws BadPaddingException, SignatureException;
+
+ /**
+ * @return array of {n, e}
+ */
+ static native byte[][] get_RSA_public_params(NativeRef.EVP_PKEY rsa);
+
+ /**
+ * @return array of {n, e, d, p, q, dmp1, dmq1, iqmp}
+ */
+ static native byte[][] get_RSA_private_params(NativeRef.EVP_PKEY rsa);
+
+ // --- ChaCha20 -----------------------
+
+ /**
+ * Returns the encrypted or decrypted version of the data.
+ */
+ static native void chacha20_encrypt_decrypt(byte[] in, int inOffset, byte[] out, int outOffset,
+ int length, byte[] key, byte[] nonce, int blockCounter);
+
+ // --- EC functions --------------------------
+
+ static native long EVP_PKEY_new_EC_KEY(
+ NativeRef.EC_GROUP groupRef, NativeRef.EC_POINT pubkeyRef, byte[] privkey);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native long EC_GROUP_new_by_curve_name(String curveName);
+
+ static native long EC_GROUP_new_arbitrary(
+ byte[] p, byte[] a, byte[] b, byte[] x, byte[] y, byte[] order, int cofactor);
+
+ static native String EC_GROUP_get_curve_name(NativeRef.EC_GROUP groupRef);
+
+ static native byte[][] EC_GROUP_get_curve(NativeRef.EC_GROUP groupRef);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native void EC_GROUP_clear_free(long groupRef);
+
+ static native long EC_GROUP_get_generator(NativeRef.EC_GROUP groupRef);
+
+ static native byte[] EC_GROUP_get_order(NativeRef.EC_GROUP groupRef);
+
+ static native int EC_GROUP_get_degree(NativeRef.EC_GROUP groupRef);
+
+ static native byte[] EC_GROUP_get_cofactor(NativeRef.EC_GROUP groupRef);
+
+ static native long EC_POINT_new(NativeRef.EC_GROUP groupRef);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native void EC_POINT_clear_free(long pointRef);
+
+ static native byte[][] EC_POINT_get_affine_coordinates(
+ NativeRef.EC_GROUP groupRef, NativeRef.EC_POINT pointRef);
+
+ static native void EC_POINT_set_affine_coordinates(
+ NativeRef.EC_GROUP groupRef, NativeRef.EC_POINT pointRef, byte[] x, byte[] y);
+
+ static native long EC_KEY_generate_key(NativeRef.EC_GROUP groupRef);
+
+ static native long EC_KEY_get1_group(NativeRef.EVP_PKEY pkeyRef);
+
+ static native byte[] EC_KEY_get_private_key(NativeRef.EVP_PKEY keyRef);
+
+ static native long EC_KEY_get_public_key(NativeRef.EVP_PKEY keyRef);
+
+ static native byte[] EC_KEY_marshal_curve_name(NativeRef.EC_GROUP groupRef) throws IOException;
+
+ static native long EC_KEY_parse_curve_name(byte[] encoded) throws IOException;
+
+ static native int ECDH_compute_key(byte[] out, int outOffset, NativeRef.EVP_PKEY publicKeyRef,
+ NativeRef.EVP_PKEY privateKeyRef) throws InvalidKeyException, IndexOutOfBoundsException;
+
+ static native int ECDSA_size(NativeRef.EVP_PKEY pkey);
+
+ static native int ECDSA_sign(byte[] data, byte[] sig, NativeRef.EVP_PKEY pkey);
+
+ static native int ECDSA_verify(byte[] data, byte[] sig, NativeRef.EVP_PKEY pkey);
+
+ // --- Curve25519 --------------
+
+ static native boolean X25519(byte[] out, byte[] privateKey, byte[] publicKey)
+ throws InvalidKeyException;
+
+ static native void X25519_keypair(byte[] outPublicKey, byte[] outPrivateKey);
+
+ // --- Message digest functions --------------
+
+ // These return const references
+ @android.compat.annotation.UnsupportedAppUsage
+ static native long EVP_get_digestbyname(String name);
+
+ @android.compat.annotation.UnsupportedAppUsage static native int EVP_MD_size(long evp_md_const);
+
+ // --- Message digest context functions --------------
+
+ @android.compat.annotation.UnsupportedAppUsage static native long EVP_MD_CTX_create();
+
+ static native void EVP_MD_CTX_cleanup(NativeRef.EVP_MD_CTX ctx);
+
+ @android.compat.annotation.UnsupportedAppUsage static native void EVP_MD_CTX_destroy(long ctx);
+
+ static native int EVP_MD_CTX_copy_ex(
+ NativeRef.EVP_MD_CTX dst_ctx, NativeRef.EVP_MD_CTX src_ctx);
+
+ // --- Digest handling functions -------------------------------------------
+
+ static native int EVP_DigestInit_ex(NativeRef.EVP_MD_CTX ctx, long evp_md);
+
+ static native void EVP_DigestUpdate(
+ NativeRef.EVP_MD_CTX ctx, byte[] buffer, int offset, int length);
+
+ static native void EVP_DigestUpdateDirect(NativeRef.EVP_MD_CTX ctx, long ptr, int length);
+
+ static native int EVP_DigestFinal_ex(NativeRef.EVP_MD_CTX ctx, byte[] hash, int offset);
+
+ // --- Signature handling functions ----------------------------------------
+
+ static native long EVP_DigestSignInit(
+ NativeRef.EVP_MD_CTX ctx, long evpMdRef, NativeRef.EVP_PKEY key);
+
+ static native long EVP_DigestVerifyInit(
+ NativeRef.EVP_MD_CTX ctx, long evpMdRef, NativeRef.EVP_PKEY key);
+
+ static native void EVP_DigestSignUpdate(
+ NativeRef.EVP_MD_CTX ctx, byte[] buffer, int offset, int length);
+
+ static native void EVP_DigestSignUpdateDirect(NativeRef.EVP_MD_CTX ctx, long ptr, int length);
+
+ static native void EVP_DigestVerifyUpdate(
+ NativeRef.EVP_MD_CTX ctx, byte[] buffer, int offset, int length);
+
+ static native void EVP_DigestVerifyUpdateDirect(NativeRef.EVP_MD_CTX ctx, long ptr, int length);
+
+ static native byte[] EVP_DigestSignFinal(NativeRef.EVP_MD_CTX ctx);
+
+ static native boolean EVP_DigestVerifyFinal(NativeRef.EVP_MD_CTX ctx, byte[] signature,
+ int offset, int length) throws IndexOutOfBoundsException;
+
+ static native long EVP_PKEY_encrypt_init(NativeRef.EVP_PKEY pkey) throws InvalidKeyException;
+
+ static native int EVP_PKEY_encrypt(NativeRef.EVP_PKEY_CTX ctx, byte[] out, int outOffset,
+ byte[] input, int inOffset, int inLength)
+ throws IndexOutOfBoundsException, BadPaddingException;
+
+ static native long EVP_PKEY_decrypt_init(NativeRef.EVP_PKEY pkey) throws InvalidKeyException;
+
+ static native int EVP_PKEY_decrypt(NativeRef.EVP_PKEY_CTX ctx, byte[] out, int outOffset,
+ byte[] input, int inOffset, int inLength)
+ throws IndexOutOfBoundsException, BadPaddingException;
+
+ static native void EVP_PKEY_CTX_free(long pkeyCtx);
+
+ static native void EVP_PKEY_CTX_set_rsa_padding(long ctx, int pad)
+ throws InvalidAlgorithmParameterException;
+
+ static native void EVP_PKEY_CTX_set_rsa_pss_saltlen(long ctx, int len)
+ throws InvalidAlgorithmParameterException;
+
+ static native void EVP_PKEY_CTX_set_rsa_mgf1_md(long ctx, long evpMdRef)
+ throws InvalidAlgorithmParameterException;
+
+ static native void EVP_PKEY_CTX_set_rsa_oaep_md(long ctx, long evpMdRef)
+ throws InvalidAlgorithmParameterException;
+
+ static native void EVP_PKEY_CTX_set_rsa_oaep_label(long ctx, byte[] label)
+ throws InvalidAlgorithmParameterException;
+
+ // --- Block ciphers -------------------------------------------------------
+
+ // These return const references
+ @android.compat.annotation.UnsupportedAppUsage
+ static native long EVP_get_cipherbyname(String string);
+
+ static native void EVP_CipherInit_ex(NativeRef.EVP_CIPHER_CTX ctx, long evpCipher, byte[] key,
+ byte[] iv, boolean encrypting);
+
+ static native int EVP_CipherUpdate(NativeRef.EVP_CIPHER_CTX ctx, byte[] out, int outOffset,
+ byte[] in, int inOffset, int inLength) throws IndexOutOfBoundsException;
+
+ static native int EVP_CipherFinal_ex(NativeRef.EVP_CIPHER_CTX ctx, byte[] out, int outOffset)
+ throws BadPaddingException, IllegalBlockSizeException;
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native int EVP_CIPHER_iv_length(long evpCipher);
+
+ @android.compat.annotation.UnsupportedAppUsage static native long EVP_CIPHER_CTX_new();
+
+ static native int EVP_CIPHER_CTX_block_size(NativeRef.EVP_CIPHER_CTX ctx);
+
+ static native int get_EVP_CIPHER_CTX_buf_len(NativeRef.EVP_CIPHER_CTX ctx);
+
+ static native boolean get_EVP_CIPHER_CTX_final_used(NativeRef.EVP_CIPHER_CTX ctx);
+
+ static native void EVP_CIPHER_CTX_set_padding(
+ NativeRef.EVP_CIPHER_CTX ctx, boolean enablePadding);
+
+ static native void EVP_CIPHER_CTX_set_key_length(NativeRef.EVP_CIPHER_CTX ctx, int keyBitSize);
+
+ static native void EVP_CIPHER_CTX_free(long ctx);
+
+ // --- AEAD ----------------------------------------------------------------
+ static native long EVP_aead_aes_128_gcm();
+
+ static native long EVP_aead_aes_256_gcm();
+
+ static native long EVP_aead_chacha20_poly1305();
+
+ static native long EVP_aead_aes_128_gcm_siv();
+
+ static native long EVP_aead_aes_256_gcm_siv();
+
+ static native int EVP_AEAD_max_overhead(long evpAead);
+
+ static native int EVP_AEAD_nonce_length(long evpAead);
+
+ static native int EVP_AEAD_CTX_seal(long evpAead, byte[] key, int tagLengthInBytes, byte[] out,
+ int outOffset, byte[] nonce, byte[] in, int inOffset, int inLength, byte[] ad)
+ throws ShortBufferException, BadPaddingException;
+
+ static native int EVP_AEAD_CTX_seal_buf(long evpAead, byte[] key, int tagLengthInBytes,
+ ByteBuffer out, byte[] nonce, ByteBuffer input, byte[] ad)
+ throws ShortBufferException, BadPaddingException;
+
+ static native int EVP_AEAD_CTX_open(long evpAead, byte[] key, int tagLengthInBytes, byte[] out,
+ int outOffset, byte[] nonce, byte[] in, int inOffset, int inLength, byte[] ad)
+ throws ShortBufferException, BadPaddingException;
+
+ static native int EVP_AEAD_CTX_open_buf(long evpAead, byte[] key, int tagLengthInBytes,
+ ByteBuffer out, byte[] nonce, ByteBuffer input, byte[] ad)
+ throws ShortBufferException, BadPaddingException;
+
+ // --- CMAC functions ------------------------------------------------------
+
+ static native long CMAC_CTX_new();
+
+ static native void CMAC_CTX_free(long ctx);
+
+ static native void CMAC_Init(NativeRef.CMAC_CTX ctx, byte[] key);
+
+ static native void CMAC_Update(NativeRef.CMAC_CTX ctx, byte[] in, int inOffset, int inLength);
+
+ static native void CMAC_UpdateDirect(NativeRef.CMAC_CTX ctx, long inPtr, int inLength);
+
+ static native byte[] CMAC_Final(NativeRef.CMAC_CTX ctx);
+
+ // --- HMAC functions ------------------------------------------------------
+
+ static native long HMAC_CTX_new();
+
+ static native void HMAC_CTX_free(long ctx);
+
+ static native void HMAC_Init_ex(NativeRef.HMAC_CTX ctx, byte[] key, long evp_md);
+
+ static native void HMAC_Update(NativeRef.HMAC_CTX ctx, byte[] in, int inOffset, int inLength);
+
+ static native void HMAC_UpdateDirect(NativeRef.HMAC_CTX ctx, long inPtr, int inLength);
+
+ static native byte[] HMAC_Final(NativeRef.HMAC_CTX ctx);
+
+ // --- RAND ----------------------------------------------------------------
+
+ @android.compat.annotation.UnsupportedAppUsage static native void RAND_bytes(byte[] output);
+
+ // --- X509_NAME -----------------------------------------------------------
+
+ static int X509_NAME_hash(X500Principal principal) {
+ return X509_NAME_hash(principal, "SHA1");
+ }
+
+ public static int X509_NAME_hash_old(X500Principal principal) {
+ return X509_NAME_hash(principal, "MD5");
+ }
+ private static int X509_NAME_hash(X500Principal principal, String algorithm) {
+ try {
+ byte[] digest = MessageDigest.getInstance(algorithm).digest(principal.getEncoded());
+ int offset = 0;
+ return (((digest[offset++] & 0xff) << 0) | ((digest[offset++] & 0xff) << 8)
+ | ((digest[offset++] & 0xff) << 16) | ((digest[offset] & 0xff) << 24));
+ } catch (NoSuchAlgorithmException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ // --- X509 ----------------------------------------------------------------
+
+ /** Used to request get_X509_GENERAL_NAME_stack get the "altname" field. */
+ static final int GN_STACK_SUBJECT_ALT_NAME = 1;
+
+ /**
+ * Used to request get_X509_GENERAL_NAME_stack get the issuerAlternativeName
+ * extension.
+ */
+ static final int GN_STACK_ISSUER_ALT_NAME = 2;
+
+ /**
+ * Used to request only non-critical types in get_X509*_ext_oids.
+ */
+ static final int EXTENSION_TYPE_NON_CRITICAL = 0;
+
+ /**
+ * Used to request only critical types in get_X509*_ext_oids.
+ */
+ static final int EXTENSION_TYPE_CRITICAL = 1;
+
+ @android.compat.annotation.UnsupportedAppUsage static native long d2i_X509_bio(long bioCtx);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native long d2i_X509(byte[] encoded) throws ParsingException;
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native long PEM_read_bio_X509(long bioCtx);
+
+ static native byte[] i2d_X509(long x509ctx, OpenSSLX509Certificate holder);
+
+ /** Takes an X509 context not an X509_PUBKEY context. */
+ static native byte[] i2d_X509_PUBKEY(long x509ctx, OpenSSLX509Certificate holder);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native byte[] ASN1_seq_pack_X509(long[] x509CertRefs);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native long[] ASN1_seq_unpack_X509_bio(long bioRef) throws ParsingException;
+
+ static native void X509_free(long x509ctx, OpenSSLX509Certificate holder);
+
+ static native int X509_cmp(long x509ctx1, OpenSSLX509Certificate holder, long x509ctx2, OpenSSLX509Certificate holder2);
+
+ static native void X509_print_ex(long bioCtx, long x509ctx, OpenSSLX509Certificate holder, long nmflag, long certflag);
+
+ static native byte[] X509_get_issuer_name(long x509ctx, OpenSSLX509Certificate holder);
+
+ static native byte[] X509_get_subject_name(long x509ctx, OpenSSLX509Certificate holder);
+
+ static native String get_X509_sig_alg_oid(long x509ctx, OpenSSLX509Certificate holder);
+
+ static native byte[] get_X509_sig_alg_parameter(long x509ctx, OpenSSLX509Certificate holder);
+
+ static native boolean[] get_X509_issuerUID(long x509ctx, OpenSSLX509Certificate holder);
+
+ static native boolean[] get_X509_subjectUID(long x509ctx, OpenSSLX509Certificate holder);
+
+ static native long X509_get_pubkey(long x509ctx, OpenSSLX509Certificate holder)
+ throws NoSuchAlgorithmException, InvalidKeyException;
+
+ static native String get_X509_pubkey_oid(long x509ctx, OpenSSLX509Certificate holder);
+
+ static native byte[] X509_get_ext_oid(long x509ctx, OpenSSLX509Certificate holder, String oid);
+
+ static native String[] get_X509_ext_oids(long x509ctx, OpenSSLX509Certificate holder, int critical);
+
+ static native Object[][] get_X509_GENERAL_NAME_stack(long x509ctx, OpenSSLX509Certificate holder, int type)
+ throws CertificateParsingException;
+
+ static native boolean[] get_X509_ex_kusage(long x509ctx, OpenSSLX509Certificate holder);
+
+ static native String[] get_X509_ex_xkusage(long x509ctx, OpenSSLX509Certificate holder);
+
+ static native int get_X509_ex_pathlen(long x509ctx, OpenSSLX509Certificate holder);
+
+ static native long X509_get_notBefore(long x509ctx, OpenSSLX509Certificate holder);
+
+ static native long X509_get_notAfter(long x509ctx, OpenSSLX509Certificate holder);
+
+ static native long X509_get_version(long x509ctx, OpenSSLX509Certificate holder);
+
+ static native byte[] X509_get_serialNumber(long x509ctx, OpenSSLX509Certificate holder);
+
+ static native void X509_verify(long x509ctx, OpenSSLX509Certificate holder, NativeRef.EVP_PKEY pkeyCtx)
+ throws BadPaddingException;
+
+ static native byte[] get_X509_tbs_cert(long x509ctx, OpenSSLX509Certificate holder);
+
+ static native byte[] get_X509_tbs_cert_without_ext(
+ long x509ctx, OpenSSLX509Certificate holder, String oid);
+
+ static native byte[] get_X509_signature(long x509ctx, OpenSSLX509Certificate holder);
+
+ static native int get_X509_ex_flags(long x509ctx, OpenSSLX509Certificate holder);
+
+ // Used by Android platform TrustedCertificateStore.
+ @SuppressWarnings("unused")
+ static native int X509_check_issued(long ctx, OpenSSLX509Certificate holder, long ctx2, OpenSSLX509Certificate holder2);
+
+ // --- PKCS7 ---------------------------------------------------------------
+
+ /** Used as the "which" field in d2i_PKCS7_bio and PEM_read_bio_PKCS7. */
+ static final int PKCS7_CERTS = 1;
+
+ /** Used as the "which" field in d2i_PKCS7_bio and PEM_read_bio_PKCS7. */
+ static final int PKCS7_CRLS = 2;
+
+ /** Returns an array of X509 or X509_CRL pointers. */
+ @android.compat.annotation.UnsupportedAppUsage
+ static native long[] d2i_PKCS7_bio(long bioCtx, int which) throws ParsingException;
+
+ /** Returns an array of X509 or X509_CRL pointers. */
+ @android.compat.annotation.UnsupportedAppUsage static native byte[] i2d_PKCS7(long[] certs);
+
+ /** Returns an array of X509 or X509_CRL pointers. */
+ @android.compat.annotation.UnsupportedAppUsage
+ static native long[] PEM_read_bio_PKCS7(long bioCtx, int which);
+
+ // --- X509_CRL ------------------------------------------------------------
+
+ @android.compat.annotation.UnsupportedAppUsage static native long d2i_X509_CRL_bio(long bioCtx);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native long PEM_read_bio_X509_CRL(long bioCtx);
+
+ static native byte[] i2d_X509_CRL(long x509CrlCtx, OpenSSLX509CRL holder);
+
+ static native void X509_CRL_free(long x509CrlCtx, OpenSSLX509CRL holder);
+
+ static native void X509_CRL_print(long bioCtx, long x509CrlCtx, OpenSSLX509CRL holder);
+
+ static native String get_X509_CRL_sig_alg_oid(long x509CrlCtx, OpenSSLX509CRL holder);
+
+ static native byte[] get_X509_CRL_sig_alg_parameter(long x509CrlCtx, OpenSSLX509CRL holder);
+
+ static native byte[] X509_CRL_get_issuer_name(long x509CrlCtx, OpenSSLX509CRL holder);
+
+ /** Returns X509_REVOKED reference that is not duplicated! */
+ static native long X509_CRL_get0_by_cert(long x509CrlCtx, OpenSSLX509CRL holder, long x509Ctx, OpenSSLX509Certificate holder2);
+
+ /** Returns X509_REVOKED reference that is not duplicated! */
+ static native long X509_CRL_get0_by_serial(long x509CrlCtx, OpenSSLX509CRL holder, byte[] serial);
+
+ /** Returns an array of X509_REVOKED that are owned by the caller. */
+ static native long[] X509_CRL_get_REVOKED(long x509CrlCtx, OpenSSLX509CRL holder);
+
+ static native String[] get_X509_CRL_ext_oids(long x509Crlctx, OpenSSLX509CRL holder, int critical);
+
+ static native byte[] X509_CRL_get_ext_oid(long x509CrlCtx, OpenSSLX509CRL holder, String oid);
+
+ static native long X509_CRL_get_version(long x509CrlCtx, OpenSSLX509CRL holder);
+
+ static native long X509_CRL_get_ext(long x509CrlCtx, OpenSSLX509CRL holder, String oid);
+
+ static native byte[] get_X509_CRL_signature(long x509ctx, OpenSSLX509CRL holder);
+
+ static native void X509_CRL_verify(long x509CrlCtx, OpenSSLX509CRL holder,
+ NativeRef.EVP_PKEY pkeyCtx) throws BadPaddingException, SignatureException,
+ NoSuchAlgorithmException, InvalidKeyException,
+ IllegalBlockSizeException;
+
+ static native byte[] get_X509_CRL_crl_enc(long x509CrlCtx, OpenSSLX509CRL holder);
+
+ static native long X509_CRL_get_lastUpdate(long x509CrlCtx, OpenSSLX509CRL holder);
+
+ static native long X509_CRL_get_nextUpdate(long x509CrlCtx, OpenSSLX509CRL holder);
+
+ // --- X509_REVOKED --------------------------------------------------------
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native long X509_REVOKED_dup(long x509RevokedCtx);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native byte[] i2d_X509_REVOKED(long x509RevokedCtx);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native String[] get_X509_REVOKED_ext_oids(long x509ctx, int critical);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native byte[] X509_REVOKED_get_ext_oid(long x509RevokedCtx, String oid);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native byte[] X509_REVOKED_get_serialNumber(long x509RevokedCtx);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native long X509_REVOKED_get_ext(long x509RevokedCtx, String oid);
+
+ /** Returns ASN1_TIME reference. */
+ @android.compat.annotation.UnsupportedAppUsage
+ static native long get_X509_REVOKED_revocationDate(long x509RevokedCtx);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native void X509_REVOKED_print(long bioRef, long x509RevokedCtx);
+
+ // --- X509_EXTENSION ------------------------------------------------------
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native int X509_supported_extension(long x509ExtensionRef);
+
+ // --- ASN1_TIME -----------------------------------------------------------
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native void ASN1_TIME_to_Calendar(long asn1TimeCtx, Calendar cal)
+ throws ParsingException;
+
+ // --- ASN1 Encoding -------------------------------------------------------
+
+ /**
+ * Allocates and returns an opaque reference to an object that can be used with other
+ * asn1_read_* functions to read the ASN.1-encoded data in val. The returned object must
+ * be freed after use by calling asn1_read_free.
+ */
+ static native long asn1_read_init(byte[] val) throws IOException;
+
+ /**
+ * Allocates and returns an opaque reference to an object that can be used with other
+ * asn1_read_* functions to read the ASN.1 sequence pointed to by cbsRef. The returned
+ * object must be freed after use by calling asn1_read_free.
+ */
+ static native long asn1_read_sequence(long cbsRef) throws IOException;
+
+ /**
+ * Returns whether the next object in the given reference is explicitly tagged with the
+ * given tag number.
+ */
+ static native boolean asn1_read_next_tag_is(long cbsRef, int tag) throws IOException;
+
+ /**
+ * Allocates and returns an opaque reference to an object that can be used with
+ * other asn1_read_* functions to read the ASN.1 data pointed to by cbsRef. The returned
+ * object must be freed after use by calling asn1_read_free.
+ */
+ static native long asn1_read_tagged(long cbsRef) throws IOException;
+
+ /**
+ * Returns the contents of an ASN.1 octet string from the given reference.
+ */
+ static native byte[] asn1_read_octetstring(long cbsRef) throws IOException;
+
+ /**
+ * Returns an ASN.1 integer from the given reference. If the integer doesn't fit
+ * in a uint64, this method will throw an IOException.
+ */
+ static native long asn1_read_uint64(long cbsRef) throws IOException;
+
+ /**
+ * Consumes an ASN.1 NULL from the given reference.
+ */
+ static native void asn1_read_null(long cbsRef) throws IOException;
+
+ /**
+ * Returns an ASN.1 OID in dotted-decimal notation (eg, "1.3.14.3.2.26" for SHA-1) from the
+ * given reference.
+ */
+ static native String asn1_read_oid(long cbsRef) throws IOException;
+
+ /**
+ * Returns whether or not the given reference has been read completely.
+ */
+ static native boolean asn1_read_is_empty(long cbsRef);
+
+ /**
+ * Frees any resources associated with the given reference. After calling, the reference
+ * must not be used again. This may be called with a zero reference, in which case nothing
+ * will be done.
+ */
+ static native void asn1_read_free(long cbsRef);
+
+ /**
+ * Allocates and returns an opaque reference to an object that can be used with other
+ * asn1_write_* functions to write ASN.1-encoded data. The returned object must be finalized
+ * after use by calling either asn1_write_finish or asn1_write_cleanup, and its resources
+ * must be freed by calling asn1_write_free.
+ */
+ static native long asn1_write_init() throws IOException;
+
+ /**
+ * Allocates and returns an opaque reference to an object that can be used with other
+ * asn1_write_* functions to write an ASN.1 sequence into the given reference. The returned
+ * reference may only be used until the next call on the parent reference. The returned
+ * object must be freed after use by calling asn1_write_free.
+ */
+ static native long asn1_write_sequence(long cbbRef) throws IOException;
+
+ /**
+ * Allocates and returns an opaque reference to an object that can be used with other
+ * asn1_write_* functions to write a explicitly-tagged ASN.1 object with the given tag
+ * into the given reference. The returned reference may only be used until the next
+ * call on the parent reference. The returned object must be freed after use by
+ * calling asn1_write_free.
+ */
+ static native long asn1_write_tag(long cbbRef, int tag) throws IOException;
+
+ /**
+ * Writes the given data into the given reference as an ASN.1-encoded octet string.
+ */
+ static native void asn1_write_octetstring(long cbbRef, byte[] data) throws IOException;
+
+ /**
+ * Writes the given value into the given reference as an ASN.1-encoded integer.
+ */
+ static native void asn1_write_uint64(long cbbRef, long value) throws IOException;
+
+ /**
+ * Writes a NULL value into the given reference.
+ */
+ static native void asn1_write_null(long cbbRef) throws IOException;
+
+ /**
+ * Writes the given OID (which must be in dotted-decimal notation) into the given reference.
+ */
+ static native void asn1_write_oid(long cbbRef, String oid) throws IOException;
+
+ /**
+ * Flushes the given reference, invalidating any child references and completing their
+ * operations. This must be called if the child references are to be freed before
+ * asn1_write_finish is called on the ultimate parent. The child references must still
+ * be freed.
+ */
+ static native void asn1_write_flush(long cbbRef) throws IOException;
+
+ /**
+ * Completes any in-progress operations and returns the ASN.1-encoded data. Either this
+ * or asn1_write_cleanup must be called on any reference returned from asn1_write_init
+ * before it is freed.
+ */
+ static native byte[] asn1_write_finish(long cbbRef) throws IOException;
+
+ /**
+ * Cleans up intermediate state in the given reference. Either this or asn1_write_finish
+ * must be called on any reference returned from asn1_write_init before it is freed.
+ */
+ static native void asn1_write_cleanup(long cbbRef);
+
+ /**
+ * Frees resources associated with the given reference. After calling, the reference
+ * must not be used again. This may be called with a zero reference, in which case nothing
+ * will be done.
+ */
+ static native void asn1_write_free(long cbbRef);
+
+ // --- BIO stream creation -------------------------------------------------
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native long create_BIO_InputStream(OpenSSLBIOInputStream is, boolean isFinite);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native long create_BIO_OutputStream(OutputStream os);
+
+ @android.compat.annotation.UnsupportedAppUsage static native void BIO_free_all(long bioRef);
+
+ // --- SSL handling --------------------------------------------------------
+
+ static final String OBSOLETE_PROTOCOL_SSLV3 = "SSLv3";
+ private static final String SUPPORTED_PROTOCOL_TLSV1 = "TLSv1";
+ private static final String SUPPORTED_PROTOCOL_TLSV1_1 = "TLSv1.1";
+ private static final String SUPPORTED_PROTOCOL_TLSV1_2 = "TLSv1.2";
+ static final String SUPPORTED_PROTOCOL_TLSV1_3 = "TLSv1.3";
+
+ static final String[] SUPPORTED_TLS_1_3_CIPHER_SUITES = new String[] {
+ "TLS_AES_128_GCM_SHA256",
+ "TLS_AES_256_GCM_SHA384",
+ "TLS_CHACHA20_POLY1305_SHA256",
+ };
+
+ // SUPPORTED_TLS_1_2_CIPHER_SUITES_SET contains all the supported cipher suites for TLS 1.2,
+ // using their Java names.
+ static final Set<String> SUPPORTED_TLS_1_2_CIPHER_SUITES_SET = new HashSet<String>();
+
+ // SUPPORTED_LEGACY_CIPHER_SUITES_SET contains all the supported cipher suites using the legacy
+ // OpenSSL-style names.
+ private static final Set<String> SUPPORTED_LEGACY_CIPHER_SUITES_SET = new HashSet<String>();
+
+ static final Set<String> SUPPORTED_TLS_1_3_CIPHER_SUITES_SET = new HashSet<String>(
+ Arrays.asList(SUPPORTED_TLS_1_3_CIPHER_SUITES));
+
+ /**
+ * TLS_EMPTY_RENEGOTIATION_INFO_SCSV is RFC 5746's renegotiation
+ * indication signaling cipher suite value. It is not a real
+ * cipher suite. It is just an indication in the default and
+ * supported cipher suite lists indicates that the implementation
+ * supports secure renegotiation.
+ * <p>
+ * In the RI, its presence means that the SCSV is sent in the
+ * cipher suite list to indicate secure renegotiation support and
+ * its absense means to send an empty TLS renegotiation info
+ * extension instead.
+ * <p>
+ * However, OpenSSL doesn't provide an API to give this level of
+ * control, instead always sending the SCSV and always including
+ * the empty renegotiation info if TLS is used (as opposed to
+ * SSL). So we simply allow TLS_EMPTY_RENEGOTIATION_INFO_SCSV to
+ * be passed for compatibility as to provide the hint that we
+ * support secure renegotiation.
+ */
+ static final String TLS_EMPTY_RENEGOTIATION_INFO_SCSV = "TLS_EMPTY_RENEGOTIATION_INFO_SCSV";
+
+ static String cipherSuiteToJava(String cipherSuite) {
+ // For historical reasons, Java uses a different name for TLS_RSA_WITH_3DES_EDE_CBC_SHA.
+ if ("TLS_RSA_WITH_3DES_EDE_CBC_SHA".equals(cipherSuite)) {
+ return "SSL_RSA_WITH_3DES_EDE_CBC_SHA";
+ }
+ return cipherSuite;
+ }
+
+ static String cipherSuiteFromJava(String javaCipherSuite) {
+ if ("SSL_RSA_WITH_3DES_EDE_CBC_SHA".equals(javaCipherSuite)) {
+ return "TLS_RSA_WITH_3DES_EDE_CBC_SHA";
+ }
+ return javaCipherSuite;
+ }
+
+ /**
+ * TLS_FALLBACK_SCSV is from
+ * https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00
+ * to indicate to the server that this is a fallback protocol
+ * request.
+ */
+ private static final String TLS_FALLBACK_SCSV = "TLS_FALLBACK_SCSV";
+
+ private static final boolean HAS_AES_HARDWARE;
+ private static final String[] SUPPORTED_TLS_1_2_CIPHER_SUITES;
+ static {
+ if (loadError == null) {
+ // If loadError is not null, it means the native code was not loaded, so
+ // get_cipher_names will throw UnsatisfiedLinkError. Populate the list of supported
+ // ciphers with BoringSSL's default, and also explicitly include 3DES.
+ // https://boringssl-review.googlesource.com/c/boringssl/+/59425 will remove 3DES
+ // from BoringSSL's default, but Conscrypt isn't quite ready to remove it yet.
+ String[] allCipherSuites = get_cipher_names("ALL:3DES");
+
+ // get_cipher_names returns an array where even indices are the standard name and odd
+ // indices are the OpenSSL name.
+ int size = allCipherSuites.length;
+ if (size % 2 != 0) {
+ throw new IllegalArgumentException(
+ "Invalid cipher list returned by get_cipher_names");
+ }
+ SUPPORTED_TLS_1_2_CIPHER_SUITES = new String[size / 2 + 2];
+ for (int i = 0; i < size; i += 2) {
+ String cipherSuite = cipherSuiteToJava(allCipherSuites[i]);
+ SUPPORTED_TLS_1_2_CIPHER_SUITES[i / 2] = cipherSuite;
+ SUPPORTED_TLS_1_2_CIPHER_SUITES_SET.add(cipherSuite);
+
+ SUPPORTED_LEGACY_CIPHER_SUITES_SET.add(allCipherSuites[i + 1]);
+ }
+ SUPPORTED_TLS_1_2_CIPHER_SUITES[size / 2] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV;
+ SUPPORTED_TLS_1_2_CIPHER_SUITES[size / 2 + 1] = TLS_FALLBACK_SCSV;
+
+ HAS_AES_HARDWARE = EVP_has_aes_hardware() == 1;
+ } else {
+ HAS_AES_HARDWARE = false;
+ SUPPORTED_TLS_1_2_CIPHER_SUITES = new String[0];
+ }
+ }
+
+ /**
+ * Returns 1 if the BoringSSL believes the CPU has AES accelerated hardware
+ * instructions. Used to determine cipher suite ordering.
+ */
+ static native int EVP_has_aes_hardware();
+
+ @android.compat.annotation.UnsupportedAppUsage static native long SSL_CTX_new();
+
+ // IMPLEMENTATION NOTE: The default list of cipher suites is a trade-off between what we'd like
+ // to use and what servers currently support. We strive to be secure enough by default. We thus
+ // avoid unacceptably weak suites (e.g., those with bulk cipher secret key shorter than 128
+ // bits), while maintaining the capability to connect to the majority of servers.
+ //
+ // Cipher suites are listed in preference order (favorite choice first) of the client. However,
+ // servers are not required to honor the order. The key rules governing the preference order
+ // are:
+ // * Prefer Forward Secrecy (i.e., cipher suites that use ECDHE and DHE for key agreement).
+ // * Prefer ChaCha20-Poly1305 to AES-GCM unless hardware support for AES is available.
+ // * Prefer AES-GCM to AES-CBC whose MAC-pad-then-encrypt approach leads to weaknesses (e.g.,
+ // Lucky 13).
+ // * Prefer 128-bit bulk encryption to 256-bit one, because 128-bit is safe enough while
+ // consuming less CPU/time/energy.
+ //
+ // NOTE: Removing cipher suites from this list needs to be done with caution, because this may
+ // prevent apps from connecting to servers they were previously able to connect to.
+
+ /** X.509 based cipher suites enabled by default (if requested), in preference order. */
+ static final String[] DEFAULT_X509_CIPHER_SUITES = HAS_AES_HARDWARE ?
+ new String[] {
+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
+ "TLS_RSA_WITH_AES_128_GCM_SHA256",
+ "TLS_RSA_WITH_AES_256_GCM_SHA384",
+ "TLS_RSA_WITH_AES_128_CBC_SHA",
+ "TLS_RSA_WITH_AES_256_CBC_SHA",
+ } :
+ new String[] {
+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
+ "TLS_RSA_WITH_AES_128_GCM_SHA256",
+ "TLS_RSA_WITH_AES_256_GCM_SHA384",
+ "TLS_RSA_WITH_AES_128_CBC_SHA",
+ "TLS_RSA_WITH_AES_256_CBC_SHA",
+ };
+
+ /** TLS-PSK cipher suites enabled by default (if requested), in preference order. */
+ static final String[] DEFAULT_PSK_CIPHER_SUITES = new String[] {
+ "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256",
+ "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA",
+ "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA",
+ "TLS_PSK_WITH_AES_128_CBC_SHA",
+ "TLS_PSK_WITH_AES_256_CBC_SHA",
+ };
+
+ static String[] getSupportedCipherSuites() {
+ return SSLUtils.concat(SUPPORTED_TLS_1_3_CIPHER_SUITES, SUPPORTED_TLS_1_2_CIPHER_SUITES.clone());
+ }
+
+ static native void SSL_CTX_free(long ssl_ctx, AbstractSessionContext holder);
+
+ static native void SSL_CTX_set_session_id_context(long ssl_ctx, AbstractSessionContext holder, byte[] sid_ctx);
+
+ static native long SSL_CTX_set_timeout(long ssl_ctx, AbstractSessionContext holder, long seconds);
+
+ static native long SSL_new(long ssl_ctx, AbstractSessionContext holder) throws SSLException;
+
+ static native void SSL_enable_tls_channel_id(long ssl, NativeSsl ssl_holder) throws SSLException;
+
+ static native byte[] SSL_get_tls_channel_id(long ssl, NativeSsl ssl_holder) throws SSLException;
+
+ static native void SSL_set1_tls_channel_id(long ssl, NativeSsl ssl_holder, NativeRef.EVP_PKEY pkey);
+
+ /**
+ * Sets the local certificates and private key.
+ *
+ * @param ssl the SSL reference.
+ * @param encodedCertificates the encoded form of the local certificate chain.
+ * @param pkey a reference to the private key.
+ * @throws SSLException if a problem occurs setting the cert/key.
+ */
+ static native void setLocalCertsAndPrivateKey(long ssl, NativeSsl ssl_holder, byte[][] encodedCertificates,
+ NativeRef.EVP_PKEY pkey) throws SSLException;
+
+ static native void SSL_set_client_CA_list(long ssl, NativeSsl ssl_holder, byte[][] asn1DerEncodedX500Principals)
+ throws SSLException;
+
+ static native long SSL_set_mode(long ssl, NativeSsl ssl_holder, long mode);
+
+ static native long SSL_set_options(long ssl, NativeSsl ssl_holder, long options);
+
+ static native long SSL_clear_options(long ssl, NativeSsl ssl_holder, long options);
+
+ static native int SSL_set_protocol_versions(long ssl, NativeSsl ssl_holder, int min_version, int max_version);
+
+ static native void SSL_enable_signed_cert_timestamps(long ssl, NativeSsl ssl_holder);
+
+ static native byte[] SSL_get_signed_cert_timestamp_list(long ssl, NativeSsl ssl_holder);
+
+ static native void SSL_set_signed_cert_timestamp_list(long ssl, NativeSsl ssl_holder, byte[] list);
+
+ static native void SSL_enable_ocsp_stapling(long ssl, NativeSsl ssl_holder);
+
+ static native byte[] SSL_get_ocsp_response(long ssl, NativeSsl ssl_holder);
+
+ static native void SSL_set_ocsp_response(long ssl, NativeSsl ssl_holder, byte[] response);
+
+ static native byte[] SSL_get_tls_unique(long ssl, NativeSsl ssl_holder);
+
+ static native byte[] SSL_export_keying_material(long ssl, NativeSsl ssl_holder, byte[] label, byte[] context, int num_bytes) throws SSLException;
+
+ static native void SSL_use_psk_identity_hint(long ssl, NativeSsl ssl_holder, String identityHint) throws SSLException;
+
+ static native void set_SSL_psk_client_callback_enabled(long ssl, NativeSsl ssl_holder, boolean enabled);
+
+ static native void set_SSL_psk_server_callback_enabled(long ssl, NativeSsl ssl_holder, boolean enabled);
+
+ /** Protocols to enable by default when "TLSv1.3" is requested. */
+ static final String[] TLSV13_PROTOCOLS = new String[] {
+ SUPPORTED_PROTOCOL_TLSV1,
+ SUPPORTED_PROTOCOL_TLSV1_1,
+ SUPPORTED_PROTOCOL_TLSV1_2,
+ SUPPORTED_PROTOCOL_TLSV1_3,
+ };
+
+ /** Protocols to enable by default when "TLSv1.2" is requested. */
+ static final String[] TLSV12_PROTOCOLS = new String[] {
+ SUPPORTED_PROTOCOL_TLSV1,
+ SUPPORTED_PROTOCOL_TLSV1_1,
+ SUPPORTED_PROTOCOL_TLSV1_2,
+ };
+
+ /** Protocols to enable by default when "TLSv1.1" is requested. */
+ static final String[] TLSV11_PROTOCOLS = TLSV12_PROTOCOLS;
+
+ /** Protocols to enable by default when "TLSv1" is requested. */
+ static final String[] TLSV1_PROTOCOLS = TLSV11_PROTOCOLS;
+
+ static final String[] DEFAULT_PROTOCOLS = TLSV13_PROTOCOLS;
+ private static final String[] SUPPORTED_PROTOCOLS = new String[] {
+ SUPPORTED_PROTOCOL_TLSV1,
+ SUPPORTED_PROTOCOL_TLSV1_1,
+ SUPPORTED_PROTOCOL_TLSV1_2,
+ SUPPORTED_PROTOCOL_TLSV1_3,
+ };
+
+ static String[] getSupportedProtocols() {
+ return SUPPORTED_PROTOCOLS.clone();
+ }
+
+ private static class Range {
+ public final String min;
+ public final String max;
+ public Range(String min, String max) {
+ this.min = min;
+ this.max = max;
+ }
+ }
+
+ private static Range getProtocolRange(String[] protocols) {
+ // TLS protocol negotiation only allows a min and max version
+ // to be set, despite the Java API allowing a sparse set of
+ // protocols to be enabled. Use the lowest contiguous range
+ // of protocols provided by the caller, which is what we've
+ // done historically.
+ List<String> protocolsList = Arrays.asList(protocols);
+ String min = null;
+ String max = null;
+ for (int i = 0; i < SUPPORTED_PROTOCOLS.length; i++) {
+ String protocol = SUPPORTED_PROTOCOLS[i];
+ if (protocolsList.contains(protocol)) {
+ if (min == null) {
+ min = protocol;
+ }
+ max = protocol;
+ } else if (min != null) {
+ break;
+ }
+ }
+ if ((min == null) || (max == null)) {
+ throw new IllegalArgumentException("No protocols enabled.");
+ }
+ return new Range(min, max);
+ }
+
+ static void setEnabledProtocols(long ssl, NativeSsl ssl_holder, String[] protocols) {
+ checkEnabledProtocols(protocols);
+ Range range = getProtocolRange(protocols);
+ SSL_set_protocol_versions(
+ ssl, ssl_holder, getProtocolConstant(range.min), getProtocolConstant(range.max));
+ }
+
+ private static int getProtocolConstant(String protocol) {
+ if (protocol.equals(SUPPORTED_PROTOCOL_TLSV1)) {
+ return NativeConstants.TLS1_VERSION;
+ } else if (protocol.equals(SUPPORTED_PROTOCOL_TLSV1_1)) {
+ return NativeConstants.TLS1_1_VERSION;
+ } else if (protocol.equals(SUPPORTED_PROTOCOL_TLSV1_2)) {
+ return NativeConstants.TLS1_2_VERSION;
+ } else if (protocol.equals(SUPPORTED_PROTOCOL_TLSV1_3)) {
+ return NativeConstants.TLS1_3_VERSION;
+ } else {
+ throw new AssertionError("Unknown protocol encountered: " + protocol);
+ }
+ }
+
+ static String[] checkEnabledProtocols(String[] protocols) {
+ if (protocols == null) {
+ throw new IllegalArgumentException("protocols == null");
+ }
+ for (String protocol : protocols) {
+ if (protocol == null) {
+ throw new IllegalArgumentException("protocols contains null");
+ }
+ if (!protocol.equals(SUPPORTED_PROTOCOL_TLSV1)
+ && !protocol.equals(SUPPORTED_PROTOCOL_TLSV1_1)
+ && !protocol.equals(SUPPORTED_PROTOCOL_TLSV1_2)
+ && !protocol.equals(SUPPORTED_PROTOCOL_TLSV1_3)
+ && !protocol.equals(OBSOLETE_PROTOCOL_SSLV3)) {
+ throw new IllegalArgumentException("protocol " + protocol + " is not supported");
+ }
+ }
+ return protocols;
+ }
+
+ static native void SSL_set_cipher_lists(long ssl, NativeSsl ssl_holder, String[] ciphers);
+
+ /**
+ * Gets the list of cipher suites enabled for the provided {@code SSL} instance.
+ *
+ * @return array of {@code SSL_CIPHER} references.
+ */
+ static native long[] SSL_get_ciphers(long ssl, NativeSsl ssl_holder);
+
+ static void setEnabledCipherSuites(
+ long ssl, NativeSsl ssl_holder, String[] cipherSuites, String[] protocols) {
+ checkEnabledCipherSuites(cipherSuites);
+ String maxProtocol = getProtocolRange(protocols).max;
+ List<String> opensslSuites = new ArrayList<String>();
+ for (int i = 0; i < cipherSuites.length; i++) {
+ String cipherSuite = cipherSuites[i];
+ if (cipherSuite.equals(TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
+ continue;
+ }
+ // Only send TLS_FALLBACK_SCSV if max version >= 1.2 to prevent inadvertent connection
+ // problems when servers upgrade. See https://github.com/google/conscrypt/issues/574
+ // for more discussion.
+ if (cipherSuite.equals(TLS_FALLBACK_SCSV)
+ && (maxProtocol.equals(SUPPORTED_PROTOCOL_TLSV1)
+ || maxProtocol.equals(SUPPORTED_PROTOCOL_TLSV1_1))) {
+ SSL_set_mode(ssl, ssl_holder, NativeConstants.SSL_MODE_SEND_FALLBACK_SCSV);
+ continue;
+ }
+ opensslSuites.add(cipherSuiteFromJava(cipherSuite));
+ }
+ SSL_set_cipher_lists(ssl, ssl_holder, opensslSuites.toArray(new String[opensslSuites.size()]));
+ }
+
+ static String[] checkEnabledCipherSuites(String[] cipherSuites) {
+ if (cipherSuites == null) {
+ throw new IllegalArgumentException("cipherSuites == null");
+ }
+ // makes sure all suites are valid, throwing on error
+ for (int i = 0; i < cipherSuites.length; i++) {
+ if (cipherSuites[i] == null) {
+ throw new IllegalArgumentException("cipherSuites[" + i + "] == null");
+ }
+ if (cipherSuites[i].equals(TLS_EMPTY_RENEGOTIATION_INFO_SCSV)
+ || cipherSuites[i].equals(TLS_FALLBACK_SCSV)) {
+ continue;
+ }
+ if (SUPPORTED_TLS_1_2_CIPHER_SUITES_SET.contains(cipherSuites[i])) {
+ continue;
+ }
+
+ // For backwards compatibility, it's allowed for |cipherSuite| to
+ // be an OpenSSL-style cipher-suite name.
+ if (SUPPORTED_LEGACY_CIPHER_SUITES_SET.contains(cipherSuites[i])) {
+ // TODO log warning about using backward compatability
+ continue;
+ }
+ throw new IllegalArgumentException(
+ "cipherSuite " + cipherSuites[i] + " is not supported.");
+ }
+ return cipherSuites;
+ }
+
+ static native void SSL_set_accept_state(long ssl, NativeSsl ssl_holder);
+
+ static native void SSL_set_connect_state(long ssl, NativeSsl ssl_holder);
+
+ static native void SSL_set_verify(long ssl, NativeSsl ssl_holder, int mode);
+
+ static native void SSL_set_session(long ssl, NativeSsl ssl_holder, long sslSessionNativePointer)
+ throws SSLException;
+
+ static native void SSL_set_session_creation_enabled(
+ long ssl, NativeSsl ssl_holder, boolean creationEnabled) throws SSLException;
+
+ static native boolean SSL_session_reused(long ssl, NativeSsl ssl_holder);
+
+ static native void SSL_accept_renegotiations(long ssl, NativeSsl ssl_holder) throws SSLException;
+
+ static native void SSL_set_tlsext_host_name(long ssl, NativeSsl ssl_holder, String hostname)
+ throws SSLException;
+ static native String SSL_get_servername(long ssl, NativeSsl ssl_holder);
+
+ static native void SSL_do_handshake(
+ long ssl, NativeSsl ssl_holder, FileDescriptor fd, SSLHandshakeCallbacks shc, int timeoutMillis)
+ throws SSLException, SocketTimeoutException, CertificateException;
+
+ public static native String SSL_get_current_cipher(long ssl, NativeSsl ssl_holder);
+
+ public static native String SSL_get_version(long ssl, NativeSsl ssl_holder);
+
+ /**
+ * Returns the peer certificate chain.
+ */
+ static native byte[][] SSL_get0_peer_certificates(long ssl, NativeSsl ssl_holder);
+
+ /**
+ * Reads with the native SSL_read function from the encrypted data stream
+ * @return -1 if error or the end of the stream is reached.
+ */
+ static native int SSL_read(long ssl, NativeSsl ssl_holder, FileDescriptor fd, SSLHandshakeCallbacks shc,
+ byte[] b, int off, int len, int readTimeoutMillis) throws IOException;
+
+ /**
+ * Writes with the native SSL_write function to the encrypted data stream.
+ */
+ static native void SSL_write(long ssl, NativeSsl ssl_holder, FileDescriptor fd,
+ SSLHandshakeCallbacks shc, byte[] b, int off, int len, int writeTimeoutMillis)
+ throws IOException;
+
+ static native void SSL_interrupt(long ssl, NativeSsl ssl_holder);
+ static native void SSL_shutdown(
+ long ssl, NativeSsl ssl_holder, FileDescriptor fd, SSLHandshakeCallbacks shc) throws IOException;
+
+ static native int SSL_get_shutdown(long ssl, NativeSsl ssl_holder);
+
+ static native void SSL_free(long ssl, NativeSsl ssl_holder);
+
+ static native long SSL_get_time(long ssl, NativeSsl ssl_holder);
+
+ static native long SSL_set_timeout(long ssl, NativeSsl ssl_holder, long millis);
+
+ static native long SSL_get_timeout(long ssl, NativeSsl ssl_holder);
+
+ static native int SSL_get_signature_algorithm_key_type(int signatureAlg);
+
+ static native byte[] SSL_session_id(long ssl, NativeSsl ssl_holder);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native byte[] SSL_SESSION_session_id(long sslSessionNativePointer);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native long SSL_SESSION_get_time(long sslSessionNativePointer);
+
+ static native long SSL_SESSION_get_timeout(long sslSessionNativePointer);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native String SSL_SESSION_get_version(long sslSessionNativePointer);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native String SSL_SESSION_cipher(long sslSessionNativePointer);
+
+ static native boolean SSL_SESSION_should_be_single_use(long sslSessionNativePointer);
+
+ static native void SSL_SESSION_up_ref(long sslSessionNativePointer);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native void SSL_SESSION_free(long sslSessionNativePointer);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native byte[] i2d_SSL_SESSION(long sslSessionNativePointer);
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static native long d2i_SSL_SESSION(byte[] data) throws IOException;
+
+ /**
+ * A collection of callbacks from the native OpenSSL code that are
+ * related to the SSL handshake initiated by SSL_do_handshake.
+ */
+ interface SSLHandshakeCallbacks {
+ /**
+ * Verify that the certificate chain is trusted.
+ *
+ * @param certificateChain chain of X.509 certificates in their encoded form
+ * @param authMethod auth algorithm name
+ *
+ * @throws CertificateException if the certificate is untrusted
+ */
+ @SuppressWarnings("unused")
+ void verifyCertificateChain(byte[][] certificateChain, String authMethod)
+ throws CertificateException;
+
+ /**
+ * Called on an SSL client when the server requests (or
+ * requires a certificate). The client can respond by using
+ * SSL_use_certificate and SSL_use_PrivateKey to set a
+ * certificate if has an appropriate one available, similar to
+ * how the server provides its certificate.
+ *
+ * @param keyTypes key types supported by the server,
+ * convertible to strings with #keyType
+ * @param asn1DerEncodedX500Principals CAs known to the server
+ */
+ @SuppressWarnings("unused")
+ void clientCertificateRequested(
+ byte[] keyTypes, int[] signatureAlgs, byte[][] asn1DerEncodedX500Principals)
+ throws CertificateEncodingException, SSLException;
+
+ /**
+ * Called when acting as a server during ClientHello processing before a decision
+ * to resume a session is made. This allows the selection of the correct server
+ * certificate based on things like Server Name Indication (SNI).
+ *
+ * @throws IOException if there was an error during certificate selection.
+ */
+ @SuppressWarnings("unused") void serverCertificateRequested() throws IOException;
+
+ /**
+ * Gets the key to be used in client mode for this connection in Pre-Shared Key (PSK) key
+ * exchange.
+ *
+ * @param identityHint PSK identity hint provided by the server or {@code null} if no hint
+ * provided.
+ * @param identity buffer to be populated with PSK identity (NULL-terminated modified UTF-8)
+ * by this method. This identity will be provided to the server.
+ * @param key buffer to be populated with key material by this method.
+ *
+ * @return number of bytes this method stored in the {@code key} buffer or {@code 0} if an
+ * error occurred in which case the handshake will be aborted.
+ */
+ int clientPSKKeyRequested(String identityHint, byte[] identity, byte[] key);
+
+ /**
+ * Gets the key to be used in server mode for this connection in Pre-Shared Key (PSK) key
+ * exchange.
+ *
+ * @param identityHint PSK identity hint provided by this server to the client or
+ * {@code null} if no hint was provided.
+ * @param identity PSK identity provided by the client.
+ * @param key buffer to be populated with key material by this method.
+ *
+ * @return number of bytes this method stored in the {@code key} buffer or {@code 0} if an
+ * error occurred in which case the handshake will be aborted.
+ */
+ int serverPSKKeyRequested(String identityHint, String identity, byte[] key);
+
+ /**
+ * Called when SSL state changes. This could be handshake completion.
+ */
+ @SuppressWarnings("unused") void onSSLStateChange(int type, int val);
+
+ /**
+ * Called when a new session has been established and may be added to the session cache.
+ * The callee is responsible for incrementing the reference count on the returned session.
+ */
+ @SuppressWarnings("unused") void onNewSessionEstablished(long sslSessionNativePtr);
+
+ /**
+ * Called for servers where TLS < 1.3 (TLS 1.3 uses session tickets rather than
+ * application session caches).
+ *
+ * <p/>Looks up the session by ID in the application's session cache. If a valid session
+ * is returned, this callback is responsible for incrementing the reference count (and any
+ * required synchronization).
+ *
+ * @param id the ID of the session to find.
+ * @return the cached session or {@code 0} if no session was found matching the given ID.
+ */
+ @SuppressWarnings("unused") long serverSessionRequested(byte[] id);
+
+ /**
+ * Called when acting as a server, the socket has an {@link
+ * ApplicationProtocolSelectorAdapter} associated with it, and the application protocol
+ * needs to be selected.
+ *
+ * @param applicationProtocols list of application protocols in length-prefix format
+ * @return the index offset of the selected protocol
+ */
+ @SuppressWarnings("unused") int selectApplicationProtocol(byte[] applicationProtocols);
+ }
+
+ static native String SSL_CIPHER_get_kx_name(long cipherAddress);
+
+ static native String[] get_cipher_names(String selection);
+
+ public static native byte[] get_ocsp_single_extension(
+ byte[] ocspResponse, String oid, long x509Ref, OpenSSLX509Certificate holder, long issuerX509Ref, OpenSSLX509Certificate holder2);
+
+ /**
+ * Returns the starting address of the memory region referenced by the provided direct
+ * {@link Buffer} or {@code 0} if the provided buffer is not direct or if such access to direct
+ * buffers is not supported by the platform.
+ *
+ * <p>NOTE: This method ignores the buffer's current {@code position}.
+ */
+ static native long getDirectBufferAddress(Buffer buf);
+
+ static native long SSL_BIO_new(long ssl, NativeSsl ssl_holder) throws SSLException;
+
+ static native int SSL_get_error(long ssl, NativeSsl ssl_holder, int ret);
+
+ static native void SSL_clear_error();
+
+ static native int SSL_pending_readable_bytes(long ssl, NativeSsl ssl_holder);
+
+ static native int SSL_pending_written_bytes_in_BIO(long bio);
+
+ /**
+ * Returns the maximum overhead, in bytes, of sealing a record with SSL.
+ */
+ static native int SSL_max_seal_overhead(long ssl, NativeSsl ssl_holder);
+
+ /**
+ * Enables ALPN for this TLS endpoint and sets the list of supported ALPN protocols in
+ * wire-format (length-prefixed 8-bit strings).
+ */
+ static native void setApplicationProtocols(
+ long ssl, NativeSsl ssl_holder, boolean client, byte[] protocols) throws IOException;
+
+ /**
+ * Called for a server endpoint only. Enables ALPN and indicates that the {@link
+ * SSLHandshakeCallbacks#selectApplicationProtocol} will be called to select the
+ * correct protocol during a handshake. Calling this method overrides
+ * {@link #setApplicationProtocols(long, NativeSsl, boolean, byte[])}.
+ */
+ static native void setHasApplicationProtocolSelector(
+ long ssl, NativeSsl ssl_holder, boolean hasSelector) throws IOException;
+
+ /**
+ * Returns the selected ALPN protocol. If the server did not select a
+ * protocol, {@code null} will be returned.
+ */
+ static native byte[] getApplicationProtocol(long ssl, NativeSsl ssl_holder);
+
+ /**
+ * Variant of the {@link #SSL_do_handshake} used by {@link ConscryptEngine}. This differs
+ * slightly from the raw BoringSSL API in that it returns the SSL error code from the
+ * operation, rather than the return value from {@code SSL_do_handshake}. This is done in
+ * order to allow to properly handle SSL errors and propagate useful exceptions.
+ *
+ * @return Returns the SSL error code for the operation when the error was {@code
+ * SSL_ERROR_NONE}, {@code SSL_ERROR_WANT_READ}, or {@code SSL_ERROR_WANT_WRITE}.
+ * @throws IOException when the error code is anything except those returned by this method.
+ */
+ static native int ENGINE_SSL_do_handshake(long ssl, NativeSsl ssl_holder, SSLHandshakeCallbacks shc)
+ throws IOException;
+
+ /**
+ * Variant of the {@link #SSL_read} for a direct {@link java.nio.ByteBuffer} used by {@link
+ * ConscryptEngine}.
+ *
+ * @return if positive, represents the number of bytes read into the given buffer.
+ * Returns {@code -SSL_ERROR_WANT_READ} if more data is needed. Returns
+ * {@code -SSL_ERROR_WANT_WRITE} if data needs to be written out to flush the BIO.
+ *
+ * @throws java.io.InterruptedIOException if the read was interrupted.
+ * @throws java.io.EOFException if the end of stream has been reached.
+ * @throws CertificateException if the application's certificate verification callback failed.
+ * Only occurs during handshake processing.
+ * @throws SSLException if any other error occurs.
+ */
+ static native int ENGINE_SSL_read_direct(long ssl, NativeSsl ssl_holder, long address, int length,
+ SSLHandshakeCallbacks shc) throws IOException, CertificateException;
+
+ /**
+ * Variant of the {@link #SSL_write} for a direct {@link java.nio.ByteBuffer} used by {@link
+ * ConscryptEngine}. This version does not lock or and does no error pre-processing.
+ */
+ static native int ENGINE_SSL_write_direct(long ssl, NativeSsl ssl_holder, long address, int length,
+ SSLHandshakeCallbacks shc) throws IOException;
+
+ /**
+ * Writes data from the given direct {@link java.nio.ByteBuffer} to the BIO.
+ */
+ static native int ENGINE_SSL_write_BIO_direct(long ssl, NativeSsl ssl_holder, long bioRef, long pos, int length,
+ SSLHandshakeCallbacks shc) throws IOException;
+
+ /**
+ * Reads data from the given BIO into a direct {@link java.nio.ByteBuffer}.
+ */
+ static native int ENGINE_SSL_read_BIO_direct(long ssl, NativeSsl ssl_holder, long bioRef, long address, int len,
+ SSLHandshakeCallbacks shc) throws IOException;
+
+ /**
+ * Forces the SSL object to process any data pending in the BIO.
+ */
+ static native void ENGINE_SSL_force_read(long ssl, NativeSsl ssl_holder,
+ SSLHandshakeCallbacks shc) throws IOException;
+
+ /**
+ * Variant of the {@link #SSL_shutdown} used by {@link ConscryptEngine}. This version does not
+ * lock.
+ */
+ static native void ENGINE_SSL_shutdown(long ssl, NativeSsl ssl_holder, SSLHandshakeCallbacks shc)
+ throws IOException;
+
+ /**
+ * Return {@code true} if BoringSSL has been built in FIPS mode.
+ */
+ static native boolean usesBoringSsl_FIPS_mode();
+
+ /**
+ * Used for testing only.
+ */
+ static native int BIO_read(long bioRef, byte[] buffer) throws IOException;
+ static native void BIO_write(long bioRef, byte[] buffer, int offset, int length)
+ throws IOException, IndexOutOfBoundsException;
+ static native long SSL_clear_mode(long ssl, NativeSsl ssl_holder, long mode);
+ static native long SSL_get_mode(long ssl, NativeSsl ssl_holder);
+ static native long SSL_get_options(long ssl, NativeSsl ssl_holder);
+ static native long SSL_get1_session(long ssl, NativeSsl ssl_holder);
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/NativeRef.java b/repackaged/common/src/main/java/com/android/org/conscrypt/NativeRef.java
new file mode 100644
index 0000000..d33ac62
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/NativeRef.java
@@ -0,0 +1,161 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2014 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.
+ */
+
+package com.android.org.conscrypt;
+
+/**
+ * Used to hold onto native OpenSSL references and run finalization on those
+ * objects. Individual types must subclass this and implement finalizer.
+ */
+abstract class NativeRef {
+ final long address;
+
+ NativeRef(long address) {
+ if (address == 0) {
+ throw new NullPointerException("address == 0");
+ }
+
+ this.address = address;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof NativeRef)) {
+ return false;
+ }
+
+ return ((NativeRef) o).address == address;
+ }
+
+ @Override
+ public int hashCode() {
+ return (int) (address ^ (address >>> 32));
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ protected void finalize() throws Throwable {
+ try {
+ if (address != 0) {
+ doFree(address);
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+ abstract void doFree(long context);
+
+ static final class CMAC_CTX extends NativeRef {
+ CMAC_CTX(long nativePointer) {
+ super(nativePointer);
+ }
+
+ @Override
+ void doFree(long context) {
+ NativeCrypto.CMAC_CTX_free(context);
+ }
+ }
+
+ static final class EC_GROUP extends NativeRef {
+ EC_GROUP(long ctx) {
+ super(ctx);
+ }
+
+ @Override
+ void doFree(long context) {
+ NativeCrypto.EC_GROUP_clear_free(context);
+ }
+ }
+
+ static final class EC_POINT extends NativeRef {
+ EC_POINT(long nativePointer) {
+ super(nativePointer);
+ }
+
+ @Override
+ void doFree(long context) {
+ NativeCrypto.EC_POINT_clear_free(context);
+ }
+ }
+
+ static final class EVP_CIPHER_CTX extends NativeRef {
+ EVP_CIPHER_CTX(long nativePointer) {
+ super(nativePointer);
+ }
+
+ @Override
+ void doFree(long context) {
+ NativeCrypto.EVP_CIPHER_CTX_free(context);
+ }
+ }
+
+ static final class EVP_MD_CTX extends NativeRef {
+ EVP_MD_CTX(long nativePointer) {
+ super(nativePointer);
+ }
+
+ @Override
+ void doFree(long context) {
+ NativeCrypto.EVP_MD_CTX_destroy(context);
+ }
+ }
+
+ static final class EVP_PKEY extends NativeRef {
+ EVP_PKEY(long nativePointer) {
+ super(nativePointer);
+ }
+
+ @Override
+ void doFree(long context) {
+ NativeCrypto.EVP_PKEY_free(context);
+ }
+ }
+
+ static final class EVP_PKEY_CTX extends NativeRef {
+ EVP_PKEY_CTX(long nativePointer) {
+ super(nativePointer);
+ }
+
+ @Override
+ void doFree(long context) {
+ NativeCrypto.EVP_PKEY_CTX_free(context);
+ }
+ }
+
+ static final class HMAC_CTX extends NativeRef {
+ HMAC_CTX(long nativePointer) {
+ super(nativePointer);
+ }
+
+ @Override
+ void doFree(long context) {
+ NativeCrypto.HMAC_CTX_free(context);
+ }
+ }
+
+ static final class SSL_SESSION extends NativeRef {
+ SSL_SESSION(long nativePointer) {
+ super(nativePointer);
+ }
+
+ @Override
+ void doFree(long context) {
+ NativeCrypto.SSL_SESSION_free(context);
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/NativeSsl.java b/repackaged/common/src/main/java/com/android/org/conscrypt/NativeSsl.java
new file mode 100644
index 0000000..82b2cc3
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/NativeSsl.java
@@ -0,0 +1,708 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.NativeConstants.SSL_MODE_CBC_RECORD_SPLITTING;
+import static com.android.org.conscrypt.NativeConstants.SSL_OP_CIPHER_SERVER_PREFERENCE;
+import static com.android.org.conscrypt.NativeConstants.SSL_OP_NO_TICKET;
+import static com.android.org.conscrypt.NativeConstants.SSL_RECEIVED_SHUTDOWN;
+import static com.android.org.conscrypt.NativeConstants.SSL_SENT_SHUTDOWN;
+import static com.android.org.conscrypt.NativeConstants.SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+import static com.android.org.conscrypt.NativeConstants.SSL_VERIFY_NONE;
+import static com.android.org.conscrypt.NativeConstants.SSL_VERIFY_PEER;
+
+import com.android.org.conscrypt.NativeCrypto.SSLHandshakeCallbacks;
+import com.android.org.conscrypt.SSLParametersImpl.AliasChooser;
+import com.android.org.conscrypt.SSLParametersImpl.PSKCallbacks;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.SocketException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import javax.crypto.SecretKey;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * A utility wrapper that abstracts operations on the underlying native SSL instance.
+ */
+final class NativeSsl {
+ private final SSLParametersImpl parameters;
+ private final SSLHandshakeCallbacks handshakeCallbacks;
+ private final AliasChooser aliasChooser;
+ private final PSKCallbacks pskCallbacks;
+ private X509Certificate[] localCertificates;
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+ private volatile long ssl;
+
+ private NativeSsl(long ssl, SSLParametersImpl parameters,
+ SSLHandshakeCallbacks handshakeCallbacks, AliasChooser aliasChooser,
+ PSKCallbacks pskCallbacks) {
+ this.ssl = ssl;
+ this.parameters = parameters;
+ this.handshakeCallbacks = handshakeCallbacks;
+ this.aliasChooser = aliasChooser;
+ this.pskCallbacks = pskCallbacks;
+ }
+
+ static NativeSsl newInstance(SSLParametersImpl parameters,
+ SSLHandshakeCallbacks handshakeCallbacks, AliasChooser chooser,
+ PSKCallbacks pskCallbacks) throws SSLException {
+ AbstractSessionContext ctx = parameters.getSessionContext();
+ long ssl = NativeCrypto.SSL_new(ctx.sslCtxNativePointer, ctx);
+ return new NativeSsl(ssl, parameters, handshakeCallbacks, chooser, pskCallbacks);
+ }
+
+ BioWrapper newBio() {
+ try {
+ return new BioWrapper();
+ } catch (SSLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ void offerToResumeSession(long sslSessionNativePointer) throws SSLException {
+ NativeCrypto.SSL_set_session(ssl, this, sslSessionNativePointer);
+ }
+
+ byte[] getSessionId() {
+ return NativeCrypto.SSL_session_id(ssl, this);
+ }
+
+ long getTime() {
+ return NativeCrypto.SSL_get_time(ssl, this);
+ }
+
+ long getTimeout() {
+ return NativeCrypto.SSL_get_timeout(ssl, this);
+ }
+
+ void setTimeout(long millis) {
+ NativeCrypto.SSL_set_timeout(ssl, this, millis);
+ }
+
+ String getCipherSuite() {
+ return NativeCrypto.cipherSuiteToJava(NativeCrypto.SSL_get_current_cipher(ssl, this));
+ }
+
+ X509Certificate[] getPeerCertificates() throws CertificateException {
+ byte[][] encoded = NativeCrypto.SSL_get0_peer_certificates(ssl, this);
+ return encoded == null ? null : SSLUtils.decodeX509CertificateChain(encoded);
+ }
+
+ X509Certificate[] getLocalCertificates() {
+ return localCertificates;
+ }
+
+ byte[] getPeerCertificateOcspData() {
+ return NativeCrypto.SSL_get_ocsp_response(ssl, this);
+ }
+
+ byte[] getTlsUnique() {
+ return NativeCrypto.SSL_get_tls_unique(ssl, this);
+ }
+
+ byte[] exportKeyingMaterial(String label, byte[] context, int length) throws SSLException {
+ if (label == null) {
+ throw new NullPointerException("Label is null");
+ }
+ byte[] labelBytes = label.getBytes(Charset.forName("US-ASCII"));
+ return NativeCrypto.SSL_export_keying_material(ssl, this, labelBytes, context, length);
+ }
+
+ byte[] getPeerTlsSctData() {
+ return NativeCrypto.SSL_get_signed_cert_timestamp_list(ssl, this);
+ }
+
+ /**
+ * @see NativeCrypto.SSLHandshakeCallbacks#clientPSKKeyRequested(String, byte[], byte[])
+ */
+ @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
+ int clientPSKKeyRequested(String identityHint, byte[] identityBytesOut, byte[] key) {
+ PSKKeyManager pskKeyManager = parameters.getPSKKeyManager();
+ if (pskKeyManager == null) {
+ return 0;
+ }
+
+ String identity = pskCallbacks.chooseClientPSKIdentity(pskKeyManager, identityHint);
+ // Store identity in NULL-terminated modified UTF-8 representation into ientityBytesOut
+ byte[] identityBytes;
+ if (identity == null) {
+ identity = "";
+ identityBytes = EmptyArray.BYTE;
+ } else if (identity.isEmpty()) {
+ identityBytes = EmptyArray.BYTE;
+ } else {
+ try {
+ identityBytes = identity.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 encoding not supported", e);
+ }
+ }
+ if (identityBytes.length + 1 > identityBytesOut.length) {
+ // Insufficient space in the output buffer
+ return 0;
+ }
+ if (identityBytes.length > 0) {
+ System.arraycopy(identityBytes, 0, identityBytesOut, 0, identityBytes.length);
+ }
+ identityBytesOut[identityBytes.length] = 0;
+
+ SecretKey secretKey = pskCallbacks.getPSKKey(pskKeyManager, identityHint, identity);
+ byte[] secretKeyBytes = secretKey.getEncoded();
+ if (secretKeyBytes == null) {
+ return 0;
+ } else if (secretKeyBytes.length > key.length) {
+ // Insufficient space in the output buffer
+ return 0;
+ }
+ System.arraycopy(secretKeyBytes, 0, key, 0, secretKeyBytes.length);
+ return secretKeyBytes.length;
+ }
+
+ /**
+ * @see NativeCrypto.SSLHandshakeCallbacks#serverPSKKeyRequested(String, String, byte[])
+ */
+ @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
+ int serverPSKKeyRequested(String identityHint, String identity, byte[] key) {
+ PSKKeyManager pskKeyManager = parameters.getPSKKeyManager();
+ if (pskKeyManager == null) {
+ return 0;
+ }
+ SecretKey secretKey = pskCallbacks.getPSKKey(pskKeyManager, identityHint, identity);
+ byte[] secretKeyBytes = secretKey.getEncoded();
+ if (secretKeyBytes == null) {
+ return 0;
+ } else if (secretKeyBytes.length > key.length) {
+ return 0;
+ }
+ System.arraycopy(secretKeyBytes, 0, key, 0, secretKeyBytes.length);
+ return secretKeyBytes.length;
+ }
+
+ void chooseClientCertificate(byte[] keyTypeBytes, int[] signatureAlgs,
+ byte[][] asn1DerEncodedPrincipals)
+ throws SSLException, CertificateEncodingException {
+ Set<String> keyTypesSet = SSLUtils.getSupportedClientKeyTypes(keyTypeBytes, signatureAlgs);
+ String[] keyTypes = keyTypesSet.toArray(new String[0]);
+
+ X500Principal[] issuers;
+ if (asn1DerEncodedPrincipals == null) {
+ issuers = null;
+ } else {
+ issuers = new X500Principal[asn1DerEncodedPrincipals.length];
+ for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
+ issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
+ }
+ }
+ X509KeyManager keyManager = parameters.getX509KeyManager();
+ String alias = (keyManager != null)
+ ? aliasChooser.chooseClientAlias(keyManager, issuers, keyTypes)
+ : null;
+ setCertificate(alias);
+ }
+
+ private void setCertificate(String alias) throws CertificateEncodingException, SSLException {
+ if (alias == null) {
+ return;
+ }
+ X509KeyManager keyManager = parameters.getX509KeyManager();
+ if (keyManager == null) {
+ return;
+ }
+ PrivateKey privateKey = keyManager.getPrivateKey(alias);
+ if (privateKey == null) {
+ return;
+ }
+ localCertificates = keyManager.getCertificateChain(alias);
+ if (localCertificates == null) {
+ return;
+ }
+ int numLocalCerts = localCertificates.length;
+ PublicKey publicKey = (numLocalCerts > 0) ? localCertificates[0].getPublicKey() : null;
+
+ // Encode the local certificates.
+ byte[][] encodedLocalCerts = new byte[numLocalCerts][];
+ for (int i = 0; i < numLocalCerts; ++i) {
+ encodedLocalCerts[i] = localCertificates[i].getEncoded();
+ }
+
+ // Convert the key so we can access a native reference.
+ final OpenSSLKey key;
+ try {
+ key = OpenSSLKey.fromPrivateKeyForTLSStackOnly(privateKey, publicKey);
+ } catch (InvalidKeyException e) {
+ throw new SSLException(e);
+ }
+
+ // Set the local certs and private key.
+ NativeCrypto.setLocalCertsAndPrivateKey(ssl, this, encodedLocalCerts, key.getNativeRef());
+ }
+
+ String getVersion() {
+ return NativeCrypto.SSL_get_version(ssl, this);
+ }
+
+ String getRequestedServerName() {
+ return NativeCrypto.SSL_get_servername(ssl, this);
+ }
+
+ byte[] getTlsChannelId() throws SSLException {
+ return NativeCrypto.SSL_get_tls_channel_id(ssl, this);
+ }
+
+ void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOException {
+ boolean enableSessionCreation = parameters.getEnableSessionCreation();
+ if (!enableSessionCreation) {
+ NativeCrypto.SSL_set_session_creation_enabled(ssl, this, false);
+ }
+
+ // Allow servers to trigger renegotiation. Some inadvisable server
+ // configurations cause them to attempt to renegotiate during
+ // certain protocols.
+ NativeCrypto.SSL_accept_renegotiations(ssl, this);
+
+ if (isClient()) {
+ NativeCrypto.SSL_set_connect_state(ssl, this);
+
+ // Configure OCSP and CT extensions for client
+ NativeCrypto.SSL_enable_ocsp_stapling(ssl, this);
+ if (parameters.isCTVerificationEnabled(hostname)) {
+ NativeCrypto.SSL_enable_signed_cert_timestamps(ssl, this);
+ }
+ } else {
+ NativeCrypto.SSL_set_accept_state(ssl, this);
+
+ // Configure OCSP for server
+ if (parameters.getOCSPResponse() != null) {
+ NativeCrypto.SSL_enable_ocsp_stapling(ssl, this);
+ }
+ }
+
+ if (parameters.getEnabledProtocols().length == 0 && parameters.isEnabledProtocolsFiltered) {
+ throw new SSLHandshakeException("No enabled protocols; "
+ + NativeCrypto.OBSOLETE_PROTOCOL_SSLV3
+ + " is no longer supported and was filtered from the list");
+ }
+ NativeCrypto.setEnabledProtocols(ssl, this, parameters.enabledProtocols);
+ NativeCrypto.setEnabledCipherSuites(
+ ssl, this, parameters.enabledCipherSuites, parameters.enabledProtocols);
+
+ if (parameters.applicationProtocols.length > 0) {
+ NativeCrypto.setApplicationProtocols(ssl, this, isClient(), parameters.applicationProtocols);
+ }
+ if (!isClient() && parameters.applicationProtocolSelector != null) {
+ NativeCrypto.setHasApplicationProtocolSelector(ssl, this, true);
+ }
+
+ // setup server certificates and private keys.
+ // clients will receive a call back to request certificates.
+ if (!isClient()) {
+ NativeCrypto.SSL_set_options(ssl, this, SSL_OP_CIPHER_SERVER_PREFERENCE);
+
+ if (parameters.sctExtension != null) {
+ NativeCrypto.SSL_set_signed_cert_timestamp_list(ssl, this, parameters.sctExtension);
+ }
+
+ if (parameters.ocspResponse != null) {
+ NativeCrypto.SSL_set_ocsp_response(ssl, this, parameters.ocspResponse);
+ }
+ }
+
+ enablePSKKeyManagerIfRequested();
+
+ if (parameters.useSessionTickets) {
+ NativeCrypto.SSL_clear_options(ssl, this, SSL_OP_NO_TICKET);
+ } else {
+ NativeCrypto.SSL_set_options(
+ ssl, this, NativeCrypto.SSL_get_options(ssl, this) | SSL_OP_NO_TICKET);
+ }
+
+ if (parameters.getUseSni() && AddressUtils.isValidSniHostname(hostname)) {
+ NativeCrypto.SSL_set_tlsext_host_name(ssl, this, hostname);
+ }
+
+ // BEAST attack mitigation (1/n-1 record splitting for CBC cipher suites
+ // with TLSv1 and SSLv3).
+ NativeCrypto.SSL_set_mode(ssl, this, SSL_MODE_CBC_RECORD_SPLITTING);
+
+ setCertificateValidation();
+ setTlsChannelId(channelIdPrivateKey);
+ }
+
+ void configureServerCertificate() throws IOException {
+ verifyWithSniMatchers(getRequestedServerName());
+ if (isClient()) {
+ return;
+ }
+ X509KeyManager keyManager = parameters.getX509KeyManager();
+ if (keyManager != null) {
+ for (String keyType : getCipherKeyTypes()) {
+ try {
+ setCertificate(aliasChooser.chooseServerAlias(keyManager, keyType));
+ } catch (CertificateEncodingException e) {
+ throw new IOException(e);
+ }
+ }
+ }
+ }
+
+ private void verifyWithSniMatchers(String serverName) throws SSLHandshakeException {
+ if (!AddressUtils.isValidSniHostname(serverName)) {
+ return;
+ }
+
+ if (!Platform.serverNamePermitted(parameters, serverName)) {
+ throw new SSLHandshakeException("SNI match failed: " + serverName);
+ }
+ }
+
+ private Set<String> getCipherKeyTypes() {
+ Set<String> keyTypes = new HashSet<>();
+ for (long sslCipherNativePointer : NativeCrypto.SSL_get_ciphers(ssl, this)) {
+ String keyType = SSLUtils.getServerX509KeyType(sslCipherNativePointer);
+ if (keyType != null) {
+ keyTypes.add(keyType);
+ }
+ }
+ return keyTypes;
+ }
+
+ // TODO(nathanmittler): Remove once after we switch to the engine socket.
+ void doHandshake(FileDescriptor fd, int timeoutMillis)
+ throws CertificateException, IOException {
+ lock.readLock().lock();
+ try {
+ if (isClosed() || fd == null || !fd.valid()) {
+ throw new SocketException("Socket is closed");
+ }
+ NativeCrypto.SSL_do_handshake(ssl, this, fd, handshakeCallbacks, timeoutMillis);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ int doHandshake() throws IOException {
+ lock.readLock().lock();
+ try {
+ return NativeCrypto.ENGINE_SSL_do_handshake(ssl, this, handshakeCallbacks);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ // TODO(nathanmittler): Remove once after we switch to the engine socket.
+ int read(FileDescriptor fd, byte[] buf, int offset, int len, int timeoutMillis)
+ throws IOException {
+ lock.readLock().lock();
+ try {
+ if (isClosed() || fd == null || !fd.valid()) {
+ throw new SocketException("Socket is closed");
+ }
+ return NativeCrypto
+ .SSL_read(ssl, this, fd, handshakeCallbacks, buf, offset, len, timeoutMillis);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ // TODO(nathanmittler): Remove once after we switch to the engine socket.
+ void write(FileDescriptor fd, byte[] buf, int offset, int len, int timeoutMillis)
+ throws IOException {
+ lock.readLock().lock();
+ try {
+ if (isClosed() || fd == null || !fd.valid()) {
+ throw new SocketException("Socket is closed");
+ }
+ NativeCrypto
+ .SSL_write(ssl, this, fd, handshakeCallbacks, buf, offset, len, timeoutMillis);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
+ private void enablePSKKeyManagerIfRequested() throws SSLException {
+ // Enable Pre-Shared Key (PSK) key exchange if requested
+ PSKKeyManager pskKeyManager = parameters.getPSKKeyManager();
+ if (pskKeyManager != null) {
+ boolean pskEnabled = false;
+ for (String enabledCipherSuite : parameters.enabledCipherSuites) {
+ if ((enabledCipherSuite != null) && enabledCipherSuite.contains("PSK")) {
+ pskEnabled = true;
+ break;
+ }
+ }
+ if (pskEnabled) {
+ if (isClient()) {
+ NativeCrypto.set_SSL_psk_client_callback_enabled(ssl, this, true);
+ } else {
+ NativeCrypto.set_SSL_psk_server_callback_enabled(ssl, this, true);
+ String identityHint = pskCallbacks.chooseServerPSKIdentityHint(pskKeyManager);
+ NativeCrypto.SSL_use_psk_identity_hint(ssl, this, identityHint);
+ }
+ }
+ }
+ }
+
+ private void setTlsChannelId(OpenSSLKey channelIdPrivateKey) throws SSLException {
+ if (!parameters.channelIdEnabled) {
+ return;
+ }
+
+ if (parameters.getUseClientMode()) {
+ // Client-side TLS Channel ID
+ if (channelIdPrivateKey == null) {
+ throw new SSLHandshakeException("Invalid TLS channel ID key specified");
+ }
+ NativeCrypto.SSL_set1_tls_channel_id(ssl, this, channelIdPrivateKey.getNativeRef());
+ } else {
+ // Server-side TLS Channel ID
+ NativeCrypto.SSL_enable_tls_channel_id(ssl, this);
+ }
+ }
+
+ private void setCertificateValidation() throws SSLException {
+ // setup peer certificate verification
+ if (!isClient()) {
+ // needing client auth takes priority...
+ boolean certRequested;
+ if (parameters.getNeedClientAuth()) {
+ NativeCrypto.SSL_set_verify(ssl, this, SSL_VERIFY_PEER
+ | SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
+ certRequested = true;
+ // ... over just wanting it...
+ } else if (parameters.getWantClientAuth()) {
+ NativeCrypto.SSL_set_verify(ssl, this, SSL_VERIFY_PEER);
+ certRequested = true;
+ // ... and we must disable verification if we don't want client auth.
+ } else {
+ NativeCrypto.SSL_set_verify(ssl, this, SSL_VERIFY_NONE);
+ certRequested = false;
+ }
+
+ if (certRequested) {
+ X509TrustManager trustManager = parameters.getX509TrustManager();
+ X509Certificate[] issuers = trustManager.getAcceptedIssuers();
+ if (issuers != null && issuers.length != 0) {
+ byte[][] issuersBytes;
+ try {
+ issuersBytes = SSLUtils.encodeSubjectX509Principals(issuers);
+ } catch (CertificateEncodingException e) {
+ throw new SSLException("Problem encoding principals", e);
+ }
+ NativeCrypto.SSL_set_client_CA_list(ssl, this, issuersBytes);
+ }
+ }
+ }
+ }
+
+ void interrupt() {
+ NativeCrypto.SSL_interrupt(ssl, this);
+ }
+
+ // TODO(nathanmittler): Remove once after we switch to the engine socket.
+ void shutdown(FileDescriptor fd) throws IOException {
+ NativeCrypto.SSL_shutdown(ssl, this, fd, handshakeCallbacks);
+ }
+
+ void shutdown() throws IOException {
+ lock.readLock().lock();
+ try {
+ NativeCrypto.ENGINE_SSL_shutdown(ssl, this, handshakeCallbacks);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ boolean wasShutdownReceived() {
+ lock.readLock().lock();
+ try {
+ return (NativeCrypto.SSL_get_shutdown(ssl, this) & SSL_RECEIVED_SHUTDOWN) != 0;
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ boolean wasShutdownSent() {
+ lock.readLock().lock();
+ try {
+ return (NativeCrypto.SSL_get_shutdown(ssl, this) & SSL_SENT_SHUTDOWN) != 0;
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ int readDirectByteBuffer(long destAddress, int destLength)
+ throws IOException, CertificateException {
+ lock.readLock().lock();
+ try {
+ return NativeCrypto.ENGINE_SSL_read_direct(
+ ssl, this, destAddress, destLength, handshakeCallbacks);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ int writeDirectByteBuffer(long sourceAddress, int sourceLength) throws IOException {
+ lock.readLock().lock();
+ try {
+ return NativeCrypto.ENGINE_SSL_write_direct(
+ ssl, this, sourceAddress, sourceLength, handshakeCallbacks);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ void forceRead() throws IOException {
+ lock.readLock().lock();
+ try {
+ NativeCrypto.ENGINE_SSL_force_read(ssl, this, handshakeCallbacks);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ int getPendingReadableBytes() {
+ lock.readLock().lock();
+ try {
+ if (!isClosed()) {
+ return NativeCrypto.SSL_pending_readable_bytes(ssl, this);
+ }
+ return 0;
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ int getMaxSealOverhead() {
+ return NativeCrypto.SSL_max_seal_overhead(ssl, this);
+ }
+
+ void close() {
+ lock.writeLock().lock();
+ try {
+ if (!isClosed()) {
+ long toFree = ssl;
+ ssl = 0L;
+ NativeCrypto.SSL_free(toFree, this);
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ boolean isClosed() {
+ return ssl == 0L;
+ }
+
+ int getError(int result) {
+ return NativeCrypto.SSL_get_error(ssl, this, result);
+ }
+
+ byte[] getApplicationProtocol() {
+ return NativeCrypto.getApplicationProtocol(ssl, this);
+ }
+
+ private boolean isClient() {
+ return parameters.getUseClientMode();
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ protected final void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * A utility wrapper that abstracts operations on the underlying native BIO instance.
+ */
+ final class BioWrapper {
+ private volatile long bio;
+
+ private BioWrapper() throws SSLException {
+ this.bio = NativeCrypto.SSL_BIO_new(ssl, NativeSsl.this);
+ }
+
+ int getPendingWrittenBytes() {
+ lock.readLock().lock();
+ try {
+ return (bio == 0L) ? 0 : NativeCrypto.SSL_pending_written_bytes_in_BIO(bio);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ int writeDirectByteBuffer(long address, int length) throws IOException {
+ lock.readLock().lock();
+ try {
+ if (isClosed()) {
+ throw new SSLException("Connection closed");
+ }
+ return NativeCrypto.ENGINE_SSL_write_BIO_direct(
+ ssl, NativeSsl.this, bio, address, length, handshakeCallbacks);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ int readDirectByteBuffer(long destAddress, int destLength) throws IOException {
+ lock.readLock().lock();
+ try {
+ if (isClosed()) {
+ throw new SSLException("Connection closed");
+ }
+ return NativeCrypto.ENGINE_SSL_read_BIO_direct(
+ ssl, NativeSsl.this, bio, destAddress, destLength, handshakeCallbacks);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ void close() {
+ lock.writeLock().lock();
+ try {
+ long toFree = bio;
+ bio = 0L;
+ if (toFree != 0L) {
+ NativeCrypto.BIO_free_all(toFree);
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/NativeSslSession.java b/repackaged/common/src/main/java/com/android/org/conscrypt/NativeSslSession.java
new file mode 100644
index 0000000..7621ae2
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/NativeSslSession.java
@@ -0,0 +1,481 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License", "www.google.com", 443);
+ * 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.SSLUtils.SessionType.OPEN_SSL_WITH_OCSP;
+import static com.android.org.conscrypt.SSLUtils.SessionType.OPEN_SSL_WITH_TLS_SCT;
+import static com.android.org.conscrypt.SSLUtils.SessionType.isSupportedType;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+
+/**
+ * A utility wrapper that abstracts operations on the underlying native SSL_SESSION instance.
+ * <p>
+ * This is abstract only to support mocking for tests.
+ */
+abstract class NativeSslSession {
+ private static final Logger logger = Logger.getLogger(NativeSslSession.class.getName());
+
+ /**
+ * Creates a new instance. Since BoringSSL does not provide an API to get access to all
+ * session information via the SSL_SESSION, we get some values (e.g. peer certs) from
+ * the {@link ConscryptSession} instead (i.e. the SSL object).
+ */
+ static NativeSslSession newInstance(NativeRef.SSL_SESSION ref, ConscryptSession session)
+ throws SSLPeerUnverifiedException {
+ AbstractSessionContext context = (AbstractSessionContext) session.getSessionContext();
+ if (context instanceof ClientSessionContext) {
+ return new Impl(context, ref, session.getPeerHost(), session.getPeerPort(),
+ session.getPeerCertificates(), getOcspResponse(session),
+ session.getPeerSignedCertificateTimestamp());
+ }
+
+ // Server's will be cached by ID and won't have any of the extra fields.
+ return new Impl(context, ref, null, -1, null, null, null);
+ }
+
+ private static byte[] getOcspResponse(ConscryptSession session) {
+ List<byte[]> ocspResponseList = session.getStatusResponses();
+ if (ocspResponseList.size() >= 1) {
+ return ocspResponseList.get(0);
+ }
+ return null;
+ }
+
+ /**
+ * Creates a new {@link NativeSslSession} instance from the provided serialized bytes, which
+ * were generated by {@link #toBytes()}.
+ *
+ * @return The new instance if successful. If unable to parse the bytes for any reason, returns
+ * {@code null}.
+ */
+ static NativeSslSession newInstance(
+ AbstractSessionContext context, byte[] data, String host, int port) {
+ ByteBuffer buf = ByteBuffer.wrap(data);
+ try {
+ int type = buf.getInt();
+ if (!isSupportedType(type)) {
+ throw new IOException("Unexpected type ID: " + type);
+ }
+
+ int length = buf.getInt();
+ checkRemaining(buf, length);
+
+ byte[] sessionData = new byte[length];
+ buf.get(sessionData);
+
+ int count = buf.getInt();
+ checkRemaining(buf, count);
+
+ java.security.cert.X509Certificate[] peerCerts =
+ new java.security.cert.X509Certificate[count];
+ for (int i = 0; i < count; i++) {
+ length = buf.getInt();
+ checkRemaining(buf, length);
+
+ byte[] certData = new byte[length];
+ buf.get(certData);
+ try {
+ peerCerts[i] = OpenSSLX509Certificate.fromX509Der(certData);
+ } catch (Exception e) {
+ throw new IOException("Can not read certificate " + i + "/" + count);
+ }
+ }
+
+ byte[] ocspData = null;
+ if (type >= OPEN_SSL_WITH_OCSP.value) {
+ // We only support one OCSP response now, but in the future
+ // we may support RFC 6961 which has multiple.
+ int countOcspResponses = buf.getInt();
+ checkRemaining(buf, countOcspResponses);
+
+ if (countOcspResponses >= 1) {
+ int ocspLength = buf.getInt();
+ checkRemaining(buf, ocspLength);
+
+ ocspData = new byte[ocspLength];
+ buf.get(ocspData);
+
+ // Skip the rest of the responses.
+ for (int i = 1; i < countOcspResponses; i++) {
+ ocspLength = buf.getInt();
+ checkRemaining(buf, ocspLength);
+ buf.position(buf.position() + ocspLength);
+ }
+ }
+ }
+
+ byte[] tlsSctData = null;
+ if (type == OPEN_SSL_WITH_TLS_SCT.value) {
+ int tlsSctDataLength = buf.getInt();
+ checkRemaining(buf, tlsSctDataLength);
+
+ if (tlsSctDataLength > 0) {
+ tlsSctData = new byte[tlsSctDataLength];
+ buf.get(tlsSctData);
+ }
+ }
+
+ if (buf.remaining() != 0) {
+ log(new AssertionError("Read entire session, but data still remains; rejecting"));
+ return null;
+ }
+
+ NativeRef.SSL_SESSION ref =
+ new NativeRef.SSL_SESSION(NativeCrypto.d2i_SSL_SESSION(sessionData));
+ return new Impl(context, ref, host, port, peerCerts, ocspData, tlsSctData);
+ } catch (IOException | BufferUnderflowException e) {
+ log(e);
+ return null;
+ }
+ }
+
+ abstract byte[] getId();
+
+ abstract boolean isValid();
+
+ /**
+ * Returns whether this session should only ever be used for resumption once.
+ */
+ abstract boolean isSingleUse();
+
+ abstract void offerToResume(NativeSsl ssl) throws SSLException;
+
+ abstract String getCipherSuite();
+
+ abstract String getProtocol();
+
+ abstract String getPeerHost();
+
+ abstract int getPeerPort();
+
+ /**
+ * Returns the OCSP stapled response. The returned array is not copied; the caller must
+ * either not modify the returned array or make a copy.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc6066">RFC 6066</a>
+ * @see <a href="https://tools.ietf.org/html/rfc6961">RFC 6961</a>
+ */
+ abstract byte[] getPeerOcspStapledResponse();
+
+ /**
+ * Returns the signed certificate timestamp (SCT) received from the peer. The returned array
+ * is not copied; the caller must either not modify the returned array or make a copy.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc6962">RFC 6962</a>
+ */
+ abstract byte[] getPeerSignedCertificateTimestamp();
+
+ /**
+ * Converts the given session to bytes.
+ *
+ * @return session data as bytes or null if the session can't be converted
+ */
+ abstract byte[] toBytes();
+
+ /**
+ * Converts this object to a {@link SSLSession}. The returned session will support only a
+ * subset of the {@link SSLSession} API.
+ */
+ abstract SSLSession toSSLSession();
+
+ /**
+ * The session wrapper implementation.
+ */
+ private static final class Impl extends NativeSslSession {
+ private final NativeRef.SSL_SESSION ref;
+
+ // BoringSSL offers no API to obtain these values directly from the SSL_SESSION.
+ private final AbstractSessionContext context;
+ private final String host;
+ private final int port;
+ private final String protocol;
+ private final String cipherSuite;
+ private final java.security.cert.X509Certificate[] peerCertificates;
+ private final byte[] peerOcspStapledResponse;
+ private final byte[] peerSignedCertificateTimestamp;
+
+ private Impl(AbstractSessionContext context, NativeRef.SSL_SESSION ref, String host,
+ int port, java.security.cert.X509Certificate[] peerCertificates,
+ byte[] peerOcspStapledResponse, byte[] peerSignedCertificateTimestamp) {
+ this.context = context;
+ this.host = host;
+ this.port = port;
+ this.peerCertificates = peerCertificates;
+ this.peerOcspStapledResponse = peerOcspStapledResponse;
+ this.peerSignedCertificateTimestamp = peerSignedCertificateTimestamp;
+ this.protocol = NativeCrypto.SSL_SESSION_get_version(ref.address);
+ this.cipherSuite =
+ NativeCrypto.cipherSuiteToJava(NativeCrypto.SSL_SESSION_cipher(ref.address));
+ this.ref = ref;
+ }
+
+ @Override
+ byte[] getId() {
+ return NativeCrypto.SSL_SESSION_session_id(ref.address);
+ }
+
+ private long getCreationTime() {
+ return NativeCrypto.SSL_SESSION_get_time(ref.address);
+ }
+
+ @Override
+ boolean isValid() {
+ long creationTimeMillis = getCreationTime();
+ // Use the minimum of the timeout from the context and the session.
+ long timeoutMillis = Math.max(0,
+ Math.min(context.getSessionTimeout(),
+ NativeCrypto.SSL_SESSION_get_timeout(ref.address)))
+ * 1000;
+ return (System.currentTimeMillis() - timeoutMillis) < creationTimeMillis;
+ }
+
+ @Override
+ boolean isSingleUse() {
+ return NativeCrypto.SSL_SESSION_should_be_single_use(ref.address);
+ }
+
+ @Override
+ void offerToResume(NativeSsl ssl) throws SSLException {
+ ssl.offerToResumeSession(ref.address);
+ }
+
+ @Override
+ String getCipherSuite() {
+ return cipherSuite;
+ }
+
+ @Override
+ String getProtocol() {
+ return protocol;
+ }
+
+ @Override
+ String getPeerHost() {
+ return host;
+ }
+
+ @Override
+ int getPeerPort() {
+ return port;
+ }
+
+ @Override
+ byte[] getPeerOcspStapledResponse() {
+ return peerOcspStapledResponse;
+ }
+
+ @Override
+ byte[] getPeerSignedCertificateTimestamp() {
+ return peerSignedCertificateTimestamp;
+ }
+
+ @Override
+ byte[] toBytes() {
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream daos = new DataOutputStream(baos);
+
+ daos.writeInt(OPEN_SSL_WITH_TLS_SCT.value); // session type ID
+
+ // Session data.
+ byte[] data = NativeCrypto.i2d_SSL_SESSION(ref.address);
+ daos.writeInt(data.length);
+ daos.write(data);
+
+ // Certificates.
+ daos.writeInt(peerCertificates.length);
+
+ for (Certificate cert : peerCertificates) {
+ data = cert.getEncoded();
+ daos.writeInt(data.length);
+ daos.write(data);
+ }
+
+ if (peerOcspStapledResponse != null) {
+ daos.writeInt(1);
+ daos.writeInt(peerOcspStapledResponse.length);
+ daos.write(peerOcspStapledResponse);
+ } else {
+ daos.writeInt(0);
+ }
+
+ if (peerSignedCertificateTimestamp != null) {
+ daos.writeInt(peerSignedCertificateTimestamp.length);
+ daos.write(peerSignedCertificateTimestamp);
+ } else {
+ daos.writeInt(0);
+ }
+
+ // TODO: local certificates?
+
+ return baos.toByteArray();
+ } catch (IOException e) {
+ // TODO(nathanmittler): Better error handling?
+ logger.log(Level.WARNING, "Failed to convert saved SSL Session: ", e);
+ return null;
+ } catch (CertificateEncodingException e) {
+ log(e);
+ return null;
+ }
+ }
+
+ @Override
+ SSLSession toSSLSession() {
+ return new SSLSession() {
+ @Override
+ public byte[] getId() {
+ return Impl.this.getId();
+ }
+
+ @Override
+ public String getCipherSuite() {
+ return Impl.this.getCipherSuite();
+ }
+
+ @Override
+ public String getProtocol() {
+ return Impl.this.getProtocol();
+ }
+
+ @Override
+ public String getPeerHost() {
+ return Impl.this.getPeerHost();
+ }
+
+ @Override
+ public int getPeerPort() {
+ return Impl.this.getPeerPort();
+ }
+
+ @Override
+ public long getCreationTime() {
+ return Impl.this.getCreationTime();
+ }
+
+ @Override
+ public boolean isValid() {
+ return Impl.this.isValid();
+ }
+
+ // UNSUPPORTED OPERATIONS
+
+ @Override
+ public SSLSessionContext getSessionContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getLastAccessedTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void invalidate() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putValue(String s, Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getValue(String s) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeValue(String s) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getPeerCertificates() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getLocalCertificates() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public javax.security.cert.X509Certificate[] getPeerCertificateChain() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getPeerPrincipal() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getLocalPrincipal() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPacketBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getApplicationBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ }
+
+ private static void log(Throwable t) {
+ // TODO(nathanmittler): Better error handling?
+ logger.log(Level.INFO, "Error inflating SSL session: {0}",
+ (t.getMessage() != null ? t.getMessage() : t.getClass().getName()));
+ }
+
+ private static void checkRemaining(ByteBuffer buf, int length) throws IOException {
+ if (length < 0) {
+ throw new IOException("Length is negative: " + length);
+ }
+ if (length > buf.remaining()) {
+ throw new IOException(
+ "Length of blob is longer than available: " + length + " > " + buf.remaining());
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OAEPParameters.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OAEPParameters.java
new file mode 100644
index 0000000..cf4ea9d
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OAEPParameters.java
@@ -0,0 +1,291 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.IOException;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+import java.util.HashMap;
+import java.util.Map;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+
+/**
+ * AlgorithmParameters implementation for OAEP. The only supported encoding format is ASN.1,
+ * as specified in RFC 4055 section 4.1.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class OAEPParameters extends AlgorithmParametersSpi {
+
+ private static final Map<String, String> OID_TO_NAME = new HashMap<String, String>();
+ private static final Map<String, String> NAME_TO_OID = new HashMap<String, String>();
+ static {
+ OID_TO_NAME.put("1.3.14.3.2.26", "SHA-1");
+ OID_TO_NAME.put("2.16.840.1.101.3.4.2.4", "SHA-224");
+ OID_TO_NAME.put("2.16.840.1.101.3.4.2.1", "SHA-256");
+ OID_TO_NAME.put("2.16.840.1.101.3.4.2.2", "SHA-384");
+ OID_TO_NAME.put("2.16.840.1.101.3.4.2.3", "SHA-512");
+ for (Map.Entry<String, String> entry : OID_TO_NAME.entrySet()) {
+ NAME_TO_OID.put(entry.getValue(), entry.getKey());
+ }
+ }
+ private static final String MGF1_OID = "1.2.840.113549.1.1.8";
+ private static final String PSPECIFIED_OID = "1.2.840.113549.1.1.9";
+
+ private OAEPParameterSpec spec = OAEPParameterSpec.DEFAULT;
+
+ public OAEPParameters() {}
+
+ @Override
+ protected void engineInit(AlgorithmParameterSpec algorithmParameterSpec)
+ throws InvalidParameterSpecException {
+ if (algorithmParameterSpec instanceof OAEPParameterSpec) {
+ this.spec = (OAEPParameterSpec) algorithmParameterSpec;
+ } else {
+ throw new InvalidParameterSpecException("Only OAEPParameterSpec is supported");
+ }
+ }
+
+ @Override
+ protected void engineInit(byte[] bytes) throws IOException {
+ long readRef = 0;
+ long seqRef = 0;
+ try {
+ readRef = NativeCrypto.asn1_read_init(bytes);
+ seqRef = NativeCrypto.asn1_read_sequence(readRef);
+ PSource.PSpecified pSpecified = PSource.PSpecified.DEFAULT;
+ String hash = readHash(seqRef);
+ String mgfHash = readMgfHash(seqRef);
+ if (NativeCrypto.asn1_read_next_tag_is(seqRef, 2)) {
+ long pSourceRef = 0;
+ long pSourceSeqRef = 0;
+ try {
+ pSourceRef = NativeCrypto.asn1_read_tagged(seqRef);
+ pSourceSeqRef = NativeCrypto.asn1_read_sequence(pSourceRef);
+ String pSourceOid = NativeCrypto.asn1_read_oid(pSourceSeqRef);
+ if (!pSourceOid.equals(PSPECIFIED_OID)) {
+ throw new IOException("Error reading ASN.1 encoding");
+ }
+ pSpecified = new PSource.PSpecified(
+ NativeCrypto.asn1_read_octetstring(pSourceSeqRef));
+ if (!NativeCrypto.asn1_read_is_empty(pSourceSeqRef)) {
+ throw new IOException("Error reading ASN.1 encoding");
+ }
+ } finally {
+ NativeCrypto.asn1_read_free(pSourceSeqRef);
+ NativeCrypto.asn1_read_free(pSourceRef);
+ }
+ }
+
+ if (!NativeCrypto.asn1_read_is_empty(seqRef)
+ || !NativeCrypto.asn1_read_is_empty(readRef)) {
+ throw new IOException("Error reading ASN.1 encoding");
+ }
+ this.spec = new OAEPParameterSpec(hash, "MGF1", new MGF1ParameterSpec(mgfHash),
+ pSpecified);
+ } finally {
+ NativeCrypto.asn1_read_free(seqRef);
+ NativeCrypto.asn1_read_free(readRef);
+ }
+ }
+
+ @Override
+ protected void engineInit(byte[] bytes, String format) throws IOException {
+ if ((format == null) || format.equals("ASN.1")) {
+ engineInit(bytes);
+ } else {
+ throw new IOException("Unsupported format: " + format);
+ }
+ }
+
+ // Shared with PSSParameters, since they share some of their encoded form
+ static String readHash(long seqRef) throws IOException {
+ if (NativeCrypto.asn1_read_next_tag_is(seqRef, 0)) {
+ long hashRef = 0;
+ try {
+ hashRef = NativeCrypto.asn1_read_tagged(seqRef);
+ return getHashName(hashRef);
+ } finally {
+ NativeCrypto.asn1_read_free(hashRef);
+ }
+ }
+ return "SHA-1";
+ }
+
+ // Shared with PSSParameters, since they share some of their encoded form
+ static String readMgfHash(long seqRef) throws IOException {
+ if (NativeCrypto.asn1_read_next_tag_is(seqRef, 1)) {
+ long mgfRef = 0;
+ long mgfSeqRef = 0;
+ try {
+ mgfRef = NativeCrypto.asn1_read_tagged(seqRef);
+ mgfSeqRef = NativeCrypto.asn1_read_sequence(mgfRef);
+ String mgfOid = NativeCrypto.asn1_read_oid(mgfSeqRef);
+ if (!mgfOid.equals(MGF1_OID)) {
+ throw new IOException("Error reading ASN.1 encoding");
+ }
+ String mgfHash = getHashName(mgfSeqRef);
+ if (!NativeCrypto.asn1_read_is_empty(mgfSeqRef)) {
+ throw new IOException("Error reading ASN.1 encoding");
+ }
+ return mgfHash;
+ } finally {
+ NativeCrypto.asn1_read_free(mgfSeqRef);
+ NativeCrypto.asn1_read_free(mgfRef);
+ }
+ }
+ return "SHA-1";
+ }
+
+ private static String getHashName(long hashRef) throws IOException {
+ long hashSeqRef = 0;
+ try {
+ hashSeqRef = NativeCrypto.asn1_read_sequence(hashRef);
+ String hashOid = NativeCrypto.asn1_read_oid(hashSeqRef);
+ if (!NativeCrypto.asn1_read_is_empty(hashSeqRef)) {
+ NativeCrypto.asn1_read_null(hashSeqRef);
+ }
+ if (!NativeCrypto.asn1_read_is_empty(hashSeqRef)
+ || !OID_TO_NAME.containsKey(hashOid)) {
+ throw new IOException("Error reading ASN.1 encoding");
+ }
+ return OID_TO_NAME.get(hashOid);
+ } finally {
+ NativeCrypto.asn1_read_free(hashSeqRef);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected <T extends AlgorithmParameterSpec> T engineGetParameterSpec(Class<T> aClass)
+ throws InvalidParameterSpecException {
+ if ((aClass != null) && aClass == OAEPParameterSpec.class) {
+ return (T) spec;
+ } else {
+ throw new InvalidParameterSpecException("Unsupported class: " + aClass);
+ }
+ }
+
+ @Override
+ protected byte[] engineGetEncoded() throws IOException {
+ long cbbRef = 0;
+ long seqRef = 0;
+ try {
+ cbbRef = NativeCrypto.asn1_write_init();
+ seqRef = NativeCrypto.asn1_write_sequence(cbbRef);
+ writeHashAndMgfHash(seqRef, spec.getDigestAlgorithm(),
+ (MGF1ParameterSpec) spec.getMGFParameters());
+ PSource.PSpecified pSource = (PSource.PSpecified) spec.getPSource();
+ // Implementations are prohibited from writing the default value for any of the fields
+ if (pSource.getValue().length != 0) {
+ long pSourceRef = 0;
+ long pSourceParamsRef = 0;
+ try {
+ pSourceRef = NativeCrypto.asn1_write_tag(seqRef, 2);
+ pSourceParamsRef = writeAlgorithmIdentifier(pSourceRef, PSPECIFIED_OID);
+ NativeCrypto.asn1_write_octetstring(pSourceParamsRef, pSource.getValue());
+ } finally {
+ NativeCrypto.asn1_write_flush(seqRef);
+ NativeCrypto.asn1_write_free(pSourceParamsRef);
+ NativeCrypto.asn1_write_free(pSourceRef);
+ }
+ }
+ return NativeCrypto.asn1_write_finish(cbbRef);
+ } catch (IOException e) {
+ NativeCrypto.asn1_write_cleanup(cbbRef);
+ throw e;
+ } finally {
+ NativeCrypto.asn1_write_free(seqRef);
+ NativeCrypto.asn1_write_free(cbbRef);
+ }
+ }
+
+ @Override
+ protected byte[] engineGetEncoded(String format) throws IOException {
+ if ((format == null) || format.equals("ASN.1")) {
+ return engineGetEncoded();
+ }
+ throw new IOException("Unsupported format: " + format);
+ }
+
+ // Shared with PSSParameters, since they share some of their encoded form
+ static void writeHashAndMgfHash(long seqRef, String hash, MGF1ParameterSpec mgfSpec) throws IOException {
+ // Implementations are prohibited from writing the default value for any of the fields
+ if (!hash.equals("SHA-1")) {
+ long hashRef = 0;
+ long hashParamsRef = 0;
+ try {
+ hashRef = NativeCrypto.asn1_write_tag(seqRef, 0);
+ hashParamsRef = writeAlgorithmIdentifier(
+ hashRef, NAME_TO_OID.get(hash));
+ NativeCrypto.asn1_write_null(hashParamsRef);
+ } finally {
+ NativeCrypto.asn1_write_flush(seqRef);
+ NativeCrypto.asn1_write_free(hashParamsRef);
+ NativeCrypto.asn1_write_free(hashRef);
+ }
+ }
+ if (!mgfSpec.getDigestAlgorithm().equals("SHA-1")) {
+ long mgfRef = 0;
+ long mgfParamsRef = 0;
+ long hashParamsRef = 0;
+ try {
+ mgfRef = NativeCrypto.asn1_write_tag(seqRef, 1);
+ mgfParamsRef = writeAlgorithmIdentifier(mgfRef, MGF1_OID);
+ hashParamsRef = writeAlgorithmIdentifier(
+ mgfParamsRef, NAME_TO_OID.get(mgfSpec.getDigestAlgorithm()));
+ NativeCrypto.asn1_write_null(hashParamsRef);
+ } finally {
+ NativeCrypto.asn1_write_flush(seqRef);
+ NativeCrypto.asn1_write_free(hashParamsRef);
+ NativeCrypto.asn1_write_free(mgfParamsRef);
+ NativeCrypto.asn1_write_free(mgfRef);
+ }
+ }
+ }
+
+ /**
+ * Writes an ASN.1 AlgorithmIdentifier structure into container, which looks like
+ * <pre>
+ * SEQUENCE
+ * OBJECT IDENTIFIER
+ * PARAMS (based on the particular algorithm)
+ * </pre>
+ * This method returns a reference to the sequence such that the params may be added to it.
+ * The reference needs to be freed with asn1_write_free once it's used.
+ */
+ private static long writeAlgorithmIdentifier(long container, String oid) throws IOException {
+ long seqRef = 0;
+ try {
+ seqRef = NativeCrypto.asn1_write_sequence(container);
+ NativeCrypto.asn1_write_oid(seqRef, oid);
+ } catch (IOException e) {
+ NativeCrypto.asn1_write_free(seqRef);
+ throw e;
+ }
+ return seqRef;
+ }
+
+ @Override
+ protected String engineToString() {
+ return "Conscrypt OAEP AlgorithmParameters";
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OidData.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OidData.java
new file mode 100644
index 0000000..d84dc4d
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OidData.java
@@ -0,0 +1,64 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Data about OIDs.
+ */
+final class OidData {
+
+ private OidData() {}
+
+ private static final Map<String, String> OID_TO_NAME_MAP = new HashMap<>();
+
+ static {
+ // NOTE: For the time being, we only have X509 signature algorithms here, since we only need
+ // them for determining the name of signature algorithms in certs and CRLs. We can add more in
+ // the future if we need them.
+
+ // Signatures
+
+ // RFC 3279
+ OID_TO_NAME_MAP.put("1.2.840.113549.1.1.2", "MD2withRSA");
+ OID_TO_NAME_MAP.put("1.2.840.113549.1.1.4", "MD5withRSA");
+ OID_TO_NAME_MAP.put("1.2.840.113549.1.1.5", "SHA1withRSA");
+ OID_TO_NAME_MAP.put("1.2.840.10040.4.3", "SHA1withDSA");
+ OID_TO_NAME_MAP.put("1.2.840.10045.4.1", "SHA1withECDSA");
+
+ // RFC 4055
+ OID_TO_NAME_MAP.put("1.2.840.113549.1.1.14", "SHA224withRSA");
+ OID_TO_NAME_MAP.put("1.2.840.113549.1.1.11", "SHA256withRSA");
+ OID_TO_NAME_MAP.put("1.2.840.113549.1.1.12", "SHA384withRSA");
+ OID_TO_NAME_MAP.put("1.2.840.113549.1.1.13", "SHA512withRSA");
+
+ // RFC 5758
+ OID_TO_NAME_MAP.put("2.16.840.1.101.3.4.3.1", "SHA224withDSA");
+ OID_TO_NAME_MAP.put("2.16.840.1.101.3.4.3.2", "SHA256withDSA");
+ OID_TO_NAME_MAP.put("1.2.840.10045.4.3.1", "SHA224withECDSA");
+ OID_TO_NAME_MAP.put("1.2.840.10045.4.3.2", "SHA256withECDSA");
+ OID_TO_NAME_MAP.put("1.2.840.10045.4.3.3", "SHA384withECDSA");
+ OID_TO_NAME_MAP.put("1.2.840.10045.4.3.4", "SHA512withECDSA");
+ }
+
+ public static String oidToAlgorithmName(String oid) {
+ return OID_TO_NAME_MAP.get(oid);
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OkHostnameVerifier.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OkHostnameVerifier.java
new file mode 100644
index 0000000..33dd05b
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OkHostnameVerifier.java
@@ -0,0 +1,288 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.cert.Certificate;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.regex.Pattern;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+
+/**
+ * A HostnameVerifier consistent with <a
+ * href="http://www.ietf.org/rfc/rfc2818.txt">RFC 2818</a>.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class OkHostnameVerifier implements ConscryptHostnameVerifier {
+ // Android-changed: Add a mode which disallows top-level domain wildcards. b/144694112
+ // public static final OkHostnameVerifier INSTANCE = new OkHostnameVerifier();
+ public static final OkHostnameVerifier INSTANCE = new OkHostnameVerifier(false);
+
+ /**
+ * Quick and dirty pattern to differentiate IP addresses from hostnames. This
+ * is an approximation of Android's private InetAddress#isNumeric API.
+ *
+ * <p>This matches IPv6 addresses as a hex string containing at least one
+ * colon, and possibly including dots after the first colon. It matches IPv4
+ * addresses as strings containing only decimal digits and dots. This pattern
+ * matches strings like "a:.23" and "54" that are neither IP addresses nor
+ * hostnames; they will be verified as IP addresses (which is a more strict
+ * verification).
+ */
+ private static final Pattern VERIFY_AS_IP_ADDRESS = Pattern.compile(
+ "([0-9a-fA-F]*:[0-9a-fA-F:.]*)|([\\d.]+)");
+
+ private static final int ALT_DNS_NAME = 2;
+ private static final int ALT_IPA_NAME = 7;
+
+ // BEGIN Android-changed: Add a mode which disallows top-level domain wildcards. b/144694112
+ // private OkHostnameVerifier() {
+ // }
+ private final boolean strictWildcardMode;
+
+ private OkHostnameVerifier(boolean strictWildcardMode) {
+ this.strictWildcardMode = strictWildcardMode;
+ }
+
+ public static OkHostnameVerifier strictInstance() {
+ return new OkHostnameVerifier(true);
+ }
+ // END Android-changed: Add a mode which disallows top-level domain wildcards. b/144694112
+
+ @Override
+ public boolean verify(X509Certificate[] certs, String host, SSLSession session) {
+ if (certs.length > 0) {
+ return verify(host, certs[0]);
+ } else {
+ try {
+ Certificate[] certificates = session.getPeerCertificates();
+ return verify(host, (X509Certificate) certificates[0]);
+ } catch (SSLException e) {
+ return false;
+ }
+ }
+ }
+
+ public boolean verify(String host, X509Certificate certificate) {
+ return verifyAsIpAddress(host)
+ ? verifyIpAddress(host, certificate)
+ : verifyHostName(host, certificate);
+ }
+
+ static boolean verifyAsIpAddress(String host) {
+ return VERIFY_AS_IP_ADDRESS.matcher(host).matches();
+ }
+
+ /**
+ * Returns true if {@code certificate} matches {@code ipAddress}.
+ */
+ private boolean verifyIpAddress(String ipAddress, X509Certificate certificate) {
+ List<String> altNames = getSubjectAltNames(certificate, ALT_IPA_NAME);
+ for (int i = 0, size = altNames.size(); i < size; i++) {
+ if (ipAddress.equalsIgnoreCase(altNames.get(i))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if {@code certificate} matches {@code hostName}.
+ */
+ @SuppressWarnings("UnusedVariable")
+ private boolean verifyHostName(String hostName, X509Certificate certificate) {
+ hostName = hostName.toLowerCase(Locale.US);
+ boolean hasDns = false;
+ List<String> altNames = getSubjectAltNames(certificate, ALT_DNS_NAME);
+ for (int i = 0, size = altNames.size(); i < size; i++) {
+ hasDns = true;
+ if (verifyHostName(hostName, altNames.get(i))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // BEGIN Android-removed: Ignore common name in hostname verification. http://b/70278814
+ /*
+ if (!hasDns) {
+ X500Principal principal = certificate.getSubjectX500Principal();
+ // RFC 2818 advises using the most specific name for matching.
+ String cn = new DistinguishedNameParser(principal).findMostSpecific("cn");
+ if (cn != null) {
+ return verifyHostName(hostName, cn);
+ }
+ }
+ */
+ // END Android-removed: Ignore common name in hostname verification. http://b/70278814
+
+ public static List<String> allSubjectAltNames(X509Certificate certificate) {
+ List<String> altIpaNames = getSubjectAltNames(certificate, ALT_IPA_NAME);
+ List<String> altDnsNames = getSubjectAltNames(certificate, ALT_DNS_NAME);
+ List<String> result = new ArrayList<>(altIpaNames.size() + altDnsNames.size());
+ result.addAll(altIpaNames);
+ result.addAll(altDnsNames);
+ return result;
+ }
+
+ @SuppressWarnings("MixedMutabilityReturnType")
+ private static List<String> getSubjectAltNames(X509Certificate certificate, int type) {
+ List<String> result = new ArrayList<>();
+ try {
+ Collection<?> subjectAltNames = certificate.getSubjectAlternativeNames();
+ if (subjectAltNames == null) {
+ return Collections.emptyList();
+ }
+ for (Object subjectAltName : subjectAltNames) {
+ List<?> entry = (List<?>) subjectAltName;
+ if (entry == null || entry.size() < 2) {
+ continue;
+ }
+ Integer altNameType = (Integer) entry.get(0);
+ if (altNameType == null) {
+ continue;
+ }
+ if (altNameType == type) {
+ String altName = (String) entry.get(1);
+ if (altName != null) {
+ result.add(altName);
+ }
+ }
+ }
+ return result;
+ } catch (CertificateParsingException e) {
+ return Collections.emptyList();
+ }
+ }
+
+ /**
+ * Returns {@code true} iff {@code hostName} matches the domain name {@code pattern}.
+ *
+ * @param hostName lower-case host name.
+ * @param pattern domain name pattern from certificate. May be a wildcard pattern such as
+ * {@code *.android.com}.
+ */
+ private boolean verifyHostName(String hostName, String pattern) {
+ // Basic sanity checks
+ // Check length == 0 instead of .isEmpty() to support Java 5.
+ if (hostName == null || hostName.length() == 0 || hostName.startsWith(".")
+ || hostName.endsWith("..")) {
+ // Invalid domain name
+ return false;
+ }
+ if (pattern == null || pattern.length() == 0 || pattern.startsWith(".")
+ || pattern.endsWith("..")) {
+ // Invalid pattern/domain name
+ return false;
+ }
+
+ // Normalize hostName and pattern by turning them into absolute domain names if they are not
+ // yet absolute. This is needed because server certificates do not normally contain absolute
+ // names or patterns, but they should be treated as absolute. At the same time, any hostName
+ // presented to this method should also be treated as absolute for the purposes of matching
+ // to the server certificate.
+ // www.android.com matches www.android.com
+ // www.android.com matches www.android.com.
+ // www.android.com. matches www.android.com.
+ // www.android.com. matches www.android.com
+ if (!hostName.endsWith(".")) {
+ hostName += '.';
+ }
+ if (!pattern.endsWith(".")) {
+ pattern += '.';
+ }
+ // hostName and pattern are now absolute domain names.
+
+ pattern = pattern.toLowerCase(Locale.US);
+ // hostName and pattern are now in lower case -- domain names are case-insensitive.
+
+ if (!pattern.contains("*")) {
+ // Not a wildcard pattern -- hostName and pattern must match exactly.
+ return hostName.equals(pattern);
+ }
+ // Wildcard pattern
+
+ // WILDCARD PATTERN RULES:
+ // 1. Asterisk (*) is only permitted in the left-most domain name label and must be the
+ // only character in that label (i.e., must match the whole left-most label).
+ // For example, *.example.com is permitted, while *a.example.com, a*.example.com,
+ // a*b.example.com, a.*.example.com are not permitted.
+ // 2. Asterisk (*) cannot match across domain name labels.
+ // For example, *.example.com matches test.example.com but does not match
+ // sub.test.example.com.
+ // 3. Wildcard patterns for single-label domain names are not permitted.
+ // 4. Android-added: if strictWildcardMode is true then wildcards matching top-level domains,
+ // e.g. *.com, are not permitted.
+
+ if (!pattern.startsWith("*.") || pattern.indexOf('*', 1) != -1) {
+ // Asterisk (*) is only permitted in the left-most domain name label and must be the only
+ // character in that label
+ return false;
+ }
+
+ // Optimization: check whether hostName is too short to match the pattern. hostName must be at
+ // least as long as the pattern because asterisk must match the whole left-most label and
+ // hostName starts with a non-empty label. Thus, asterisk has to match one or more characters.
+ if (hostName.length() < pattern.length()) {
+ // hostName too short to match the pattern.
+ return false;
+ }
+
+ if ("*.".equals(pattern)) {
+ // Wildcard pattern for single-label domain name -- not permitted.
+ return false;
+ }
+
+ // BEGIN Android-added: Disallow top-level wildcards in strict mode. http://b/144694112
+ if (strictWildcardMode) {
+ // By this point we know the pattern has been normalised and starts with a wildcard,
+ // i.e. "*.domainpart."
+ String domainPart = pattern.substring(2, pattern.length() - 1);
+ // If the domain part contains no dots then this pattern will match top level domains.
+ if (domainPart.indexOf('.') < 0) {
+ return false;
+ }
+ }
+ // END Android-added: Disallow top-level wildcards in strict mode. http://b/144694112
+
+ // hostName must end with the region of pattern following the asterisk.
+ String suffix = pattern.substring(1);
+ if (!hostName.endsWith(suffix)) {
+ // hostName does not end with the suffix
+ return false;
+ }
+
+ // Check that asterisk did not match across domain name labels.
+ int suffixStartIndexInHostName = hostName.length() - suffix.length();
+ if ((suffixStartIndexInHostName > 0)
+ && (hostName.lastIndexOf('.', suffixStartIndexInHostName - 1) != -1)) {
+ // Asterisk is matching across domain name labels -- not permitted.
+ return false;
+ }
+
+ // hostName matches pattern
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLAeadCipher.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLAeadCipher.java
new file mode 100644
index 0000000..383ba4e
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLAeadCipher.java
@@ -0,0 +1,434 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.nio.ByteBuffer;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Arrays;
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public abstract class OpenSSLAeadCipher extends OpenSSLCipher {
+ /**
+ * Controls whether no-copy optimizations for direct ByteBuffers are enabled.
+ */
+ private static final boolean ENABLE_BYTEBUFFER_OPTIMIZATIONS = true;
+
+ /**
+ * The default tag size when one is not specified. Default to
+ * full-length tags (128-bits or 16 octets).
+ */
+ static final int DEFAULT_TAG_SIZE_BITS = 16 * 8;
+
+ /**
+ * Keeps track of the last used block size.
+ */
+ private static int lastGlobalMessageSize = 32;
+
+ /**
+ * The previously used key to prevent key + nonce (IV) reuse.
+ */
+ private byte[] previousKey;
+
+ /**
+ * The previously used nonce (IV) to prevent key + nonce reuse.
+ */
+ private byte[] previousIv;
+
+ /**
+ * When set this instance must be initialized before use again. This prevents key
+ * and IV reuse.
+ */
+ private boolean mustInitialize;
+
+ /**
+ * The byte array containing the bytes written.
+ */
+ byte[] buf;
+
+ /**
+ * The number of bytes written.
+ */
+ int bufCount;
+
+ /**
+ * AEAD cipher reference.
+ */
+ long evpAead;
+
+ /**
+ * Additional authenticated data.
+ */
+ private byte[] aad;
+
+ /**
+ * The length of the AEAD cipher tag in bytes.
+ */
+ int tagLengthInBytes;
+
+ protected OpenSSLAeadCipher(Mode mode) {
+ super(mode, Padding.NOPADDING);
+ }
+
+ private void checkInitialization() {
+ if (mustInitialize) {
+ throw new IllegalStateException(
+ "Cannot re-use same key and IV for multiple encryptions");
+ }
+ }
+
+ /** Constant-time array comparison. Since we are using this to compare keys, we want to
+ * ensure there's no opportunity for a timing attack. */
+ private boolean arraysAreEqual(byte[] a, byte[] b) {
+ if (a.length != b.length) {
+ return false;
+ }
+
+ int diff = 0;
+ for (int i = 0; i < a.length; i++) {
+ diff |= a[i] ^ b[i];
+ }
+ return diff == 0;
+ }
+
+ private void expand(int i) {
+ /* Can the buffer handle i more bytes, if not expand it */
+ if (bufCount + i <= buf.length) {
+ return;
+ }
+
+ byte[] newbuf = new byte[(bufCount + i) * 2];
+ System.arraycopy(buf, 0, newbuf, 0, bufCount);
+ buf = newbuf;
+ }
+
+ private void reset() {
+ aad = null;
+ final int lastBufSize = lastGlobalMessageSize;
+ if (buf == null) {
+ buf = new byte[lastBufSize];
+ } else if (bufCount > 0 && bufCount != lastBufSize) {
+ lastGlobalMessageSize = bufCount;
+ if (buf.length != bufCount) {
+ buf = new byte[bufCount];
+ }
+ }
+ bufCount = 0;
+ }
+
+ @Override
+ void engineInitInternal(byte[] encodedKey, AlgorithmParameterSpec params,
+ SecureRandom random) throws InvalidKeyException,
+ InvalidAlgorithmParameterException {
+ byte[] iv;
+ final int tagLenBits;
+ if (params == null) {
+ iv = null;
+ tagLenBits = DEFAULT_TAG_SIZE_BITS;
+ } else {
+ GCMParameters gcmParams = Platform.fromGCMParameterSpec(params);
+ if (gcmParams != null) {
+ iv = gcmParams.getIV();
+ tagLenBits = gcmParams.getTLen();
+ } else if (params instanceof IvParameterSpec) {
+ IvParameterSpec ivParams = (IvParameterSpec) params;
+ iv = ivParams.getIV();
+ tagLenBits = DEFAULT_TAG_SIZE_BITS;
+ } else {
+ iv = null;
+ tagLenBits = DEFAULT_TAG_SIZE_BITS;
+ }
+ }
+
+ checkSupportedTagLength(tagLenBits);
+
+ tagLengthInBytes = tagLenBits / 8;
+
+ final boolean encrypting = isEncrypting();
+
+ evpAead = getEVP_AEAD(encodedKey.length);
+
+ final int expectedIvLength = NativeCrypto.EVP_AEAD_nonce_length(evpAead);
+ if (iv == null && expectedIvLength != 0) {
+ if (!encrypting) {
+ throw new InvalidAlgorithmParameterException("IV must be specified in " + mode
+ + " mode");
+ }
+
+ iv = new byte[expectedIvLength];
+ if (random != null) {
+ random.nextBytes(iv);
+ } else {
+ NativeCrypto.RAND_bytes(iv);
+ }
+ } else if (expectedIvLength == 0 && iv != null) {
+ throw new InvalidAlgorithmParameterException("IV not used in " + mode + " mode");
+ } else if (iv != null && iv.length != expectedIvLength) {
+ throw new InvalidAlgorithmParameterException("Expected IV length of "
+ + expectedIvLength + " but was " + iv.length);
+ }
+
+ if (isEncrypting() && iv != null && !allowsNonceReuse()) {
+ if (previousKey != null && previousIv != null
+ && arraysAreEqual(previousKey, encodedKey)
+ && arraysAreEqual(previousIv, iv)) {
+ mustInitialize = true;
+ throw new InvalidAlgorithmParameterException(
+ "When using AEAD key and IV must not be re-used");
+ }
+
+ this.previousKey = encodedKey;
+ this.previousIv = iv;
+ }
+ mustInitialize = false;
+ this.iv = iv;
+ reset();
+ }
+
+ void checkSupportedTagLength(int tagLenBits)
+ throws InvalidAlgorithmParameterException {
+ if (tagLenBits % 8 != 0) {
+ throw new InvalidAlgorithmParameterException(
+ "Tag length must be a multiple of 8; was " + tagLenBits);
+ }
+ }
+
+ /**
+ * Returns whether reusing nonces is allowed (aka, whether this is nonce misuse-resistant).
+ * Most AEAD ciphers are not, but some are specially constructed so that reusing a key/nonce
+ * pair is safe.
+ */
+ boolean allowsNonceReuse() {
+ return false;
+ }
+
+ @Override
+ protected int engineDoFinal(ByteBuffer input, ByteBuffer output)
+ throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
+ if (!ENABLE_BYTEBUFFER_OPTIMIZATIONS) {
+ return super.engineDoFinal(input, output);
+ }
+ if (input == null || output == null) {
+ throw new NullPointerException("Null ByteBuffer Error");
+ }
+ if (getOutputSizeForFinal(input.remaining()) > output.remaining()) {
+ throw new ShortBufferWithoutStackTraceException("Insufficient Bytes for Output Buffer");
+ }
+ if (output.isReadOnly()) {
+ throw new IllegalArgumentException("Cannot write to Read Only ByteBuffer");
+ }
+ if (bufCount != 0) {
+ return super.engineDoFinal(input, output); // traditional case
+ }
+ int bytesWritten;
+ if (!input.isDirect()) {
+ int incap = input.remaining();
+ ByteBuffer inputClone = ByteBuffer.allocateDirect(incap);
+ inputClone.mark();
+ inputClone.put(input);
+ inputClone.reset();
+ input = inputClone;
+ }
+ if (!output.isDirect()) {
+ ByteBuffer outputClone =
+ ByteBuffer.allocateDirect(getOutputSizeForFinal(input.remaining()));
+ bytesWritten = doFinalInternal(input, outputClone);
+ output.put(outputClone);
+ input.position(input.limit()); // API reasons
+ } else {
+ bytesWritten = doFinalInternal(input, output);
+ output.position(output.position() + bytesWritten);
+ input.position(input.limit()); // API reasons
+ }
+
+ return bytesWritten;
+ }
+
+ @Override
+ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output,
+ int outputOffset) throws ShortBufferException, IllegalBlockSizeException,
+ BadPaddingException {
+ // Because the EVP_AEAD updateInternal processes input but doesn't create any output
+ // (and thus can't check the output buffer), we need to add this check before the
+ // superclass' processing to ensure that updateInternal is never called if the
+ // output buffer isn't large enough.
+ if (output != null) {
+ if (getOutputSizeForFinal(inputLen) > output.length - outputOffset) {
+ throw new ShortBufferWithoutStackTraceException("Insufficient output space");
+ }
+ }
+ return super.engineDoFinal(input, inputOffset, inputLen, output, outputOffset);
+ }
+
+ @Override
+ int updateInternal(byte[] input, int inputOffset, int inputLen, byte[] output,
+ int outputOffset, int maximumLen) throws ShortBufferException {
+ checkInitialization();
+ if (buf == null) {
+ throw new IllegalStateException("Cipher not initialized");
+ }
+
+ ArrayUtils.checkOffsetAndCount(input.length, inputOffset, inputLen);
+ if (inputLen > 0) {
+ expand(inputLen);
+ System.arraycopy(input, inputOffset, buf, this.bufCount, inputLen);
+ this.bufCount += inputLen;
+ }
+ return 0;
+ }
+
+ @SuppressWarnings("LiteralClassName")
+ private void throwAEADBadTagExceptionIfAvailable(String message, Throwable cause)
+ throws BadPaddingException {
+ Constructor<?> aeadBadTagConstructor;
+ try {
+ aeadBadTagConstructor = Class.forName("javax.crypto.AEADBadTagException")
+ .getConstructor(String.class);
+ } catch (Exception ignored) {
+ return;
+ }
+
+ BadPaddingException badTagException = null;
+ try {
+ badTagException = (BadPaddingException) aeadBadTagConstructor.newInstance(message);
+ badTagException.initCause(cause);
+ } catch (IllegalAccessException e2) {
+ // Fall through
+ } catch (InstantiationException e2) {
+ // Fall through
+ } catch (InvocationTargetException e2) {
+ throw(BadPaddingException) new BadPaddingException().initCause(
+ e2.getTargetException());
+ }
+ if (badTagException != null) {
+ throw badTagException;
+ }
+ }
+
+ int doFinalInternal(ByteBuffer input, ByteBuffer output)
+ throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
+ checkInitialization();
+ final int bytesWritten;
+ try {
+ if (isEncrypting()) {
+ bytesWritten = NativeCrypto.EVP_AEAD_CTX_seal_buf(
+ evpAead, encodedKey, tagLengthInBytes, output, iv, input, aad);
+ } else {
+ bytesWritten = NativeCrypto.EVP_AEAD_CTX_open_buf(
+ evpAead, encodedKey, tagLengthInBytes, output, iv, input, aad);
+ }
+ } catch (BadPaddingException e) {
+ throwAEADBadTagExceptionIfAvailable(e.getMessage(), e.getCause());
+ throw e;
+ }
+ if (isEncrypting()) {
+ mustInitialize = true;
+ }
+ return bytesWritten;
+ }
+
+ @Override
+ int doFinalInternal(byte[] output, int outputOffset, int maximumLen)
+ throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
+ checkInitialization();
+ final int bytesWritten;
+ try {
+ if (isEncrypting()) {
+ bytesWritten = NativeCrypto.EVP_AEAD_CTX_seal(evpAead, encodedKey,
+ tagLengthInBytes, output, outputOffset, iv, buf, 0, bufCount, aad);
+ } else {
+ bytesWritten = NativeCrypto.EVP_AEAD_CTX_open(evpAead, encodedKey,
+ tagLengthInBytes, output, outputOffset, iv, buf, 0, bufCount, aad);
+ }
+ } catch (BadPaddingException e) {
+ throwAEADBadTagExceptionIfAvailable(e.getMessage(), e.getCause());
+ throw e;
+ }
+ if (isEncrypting()) {
+ mustInitialize = true;
+ }
+ reset();
+ return bytesWritten;
+ }
+
+ @Override
+ void checkSupportedPadding(Padding padding) throws NoSuchPaddingException {
+ if (padding != Padding.NOPADDING) {
+ throw new NoSuchPaddingException("Must be NoPadding for AEAD ciphers");
+ }
+ }
+
+ /**
+ * AEAD buffers everything until a final output.
+ */
+ @Override
+ int getOutputSizeForUpdate(int inputLen) {
+ return 0;
+ }
+
+ @Override
+ int getOutputSizeForFinal(int inputLen) {
+ return bufCount + inputLen
+ + (isEncrypting() ? NativeCrypto.EVP_AEAD_max_overhead(evpAead) : 0);
+ }
+
+ // Intentionally missing Override to compile on old versions of Android
+ @SuppressWarnings("MissingOverride")
+ protected void engineUpdateAAD(byte[] input, int inputOffset, int inputLen) {
+ checkInitialization();
+ if (aad == null) {
+ aad = Arrays.copyOfRange(input, inputOffset, inputOffset + inputLen);
+ } else {
+ int newSize = aad.length + inputLen;
+ byte[] newaad = new byte[newSize];
+ System.arraycopy(aad, 0, newaad, 0, aad.length);
+ System.arraycopy(input, inputOffset, newaad, aad.length, inputLen);
+ aad = newaad;
+ }
+ }
+
+ // Intentionally missing Override to compile on old versions of Android
+ @SuppressWarnings("MissingOverride")
+ protected void engineUpdateAAD(ByteBuffer buf) {
+ checkInitialization();
+ if (aad == null) {
+ aad = new byte[buf.remaining()];
+ buf.get(aad);
+ } else {
+ int newSize = aad.length + buf.remaining();
+ byte[] newaad = new byte[newSize];
+ System.arraycopy(aad, 0, newaad, 0, aad.length);
+ buf.get(newaad, aad.length, buf.remaining());
+ aad = newaad;
+ }
+ }
+
+ abstract long getEVP_AEAD(int keyLength) throws InvalidKeyException;
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLAeadCipherAES.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLAeadCipherAES.java
new file mode 100644
index 0000000..cfb69c0
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLAeadCipherAES.java
@@ -0,0 +1,243 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public abstract class OpenSSLAeadCipherAES extends OpenSSLAeadCipher {
+ private static final int AES_BLOCK_SIZE = 16;
+
+ OpenSSLAeadCipherAES(Mode mode) {
+ super(mode);
+ }
+
+ @Override
+ void checkSupportedKeySize(int keyLength) throws InvalidKeyException {
+ switch (keyLength) {
+ case 16: // AES 128
+ case 32: // AES 256
+ return;
+ default:
+ throw new InvalidKeyException("Unsupported key size: " + keyLength
+ + " bytes (must be 16 or 32)");
+ }
+ }
+
+ @Override
+ String getBaseCipherName() {
+ return "AES";
+ }
+
+ @Override
+ int getCipherBlockSize() {
+ return AES_BLOCK_SIZE;
+ }
+
+ @Override
+ protected AlgorithmParameterSpec getParameterSpec(AlgorithmParameters params)
+ throws InvalidAlgorithmParameterException {
+ if (params != null) {
+ AlgorithmParameterSpec spec = Platform.fromGCMParameters(params);
+ if (spec != null) {
+ return spec;
+ }
+ return super.getParameterSpec(params);
+ }
+ return null;
+ }
+
+ @Override
+ protected AlgorithmParameters engineGetParameters() {
+ // iv will be non-null after initialization.
+ if (iv == null) {
+ return null;
+ }
+
+ AlgorithmParameterSpec spec = Platform.toGCMParameterSpec(
+ tagLengthInBytes * 8, iv);
+ if (spec == null) {
+ // The platform doesn't support GCMParameterSpec. Fall back to
+ // the generic AES parameters so at least the caller can get the
+ // IV.
+ return super.engineGetParameters();
+ }
+
+ try {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("GCM");
+ params.init(spec);
+ return params;
+ } catch (NoSuchAlgorithmException e) {
+ // We should not get here.
+ throw (Error) new AssertionError("GCM not supported").initCause(e);
+ } catch (InvalidParameterSpecException e) {
+ // This may happen since Conscrypt doesn't provide this itself.
+ return null;
+ }
+ }
+
+ @Override
+ int getOutputSizeForFinal(int inputLen) {
+ // For GCM, the tag is a fixed length and there is no padding or other
+ // concerns, so we can calculate the exact length required without a
+ // native call
+ if (isEncrypting()) {
+ return bufCount + inputLen + tagLengthInBytes;
+ } else {
+ return Math.max(0, bufCount + inputLen - tagLengthInBytes);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class GCM extends OpenSSLAeadCipherAES {
+
+ public GCM() {
+ super(Mode.GCM);
+ }
+
+ @Override
+ void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException {
+ if (mode != Mode.GCM) {
+ throw new NoSuchAlgorithmException("Mode must be GCM");
+ }
+ }
+
+ @Override
+ long getEVP_AEAD(int keyLength) throws InvalidKeyException {
+ if (keyLength == 16) {
+ return NativeCrypto.EVP_aead_aes_128_gcm();
+ } else if (keyLength == 32) {
+ return NativeCrypto.EVP_aead_aes_256_gcm();
+ } else {
+ throw new RuntimeException("Unexpected key length: " + keyLength);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class AES_128 extends GCM {
+ public AES_128() {}
+
+ @Override
+ void checkSupportedKeySize(int keyLength) throws InvalidKeyException {
+ if (keyLength != 16) { // 128 bits
+ throw new InvalidKeyException(
+ "Unsupported key size: " + keyLength + " bytes (must be 16)");
+ }
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class AES_256 extends GCM {
+ public AES_256() {}
+
+ @Override
+ void checkSupportedKeySize(int keyLength) throws InvalidKeyException {
+ if (keyLength != 32) { // 256 bits
+ throw new InvalidKeyException(
+ "Unsupported key size: " + keyLength + " bytes (must be 32)");
+ }
+ }
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class GCM_SIV extends OpenSSLAeadCipherAES {
+ public GCM_SIV() {
+ super(Mode.GCM_SIV);
+ }
+
+ @Override
+ void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException {
+ if (mode != Mode.GCM_SIV) {
+ throw new NoSuchAlgorithmException("Mode must be GCM-SIV");
+ }
+ }
+
+ @Override
+ boolean allowsNonceReuse() {
+ return true;
+ }
+
+ @Override
+ void checkSupportedTagLength(int tagLengthInBits)
+ throws InvalidAlgorithmParameterException {
+ // GCM_SIV only supports full-size tags
+ if (tagLengthInBits != DEFAULT_TAG_SIZE_BITS) {
+ throw new InvalidAlgorithmParameterException(
+ "Tag length must be " + DEFAULT_TAG_SIZE_BITS + " bits");
+ }
+ }
+
+ @Override
+ long getEVP_AEAD(int keyLength) throws InvalidKeyException {
+ if (keyLength == 16) {
+ return NativeCrypto.EVP_aead_aes_128_gcm_siv();
+ } else if (keyLength == 32) {
+ return NativeCrypto.EVP_aead_aes_256_gcm_siv();
+ } else {
+ throw new RuntimeException("Unexpected key length: " + keyLength);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class AES_128 extends GCM_SIV {
+ public AES_128() {}
+
+ @Override
+ void checkSupportedKeySize(int keyLength) throws InvalidKeyException {
+ if (keyLength != 16) { // 128 bits
+ throw new InvalidKeyException(
+ "Unsupported key size: " + keyLength + " bytes (must be 16)");
+ }
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class AES_256 extends GCM_SIV {
+ public AES_256() {}
+
+ @Override
+ void checkSupportedKeySize(int keyLength) throws InvalidKeyException {
+ if (keyLength != 32) { // 256 bits
+ throw new InvalidKeyException(
+ "Unsupported key size: " + keyLength + " bytes (must be 32)");
+ }
+ }
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLAeadCipherChaCha20.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLAeadCipherChaCha20.java
new file mode 100644
index 0000000..2587ba0
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLAeadCipherChaCha20.java
@@ -0,0 +1,77 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class OpenSSLAeadCipherChaCha20 extends OpenSSLAeadCipher {
+ public OpenSSLAeadCipherChaCha20() {
+ super(Mode.POLY1305);
+ }
+
+ @Override
+ void checkSupportedKeySize(int keyLength) throws InvalidKeyException {
+ if (keyLength != 32) {
+ throw new InvalidKeyException("Unsupported key size: " + keyLength
+ + " bytes (must be 32)");
+ }
+ }
+
+ @Override
+ String getBaseCipherName() {
+ return "ChaCha20";
+ }
+
+ @Override
+ int getCipherBlockSize() {
+ return 0;
+ }
+
+ @Override
+ void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException {
+ if (mode != Mode.POLY1305) {
+ throw new NoSuchAlgorithmException("Mode must be Poly1305");
+ }
+ }
+
+ @Override
+ long getEVP_AEAD(int keyLength) throws InvalidKeyException {
+ if (keyLength == 32) {
+ return NativeCrypto.EVP_aead_chacha20_poly1305();
+ } else {
+ throw new RuntimeException("Unexpected key length: " + keyLength);
+ }
+ }
+
+ @Override
+ int getOutputSizeForFinal(int inputLen) {
+ // For ChaCha20+Poly1305, the tag is always 16 bytes long and there is no
+ // padding or other concerns, so we can calculate the exact length required
+ // without a native call
+ if (isEncrypting()) {
+ return bufCount + inputLen + 16;
+ } else {
+ return Math.max(0, bufCount + inputLen - 16);
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLBIOInputStream.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLBIOInputStream.java
new file mode 100644
index 0000000..0f73d3f
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLBIOInputStream.java
@@ -0,0 +1,111 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Provides an interface to OpenSSL's BIO system directly from a Java
+ * InputStream. It allows an OpenSSL API to read directly from something more
+ * flexible interface than a byte array.
+ */
+class OpenSSLBIOInputStream extends FilterInputStream {
+ private long ctx;
+
+ @android.compat.annotation.UnsupportedAppUsage
+ OpenSSLBIOInputStream(InputStream is, boolean isFinite) {
+ super(is);
+
+ ctx = NativeCrypto.create_BIO_InputStream(this, isFinite);
+ }
+
+ @android.compat.annotation.UnsupportedAppUsage
+ long getBioContext() {
+ return ctx;
+ }
+
+ @android.compat.annotation.UnsupportedAppUsage
+ void release() {
+ NativeCrypto.BIO_free_all(ctx);
+ }
+
+ /**
+ * Similar to a {@code readLine} method, but matches what OpenSSL expects
+ * from a {@code BIO_gets} method.
+ */
+ int gets(byte[] buffer) throws IOException {
+ if (buffer == null || buffer.length == 0) {
+ return 0;
+ }
+
+ int offset = 0;
+ int inputByte = 0;
+ while (offset < buffer.length) {
+ inputByte = read();
+ if (inputByte == -1) {
+ // EOF
+ break;
+ }
+ if (inputByte == '\n') {
+ if (offset == 0) {
+ // If we haven't read anything yet, ignore CRLF.
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ buffer[offset++] = (byte) inputByte;
+ }
+
+ return offset;
+ }
+
+ @Override
+ public int read(byte[] buffer) throws IOException {
+ return read(buffer, 0, buffer.length);
+ }
+
+ // InputStream.read() is allowed to return less than len bytes, and the socket InputStreams
+ // that are used with this class typically do so when the length requested is more than what
+ // is already buffered, but some users of BoringSSL's BIO APIs expect that any read call either
+ // fills the buffer completely, fails, or reaches EOF. We patch over this difference by
+ // repeatedly calling super.read() until it indicates EOF or we fill the buffer.
+ @Override
+ public int read(byte[] buffer, int offset, int len) throws IOException {
+ if (offset < 0 || len < 0 || len > buffer.length - offset) {
+ throw new IndexOutOfBoundsException("Invalid bounds");
+ }
+ if (len == 0) {
+ return 0;
+ }
+ int totalRead = 0;
+ int read;
+ do {
+ read = super.read(buffer, offset + totalRead, len - totalRead - offset);
+ if (read == -1) {
+ break;
+ }
+ totalRead += read;
+ } while (offset + totalRead < len);
+
+ return totalRead == 0 ? -1 : totalRead;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLBaseDHKeyAgreement.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLBaseDHKeyAgreement.java
new file mode 100644
index 0000000..3261847
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLBaseDHKeyAgreement.java
@@ -0,0 +1,160 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2013 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import javax.crypto.KeyAgreementSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * Generic base classe for Diffie-Hellman style key agreement backed by the OpenSSL engine.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public abstract class OpenSSLBaseDHKeyAgreement<T> extends KeyAgreementSpi {
+
+ /** OpenSSL handle of the private key. Only available after the engine has been initialized. */
+ private T mPrivateKey;
+
+ /**
+ * Expected length (in bytes) of the agreed key ({@link #mResult}). Only available after the
+ * engine has been initialized.
+ */
+ private int mExpectedResultLength;
+
+ /** Agreed key. Only available after {@link #engineDoPhase(Key, boolean)} completes. */
+ private byte[] mResult;
+
+ protected OpenSSLBaseDHKeyAgreement() {}
+
+ @Override
+ public Key engineDoPhase(Key key, boolean lastPhase) throws InvalidKeyException {
+ if (mPrivateKey == null) {
+ throw new IllegalStateException("Not initialized");
+ }
+ if (!lastPhase) {
+ throw new IllegalStateException("DH only has one phase");
+ }
+
+ if (key == null) {
+ throw new InvalidKeyException("key == null");
+ }
+ if (!(key instanceof PublicKey)) {
+ throw new InvalidKeyException("Not a public key: " + key.getClass());
+ }
+ T openSslPublicKey = convertPublicKey((PublicKey) key);
+
+ byte[] buffer = new byte[mExpectedResultLength];
+ int actualResultLength = computeKey(buffer, openSslPublicKey, mPrivateKey);
+ byte[] result;
+ if (actualResultLength == -1) {
+ throw new RuntimeException("Engine returned -1");
+ } else if (actualResultLength == mExpectedResultLength) {
+ // The output is as long as expected -- use the whole buffer
+ result = buffer;
+ } else if (actualResultLength < mExpectedResultLength) {
+ // The output is shorter than expected -- use only what's produced by the engine
+ result = new byte[actualResultLength];
+ System.arraycopy(buffer, 0, mResult, 0, mResult.length);
+ } else {
+ // The output is longer than expected
+ throw new RuntimeException("Engine produced a longer than expected result. Expected: "
+ + mExpectedResultLength + ", actual: " + actualResultLength);
+ }
+ mResult = result;
+
+ return null; // No intermediate key
+ }
+
+ protected abstract T convertPublicKey(PublicKey key) throws InvalidKeyException;
+
+ protected abstract T convertPrivateKey(PrivateKey key) throws InvalidKeyException;
+
+ /**
+ * Given the public key {@code theirPublicKey} and the private key {@code ourPrivateKey} write the shared secret
+ * to {@code buffer} and return the actual output size.
+ */
+ protected abstract int computeKey(byte[] buffer, T theirPublicKey, T ourPrivateKey) throws InvalidKeyException;
+
+ @Override
+ protected int engineGenerateSecret(byte[] sharedSecret, int offset)
+ throws ShortBufferException {
+ checkCompleted();
+ int available = sharedSecret.length - offset;
+ if (mResult.length > available) {
+ throw new ShortBufferWithoutStackTraceException(
+ "Needed: " + mResult.length + ", available: " + available);
+ }
+
+ System.arraycopy(mResult, 0, sharedSecret, offset, mResult.length);
+ return mResult.length;
+ }
+
+ @Override
+ protected byte[] engineGenerateSecret() {
+ checkCompleted();
+ return mResult;
+ }
+
+ @Override
+ protected SecretKey engineGenerateSecret(String algorithm) {
+ checkCompleted();
+ return new SecretKeySpec(engineGenerateSecret(), algorithm);
+ }
+
+ @Override
+ protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException {
+ if (key == null) {
+ throw new InvalidKeyException("key == null");
+ }
+ if (!(key instanceof PrivateKey)) {
+ throw new InvalidKeyException("Not a private key: " + key.getClass());
+ }
+
+ T privateKey = convertPrivateKey((PrivateKey) key);
+ mExpectedResultLength = getOutputSize(privateKey);
+ mPrivateKey = privateKey;
+ }
+
+ /** Returns the expected result length for the given {@code key}. */
+ protected abstract int getOutputSize(T key);
+
+ @Override
+ protected void engineInit(Key key, AlgorithmParameterSpec params,
+ SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
+ // ECDH doesn't need an AlgorithmParameterSpec
+ if (params != null) {
+ throw new InvalidAlgorithmParameterException("No algorithm parameters supported");
+ }
+ engineInit(key, random);
+ }
+
+ private void checkCompleted() {
+ if (mResult == null) {
+ throw new IllegalStateException("Key agreement not completed");
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLCipher.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLCipher.java
new file mode 100644
index 0000000..8b8a90b
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLCipher.java
@@ -0,0 +1,489 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
+import java.util.Locale;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * An implementation of {@link Cipher} using BoringSSL as the backing library.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public abstract class OpenSSLCipher extends CipherSpi {
+
+ /**
+ * Modes that a block cipher may support.
+ */
+ enum Mode {
+ NONE,
+ CBC,
+ CTR,
+ ECB,
+ GCM,
+ GCM_SIV,
+ POLY1305,
+ ;
+
+ public static Mode getNormalized(String modeString) {
+ modeString = modeString.toUpperCase(Locale.US);
+ // We use GCM-SIV as the mode string, but - isn't a valid identifier character, so
+ // we need to ensure GCM-SIV is recognized and GCM_SIV isn't.
+ if (modeString.equals("GCM-SIV")) {
+ return GCM_SIV;
+ } else if (modeString.equals("GCM_SIV")) {
+ throw new IllegalArgumentException("Invalid mode");
+ } else {
+ return Mode.valueOf(modeString);
+ }
+ }
+ }
+
+ /**
+ * Paddings that a block cipher may support.
+ */
+ enum Padding {
+ NOPADDING,
+ PKCS5PADDING,
+ PKCS7PADDING,
+ ;
+
+ public static Padding getNormalized(String value) {
+ Padding p = Padding.valueOf(value.toUpperCase(Locale.US));
+ if (p == PKCS7PADDING) {
+ return PKCS5PADDING;
+ }
+ return p;
+ }
+ }
+
+ /**
+ * The current cipher mode.
+ */
+ Mode mode = Mode.ECB;
+
+ /**
+ * The current cipher padding.
+ */
+ private Padding padding = Padding.PKCS5PADDING;
+
+ /**
+ * May be used when reseting the cipher instance after calling
+ * {@code doFinal}.
+ */
+ byte[] encodedKey;
+
+ /**
+ * The Initial Vector (IV) used for the current cipher.
+ */
+ byte[] iv;
+
+ /**
+ * Current cipher mode: encrypting or decrypting.
+ */
+ private boolean encrypting;
+
+ /**
+ * The block size of the current cipher.
+ */
+ private int blockSize;
+
+ OpenSSLCipher() {
+ }
+
+ OpenSSLCipher(Mode mode, Padding padding) {
+ this.mode = mode;
+ this.padding = padding;
+ blockSize = getCipherBlockSize();
+ }
+
+ /**
+ * API-specific implementation of initializing the cipher. The
+ * {@link #isEncrypting()} function will tell whether it should be
+ * initialized for encryption or decryption. The {@code encodedKey} will be
+ * the bytes of a supported key size.
+ */
+ abstract void engineInitInternal(byte[] encodedKey, AlgorithmParameterSpec params,
+ SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+ /**
+ * API-specific implementation of updating the cipher. The
+ * {@code maximumLen} will be the maximum length of the output as returned
+ * by {@link #getOutputSizeForUpdate(int)}. The return value must be the
+ * number of bytes processed and placed into {@code output}. On error, an
+ * exception must be thrown.
+ */
+ abstract int updateInternal(byte[] input, int inputOffset, int inputLen,
+ byte[] output, int outputOffset, int maximumLen) throws ShortBufferException;
+
+ /**
+ * API-specific implementation of the final block. The {@code maximumLen}
+ * will be the maximum length of the possible output as returned by
+ * {@link #getOutputSizeForFinal(int)}. The return value must be the number
+ * of bytes processed and placed into {@code output}. On error, an exception
+ * must be thrown.
+ */
+ abstract int doFinalInternal(byte[] output, int outputOffset, int maximumLen)
+ throws IllegalBlockSizeException, BadPaddingException, ShortBufferException;
+
+ /**
+ * Returns the standard name for the particular algorithm.
+ */
+ abstract String getBaseCipherName();
+
+ /**
+ * Checks whether the cipher supports this particular {@code keySize} (in
+ * bytes) and throws {@code InvalidKeyException} if it doesn't.
+ */
+ abstract void checkSupportedKeySize(int keySize) throws InvalidKeyException;
+
+ /**
+ * Checks whether the cipher supports this particular cipher {@code mode}
+ * and throws {@code NoSuchAlgorithmException} if it doesn't.
+ */
+ abstract void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException;
+
+ /**
+ * Checks whether the cipher supports this particular cipher {@code padding}
+ * and throws {@code NoSuchPaddingException} if it doesn't.
+ */
+ abstract void checkSupportedPadding(Padding padding) throws NoSuchPaddingException;
+
+ abstract int getCipherBlockSize();
+
+ boolean supportsVariableSizeKey() {
+ return false;
+ }
+
+ boolean supportsVariableSizeIv() {
+ return false;
+ }
+
+ @Override
+ protected void engineSetMode(String modeStr) throws NoSuchAlgorithmException {
+ final Mode mode;
+ try {
+ mode = Mode.getNormalized(modeStr);
+ } catch (IllegalArgumentException e) {
+ NoSuchAlgorithmException newE = new NoSuchAlgorithmException("No such mode: " + modeStr);
+ newE.initCause(e);
+ throw newE;
+ }
+ checkSupportedMode(mode);
+ this.mode = mode;
+ }
+
+ @Override
+ protected void engineSetPadding(String paddingStr) throws NoSuchPaddingException {
+ final Padding padding;
+ try {
+ padding = Padding.getNormalized(paddingStr);
+ } catch (IllegalArgumentException e) {
+ NoSuchPaddingException newE = new NoSuchPaddingException("No such padding: "
+ + paddingStr);
+ newE.initCause(e);
+ throw newE;
+ }
+ checkSupportedPadding(padding);
+ this.padding = padding;
+ }
+
+ /**
+ * Returns the padding type for which this cipher is initialized.
+ */
+ Padding getPadding() {
+ return padding;
+ }
+
+ @Override
+ protected int engineGetBlockSize() {
+ return blockSize;
+ }
+
+ /**
+ * The size of output if {@code doFinal()} is called with this
+ * {@code inputLen}. If padding is enabled and the size of the input puts it
+ * right at the block size, it will add another block for the padding.
+ */
+ abstract int getOutputSizeForFinal(int inputLen);
+
+ /**
+ * The size of output if {@code update()} is called with this
+ * {@code inputLen}. If padding is enabled and the size of the input puts it
+ * right at the block size, it will add another block for the padding.
+ */
+ abstract int getOutputSizeForUpdate(int inputLen);
+
+ @Override
+ protected int engineGetOutputSize(int inputLen) {
+ return Math.max(getOutputSizeForUpdate(inputLen), getOutputSizeForFinal(inputLen));
+ }
+
+ @Override
+ protected byte[] engineGetIV() {
+ return iv;
+ }
+
+ @Override
+ protected AlgorithmParameters engineGetParameters() {
+ if (iv != null && iv.length > 0) {
+ try {
+ AlgorithmParameters params = AlgorithmParameters.getInstance(getBaseCipherName());
+ params.init(new IvParameterSpec(iv));
+ return params;
+ } catch (NoSuchAlgorithmException e) {
+ return null;
+ } catch (InvalidParameterSpecException e) {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ protected AlgorithmParameterSpec getParameterSpec(AlgorithmParameters params)
+ throws InvalidAlgorithmParameterException {
+ if (params != null) {
+ try {
+ return params.getParameterSpec(IvParameterSpec.class);
+ } catch (InvalidParameterSpecException e) {
+ throw new InvalidAlgorithmParameterException(
+ "Params must be convertible to IvParameterSpec", e);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
+ checkAndSetEncodedKey(opmode, key);
+ try {
+ engineInitInternal(this.encodedKey, null, random);
+ } catch (InvalidAlgorithmParameterException e) {
+ // This can't actually happen since we pass in null.
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
+ SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
+ checkAndSetEncodedKey(opmode, key);
+ engineInitInternal(this.encodedKey, params, random);
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ AlgorithmParameterSpec spec = getParameterSpec(params);
+ engineInit(opmode, key, spec, random);
+ }
+
+ @Override
+ protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
+ final int maximumLen = getOutputSizeForUpdate(inputLen);
+
+ /* See how large our output buffer would need to be. */
+ final byte[] output;
+ if (maximumLen > 0) {
+ output = new byte[maximumLen];
+ } else {
+ output = EmptyArray.BYTE;
+ }
+
+ final int bytesWritten;
+ try {
+ bytesWritten = updateInternal(input, inputOffset, inputLen, output, 0, maximumLen);
+ } catch (ShortBufferException e) {
+ /* This shouldn't happen. */
+ throw new RuntimeException("calculated buffer size was wrong: " + maximumLen);
+ }
+
+ if (output.length == bytesWritten) {
+ return output;
+ } else if (bytesWritten == 0) {
+ return EmptyArray.BYTE;
+ } else {
+ return Arrays.copyOfRange(output, 0, bytesWritten);
+ }
+ }
+
+ @Override
+ protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output,
+ int outputOffset) throws ShortBufferException {
+ final int maximumLen = getOutputSizeForUpdate(inputLen);
+ return updateInternal(input, inputOffset, inputLen, output, outputOffset, maximumLen);
+ }
+
+ @Override
+ protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException {
+ final int maximumLen = getOutputSizeForFinal(inputLen);
+ /* Assume that we'll output exactly on a byte boundary. */
+ final byte[] output = new byte[maximumLen];
+
+ int bytesWritten;
+ if (inputLen > 0) {
+ try {
+ bytesWritten = updateInternal(input, inputOffset, inputLen, output, 0, maximumLen);
+ } catch (ShortBufferException e) {
+ /* This should not happen since we sized our own buffer. */
+ throw new RuntimeException("our calculated buffer was too small", e);
+ }
+ } else {
+ bytesWritten = 0;
+ }
+
+ try {
+ bytesWritten += doFinalInternal(output, bytesWritten, maximumLen - bytesWritten);
+ } catch (ShortBufferException e) {
+ /* This should not happen since we sized our own buffer. */
+ throw new RuntimeException("our calculated buffer was too small", e);
+ }
+
+ if (bytesWritten == output.length) {
+ return output;
+ } else if (bytesWritten == 0) {
+ return EmptyArray.BYTE;
+ } else {
+ return Arrays.copyOfRange(output, 0, bytesWritten);
+ }
+ }
+
+ @Override
+ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output,
+ int outputOffset) throws ShortBufferException, IllegalBlockSizeException,
+ BadPaddingException {
+ if (output == null) {
+ throw new NullPointerException("output == null");
+ }
+
+ int maximumLen = getOutputSizeForFinal(inputLen);
+
+ final int bytesWritten;
+ if (inputLen > 0) {
+ bytesWritten = updateInternal(input, inputOffset, inputLen, output, outputOffset,
+ maximumLen);
+ outputOffset += bytesWritten;
+ maximumLen -= bytesWritten;
+ } else {
+ bytesWritten = 0;
+ }
+
+ return bytesWritten + doFinalInternal(output, outputOffset, maximumLen);
+ }
+
+ @Override
+ protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException {
+ try {
+ byte[] encoded = key.getEncoded();
+ return engineDoFinal(encoded, 0, encoded.length);
+ } catch (BadPaddingException e) {
+ IllegalBlockSizeException newE = new IllegalBlockSizeException();
+ newE.initCause(e);
+ throw newE;
+ }
+ }
+
+ @Override
+ protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)
+ throws InvalidKeyException, NoSuchAlgorithmException {
+ try {
+ byte[] encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
+ if (wrappedKeyType == Cipher.PUBLIC_KEY) {
+ KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm);
+ return keyFactory.generatePublic(new X509EncodedKeySpec(encoded));
+ } else if (wrappedKeyType == Cipher.PRIVATE_KEY) {
+ KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm);
+ return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encoded));
+ } else if (wrappedKeyType == Cipher.SECRET_KEY) {
+ return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
+ } else {
+ throw new UnsupportedOperationException("wrappedKeyType == " + wrappedKeyType);
+ }
+ } catch (IllegalBlockSizeException e) {
+ throw new InvalidKeyException(e);
+ } catch (BadPaddingException e) {
+ throw new InvalidKeyException(e);
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
+ @Override
+ protected int engineGetKeySize(Key key) throws InvalidKeyException {
+ if (!(key instanceof SecretKey)) {
+ throw new InvalidKeyException("Only SecretKey is supported");
+ }
+ byte[] encodedKey = key.getEncoded();
+ if (encodedKey == null) {
+ throw new InvalidKeyException("key.getEncoded() == null");
+ }
+ checkSupportedKeySize(encodedKey.length);
+ // The return value is in bits
+ return encodedKey.length * 8;
+ }
+
+ private byte[] checkAndSetEncodedKey(int opmode, Key key) throws InvalidKeyException {
+ if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE) {
+ encrypting = true;
+ } else if (opmode == Cipher.DECRYPT_MODE || opmode == Cipher.UNWRAP_MODE) {
+ encrypting = false;
+ } else {
+ throw new InvalidParameterException("Unsupported opmode " + opmode);
+ }
+
+ if (!(key instanceof SecretKey)) {
+ throw new InvalidKeyException("Only SecretKey is supported");
+ }
+
+ final byte[] encodedKey = key.getEncoded();
+ if (encodedKey == null) {
+ throw new InvalidKeyException("key.getEncoded() == null");
+ }
+ checkSupportedKeySize(encodedKey.length);
+ this.encodedKey = encodedKey;
+ return encodedKey;
+ }
+
+ boolean isEncrypting() {
+ return encrypting;
+ }
+
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLCipherChaCha20.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLCipherChaCha20.java
new file mode 100644
index 0000000..4e686e4
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLCipherChaCha20.java
@@ -0,0 +1,158 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+
+/**
+ * Implementation of the ChaCha20 stream cipher.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class OpenSSLCipherChaCha20 extends OpenSSLCipher {
+
+ private static final int BLOCK_SIZE_BYTES = 64;
+ private static final int NONCE_SIZE_BYTES = 12;
+
+ // BoringSSL's interface encrypts by the block, so we need to keep track of whether we
+ // had unused keystream bytes at the end of the previous encryption operation, so that
+ // we can use them before moving on to the next block.
+ private int currentBlockConsumedBytes = 0;
+ private int blockCounter = 0;
+
+ public OpenSSLCipherChaCha20() {}
+
+ @Override
+ void engineInitInternal(byte[] encodedKey, AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidAlgorithmParameterException {
+ if (params instanceof IvParameterSpec) {
+ IvParameterSpec ivParams = (IvParameterSpec) params;
+ if (ivParams.getIV().length != NONCE_SIZE_BYTES) {
+ throw new InvalidAlgorithmParameterException("IV must be 12 bytes long");
+ }
+ iv = ivParams.getIV();
+ } else {
+ if (!isEncrypting()) {
+ throw new InvalidAlgorithmParameterException(
+ "IV must be specified when decrypting");
+ }
+ iv = new byte[NONCE_SIZE_BYTES];
+ if (random != null) {
+ random.nextBytes(iv);
+ } else {
+ NativeCrypto.RAND_bytes(iv);
+ }
+ }
+ }
+
+ @Override
+ int updateInternal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset,
+ int maximumLen) throws ShortBufferException {
+ if (inputLen > output.length - outputOffset) {
+ throw new ShortBufferWithoutStackTraceException("Insufficient output space");
+ }
+ int inputLenRemaining = inputLen;
+ if (currentBlockConsumedBytes > 0) {
+ // A previous operation ended with a partial block, so we need to encrypt using
+ // the remainder of that block before beginning to use the next block
+ int len = Math.min(BLOCK_SIZE_BYTES - currentBlockConsumedBytes, inputLenRemaining);
+ byte[] singleBlock = new byte[BLOCK_SIZE_BYTES];
+ byte[] singleBlockOut = new byte[BLOCK_SIZE_BYTES];
+ System.arraycopy(input, inputOffset, singleBlock, currentBlockConsumedBytes, len);
+ NativeCrypto.chacha20_encrypt_decrypt(singleBlock, 0, singleBlockOut, 0,
+ BLOCK_SIZE_BYTES, encodedKey, iv, blockCounter);
+ System.arraycopy(singleBlockOut, currentBlockConsumedBytes, output, outputOffset, len);
+ currentBlockConsumedBytes += len;
+ if (currentBlockConsumedBytes < BLOCK_SIZE_BYTES) {
+ // We still didn't finish this block, so we're done.
+ return len;
+ }
+ currentBlockConsumedBytes = 0;
+ inputOffset += len;
+ outputOffset += len;
+ inputLenRemaining -= len;
+ blockCounter++;
+ }
+ NativeCrypto.chacha20_encrypt_decrypt(input, inputOffset, output,
+ outputOffset, inputLenRemaining, encodedKey, iv, blockCounter);
+ currentBlockConsumedBytes = inputLenRemaining % BLOCK_SIZE_BYTES;
+ blockCounter += inputLenRemaining / BLOCK_SIZE_BYTES;
+ return inputLen;
+ }
+
+ @Override
+ int doFinalInternal(byte[] output, int outputOffset, int maximumLen) {
+ reset();
+ return 0;
+ }
+
+ private void reset() {
+ blockCounter = 0;
+ currentBlockConsumedBytes = 0;
+ }
+
+ @Override
+ String getBaseCipherName() {
+ return "ChaCha20";
+ }
+
+ @Override
+ void checkSupportedKeySize(int keySize) throws InvalidKeyException {
+ if (keySize != 32) {
+ throw new InvalidKeyException("Unsupported key size: " + keySize
+ + " bytes (must be 32)");
+ }
+ }
+
+ @Override
+ void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException {
+ if (mode != Mode.NONE) {
+ throw new NoSuchAlgorithmException("Mode must be NONE");
+ }
+ }
+
+ @Override
+ void checkSupportedPadding(Padding padding) throws NoSuchPaddingException {
+ if (padding != Padding.NOPADDING) {
+ throw new NoSuchPaddingException("Must be NoPadding");
+ }
+ }
+
+ @Override
+ int getCipherBlockSize() {
+ return 0;
+ }
+
+ @Override
+ int getOutputSizeForFinal(int inputLen) {
+ return inputLen;
+ }
+
+ @Override
+ int getOutputSizeForUpdate(int inputLen) {
+ return inputLen;
+ }
+
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLCipherRSA.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLCipherRSA.java
new file mode 100644
index 0000000..3910212
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLCipherRSA.java
@@ -0,0 +1,659 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
+import java.util.Locale;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public abstract class OpenSSLCipherRSA extends CipherSpi {
+ /**
+ * The current OpenSSL key we're operating on.
+ */
+ OpenSSLKey key;
+
+ /**
+ * Current key type: private or public.
+ */
+ boolean usingPrivateKey;
+
+ /**
+ * Current cipher mode: encrypting or decrypting.
+ */
+ boolean encrypting;
+
+ /**
+ * Buffer for operations
+ */
+ private byte[] buffer;
+
+ /**
+ * Current offset in the buffer.
+ */
+ private int bufferOffset;
+
+ /**
+ * Flag that indicates an exception should be thrown when the input is too
+ * large during doFinal.
+ */
+ private boolean inputTooLarge;
+
+ /**
+ * Current padding mode
+ */
+ int padding = NativeConstants.RSA_PKCS1_PADDING;
+
+ OpenSSLCipherRSA(int padding) {
+ this.padding = padding;
+ }
+
+ @Override
+ protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
+ final String modeUpper = mode.toUpperCase(Locale.ROOT);
+ if ("NONE".equals(modeUpper) || "ECB".equals(modeUpper)) {
+ return;
+ }
+
+ throw new NoSuchAlgorithmException("mode not supported: " + mode);
+ }
+
+ @Override
+ protected void engineSetPadding(String padding) throws NoSuchPaddingException {
+ final String paddingUpper = padding.toUpperCase(Locale.ROOT);
+ if ("PKCS1PADDING".equals(paddingUpper)) {
+ this.padding = NativeConstants.RSA_PKCS1_PADDING;
+ return;
+ }
+ if ("NOPADDING".equals(paddingUpper)) {
+ this.padding = NativeConstants.RSA_NO_PADDING;
+ return;
+ }
+
+ throw new NoSuchPaddingException("padding not supported: " + padding);
+ }
+
+ @Override
+ protected int engineGetBlockSize() {
+ if (encrypting) {
+ return paddedBlockSizeBytes();
+ }
+ return keySizeBytes();
+ }
+
+ @Override
+ protected int engineGetOutputSize(int inputLen) {
+ if (encrypting) {
+ return keySizeBytes();
+ }
+ return paddedBlockSizeBytes();
+ }
+
+ int paddedBlockSizeBytes() {
+ int paddedBlockSizeBytes = keySizeBytes();
+ if (padding == NativeConstants.RSA_PKCS1_PADDING) {
+ paddedBlockSizeBytes--; // for 0 prefix
+ paddedBlockSizeBytes -= 10; // PKCS1 padding header length
+ }
+ return paddedBlockSizeBytes;
+ }
+
+ int keySizeBytes() {
+ if (!isInitialized()) {
+ throw new IllegalStateException("cipher is not initialized");
+ }
+ return NativeCrypto.RSA_size(this.key.getNativeRef());
+ }
+
+ /**
+ * Returns {@code true} if the cipher has been initialized.
+ */
+ boolean isInitialized() {
+ return key != null;
+ }
+
+ @Override
+ protected byte[] engineGetIV() {
+ return null;
+ }
+
+ @Override
+ protected AlgorithmParameters engineGetParameters() {
+ return null;
+ }
+
+ void doCryptoInit(AlgorithmParameterSpec spec)
+ throws InvalidAlgorithmParameterException, InvalidKeyException {}
+
+ void engineInitInternal(int opmode, Key key, AlgorithmParameterSpec spec)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE) {
+ encrypting = true;
+ } else if (opmode == Cipher.DECRYPT_MODE || opmode == Cipher.UNWRAP_MODE) {
+ encrypting = false;
+ } else {
+ throw new InvalidParameterException("Unsupported opmode " + opmode);
+ }
+
+ if (key instanceof OpenSSLRSAPrivateKey) {
+ OpenSSLRSAPrivateKey rsaPrivateKey = (OpenSSLRSAPrivateKey) key;
+ usingPrivateKey = true;
+ this.key = rsaPrivateKey.getOpenSSLKey();
+ } else if (key instanceof RSAPrivateCrtKey) {
+ RSAPrivateCrtKey rsaPrivateKey = (RSAPrivateCrtKey) key;
+ usingPrivateKey = true;
+ this.key = OpenSSLRSAPrivateCrtKey.getInstance(rsaPrivateKey);
+ } else if (key instanceof RSAPrivateKey) {
+ RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) key;
+ usingPrivateKey = true;
+ this.key = OpenSSLRSAPrivateKey.getInstance(rsaPrivateKey);
+ } else if (key instanceof OpenSSLRSAPublicKey) {
+ OpenSSLRSAPublicKey rsaPublicKey = (OpenSSLRSAPublicKey) key;
+ usingPrivateKey = false;
+ this.key = rsaPublicKey.getOpenSSLKey();
+ } else if (key instanceof RSAPublicKey) {
+ RSAPublicKey rsaPublicKey = (RSAPublicKey) key;
+ usingPrivateKey = false;
+ this.key = OpenSSLRSAPublicKey.getInstance(rsaPublicKey);
+ } else {
+ if (null == key) {
+ throw new InvalidKeyException("RSA private or public key is null");
+ }
+
+ throw new InvalidKeyException("Need RSA private or public key");
+ }
+
+ buffer = new byte[NativeCrypto.RSA_size(this.key.getNativeRef())];
+ bufferOffset = 0;
+ inputTooLarge = false;
+
+ doCryptoInit(spec);
+ }
+
+ @Override
+ protected int engineGetKeySize(Key key) throws InvalidKeyException {
+ if (key instanceof OpenSSLRSAPrivateKey) {
+ return ((OpenSSLRSAPrivateKey) key).getModulus().bitLength();
+ }
+ if (key instanceof RSAPrivateCrtKey) {
+ return ((RSAPrivateCrtKey) key).getModulus().bitLength();
+ }
+ if (key instanceof RSAPrivateKey) {
+ return ((RSAPrivateKey) key).getModulus().bitLength();
+ }
+ if (key instanceof OpenSSLRSAPublicKey) {
+ return ((OpenSSLRSAPublicKey) key).getModulus().bitLength();
+ }
+ if (key instanceof RSAPublicKey) {
+ return ((RSAPublicKey) key).getModulus().bitLength();
+ }
+ if (null == key) {
+ throw new InvalidKeyException("RSA private or public key is null");
+ }
+ throw new InvalidKeyException("Need RSA private or public key");
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
+ try {
+ engineInitInternal(opmode, key, null);
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new InvalidKeyException("Algorithm parameters rejected when none supplied", e);
+ }
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
+ SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (params != null) {
+ throw new InvalidAlgorithmParameterException("unknown param type: "
+ + params.getClass().getName());
+ }
+
+ engineInitInternal(opmode, key, params);
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (params != null) {
+ throw new InvalidAlgorithmParameterException("unknown param type: "
+ + params.getClass().getName());
+ }
+
+ engineInitInternal(opmode, key, null);
+ }
+
+ @Override
+ protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
+ if (bufferOffset + inputLen > buffer.length) {
+ inputTooLarge = true;
+ return EmptyArray.BYTE;
+ }
+
+ System.arraycopy(input, inputOffset, buffer, bufferOffset, inputLen);
+ bufferOffset += inputLen;
+ return EmptyArray.BYTE;
+ }
+
+ @Override
+ protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output,
+ int outputOffset) throws ShortBufferException {
+ engineUpdate(input, inputOffset, inputLen);
+ return 0;
+ }
+
+ @Override
+ protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException {
+ if (input != null) {
+ engineUpdate(input, inputOffset, inputLen);
+ }
+
+ if (inputTooLarge) {
+ throw new IllegalBlockSizeException("input must be under " + buffer.length + " bytes");
+ }
+
+ final byte[] tmpBuf;
+ if (bufferOffset != buffer.length) {
+ if (padding == NativeConstants.RSA_NO_PADDING) {
+ tmpBuf = new byte[buffer.length];
+ System.arraycopy(buffer, 0, tmpBuf, buffer.length - bufferOffset, bufferOffset);
+ } else {
+ tmpBuf = Arrays.copyOf(buffer, bufferOffset);
+ }
+ } else {
+ tmpBuf = buffer;
+ }
+
+ byte[] output = new byte[buffer.length];
+ int resultSize = doCryptoOperation(tmpBuf, output);
+ if (!encrypting && resultSize != output.length) {
+ output = Arrays.copyOf(output, resultSize);
+ }
+
+ bufferOffset = 0;
+ return output;
+ }
+
+ abstract int doCryptoOperation(final byte[] tmpBuf, byte[] output)
+ throws BadPaddingException, IllegalBlockSizeException;
+
+ @Override
+ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output,
+ int outputOffset) throws ShortBufferException, IllegalBlockSizeException,
+ BadPaddingException {
+ byte[] b = engineDoFinal(input, inputOffset, inputLen);
+
+ final int lastOffset = outputOffset + b.length;
+ if (lastOffset > output.length) {
+ throw new ShortBufferWithoutStackTraceException(
+ "output buffer is too small " + output.length + " < " + lastOffset);
+ }
+
+ System.arraycopy(b, 0, output, outputOffset, b.length);
+ return b.length;
+ }
+
+ @Override
+ protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException {
+ try {
+ byte[] encoded = key.getEncoded();
+ return engineDoFinal(encoded, 0, encoded.length);
+ } catch (BadPaddingException e) {
+ IllegalBlockSizeException newE = new IllegalBlockSizeException();
+ newE.initCause(e);
+ throw newE;
+ }
+ }
+
+ @Override
+ protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
+ int wrappedKeyType) throws InvalidKeyException, NoSuchAlgorithmException {
+ try {
+ byte[] encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
+ if (wrappedKeyType == Cipher.PUBLIC_KEY) {
+ KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm);
+ return keyFactory.generatePublic(new X509EncodedKeySpec(encoded));
+ } else if (wrappedKeyType == Cipher.PRIVATE_KEY) {
+ KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm);
+ return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encoded));
+ } else if (wrappedKeyType == Cipher.SECRET_KEY) {
+ return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
+ } else {
+ throw new UnsupportedOperationException("wrappedKeyType == " + wrappedKeyType);
+ }
+ } catch (IllegalBlockSizeException e) {
+ throw new InvalidKeyException(e);
+ } catch (BadPaddingException e) {
+ throw new InvalidKeyException(e);
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public abstract static class DirectRSA extends OpenSSLCipherRSA {
+ protected DirectRSA(int padding) {
+ super(padding);
+ }
+
+ @Override
+ int doCryptoOperation(final byte[] tmpBuf, byte[] output)
+ throws BadPaddingException, IllegalBlockSizeException {
+ int resultSize;
+ if (encrypting) {
+ if (usingPrivateKey) {
+ resultSize = NativeCrypto.RSA_private_encrypt(
+ tmpBuf.length, tmpBuf, output, key.getNativeRef(), padding);
+ } else {
+ resultSize = NativeCrypto.RSA_public_encrypt(
+ tmpBuf.length, tmpBuf, output, key.getNativeRef(), padding);
+ }
+ } else {
+ try {
+ if (usingPrivateKey) {
+ resultSize = NativeCrypto.RSA_private_decrypt(
+ tmpBuf.length, tmpBuf, output, key.getNativeRef(), padding);
+ } else {
+ resultSize = NativeCrypto.RSA_public_decrypt(
+ tmpBuf.length, tmpBuf, output, key.getNativeRef(), padding);
+ }
+ } catch (SignatureException e) {
+ IllegalBlockSizeException newE = new IllegalBlockSizeException();
+ newE.initCause(e);
+ throw newE;
+ }
+ }
+ return resultSize;
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class PKCS1 extends DirectRSA {
+ public PKCS1() {
+ super(NativeConstants.RSA_PKCS1_PADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class Raw extends DirectRSA {
+ public Raw() {
+ super(NativeConstants.RSA_NO_PADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class OAEP extends OpenSSLCipherRSA {
+ private long oaepMd;
+ private int oaepMdSizeBytes;
+
+ private long mgf1Md;
+
+ private byte[] label;
+
+ private NativeRef.EVP_PKEY_CTX pkeyCtx;
+
+ public OAEP(long defaultMd, int defaultMdSizeBytes) {
+ super(NativeConstants.RSA_PKCS1_OAEP_PADDING);
+ oaepMd = mgf1Md = defaultMd;
+ oaepMdSizeBytes = defaultMdSizeBytes;
+ }
+
+ @Override
+ protected AlgorithmParameters engineGetParameters() {
+ if (!isInitialized()) {
+ return null;
+ }
+
+ try {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("OAEP");
+
+ final PSource pSrc;
+ if (label == null) {
+ pSrc = PSource.PSpecified.DEFAULT;
+ } else {
+ pSrc = new PSource.PSpecified(label);
+ }
+
+ params.init(new OAEPParameterSpec(
+ EvpMdRef.getJcaDigestAlgorithmStandardNameFromEVP_MD(oaepMd),
+ EvpMdRef.MGF1_ALGORITHM_NAME,
+ new MGF1ParameterSpec(
+ EvpMdRef.getJcaDigestAlgorithmStandardNameFromEVP_MD(mgf1Md)),
+ pSrc));
+ return params;
+ } catch (NoSuchAlgorithmException e) {
+ // We should not get here.
+ throw (Error) new AssertionError("OAEP not supported").initCause(e);
+ } catch (InvalidParameterSpecException e) {
+ throw new RuntimeException("No providers of AlgorithmParameters.OAEP available");
+ }
+ }
+
+ @Override
+ protected void engineSetPadding(String padding) throws NoSuchPaddingException {
+ String paddingUpper = padding.toUpperCase(Locale.US);
+ if (paddingUpper.equals("OAEPPADDING")) {
+ this.padding = NativeConstants.RSA_PKCS1_OAEP_PADDING;
+ return;
+ }
+
+ throw new NoSuchPaddingException("Only OAEP padding is supported");
+ }
+
+ @Override
+ protected void engineInit(
+ int opmode, Key key, AlgorithmParameterSpec spec, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (spec != null && !(spec instanceof OAEPParameterSpec)) {
+ throw new InvalidAlgorithmParameterException(
+ "Only OAEPParameterSpec accepted in OAEP mode");
+ }
+
+ engineInitInternal(opmode, key, spec);
+ }
+
+ @Override
+ protected void engineInit(
+ int opmode, Key key, AlgorithmParameters params, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ OAEPParameterSpec spec = null;
+ if (params != null) {
+ try {
+ spec = params.getParameterSpec(OAEPParameterSpec.class);
+ } catch (InvalidParameterSpecException e) {
+ throw new InvalidAlgorithmParameterException(
+ "Only OAEP parameters are supported", e);
+ }
+ }
+
+ engineInitInternal(opmode, key, spec);
+ }
+
+ @Override
+ void engineInitInternal(int opmode, Key key, AlgorithmParameterSpec spec)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE) {
+ if (!(key instanceof PublicKey)) {
+ throw new InvalidKeyException("Only public keys may be used to encrypt");
+ }
+ } else if (opmode == Cipher.DECRYPT_MODE || opmode == Cipher.UNWRAP_MODE) {
+ if (!(key instanceof PrivateKey)) {
+ throw new InvalidKeyException("Only private keys may be used to decrypt");
+ }
+ }
+ super.engineInitInternal(opmode, key, spec);
+ }
+
+ @Override
+ void doCryptoInit(AlgorithmParameterSpec spec)
+ throws InvalidAlgorithmParameterException, InvalidKeyException {
+ pkeyCtx = new NativeRef.EVP_PKEY_CTX(encrypting
+ ? NativeCrypto.EVP_PKEY_encrypt_init(key.getNativeRef())
+ : NativeCrypto.EVP_PKEY_decrypt_init(key.getNativeRef()));
+
+ if (spec instanceof OAEPParameterSpec) {
+ readOAEPParameters((OAEPParameterSpec) spec);
+ }
+
+ NativeCrypto.EVP_PKEY_CTX_set_rsa_padding(
+ pkeyCtx.address, NativeConstants.RSA_PKCS1_OAEP_PADDING);
+ NativeCrypto.EVP_PKEY_CTX_set_rsa_oaep_md(pkeyCtx.address, oaepMd);
+ NativeCrypto.EVP_PKEY_CTX_set_rsa_mgf1_md(pkeyCtx.address, mgf1Md);
+ if (label != null && label.length > 0) {
+ NativeCrypto.EVP_PKEY_CTX_set_rsa_oaep_label(pkeyCtx.address, label);
+ }
+ }
+
+ @Override
+ int paddedBlockSizeBytes() {
+ int paddedBlockSizeBytes = keySizeBytes();
+ // Size described in step 2 of decoding algorithm, but extra byte
+ // needed to make sure it's smaller than the RSA key modulus size.
+ // https://tools.ietf.org/html/rfc2437#section-9.1.1.2
+ return paddedBlockSizeBytes - (2 * oaepMdSizeBytes + 2);
+ }
+
+ private void readOAEPParameters(OAEPParameterSpec spec)
+ throws InvalidAlgorithmParameterException {
+ String mgfAlgUpper = spec.getMGFAlgorithm().toUpperCase(Locale.US);
+ AlgorithmParameterSpec mgfSpec = spec.getMGFParameters();
+ if ((!EvpMdRef.MGF1_ALGORITHM_NAME.equals(mgfAlgUpper)
+ && !EvpMdRef.MGF1_OID.equals(mgfAlgUpper))
+ || !(mgfSpec instanceof MGF1ParameterSpec)) {
+ throw new InvalidAlgorithmParameterException(
+ "Only MGF1 supported as mask generation function");
+ }
+
+ MGF1ParameterSpec mgf1spec = (MGF1ParameterSpec) mgfSpec;
+ String oaepAlgUpper = spec.getDigestAlgorithm().toUpperCase(Locale.US);
+ try {
+ oaepMd = EvpMdRef.getEVP_MDByJcaDigestAlgorithmStandardName(oaepAlgUpper);
+ oaepMdSizeBytes =
+ EvpMdRef.getDigestSizeBytesByJcaDigestAlgorithmStandardName(oaepAlgUpper);
+ mgf1Md = EvpMdRef.getEVP_MDByJcaDigestAlgorithmStandardName(
+ mgf1spec.getDigestAlgorithm());
+ } catch (NoSuchAlgorithmException e) {
+ throw new InvalidAlgorithmParameterException(e);
+ }
+
+ PSource pSource = spec.getPSource();
+ if (!"PSpecified".equals(pSource.getAlgorithm())
+ || !(pSource instanceof PSource.PSpecified)) {
+ throw new InvalidAlgorithmParameterException(
+ "Only PSpecified accepted for PSource");
+ }
+ label = ((PSource.PSpecified) pSource).getValue();
+ }
+
+ @Override
+ int doCryptoOperation(byte[] tmpBuf, byte[] output)
+ throws BadPaddingException, IllegalBlockSizeException {
+ if (encrypting) {
+ return NativeCrypto.EVP_PKEY_encrypt(pkeyCtx, output, 0, tmpBuf, 0, tmpBuf.length);
+ } else {
+ return NativeCrypto.EVP_PKEY_decrypt(pkeyCtx, output, 0, tmpBuf, 0, tmpBuf.length);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA1 extends OAEP {
+ public SHA1() {
+ super(EvpMdRef.SHA1.EVP_MD, EvpMdRef.SHA1.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA224 extends OAEP {
+ public SHA224() {
+ super(EvpMdRef.SHA224.EVP_MD, EvpMdRef.SHA224.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA256 extends OAEP {
+ public SHA256() {
+ super(EvpMdRef.SHA256.EVP_MD, EvpMdRef.SHA256.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA384 extends OAEP {
+ public SHA384() {
+ super(EvpMdRef.SHA384.EVP_MD, EvpMdRef.SHA384.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA512 extends OAEP {
+ public SHA512() {
+ super(EvpMdRef.SHA512.EVP_MD, EvpMdRef.SHA512.SIZE_BYTES);
+ }
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLContextImpl.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLContextImpl.java
new file mode 100644
index 0000000..bcadddf
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLContextImpl.java
@@ -0,0 +1,211 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.Platform.wrapEngine;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyManagementException;
+import java.security.SecureRandom;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContextSpi;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+/**
+ * OpenSSL-backed SSLContext service provider interface.
+ *
+ * <p>Public to allow contruction via the provider framework.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public abstract class OpenSSLContextImpl extends SSLContextSpi {
+ /**
+ * The default SSLContextImpl for use with
+ * SSLContext.getInstance("Default"). Protected by the
+ * DefaultSSLContextImpl.class monitor.
+ */
+ private static DefaultSSLContextImpl defaultSslContextImpl;
+
+ /** TLS protocols to enable by default. */
+ private final String[] protocols;
+
+ /** Client session cache. */
+ private final ClientSessionContext clientSessionContext;
+
+ /** Server session cache. */
+ private final ServerSessionContext serverSessionContext;
+
+ SSLParametersImpl sslParameters;
+
+ /** Allows outside callers to get the preferred SSLContext. */
+ @android.compat.annotation.UnsupportedAppUsage
+ static OpenSSLContextImpl getPreferred() {
+ return new TLSv13();
+ }
+
+ OpenSSLContextImpl(String[] protocols) {
+ this.protocols = protocols;
+ clientSessionContext = new ClientSessionContext();
+ serverSessionContext = new ServerSessionContext();
+ }
+
+ // BEGIN Android-added: Restore missing constructor that is used by apps
+ @android.compat.annotation.UnsupportedAppUsage
+ private OpenSSLContextImpl() throws GeneralSecurityException, IOException {
+ this(NativeCrypto.TLSV13_PROTOCOLS, true);
+ }
+ // END Android-added: Restore missing constructor that is used by apps
+
+ /**
+ * Constuctor for the DefaultSSLContextImpl. The unused boolean parameter is solely to
+ * indicate that this constructor is desired.
+ */
+ @SuppressWarnings("StaticAssignmentInConstructor")
+ OpenSSLContextImpl(String[] protocols, boolean unused)
+ throws GeneralSecurityException, IOException {
+ synchronized (DefaultSSLContextImpl.class) {
+ this.protocols = null;
+ // This is the only place defaultSslContextImpl is read or written so all
+ // access is actually synchronized.
+ if (defaultSslContextImpl == null) {
+ clientSessionContext = new ClientSessionContext();
+ serverSessionContext = new ServerSessionContext();
+ defaultSslContextImpl = (DefaultSSLContextImpl) this;
+ } else {
+ clientSessionContext =
+ (ClientSessionContext)
+ defaultSslContextImpl.engineGetClientSessionContext();
+ serverSessionContext =
+ (ServerSessionContext)
+ defaultSslContextImpl.engineGetServerSessionContext();
+ }
+ sslParameters = new SSLParametersImpl(defaultSslContextImpl.getKeyManagers(),
+ defaultSslContextImpl.getTrustManagers(), null, clientSessionContext,
+ serverSessionContext, protocols);
+ }
+ }
+
+ /**
+ * Initializes this {@code SSLContext} instance. All of the arguments are
+ * optional, and the security providers will be searched for the required
+ * implementations of the needed algorithms.
+ *
+ * @param kms the key sources or {@code null}
+ * @param tms the trust decision sources or {@code null}
+ * @param sr the randomness source or {@code null}
+ * @throws KeyManagementException if initializing this instance fails
+ */
+ @Override
+ public void engineInit(KeyManager[] kms, TrustManager[] tms, SecureRandom sr)
+ throws KeyManagementException {
+ sslParameters = new SSLParametersImpl(
+ kms, tms, sr, clientSessionContext, serverSessionContext, protocols);
+ }
+
+ @Override
+ public SSLSocketFactory engineGetSocketFactory() {
+ if (sslParameters == null) {
+ throw new IllegalStateException("SSLContext is not initialized.");
+ }
+ return Platform.wrapSocketFactoryIfNeeded(new OpenSSLSocketFactoryImpl(sslParameters));
+ }
+
+ @Override
+ public SSLServerSocketFactory engineGetServerSocketFactory() {
+ if (sslParameters == null) {
+ throw new IllegalStateException("SSLContext is not initialized.");
+ }
+ return new OpenSSLServerSocketFactoryImpl(sslParameters);
+ }
+
+ @Override
+ public SSLEngine engineCreateSSLEngine(String host, int port) {
+ if (sslParameters == null) {
+ throw new IllegalStateException("SSLContext is not initialized.");
+ }
+ SSLParametersImpl p = (SSLParametersImpl) sslParameters.clone();
+ p.setUseClientMode(false);
+ return wrapEngine(new ConscryptEngine(host, port, p));
+ }
+
+ @Override
+ public SSLEngine engineCreateSSLEngine() {
+ if (sslParameters == null) {
+ throw new IllegalStateException("SSLContext is not initialized.");
+ }
+ SSLParametersImpl p = (SSLParametersImpl) sslParameters.clone();
+ p.setUseClientMode(false);
+ return wrapEngine(new ConscryptEngine(p));
+ }
+
+ @Override
+ public SSLSessionContext engineGetServerSessionContext() {
+ return serverSessionContext;
+ }
+
+ @Override
+ public SSLSessionContext engineGetClientSessionContext() {
+ return clientSessionContext;
+ }
+
+ /**
+ * Public to allow construction via the provider framework.
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class TLSv13 extends OpenSSLContextImpl {
+ public TLSv13() {
+ super(NativeCrypto.TLSV13_PROTOCOLS);
+ }
+ }
+
+ /**
+ * Public to allow construction via the provider framework.
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class TLSv12 extends OpenSSLContextImpl {
+ @android.compat.annotation.UnsupportedAppUsage
+ public TLSv12() {
+ super(NativeCrypto.TLSV12_PROTOCOLS);
+ }
+ }
+
+ /**
+ * Public to allow construction via the provider framework.
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class TLSv11 extends OpenSSLContextImpl {
+ public TLSv11() {
+ super(NativeCrypto.TLSV11_PROTOCOLS);
+ }
+ }
+
+ /**
+ * Public to allow construction via the provider framework.
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class TLSv1 extends OpenSSLContextImpl {
+ public TLSv1() {
+ super(NativeCrypto.TLSV1_PROTOCOLS);
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECDHKeyAgreement.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECDHKeyAgreement.java
new file mode 100644
index 0000000..69f614b
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECDHKeyAgreement.java
@@ -0,0 +1,55 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2013 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * Elliptic Curve Diffie-Hellman key agreement backed by the OpenSSL engine.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class OpenSSLECDHKeyAgreement extends OpenSSLBaseDHKeyAgreement<OpenSSLKey> {
+ public OpenSSLECDHKeyAgreement() {}
+
+ @Override
+ protected OpenSSLKey convertPublicKey(PublicKey key) throws InvalidKeyException {
+ return OpenSSLKey.fromPublicKey(key);
+ }
+
+ @Override
+ protected OpenSSLKey convertPrivateKey(PrivateKey key) throws InvalidKeyException {
+ return OpenSSLKey.fromPrivateKey(key);
+ }
+
+ @Override
+ protected int computeKey(byte[] buffer, OpenSSLKey theirPublicKey, OpenSSLKey ourPrivateKey)
+ throws InvalidKeyException {
+ return NativeCrypto.ECDH_compute_key(
+ buffer, 0, theirPublicKey.getNativeRef(), ourPrivateKey.getNativeRef());
+ }
+
+ @Override
+ protected int getOutputSize(OpenSSLKey openSslKey) {
+ int fieldSizeBits = NativeCrypto.EC_GROUP_get_degree(new NativeRef.EC_GROUP(
+ NativeCrypto.EC_KEY_get1_group(openSslKey.getNativeRef())));
+ return (fieldSizeBits + 7) / 8;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECGroupContext.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECGroupContext.java
new file mode 100644
index 0000000..3b5d8b6
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECGroupContext.java
@@ -0,0 +1,198 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.spec.ECField;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.EllipticCurve;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents a BoringSSL EC_GROUP object.
+ */
+final class OpenSSLECGroupContext {
+ private static final Map<String, String> ALIASES = new HashMap<>();
+ static {
+ // Workaround for OpenSSL not supporting SECG names for NIST P-256 (aka
+ // ANSI X9.62 prime256v1).
+ ALIASES.put("secp256r1", "prime256v1");
+ // OpenJDK uses string OIDs as names in lots of places, and expects them to
+ // be accepted in ECGenParameterSpec as well, so accept those
+ ALIASES.put("1.3.132.0.33", "secp224r1");
+ ALIASES.put("1.3.132.0.34", "secp384r1");
+ ALIASES.put("1.3.132.0.35", "secp521r1");
+ ALIASES.put("1.2.840.10045.3.1.7", "prime256v1");
+ }
+
+ private final NativeRef.EC_GROUP groupCtx;
+
+ OpenSSLECGroupContext(NativeRef.EC_GROUP groupCtx) {
+ this.groupCtx = groupCtx;
+ }
+
+ static OpenSSLECGroupContext getCurveByName(String curveName) {
+ if (ALIASES.containsKey(curveName)) {
+ curveName = ALIASES.get(curveName);
+ }
+
+ final long ctx = NativeCrypto.EC_GROUP_new_by_curve_name(curveName);
+ if (ctx == 0) {
+ return null;
+ }
+ NativeRef.EC_GROUP groupRef = new NativeRef.EC_GROUP(ctx);
+
+ return new OpenSSLECGroupContext(groupRef);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ throw new IllegalArgumentException("OpenSSLECGroupContext.equals is not defined");
+ }
+
+ @Override
+ public int hashCode() {
+ // TODO Auto-generated method stub
+ return super.hashCode();
+ }
+
+ NativeRef.EC_GROUP getNativeRef() {
+ return groupCtx;
+ }
+
+ static OpenSSLECGroupContext getInstance(ECParameterSpec params)
+ throws InvalidAlgorithmParameterException {
+ String curveName = Platform.getCurveName(params);
+ if (curveName != null) {
+ return OpenSSLECGroupContext.getCurveByName(curveName);
+ }
+
+ // Try to find recognise the underlying curve from the parameters.
+ final EllipticCurve curve = params.getCurve();
+ final ECField field = curve.getField();
+
+ final BigInteger p;
+ if (field instanceof ECFieldFp) {
+ p = ((ECFieldFp) field).getP();
+ } else {
+ throw new InvalidParameterException("unhandled field class "
+ + field.getClass().getName());
+ }
+
+ final ECPoint generator = params.getGenerator();
+ final BigInteger b = curve.getB();
+ final BigInteger x = generator.getAffineX();
+ final BigInteger y = generator.getAffineY();
+
+ // The 'a' value isn't checked in the following because it's unclear
+ // whether users would set it to -3 or p-3.
+ switch (p.bitLength()) {
+ case 224:
+ if (p.toString(16).equals("ffffffffffffffffffffffffffffffff000000000000000000000001") &&
+ b.toString(16).equals("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4") &&
+ x.toString(16).equals("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21") &&
+ y.toString(16).equals("bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34")) {
+ curveName = "secp224r1";
+ }
+ break;
+ case 256:
+ if (p.toString(16).equals("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff") &&
+ b.toString(16).equals("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b") &&
+ x.toString(16).equals("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296") &&
+ y.toString(16).equals("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5")) {
+ curveName = "prime256v1";
+ }
+ break;
+ case 384:
+ if (p.toString(16).equals("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff") &&
+ b.toString(16).equals("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef") &&
+ x.toString(16).equals("aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7") &&
+ y.toString(16).equals("3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f")) {
+ curveName = "secp384r1";
+ }
+ break;
+ case 521:
+ if (p.toString(16).equals("1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") &&
+ b.toString(16).equals("51953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00") &&
+ x.toString(16).equals("c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66") &&
+ y.toString(16).equals("11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650")) {
+ curveName = "secp521r1";
+ }
+ break;
+ }
+
+ if (curveName != null) {
+ return OpenSSLECGroupContext.getCurveByName(curveName);
+ }
+
+ final BigInteger a = curve.getA();
+ final BigInteger order = params.getOrder();
+ final int cofactor = params.getCofactor();
+
+ long group;
+ try {
+ group = NativeCrypto.EC_GROUP_new_arbitrary(
+ p.toByteArray(), a.toByteArray(), b.toByteArray(), x.toByteArray(),
+ y.toByteArray(), order.toByteArray(), cofactor);
+ } catch (Throwable exception) {
+ throw new InvalidAlgorithmParameterException("EC_GROUP_new_arbitrary failed",
+ exception);
+ }
+
+ if (group == 0) {
+ throw new InvalidAlgorithmParameterException("EC_GROUP_new_arbitrary returned NULL");
+ }
+
+ NativeRef.EC_GROUP groupRef = new NativeRef.EC_GROUP(group);
+
+ return new OpenSSLECGroupContext(groupRef);
+ }
+
+ String getCurveName() {
+ return NativeCrypto.EC_GROUP_get_curve_name(groupCtx);
+ }
+
+ ECParameterSpec getECParameterSpec() {
+ final String curveName = NativeCrypto.EC_GROUP_get_curve_name(groupCtx);
+
+ final byte[][] curveParams = NativeCrypto.EC_GROUP_get_curve(groupCtx);
+ final BigInteger p = new BigInteger(curveParams[0]);
+ final BigInteger a = new BigInteger(curveParams[1]);
+ final BigInteger b = new BigInteger(curveParams[2]);
+
+ final ECField field = new ECFieldFp(p);
+
+ final EllipticCurve curve = new EllipticCurve(field, a, b);
+
+ final OpenSSLECPointContext generatorCtx = new OpenSSLECPointContext(this,
+ new NativeRef.EC_POINT(NativeCrypto.EC_GROUP_get_generator(groupCtx)));
+ final ECPoint generator = generatorCtx.getECPoint();
+
+ final BigInteger order = new BigInteger(NativeCrypto.EC_GROUP_get_order(groupCtx));
+ final BigInteger cofactor = new BigInteger(NativeCrypto.EC_GROUP_get_cofactor(groupCtx));
+
+ ECParameterSpec spec = new ECParameterSpec(curve, generator, order, cofactor.intValue());
+ Platform.setCurveName(spec, curveName);
+ return spec;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECKeyFactory.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECKeyFactory.java
new file mode 100644
index 0000000..65cb202
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECKeyFactory.java
@@ -0,0 +1,205 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2013 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+/**
+ * An implementation of a {@link KeyFactorySpi} for EC keys based on BoringSSL.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class OpenSSLECKeyFactory extends KeyFactorySpi {
+
+ public OpenSSLECKeyFactory() {}
+
+ @Override
+ protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException {
+ if (keySpec == null) {
+ throw new InvalidKeySpecException("keySpec == null");
+ }
+
+ if (keySpec instanceof ECPublicKeySpec) {
+ return new OpenSSLECPublicKey((ECPublicKeySpec) keySpec);
+ } else if (keySpec instanceof X509EncodedKeySpec) {
+ return OpenSSLKey.getPublicKey((X509EncodedKeySpec) keySpec, NativeConstants.EVP_PKEY_EC);
+ }
+ throw new InvalidKeySpecException("Must use ECPublicKeySpec or X509EncodedKeySpec; was "
+ + keySpec.getClass().getName());
+ }
+
+ @Override
+ protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException {
+ if (keySpec == null) {
+ throw new InvalidKeySpecException("keySpec == null");
+ }
+
+ if (keySpec instanceof ECPrivateKeySpec) {
+ return new OpenSSLECPrivateKey((ECPrivateKeySpec) keySpec);
+ } else if (keySpec instanceof PKCS8EncodedKeySpec) {
+ return OpenSSLKey.getPrivateKey((PKCS8EncodedKeySpec) keySpec,
+ NativeConstants.EVP_PKEY_EC);
+ }
+ throw new InvalidKeySpecException("Must use ECPrivateKeySpec or PKCS8EncodedKeySpec; was "
+ + keySpec.getClass().getName());
+ }
+
+ @Override
+ protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
+ throws InvalidKeySpecException {
+ if (key == null) {
+ throw new InvalidKeySpecException("key == null");
+ }
+
+ if (keySpec == null) {
+ throw new InvalidKeySpecException("keySpec == null");
+ }
+
+ if (!"EC".equals(key.getAlgorithm())) {
+ throw new InvalidKeySpecException("Key must be an EC key");
+ }
+
+ if (key instanceof ECPublicKey && ECPublicKeySpec.class.isAssignableFrom(keySpec)) {
+ ECPublicKey ecKey = (ECPublicKey) key;
+ @SuppressWarnings("unchecked")
+ T result = (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams());
+ return result;
+ } else if (key instanceof PublicKey && ECPublicKeySpec.class.isAssignableFrom(keySpec)) {
+ final byte[] encoded = key.getEncoded();
+ if (!"X.509".equals(key.getFormat()) || encoded == null) {
+ throw new InvalidKeySpecException("Not a valid X.509 encoding");
+ }
+ ECPublicKey ecKey = (ECPublicKey) engineGeneratePublic(new X509EncodedKeySpec(encoded));
+ @SuppressWarnings("unchecked")
+ T result = (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams());
+ return result;
+ } else if (key instanceof ECPrivateKey
+ && ECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
+ ECPrivateKey ecKey = (ECPrivateKey) key;
+ @SuppressWarnings("unchecked")
+ T result = (T) new ECPrivateKeySpec(ecKey.getS(), ecKey.getParams());
+ return result;
+ } else if (key instanceof PrivateKey && ECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
+ final byte[] encoded = key.getEncoded();
+ if (!"PKCS#8".equals(key.getFormat()) || encoded == null) {
+ throw new InvalidKeySpecException("Not a valid PKCS#8 encoding");
+ }
+ ECPrivateKey ecKey =
+ (ECPrivateKey) engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
+ @SuppressWarnings("unchecked")
+ T result = (T) new ECPrivateKeySpec(ecKey.getS(), ecKey.getParams());
+ return result;
+ } else if (key instanceof PrivateKey
+ && PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) {
+ final byte[] encoded = key.getEncoded();
+ if (!"PKCS#8".equals(key.getFormat())) {
+ throw new InvalidKeySpecException("Encoding type must be PKCS#8; was "
+ + key.getFormat());
+ } else if (encoded == null) {
+ throw new InvalidKeySpecException("Key is not encodable");
+ }
+ @SuppressWarnings("unchecked") T result = (T) new PKCS8EncodedKeySpec(encoded);
+ return result;
+ } else if (key instanceof PublicKey && X509EncodedKeySpec.class.isAssignableFrom(keySpec)) {
+ final byte[] encoded = key.getEncoded();
+ if (!"X.509".equals(key.getFormat())) {
+ throw new InvalidKeySpecException("Encoding type must be X.509; was "
+ + key.getFormat());
+ } else if (encoded == null) {
+ throw new InvalidKeySpecException("Key is not encodable");
+ }
+ @SuppressWarnings("unchecked") T result = (T) new X509EncodedKeySpec(encoded);
+ return result;
+ } else {
+ throw new InvalidKeySpecException("Unsupported key type and key spec combination; key="
+ + key.getClass().getName() + ", keySpec=" + keySpec.getName());
+ }
+ }
+
+ @Override
+ protected Key engineTranslateKey(Key key) throws InvalidKeyException {
+ if (key == null) {
+ throw new InvalidKeyException("key == null");
+ }
+ if ((key instanceof OpenSSLECPublicKey) || (key instanceof OpenSSLECPrivateKey)) {
+ return key;
+ } else if (key instanceof ECPublicKey) {
+ ECPublicKey ecKey = (ECPublicKey) key;
+
+ ECPoint w = ecKey.getW();
+
+ ECParameterSpec params = ecKey.getParams();
+
+ try {
+ return engineGeneratePublic(new ECPublicKeySpec(w, params));
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e);
+ }
+ } else if (key instanceof ECPrivateKey) {
+ ECPrivateKey ecKey = (ECPrivateKey) key;
+
+ BigInteger s = ecKey.getS();
+
+ ECParameterSpec params = ecKey.getParams();
+
+ try {
+ return engineGeneratePrivate(new ECPrivateKeySpec(s, params));
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e);
+ }
+ } else if ((key instanceof PrivateKey) && "PKCS#8".equals(key.getFormat())) {
+ byte[] encoded = key.getEncoded();
+ if (encoded == null) {
+ throw new InvalidKeyException("Key does not support encoding");
+ }
+ try {
+ return engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e);
+ }
+ } else if ((key instanceof PublicKey) && "X.509".equals(key.getFormat())) {
+ byte[] encoded = key.getEncoded();
+ if (encoded == null) {
+ throw new InvalidKeyException("Key does not support encoding");
+ }
+ try {
+ return engineGeneratePublic(new X509EncodedKeySpec(encoded));
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e);
+ }
+ } else {
+ throw new InvalidKeyException("Key must be EC public or private key; was "
+ + key.getClass().getName());
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECKeyPairGenerator.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECKeyPairGenerator.java
new file mode 100644
index 0000000..e288bca
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECKeyPairGenerator.java
@@ -0,0 +1,136 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * An implementation of {@link KeyPairGenerator} for EC keys which uses BoringSSL to perform all the
+ * operations.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class OpenSSLECKeyPairGenerator extends KeyPairGenerator {
+ private static final String ALGORITHM = "EC";
+
+ private static final int DEFAULT_KEY_SIZE = 256;
+
+ private static final Map<Integer, String> SIZE_TO_CURVE_NAME = new HashMap<Integer, String>();
+
+ static {
+ /* NIST curves */
+ SIZE_TO_CURVE_NAME.put(224, "secp224r1");
+ SIZE_TO_CURVE_NAME.put(256, "prime256v1");
+ SIZE_TO_CURVE_NAME.put(384, "secp384r1");
+ SIZE_TO_CURVE_NAME.put(521, "secp521r1");
+ }
+
+ private OpenSSLECGroupContext group;
+
+ public OpenSSLECKeyPairGenerator() {
+ super(ALGORITHM);
+ }
+
+ @Override
+ public KeyPair generateKeyPair() {
+ if (group == null) {
+ final String curveName = SIZE_TO_CURVE_NAME.get(DEFAULT_KEY_SIZE);
+ group = OpenSSLECGroupContext.getCurveByName(curveName);
+ if (group == null) {
+ throw new RuntimeException("Curve not recognized: " + curveName);
+ }
+ }
+
+ final OpenSSLKey key = new OpenSSLKey(
+ NativeCrypto.EC_KEY_generate_key(group.getNativeRef()));
+ return new KeyPair(new OpenSSLECPublicKey(group, key), new OpenSSLECPrivateKey(group, key));
+ }
+
+ @Override
+ public void initialize(int keysize, SecureRandom random) {
+ final String name = SIZE_TO_CURVE_NAME.get(keysize);
+ if (name == null) {
+ throw new InvalidParameterException("unknown key size " + keysize);
+ }
+
+ /*
+ * Store the group in a temporary variable until we know this is a valid
+ * group.
+ */
+ final OpenSSLECGroupContext possibleGroup = OpenSSLECGroupContext.getCurveByName(name);
+ if (possibleGroup == null) {
+ throw new InvalidParameterException("unknown curve " + name);
+ }
+
+ group = possibleGroup;
+ }
+
+ @Override
+ public void initialize(AlgorithmParameterSpec param, SecureRandom random)
+ throws InvalidAlgorithmParameterException {
+ if (param instanceof ECParameterSpec) {
+ ECParameterSpec ecParam = (ECParameterSpec) param;
+
+ group = OpenSSLECGroupContext.getInstance(ecParam);
+ } else if (param instanceof ECGenParameterSpec) {
+ ECGenParameterSpec ecParam = (ECGenParameterSpec) param;
+
+ final String curveName = ecParam.getName();
+
+ /*
+ * Store the group in a temporary variable until we know this is a
+ * valid group.
+ */
+ final OpenSSLECGroupContext possibleGroup = OpenSSLECGroupContext
+ .getCurveByName(curveName);
+ if (possibleGroup == null) {
+ throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
+ }
+
+ group = possibleGroup;
+ } else {
+ throw new InvalidAlgorithmParameterException(
+ "parameter must be ECParameterSpec or ECGenParameterSpec");
+ }
+ }
+
+ /** For testing. */
+ public static void assertCurvesAreValid() {
+ ArrayList<String> invalidCurves = new ArrayList<String>();
+ for (String curveName : SIZE_TO_CURVE_NAME.values()) {
+ if (OpenSSLECGroupContext.getCurveByName(curveName) == null) {
+ invalidCurves.add(curveName);
+ }
+ }
+ if (invalidCurves.size() > 0) {
+ throw new AssertionError("Invalid curve names: "
+ + Arrays.toString(invalidCurves.toArray()));
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECPointContext.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECPointContext.java
new file mode 100644
index 0000000..8a6824d
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECPointContext.java
@@ -0,0 +1,64 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.math.BigInteger;
+import java.security.spec.ECPoint;
+
+final class OpenSSLECPointContext {
+ private final OpenSSLECGroupContext group;
+ private final NativeRef.EC_POINT pointCtx;
+
+ OpenSSLECPointContext(OpenSSLECGroupContext group, NativeRef.EC_POINT pointCtx) {
+ this.group = group;
+ this.pointCtx = pointCtx;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ throw new IllegalArgumentException("OpenSSLECPointContext.equals is not defined.");
+ }
+
+ ECPoint getECPoint() {
+ final byte[][] generatorCoords = NativeCrypto.EC_POINT_get_affine_coordinates(
+ group.getNativeRef(), pointCtx);
+ final BigInteger x = new BigInteger(generatorCoords[0]);
+ final BigInteger y = new BigInteger(generatorCoords[1]);
+ return new ECPoint(x, y);
+ }
+
+ @Override
+ public int hashCode() {
+ // TODO Auto-generated method stub
+ return super.hashCode();
+ }
+
+ NativeRef.EC_POINT getNativeRef() {
+ return pointCtx;
+ }
+
+ static OpenSSLECPointContext getInstance(OpenSSLECGroupContext group,
+ ECPoint javaPoint) {
+ OpenSSLECPointContext point = new OpenSSLECPointContext(group, new NativeRef.EC_POINT(
+ NativeCrypto.EC_POINT_new(group.getNativeRef())));
+ NativeCrypto.EC_POINT_set_affine_coordinates(group.getNativeRef(),
+ point.getNativeRef(), javaPoint.getAffineX().toByteArray(),
+ javaPoint.getAffineY().toByteArray());
+ return point;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECPrivateKey.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECPrivateKey.java
new file mode 100644
index 0000000..6bb0c72
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECPrivateKey.java
@@ -0,0 +1,263 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.ECKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Arrays;
+
+/**
+ * An implementation of a {@link PrivateKey} for EC keys based on BoringSSL.
+ */
+final class OpenSSLECPrivateKey implements ECPrivateKey, OpenSSLKeyHolder {
+ private static final long serialVersionUID = -4036633595001083922L;
+
+ private static final String ALGORITHM = "EC";
+
+ private transient OpenSSLKey key;
+
+ private transient OpenSSLECGroupContext group;
+
+ OpenSSLECPrivateKey(OpenSSLECGroupContext group, OpenSSLKey key) {
+ this.group = group;
+ this.key = key;
+ }
+
+ OpenSSLECPrivateKey(OpenSSLKey key) {
+ this.group = new OpenSSLECGroupContext(new NativeRef.EC_GROUP(
+ NativeCrypto.EC_KEY_get1_group(key.getNativeRef())));
+ this.key = key;
+ }
+
+ OpenSSLECPrivateKey(ECPrivateKeySpec ecKeySpec) throws InvalidKeySpecException {
+ try {
+ group = OpenSSLECGroupContext.getInstance(ecKeySpec.getParams());
+ final BigInteger privKey = ecKeySpec.getS();
+ key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_EC_KEY(group.getNativeRef(), null,
+ privKey.toByteArray()));
+ } catch (Exception e) {
+ throw new InvalidKeySpecException(e);
+ }
+ }
+
+ static OpenSSLKey wrapPlatformKey(ECPrivateKey ecPrivateKey) throws InvalidKeyException {
+ OpenSSLECGroupContext group;
+ try {
+ group = OpenSSLECGroupContext.getInstance(ecPrivateKey.getParams());
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new InvalidKeyException("Unknown group parameters", e);
+ }
+ return wrapPlatformKey(ecPrivateKey, group);
+ }
+
+ /**
+ * Wraps the provided private key for use in the TLS/SSL stack only. Sign/decrypt operations
+ * using the key will be delegated to the {@code Signature}/{@code Cipher} implementation of the
+ * provider which accepts the key.
+ */
+ static OpenSSLKey wrapJCAPrivateKeyForTLSStackOnly(PrivateKey privateKey,
+ PublicKey publicKey) throws InvalidKeyException {
+ ECParameterSpec params = null;
+ if (privateKey instanceof ECKey) {
+ params = ((ECKey) privateKey).getParams();
+ } else if (publicKey instanceof ECKey) {
+ params = ((ECKey) publicKey).getParams();
+ }
+ if (params == null) {
+ throw new InvalidKeyException("EC parameters not available. Private: " + privateKey
+ + ", public: " + publicKey);
+ }
+ return wrapJCAPrivateKeyForTLSStackOnly(privateKey, params);
+ }
+
+ /**
+ * Wraps the provided private key for use in the TLS/SSL stack only. Sign/decrypt operations
+ * using the key will be delegated to the {@code Signature}/{@code Cipher} implementation of the
+ * provider which accepts the key.
+ */
+ static OpenSSLKey wrapJCAPrivateKeyForTLSStackOnly(PrivateKey privateKey,
+ ECParameterSpec params) throws InvalidKeyException {
+ if (params == null) {
+ if (privateKey instanceof ECKey) {
+ params = ((ECKey) privateKey).getParams();
+ }
+ }
+ if (params == null) {
+ throw new InvalidKeyException("EC parameters not available: " + privateKey);
+ }
+
+ OpenSSLECGroupContext group;
+ try {
+ group = OpenSSLECGroupContext.getInstance(params);
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new InvalidKeyException("Invalid EC parameters: " + params);
+ }
+
+ return new OpenSSLKey(
+ NativeCrypto.getECPrivateKeyWrapper(privateKey, group.getNativeRef()), true);
+ }
+
+ private static OpenSSLKey wrapPlatformKey(ECPrivateKey ecPrivateKey,
+ OpenSSLECGroupContext group) throws InvalidKeyException {
+ return new OpenSSLKey(NativeCrypto.getECPrivateKeyWrapper(ecPrivateKey,
+ group.getNativeRef()), true);
+ }
+
+ static OpenSSLKey getInstance(ECPrivateKey ecPrivateKey) throws InvalidKeyException {
+ try {
+ OpenSSLECGroupContext group = OpenSSLECGroupContext.getInstance(ecPrivateKey
+ .getParams());
+
+ /*
+ * If the key is not encodable (PKCS11-like key), then wrap it and
+ * use JNI upcalls to satisfy requests.
+ */
+ if (ecPrivateKey.getFormat() == null) {
+ return wrapPlatformKey(ecPrivateKey, group);
+ }
+
+ final BigInteger privKey = ecPrivateKey.getS();
+ return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_EC_KEY(group.getNativeRef(), null,
+ privKey.toByteArray()));
+ } catch (Exception e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return ALGORITHM;
+ }
+
+ @Override
+ public String getFormat() {
+ if (key.isHardwareBacked()) {
+ return null;
+ }
+ return "PKCS#8";
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ if (key.isHardwareBacked()) {
+ return null;
+ }
+ return NativeCrypto.EVP_marshal_private_key(key.getNativeRef());
+ }
+
+ @Override
+ public ECParameterSpec getParams() {
+ return group.getECParameterSpec();
+ }
+
+ @Override
+ public BigInteger getS() {
+ if (key.isHardwareBacked()) {
+ throw new UnsupportedOperationException("Private key value S cannot be extracted");
+ }
+ return getPrivateKey();
+ }
+
+ private BigInteger getPrivateKey() {
+ return new BigInteger(NativeCrypto.EC_KEY_get_private_key(key.getNativeRef()));
+ }
+
+ @Override
+ public OpenSSLKey getOpenSSLKey() {
+ return key;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (o instanceof OpenSSLECPrivateKey) {
+ OpenSSLECPrivateKey other = (OpenSSLECPrivateKey) o;
+ return key.equals(other.key);
+ }
+
+ if (!(o instanceof ECPrivateKey)) {
+ return false;
+ }
+
+ final ECPrivateKey other = (ECPrivateKey) o;
+ if (!getPrivateKey().equals(other.getS())) {
+ return false;
+ }
+
+ final ECParameterSpec spec = getParams();
+ final ECParameterSpec otherSpec = other.getParams();
+
+ return spec.getCurve().equals(otherSpec.getCurve())
+ && spec.getGenerator().equals(otherSpec.getGenerator())
+ && spec.getOrder().equals(otherSpec.getOrder())
+ && spec.getCofactor() == otherSpec.getCofactor();
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(NativeCrypto.EVP_marshal_private_key(key.getNativeRef()));
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("OpenSSLECPrivateKey{");
+ sb.append("params={");
+ sb.append(NativeCrypto.EVP_PKEY_print_params(key.getNativeRef()));
+ sb.append("}}");
+ return sb.toString();
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+
+ byte[] encoded = (byte[]) stream.readObject();
+
+ try {
+ key = new OpenSSLKey(NativeCrypto.EVP_parse_private_key(encoded));
+ } catch (ParsingException e) {
+ throw new IOException(e);
+ }
+ group = new OpenSSLECGroupContext(new NativeRef.EC_GROUP(
+ NativeCrypto.EC_KEY_get1_group(key.getNativeRef())));
+ }
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ if (key.isHardwareBacked()) {
+ throw new NotSerializableException("Hardware backed keys cannot be serialized");
+ }
+
+ stream.defaultWriteObject();
+ stream.writeObject(getEncoded());
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECPublicKey.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECPublicKey.java
new file mode 100644
index 0000000..37fd102
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECPublicKey.java
@@ -0,0 +1,178 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.security.InvalidKeyException;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Arrays;
+
+/**
+ * An implementation of a {@link java.security.PublicKey} for EC keys based on BoringSSL.
+ */
+final class OpenSSLECPublicKey implements ECPublicKey, OpenSSLKeyHolder {
+ private static final long serialVersionUID = 3215842926808298020L;
+
+ private static final String ALGORITHM = "EC";
+
+ private transient OpenSSLKey key;
+
+ private transient OpenSSLECGroupContext group;
+
+ OpenSSLECPublicKey(OpenSSLECGroupContext group, OpenSSLKey key) {
+ this.group = group;
+ this.key = key;
+ }
+
+ OpenSSLECPublicKey(OpenSSLKey key) {
+ this.group = new OpenSSLECGroupContext(new NativeRef.EC_GROUP(
+ NativeCrypto.EC_KEY_get1_group(key.getNativeRef())));
+ this.key = key;
+ }
+
+ OpenSSLECPublicKey(ECPublicKeySpec ecKeySpec) throws InvalidKeySpecException {
+ try {
+ group = OpenSSLECGroupContext.getInstance(ecKeySpec.getParams());
+ OpenSSLECPointContext pubKey = OpenSSLECPointContext.getInstance(group,
+ ecKeySpec.getW());
+ key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_EC_KEY(group.getNativeRef(),
+ pubKey.getNativeRef(), null));
+ } catch (Exception e) {
+ throw new InvalidKeySpecException(e);
+ }
+ }
+
+ static OpenSSLKey getInstance(ECPublicKey ecPublicKey) throws InvalidKeyException {
+ try {
+ OpenSSLECGroupContext group = OpenSSLECGroupContext
+ .getInstance(ecPublicKey.getParams());
+ OpenSSLECPointContext pubKey = OpenSSLECPointContext.getInstance(group,
+ ecPublicKey.getW());
+ return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_EC_KEY(group.getNativeRef(),
+ pubKey.getNativeRef(), null));
+ } catch (Exception e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return ALGORITHM;
+ }
+
+ @Override
+ public String getFormat() {
+ return "X.509";
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return NativeCrypto.EVP_marshal_public_key(key.getNativeRef());
+ }
+
+ @Override
+ public ECParameterSpec getParams() {
+ return group.getECParameterSpec();
+ }
+
+ private ECPoint getPublicKey() {
+ final OpenSSLECPointContext pubKey = new OpenSSLECPointContext(group,
+ new NativeRef.EC_POINT(NativeCrypto.EC_KEY_get_public_key(key.getNativeRef())));
+
+ return pubKey.getECPoint();
+ }
+
+ @Override
+ public ECPoint getW() {
+ return getPublicKey();
+ }
+
+ @Override
+ public OpenSSLKey getOpenSSLKey() {
+ return key;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (o instanceof OpenSSLECPublicKey) {
+ OpenSSLECPublicKey other = (OpenSSLECPublicKey) o;
+ return key.equals(other.key);
+ }
+
+ if (!(o instanceof ECPublicKey)) {
+ return false;
+ }
+
+ final ECPublicKey other = (ECPublicKey) o;
+ if (!getPublicKey().equals(other.getW())) {
+ return false;
+ }
+
+ final ECParameterSpec spec = getParams();
+ final ECParameterSpec otherSpec = other.getParams();
+
+ return spec.getCurve().equals(otherSpec.getCurve())
+ && spec.getGenerator().equals(otherSpec.getGenerator())
+ && spec.getOrder().equals(otherSpec.getOrder())
+ && spec.getCofactor() == otherSpec.getCofactor();
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(NativeCrypto.EVP_marshal_public_key(key.getNativeRef()));
+ }
+
+ @Override
+ public String toString() {
+ return NativeCrypto.EVP_PKEY_print_public(key.getNativeRef());
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+
+ byte[] encoded = (byte[]) stream.readObject();
+
+ try {
+ key = new OpenSSLKey(NativeCrypto.EVP_parse_public_key(encoded));
+ } catch (ParsingException e) {
+ throw new IOException(e);
+ }
+ group = new OpenSSLECGroupContext(new NativeRef.EC_GROUP(
+ NativeCrypto.EC_KEY_get1_group(key.getNativeRef())));
+ }
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ if (key.isHardwareBacked()) {
+ throw new NotSerializableException("Hardware backed keys cannot be serialized");
+ }
+ stream.defaultWriteObject();
+ stream.writeObject(getEncoded());
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLEvpCipher.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLEvpCipher.java
new file mode 100644
index 0000000..765282d
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLEvpCipher.java
@@ -0,0 +1,212 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+import com.android.org.conscrypt.NativeRef.EVP_CIPHER_CTX;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public abstract class OpenSSLEvpCipher extends OpenSSLCipher {
+ /**
+ * Native pointer for the OpenSSL EVP_CIPHER context.
+ */
+ private final EVP_CIPHER_CTX cipherCtx = new EVP_CIPHER_CTX(
+ NativeCrypto.EVP_CIPHER_CTX_new());
+
+ /**
+ * Whether the cipher has processed any data yet. EVP_CIPHER doesn't
+ * like calling "doFinal()" in decryption mode without processing any
+ * updates.
+ */
+ private boolean calledUpdate;
+
+ /**
+ * The block size of the current mode.
+ */
+ private int modeBlockSize;
+
+ protected OpenSSLEvpCipher(Mode mode, Padding padding) {
+ super(mode, padding);
+ }
+
+ @Override
+ void engineInitInternal(byte[] encodedKey, AlgorithmParameterSpec params,
+ SecureRandom random) throws InvalidKeyException,
+ InvalidAlgorithmParameterException {
+ byte[] iv;
+ if (params instanceof IvParameterSpec) {
+ IvParameterSpec ivParams = (IvParameterSpec) params;
+ iv = ivParams.getIV();
+ } else {
+ iv = null;
+ }
+
+ final long cipherType = NativeCrypto.EVP_get_cipherbyname(getCipherName(
+ encodedKey.length, mode));
+ if (cipherType == 0) {
+ throw new InvalidAlgorithmParameterException("Cannot find name for key length = "
+ + (encodedKey.length * 8) + " and mode = " + mode);
+ }
+
+ final boolean encrypting = isEncrypting();
+
+ final int expectedIvLength = NativeCrypto.EVP_CIPHER_iv_length(cipherType);
+ if (iv == null && expectedIvLength != 0) {
+ if (!encrypting) {
+ throw new InvalidAlgorithmParameterException("IV must be specified in " + mode
+ + " mode");
+ }
+
+ iv = new byte[expectedIvLength];
+ if (random != null) {
+ random.nextBytes(iv);
+ } else {
+ NativeCrypto.RAND_bytes(iv);
+ }
+ } else if (expectedIvLength == 0 && iv != null) {
+ throw new InvalidAlgorithmParameterException("IV not used in " + mode + " mode");
+ } else if (iv != null && iv.length != expectedIvLength) {
+ throw new InvalidAlgorithmParameterException("expected IV length of "
+ + expectedIvLength + " but was " + iv.length);
+ }
+
+ this.iv = iv;
+
+ if (supportsVariableSizeKey()) {
+ NativeCrypto.EVP_CipherInit_ex(cipherCtx, cipherType, null, null, encrypting);
+ NativeCrypto.EVP_CIPHER_CTX_set_key_length(cipherCtx, encodedKey.length);
+ NativeCrypto.EVP_CipherInit_ex(cipherCtx, 0, encodedKey, iv, isEncrypting());
+ } else {
+ NativeCrypto.EVP_CipherInit_ex(cipherCtx, cipherType, encodedKey, iv, encrypting);
+ }
+
+ // OpenSSL only supports PKCS5 Padding.
+ NativeCrypto
+ .EVP_CIPHER_CTX_set_padding(cipherCtx, getPadding() == Padding.PKCS5PADDING);
+ modeBlockSize = NativeCrypto.EVP_CIPHER_CTX_block_size(cipherCtx);
+ calledUpdate = false;
+ }
+
+ @Override
+ int updateInternal(byte[] input, int inputOffset, int inputLen, byte[] output,
+ int outputOffset, int maximumLen) throws ShortBufferException {
+ final int intialOutputOffset = outputOffset;
+
+ final int bytesLeft = output.length - outputOffset;
+ if (bytesLeft < maximumLen) {
+ throw new ShortBufferWithoutStackTraceException(
+ "output buffer too small during update: " + bytesLeft + " < " + maximumLen);
+ }
+
+ outputOffset += NativeCrypto.EVP_CipherUpdate(cipherCtx, output, outputOffset, input,
+ inputOffset, inputLen);
+
+ calledUpdate = true;
+
+ return outputOffset - intialOutputOffset;
+ }
+
+ @Override
+ int doFinalInternal(byte[] output, int outputOffset, int maximumLen)
+ throws IllegalBlockSizeException, BadPaddingException, ShortBufferException {
+ /* Remember this so we can tell how many characters were written. */
+ final int initialOutputOffset = outputOffset;
+
+ /*
+ * If we're decrypting and haven't had any input, we should return
+ * null. Otherwise OpenSSL will complain if we call final.
+ */
+ if (!isEncrypting() && !calledUpdate) {
+ return 0;
+ }
+
+ /* Allow OpenSSL to pad if necessary and clean up state. */
+ final int bytesLeft = output.length - outputOffset;
+ final int writtenBytes;
+ if (bytesLeft >= maximumLen) {
+ writtenBytes = NativeCrypto.EVP_CipherFinal_ex(cipherCtx, output, outputOffset);
+ } else {
+ final byte[] lastBlock = new byte[maximumLen];
+ writtenBytes = NativeCrypto.EVP_CipherFinal_ex(cipherCtx, lastBlock, 0);
+ if (writtenBytes > bytesLeft) {
+ throw new ShortBufferWithoutStackTraceException(
+ "buffer is too short: " + writtenBytes + " > " + bytesLeft);
+ } else if (writtenBytes > 0) {
+ System.arraycopy(lastBlock, 0, output, outputOffset, writtenBytes);
+ }
+ }
+ outputOffset += writtenBytes;
+
+ reset();
+
+ return outputOffset - initialOutputOffset;
+ }
+
+ @Override
+ int getOutputSizeForFinal(int inputLen) {
+ if (modeBlockSize == 1) {
+ return inputLen;
+ } else {
+ final int buffered = NativeCrypto.get_EVP_CIPHER_CTX_buf_len(cipherCtx);
+
+ if (getPadding() == Padding.NOPADDING) {
+ return buffered + inputLen;
+ } else {
+ final boolean finalUsed = NativeCrypto.get_EVP_CIPHER_CTX_final_used(cipherCtx);
+ // There is an additional buffer containing the possible final block.
+ int totalLen = inputLen + buffered + (finalUsed ? modeBlockSize : 0);
+ // Extra block for remainder bytes plus padding.
+ // In case it's encrypting and there are no remainder bytes, add an extra block
+ // consisting only of padding.
+ totalLen += ((totalLen % modeBlockSize != 0) || isEncrypting())
+ ? modeBlockSize : 0;
+ // The minimum multiple of {@code modeBlockSize} that can hold all the bytes.
+ return totalLen - (totalLen % modeBlockSize);
+ }
+ }
+ }
+
+ @Override
+ int getOutputSizeForUpdate(int inputLen) {
+ return getOutputSizeForFinal(inputLen);
+ }
+
+ /**
+ * Returns the OpenSSL cipher name for the particular {@code keySize}
+ * and cipher {@code mode}.
+ */
+ abstract String getCipherName(int keySize, Mode mode);
+
+ /**
+ * Reset this Cipher instance state to process a new chunk of data.
+ */
+ private void reset() {
+ NativeCrypto.EVP_CipherInit_ex(cipherCtx, 0, encodedKey, iv, isEncrypting());
+ calledUpdate = false;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLEvpCipherAES.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLEvpCipherAES.java
new file mode 100644
index 0000000..ee65b30
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLEvpCipherAES.java
@@ -0,0 +1,317 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Locale;
+import javax.crypto.NoSuchPaddingException;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public abstract class OpenSSLEvpCipherAES extends OpenSSLEvpCipher {
+ private static final int AES_BLOCK_SIZE = 16;
+
+ OpenSSLEvpCipherAES(Mode mode, Padding padding) {
+ super(mode, padding);
+ }
+
+ @Override
+ void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException {
+ switch (mode) {
+ case CBC:
+ case CTR:
+ case ECB:
+ return;
+ default:
+ throw new NoSuchAlgorithmException("Unsupported mode " + mode.toString());
+ }
+ }
+
+ @Override
+ void checkSupportedPadding(Padding padding) throws NoSuchPaddingException {
+ switch (padding) {
+ case NOPADDING:
+ case PKCS5PADDING:
+ return;
+ default:
+ throw new NoSuchPaddingException(
+ "Unsupported padding " + padding.toString());
+ }
+ }
+
+ @Override
+ String getBaseCipherName() {
+ return "AES";
+ }
+
+ @Override
+ String getCipherName(int keyLength, Mode mode) {
+ return "aes-" + (keyLength * 8) + "-" + mode.toString().toLowerCase(Locale.US);
+ }
+
+ @Override
+ int getCipherBlockSize() {
+ return AES_BLOCK_SIZE;
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class AES extends OpenSSLEvpCipherAES {
+ AES(Mode mode, Padding padding) {
+ super(mode, padding);
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class CBC extends AES {
+ CBC(Padding padding) {
+ super(Mode.CBC, padding);
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class NoPadding extends AES.CBC {
+ public NoPadding() {
+ super(Padding.NOPADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class PKCS5Padding extends AES.CBC {
+ public PKCS5Padding() {
+ super(Padding.PKCS5PADDING);
+ }
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class CTR extends AES {
+ public CTR() {
+ super(Mode.CTR, Padding.NOPADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class ECB extends AES {
+ ECB(Padding padding) {
+ super(Mode.ECB, padding);
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class NoPadding extends AES.ECB {
+ public NoPadding() {
+ super(Padding.NOPADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class PKCS5Padding extends AES.ECB {
+ public PKCS5Padding() {
+ super(Padding.PKCS5PADDING);
+ }
+ }
+ }
+
+ @Override
+ void checkSupportedKeySize(int keyLength) throws InvalidKeyException {
+ switch (keyLength) {
+ case 16: // AES 128
+ case 24: // AES 192
+ case 32: // AES 256
+ return;
+ default:
+ throw new InvalidKeyException("Unsupported key size: " + keyLength
+ + " bytes");
+ }
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class AES_128 extends OpenSSLEvpCipherAES {
+ AES_128(Mode mode, Padding padding) {
+ super(mode, padding);
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class CBC extends AES_128 {
+ CBC(Padding padding) {
+ super(Mode.CBC, padding);
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class NoPadding extends AES_128.CBC {
+ public NoPadding() {
+ super(Padding.NOPADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class PKCS5Padding extends AES_128.CBC {
+ public PKCS5Padding() {
+ super(Padding.PKCS5PADDING);
+ }
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class CTR extends AES_128 {
+ public CTR() {
+ super(Mode.CTR, Padding.NOPADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class ECB extends AES_128 {
+ ECB(Padding padding) {
+ super(Mode.ECB, padding);
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class NoPadding extends AES_128.ECB {
+ public NoPadding() {
+ super(Padding.NOPADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class PKCS5Padding extends AES_128.ECB {
+ public PKCS5Padding() {
+ super(Padding.PKCS5PADDING);
+ }
+ }
+ }
+
+ @Override
+ void checkSupportedKeySize(int keyLength) throws InvalidKeyException {
+ if (keyLength != 16) { // 128 bits
+ throw new InvalidKeyException("Unsupported key size: " + keyLength + " bytes");
+ }
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class AES_256 extends OpenSSLEvpCipherAES {
+ AES_256(Mode mode, Padding padding) {
+ super(mode, padding);
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class CBC extends AES_256 {
+ CBC(Padding padding) {
+ super(Mode.CBC, padding);
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class NoPadding extends AES_256.CBC {
+ public NoPadding() {
+ super(Padding.NOPADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class PKCS5Padding extends AES_256.CBC {
+ public PKCS5Padding() {
+ super(Padding.PKCS5PADDING);
+ }
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class CTR extends AES_256 {
+ public CTR() {
+ super(Mode.CTR, Padding.NOPADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class ECB extends AES_256 {
+ ECB(Padding padding) {
+ super(Mode.ECB, padding);
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class NoPadding extends AES_256.ECB {
+ public NoPadding() {
+ super(Padding.NOPADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class PKCS5Padding extends AES_256.ECB {
+ public PKCS5Padding() {
+ super(Padding.PKCS5PADDING);
+ }
+ }
+ }
+
+ @Override
+ void checkSupportedKeySize(int keyLength) throws InvalidKeyException {
+ if (keyLength != 32) { // 256 bits
+ throw new InvalidKeyException("Unsupported key size: " + keyLength + " bytes");
+ }
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLEvpCipherARC4.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLEvpCipherARC4.java
new file mode 100644
index 0000000..80994b0
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLEvpCipherARC4.java
@@ -0,0 +1,71 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import javax.crypto.NoSuchPaddingException;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class OpenSSLEvpCipherARC4 extends OpenSSLEvpCipher {
+ public OpenSSLEvpCipherARC4() {
+ // Modes and padding don't make sense for ARC4.
+ super(Mode.ECB, Padding.NOPADDING);
+ }
+
+ @Override
+ String getBaseCipherName() {
+ return "ARCFOUR";
+ }
+
+ @Override
+ String getCipherName(int keySize, Mode mode) {
+ return "rc4";
+ }
+
+ @Override
+ void checkSupportedKeySize(int keySize) throws InvalidKeyException {
+ }
+
+ @Override
+ void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException {
+ if (mode != Mode.NONE && mode != Mode.ECB) {
+ throw new NoSuchAlgorithmException("Unsupported mode " + mode.toString());
+ }
+ }
+
+ @Override
+ void checkSupportedPadding(Padding padding) throws NoSuchPaddingException {
+ if (padding != Padding.NOPADDING) {
+ throw new NoSuchPaddingException("Unsupported padding " + padding.toString());
+ }
+ }
+
+ @Override
+ int getCipherBlockSize() {
+ return 0;
+ }
+
+ @Override
+ boolean supportsVariableSizeKey() {
+ return true;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLEvpCipherDESEDE.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLEvpCipherDESEDE.java
new file mode 100644
index 0000000..9e8d50c
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLEvpCipherDESEDE.java
@@ -0,0 +1,110 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Locale;
+import javax.crypto.NoSuchPaddingException;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public abstract class OpenSSLEvpCipherDESEDE extends OpenSSLEvpCipher {
+ private static final int DES_BLOCK_SIZE = 8;
+
+ OpenSSLEvpCipherDESEDE(Mode mode, Padding padding) {
+ super(mode, padding);
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class CBC extends OpenSSLEvpCipherDESEDE {
+ CBC(Padding padding) {
+ super(Mode.CBC, padding);
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class NoPadding extends CBC {
+ public NoPadding() {
+ super(Padding.NOPADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class PKCS5Padding extends CBC {
+ public PKCS5Padding() {
+ super(Padding.PKCS5PADDING);
+ }
+ }
+ }
+
+ @Override
+ String getBaseCipherName() {
+ return "DESede";
+ }
+
+ @Override
+ String getCipherName(int keySize, Mode mode) {
+ final String baseCipherName;
+ if (keySize == 16) {
+ baseCipherName = "des-ede";
+ } else {
+ baseCipherName = "des-ede3";
+ }
+
+ return baseCipherName + "-" + mode.toString().toLowerCase(Locale.US);
+ }
+
+ @Override
+ void checkSupportedKeySize(int keySize) throws InvalidKeyException {
+ if (keySize != 16 && keySize != 24) {
+ throw new InvalidKeyException("key size must be 128 or 192 bits");
+ }
+ }
+
+ @Override
+ void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException {
+ if (mode != Mode.CBC) {
+ throw new NoSuchAlgorithmException("Unsupported mode " + mode.toString());
+ }
+ }
+
+ @Override
+ void checkSupportedPadding(Padding padding) throws NoSuchPaddingException {
+ switch (padding) {
+ case NOPADDING:
+ case PKCS5PADDING:
+ return;
+ default:
+ throw new NoSuchPaddingException("Unsupported padding "
+ + padding.toString());
+ }
+ }
+
+ @Override
+ int getCipherBlockSize() {
+ return DES_BLOCK_SIZE;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLKey.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLKey.java
new file mode 100644
index 0000000..bc09c81
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLKey.java
@@ -0,0 +1,373 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+import java.io.InputStream;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+/**
+ * Represents a BoringSSL {@code EVP_PKEY}.
+ */
+final class OpenSSLKey {
+ private final NativeRef.EVP_PKEY ctx;
+
+ private final boolean wrapped;
+
+ // If true, indicates that this key is hardware-backed, e.g. stored in a TEE keystore.
+ // Conscrypt never creates such keys, but setting this field to true allows developers
+ // to create an EVP_PKEY from a hardware-backed key and then create an OpenSSLKey from it
+ // which can be used with Conscrypt.
+ // Hardware-backed keys cannot be serialised or have any private key material extracted.
+ private final boolean hardwareBacked;
+
+ @android.compat.annotation.UnsupportedAppUsage
+ OpenSSLKey(long ctx) {
+ this(ctx, false);
+ }
+
+ OpenSSLKey(long ctx, boolean wrapped) {
+ this(ctx, wrapped, false);
+ }
+
+ // Constructor for users who need to set the |hardwareBacked| field to true.
+ // See the field documentation for more information.
+ OpenSSLKey(long ctx, boolean wrapped, boolean hardwareBacked) {
+ this.ctx = new NativeRef.EVP_PKEY(ctx);
+ this.wrapped = wrapped;
+ this.hardwareBacked = hardwareBacked;
+ }
+
+ /**
+ * Returns the EVP_PKEY context for use in JNI calls.
+ */
+ @android.compat.annotation.UnsupportedAppUsage
+ NativeRef.EVP_PKEY getNativeRef() {
+ return ctx;
+ }
+
+ boolean isWrapped() {
+ return wrapped;
+ }
+
+ boolean isHardwareBacked() {
+ return hardwareBacked;
+ }
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static OpenSSLKey fromPrivateKey(PrivateKey key) throws InvalidKeyException {
+ if (key instanceof OpenSSLKeyHolder) {
+ return ((OpenSSLKeyHolder) key).getOpenSSLKey();
+ }
+
+ final String keyFormat = key.getFormat();
+ if (keyFormat == null) {
+ return wrapPrivateKey(key);
+ } else if (!"PKCS#8".equals(key.getFormat())) {
+ throw new InvalidKeyException("Unknown key format " + keyFormat);
+ }
+
+ final byte[] encoded = key.getEncoded();
+ if (encoded == null) {
+ throw new InvalidKeyException("Key encoding is null");
+ }
+
+ try {
+ return new OpenSSLKey(NativeCrypto.EVP_parse_private_key(key.getEncoded()));
+ } catch (ParsingException e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
+ /**
+ * Parse a private key in PEM encoding from the provided input stream.
+ *
+ * @throws InvalidKeyException if parsing fails
+ */
+ static OpenSSLKey fromPrivateKeyPemInputStream(InputStream is)
+ throws InvalidKeyException {
+ OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is, true);
+ try {
+ long keyCtx = NativeCrypto.PEM_read_bio_PrivateKey(bis.getBioContext());
+ if (keyCtx == 0L) {
+ return null;
+ }
+
+ return new OpenSSLKey(keyCtx);
+ } catch (Exception e) {
+ throw new InvalidKeyException(e);
+ } finally {
+ bis.release();
+ }
+ }
+
+ /**
+ * Gets an {@code OpenSSLKey} instance backed by the provided private key. The resulting key is
+ * usable only by this provider's TLS/SSL stack.
+ *
+ * @param privateKey private key.
+ * @param publicKey corresponding public key or {@code null} if not available. Some opaque
+ * private keys cannot be used by the TLS/SSL stack without the public key.
+ */
+ static OpenSSLKey fromPrivateKeyForTLSStackOnly(
+ PrivateKey privateKey, PublicKey publicKey) throws InvalidKeyException {
+ OpenSSLKey result = getOpenSSLKey(privateKey);
+ if (result != null) {
+ return result;
+ }
+
+ result = fromKeyMaterial(privateKey);
+ if (result != null) {
+ return result;
+ }
+
+ return wrapJCAPrivateKeyForTLSStackOnly(privateKey, publicKey);
+ }
+
+ /**
+ * Gets an {@code OpenSSLKey} instance backed by the provided EC private key. The resulting key
+ * is usable only by this provider's TLS/SSL stack.
+ *
+ * @param key private key.
+ * @param ecParams EC parameters {@code null} if not available. Some opaque private keys cannot
+ * be used by the TLS/SSL stack without the parameters because the private key itself
+ * might not expose the parameters.
+ */
+ static OpenSSLKey fromECPrivateKeyForTLSStackOnly(
+ PrivateKey key, ECParameterSpec ecParams) throws InvalidKeyException {
+ OpenSSLKey result = getOpenSSLKey(key);
+ if (result != null) {
+ return result;
+ }
+
+ result = fromKeyMaterial(key);
+ if (result != null) {
+ return result;
+ }
+
+ return OpenSSLECPrivateKey.wrapJCAPrivateKeyForTLSStackOnly(key, ecParams);
+ }
+
+ /**
+ * Gets the {@code OpenSSLKey} instance of the provided key.
+ *
+ * @return instance or {@code null} if the {@code key} is not backed by OpenSSL's
+ * {@code EVP_PKEY}.
+ */
+ private static OpenSSLKey getOpenSSLKey(PrivateKey key) {
+ if (key instanceof OpenSSLKeyHolder) {
+ return ((OpenSSLKeyHolder) key).getOpenSSLKey();
+ }
+
+ if ("RSA".equals(key.getAlgorithm())) {
+ return Platform.wrapRsaKey(key);
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets an {@code OpenSSLKey} instance initialized with the key material of the provided key.
+ *
+ * @return instance or {@code null} if the {@code key} does not export its key material in a
+ * suitable format.
+ */
+ private static OpenSSLKey fromKeyMaterial(PrivateKey key) throws InvalidKeyException {
+ if (!"PKCS#8".equals(key.getFormat())) {
+ return null;
+ }
+ byte[] encoded = key.getEncoded();
+ if (encoded == null) {
+ return null;
+ }
+ try {
+ return new OpenSSLKey(NativeCrypto.EVP_parse_private_key(encoded));
+ } catch (ParsingException e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
+ /**
+ * Wraps the provided private key for use in the TLS/SSL stack only. Sign/decrypt operations
+ * using the key will be delegated to the {@code Signature}/{@code Cipher} implementation of the
+ * provider which accepts the key.
+ */
+ private static OpenSSLKey wrapJCAPrivateKeyForTLSStackOnly(PrivateKey privateKey,
+ PublicKey publicKey) throws InvalidKeyException {
+ String keyAlgorithm = privateKey.getAlgorithm();
+ if ("RSA".equals(keyAlgorithm)) {
+ return OpenSSLRSAPrivateKey.wrapJCAPrivateKeyForTLSStackOnly(privateKey, publicKey);
+ } else if ("EC".equals(keyAlgorithm)) {
+ return OpenSSLECPrivateKey.wrapJCAPrivateKeyForTLSStackOnly(privateKey, publicKey);
+ } else {
+ throw new InvalidKeyException("Unsupported key algorithm: " + keyAlgorithm);
+ }
+ }
+
+ private static OpenSSLKey wrapPrivateKey(PrivateKey key) throws InvalidKeyException {
+ if (key instanceof RSAPrivateKey) {
+ return OpenSSLRSAPrivateKey.wrapPlatformKey((RSAPrivateKey) key);
+ } else if (key instanceof ECPrivateKey) {
+ return OpenSSLECPrivateKey.wrapPlatformKey((ECPrivateKey) key);
+ } else {
+ throw new InvalidKeyException("Unknown key type: " + key.toString());
+ }
+ }
+
+ static OpenSSLKey fromPublicKey(PublicKey key) throws InvalidKeyException {
+ if (key instanceof OpenSSLKeyHolder) {
+ return ((OpenSSLKeyHolder) key).getOpenSSLKey();
+ }
+
+ if (!"X.509".equals(key.getFormat())) {
+ throw new InvalidKeyException("Unknown key format " + key.getFormat());
+ }
+
+ final byte[] encoded = key.getEncoded();
+ if (encoded == null) {
+ throw new InvalidKeyException("Key encoding is null");
+ }
+
+ try {
+ return new OpenSSLKey(NativeCrypto.EVP_parse_public_key(key.getEncoded()));
+ } catch (Exception e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
+ /**
+ * Parse a public key in PEM encoding from the provided input stream.
+ *
+ * @throws InvalidKeyException if parsing fails
+ */
+ static OpenSSLKey fromPublicKeyPemInputStream(InputStream is)
+ throws InvalidKeyException {
+ OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is, true);
+ try {
+ long keyCtx = NativeCrypto.PEM_read_bio_PUBKEY(bis.getBioContext());
+ if (keyCtx == 0L) {
+ return null;
+ }
+
+ return new OpenSSLKey(keyCtx);
+ } catch (Exception e) {
+ throw new InvalidKeyException(e);
+ } finally {
+ bis.release();
+ }
+ }
+
+ @android.compat.annotation.UnsupportedAppUsage
+ PublicKey getPublicKey() throws NoSuchAlgorithmException {
+ switch (NativeCrypto.EVP_PKEY_type(ctx)) {
+ case NativeConstants.EVP_PKEY_RSA:
+ return new OpenSSLRSAPublicKey(this);
+ case NativeConstants.EVP_PKEY_EC:
+ return new OpenSSLECPublicKey(this);
+ default:
+ throw new NoSuchAlgorithmException("unknown PKEY type");
+ }
+ }
+
+ static PublicKey getPublicKey(X509EncodedKeySpec keySpec, int type)
+ throws InvalidKeySpecException {
+ X509EncodedKeySpec x509KeySpec = keySpec;
+
+ final OpenSSLKey key;
+ try {
+ key = new OpenSSLKey(NativeCrypto.EVP_parse_public_key(x509KeySpec.getEncoded()));
+ } catch (Exception e) {
+ throw new InvalidKeySpecException(e);
+ }
+
+ if (NativeCrypto.EVP_PKEY_type(key.getNativeRef()) != type) {
+ throw new InvalidKeySpecException("Unexpected key type");
+ }
+
+ try {
+ return key.getPublicKey();
+ } catch (NoSuchAlgorithmException e) {
+ throw new InvalidKeySpecException(e);
+ }
+ }
+
+ PrivateKey getPrivateKey() throws NoSuchAlgorithmException {
+ switch (NativeCrypto.EVP_PKEY_type(ctx)) {
+ case NativeConstants.EVP_PKEY_RSA:
+ return OpenSSLRSAPrivateKey.getInstance(this);
+ case NativeConstants.EVP_PKEY_EC:
+ return new OpenSSLECPrivateKey(this);
+ default:
+ throw new NoSuchAlgorithmException("unknown PKEY type");
+ }
+ }
+
+ static PrivateKey getPrivateKey(PKCS8EncodedKeySpec keySpec, int type)
+ throws InvalidKeySpecException {
+ PKCS8EncodedKeySpec pkcs8KeySpec = keySpec;
+
+ final OpenSSLKey key;
+ try {
+ key = new OpenSSLKey(NativeCrypto.EVP_parse_private_key(pkcs8KeySpec.getEncoded()));
+ } catch (Exception e) {
+ throw new InvalidKeySpecException(e);
+ }
+
+ if (NativeCrypto.EVP_PKEY_type(key.getNativeRef()) != type) {
+ throw new InvalidKeySpecException("Unexpected key type");
+ }
+
+ try {
+ return key.getPrivateKey();
+ } catch (NoSuchAlgorithmException e) {
+ throw new InvalidKeySpecException(e);
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (!(o instanceof OpenSSLKey)) {
+ return false;
+ }
+
+ OpenSSLKey other = (OpenSSLKey) o;
+ if (ctx.equals(other.getNativeRef())) {
+ return true;
+ }
+
+ return NativeCrypto.EVP_PKEY_cmp(ctx, other.getNativeRef()) == 1;
+ }
+
+ @Override
+ public int hashCode() {
+ return ctx.hashCode();
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLKeyHolder.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLKeyHolder.java
new file mode 100644
index 0000000..32c70d7
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLKeyHolder.java
@@ -0,0 +1,27 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2013 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.
+ */
+
+package com.android.org.conscrypt;
+
+/**
+ * Marker interface for classes that hold an {@link OpenSSLKey}.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public interface OpenSSLKeyHolder {
+ @android.compat.annotation.UnsupportedAppUsage OpenSSLKey getOpenSSLKey();
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLMac.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLMac.java
new file mode 100644
index 0000000..62414fc
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLMac.java
@@ -0,0 +1,281 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.nio.ByteBuffer;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.AlgorithmParameterSpec;
+import javax.crypto.MacSpi;
+import javax.crypto.SecretKey;
+
+/**
+ * An implementation of {@link javax.crypto.Mac} which uses BoringSSL to perform all the operations.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public abstract class OpenSSLMac extends MacSpi {
+ /**
+ * The secret key used in this keyed MAC.
+ */
+ protected byte[] keyBytes;
+
+ /**
+ * Holds the output size of the message digest.
+ */
+ private final int size;
+
+ /**
+ * Holds a dummy buffer for writing single bytes to the digest.
+ */
+ private final byte[] singleByte = new byte[1];
+
+ private OpenSSLMac(int size) {
+ this.size = size;
+ }
+
+ /**
+ * Creates and initializes the relevant BoringSSL *MAC context.
+ */
+ protected abstract void resetContext();
+
+ /**
+ * Passes the contents of a direct ByteBuffer to the relevant BoringSSL *MAC function.
+ */
+ protected abstract void updateDirect(long ptr, int len);
+
+ @Override
+ protected int engineGetMacLength() {
+ return size;
+ }
+
+ @Override
+ protected void engineInit(Key key, AlgorithmParameterSpec params) throws InvalidKeyException,
+ InvalidAlgorithmParameterException {
+ if (!(key instanceof SecretKey)) {
+ throw new InvalidKeyException("key must be a SecretKey");
+ }
+
+ if (params != null) {
+ throw new InvalidAlgorithmParameterException("unknown parameter type");
+ }
+
+ keyBytes = key.getEncoded();
+ if (keyBytes == null) {
+ throw new InvalidKeyException("key cannot be encoded");
+ }
+
+ resetContext();
+ }
+
+ @Override
+ protected void engineUpdate(byte input) {
+ singleByte[0] = input;
+ engineUpdate(singleByte, 0, 1);
+ }
+
+ @Override
+ protected void engineUpdate(ByteBuffer input) {
+ // Optimization: Avoid copying/allocation for direct buffers because their contents are
+ // stored as a contiguous region in memory and thus can be efficiently accessed from native
+ // code.
+ if (!input.hasRemaining()) {
+ return;
+ }
+
+ if (!input.isDirect()) {
+ super.engineUpdate(input);
+ return;
+ }
+
+ long baseAddress = NativeCrypto.getDirectBufferAddress(input);
+ if (baseAddress == 0) {
+ // Direct buffers' contents can't be accessed from JNI -- superclass's implementation
+ // is good enough to handle this.
+ super.engineUpdate(input);
+ return;
+ }
+
+ // MAC the contents between Buffer's position and limit (remaining() number of bytes)
+ int position = input.position();
+ if (position < 0) {
+ throw new IllegalStateException("Negative position");
+ }
+ long ptr = baseAddress + position;
+ int len = input.remaining();
+ if (len < 0) {
+ throw new IllegalStateException("Negative remaining amount");
+ }
+
+ updateDirect(ptr, len);
+ input.position(position + len);
+ }
+
+ @Override
+ protected byte[] engineDoFinal() {
+ final byte[] output = doFinal();
+ resetContext();
+ return output;
+ }
+
+ protected abstract byte[] doFinal();
+
+ @Override
+ protected void engineReset() {
+ resetContext();
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class Hmac extends OpenSSLMac {
+ private NativeRef.HMAC_CTX ctx;
+
+ /**
+ * Holds the EVP_MD for the hashing algorithm, e.g.
+ * EVP_get_digestbyname("sha1");
+ */
+ private final long evpMd;
+
+ public Hmac(long evpMd, int size) {
+ super(size);
+ this.evpMd = evpMd;
+ }
+
+ @Override
+ protected void resetContext() {
+ NativeRef.HMAC_CTX ctxLocal = new NativeRef.HMAC_CTX(NativeCrypto.HMAC_CTX_new());
+ if (keyBytes != null) {
+ NativeCrypto.HMAC_Init_ex(ctxLocal, keyBytes, evpMd);
+ }
+ this.ctx = ctxLocal;
+ }
+
+ @Override
+ protected void engineUpdate(byte[] input, int offset, int len) {
+ final NativeRef.HMAC_CTX ctxLocal = ctx;
+ NativeCrypto.HMAC_Update(ctxLocal, input, offset, len);
+ }
+
+ @Override
+ protected void updateDirect(long ptr, int len) {
+ final NativeRef.HMAC_CTX ctxLocal = ctx;
+ NativeCrypto.HMAC_UpdateDirect(ctxLocal, ptr, len);
+ }
+
+ @Override
+ protected byte[] doFinal() {
+ final NativeRef.HMAC_CTX ctxLocal = ctx;
+ return NativeCrypto.HMAC_Final(ctxLocal);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class HmacMD5 extends Hmac {
+ public HmacMD5() {
+ super(EvpMdRef.MD5.EVP_MD, EvpMdRef.MD5.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class HmacSHA1 extends Hmac {
+ public HmacSHA1() {
+ super(EvpMdRef.SHA1.EVP_MD, EvpMdRef.SHA1.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class HmacSHA224 extends Hmac {
+ public HmacSHA224() {
+ super(EvpMdRef.SHA224.EVP_MD, EvpMdRef.SHA224.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class HmacSHA256 extends Hmac {
+ public HmacSHA256() {
+ super(EvpMdRef.SHA256.EVP_MD, EvpMdRef.SHA256.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class HmacSHA384 extends Hmac {
+ public HmacSHA384() {
+ super(EvpMdRef.SHA384.EVP_MD, EvpMdRef.SHA384.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class HmacSHA512 extends Hmac {
+ public HmacSHA512() {
+ super(EvpMdRef.SHA512.EVP_MD, EvpMdRef.SHA512.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class AesCmac extends OpenSSLMac {
+ private NativeRef.CMAC_CTX ctx;
+
+ public AesCmac() {
+ super(16);
+ }
+
+ @Override
+ protected void resetContext() {
+ NativeRef.CMAC_CTX ctxLocal = new NativeRef.CMAC_CTX(NativeCrypto.CMAC_CTX_new());
+ if (keyBytes != null) {
+ NativeCrypto.CMAC_Init(ctxLocal, keyBytes);
+ }
+ this.ctx = ctxLocal;
+ }
+
+ @Override
+ protected void updateDirect(long ptr, int len) {
+ final NativeRef.CMAC_CTX ctxLocal = ctx;
+ NativeCrypto.CMAC_UpdateDirect(ctxLocal, ptr, len);
+ }
+
+ @Override
+ protected byte[] doFinal() {
+ final NativeRef.CMAC_CTX ctxLocal = ctx;
+ return NativeCrypto.CMAC_Final(ctxLocal);
+ }
+
+ @Override
+ protected void engineUpdate(byte[] input, int offset, int len) {
+ final NativeRef.CMAC_CTX ctxLocal = ctx;
+ NativeCrypto.CMAC_Update(ctxLocal, input, offset, len);
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLMessageDigestJDK.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLMessageDigestJDK.java
new file mode 100644
index 0000000..2e756b5
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLMessageDigestJDK.java
@@ -0,0 +1,237 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2008 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.nio.ByteBuffer;
+import java.security.MessageDigestSpi;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * Implements the JDK MessageDigest interface using OpenSSL's EVP API.
+ * @hide This class is not part of the Android public SDK API
+ */
+@libcore.api.IntraCoreApi
+@Internal
+public class OpenSSLMessageDigestJDK extends MessageDigestSpi implements Cloneable {
+ private final NativeRef.EVP_MD_CTX ctx;
+
+ /**
+ * Holds the EVP_MD for the hashing algorithm, e.g. EVP_get_digestbyname("sha1");
+ */
+ private final long evp_md;
+
+ /**
+ * Holds the output size of the message digest.
+ */
+ private final int size;
+
+ /**
+ * Holds a dummy buffer for writing single bytes to the digest.
+ */
+ private final byte[] singleByte = new byte[1];
+
+ /**
+ * Whether the digest struct has been initialized inside EVP_MD_CTX.
+ */
+ private boolean digestInitializedInContext;
+
+ /**
+ * Creates a new OpenSSLMessageDigest instance for the given algorithm name.
+ */
+ private OpenSSLMessageDigestJDK(long evp_md, int size) throws NoSuchAlgorithmException {
+ this.evp_md = evp_md;
+ this.size = size;
+ NativeRef.EVP_MD_CTX ctxLocal = new NativeRef.EVP_MD_CTX(NativeCrypto.EVP_MD_CTX_create());
+ this.ctx = ctxLocal;
+ }
+
+ private OpenSSLMessageDigestJDK(long evp_md, int size, NativeRef.EVP_MD_CTX ctx,
+ boolean digestInitializedInContext) {
+ this.evp_md = evp_md;
+ this.size = size;
+ this.ctx = ctx;
+ this.digestInitializedInContext = digestInitializedInContext;
+ }
+
+ private synchronized void ensureDigestInitializedInContext() {
+ if (!digestInitializedInContext) {
+ final NativeRef.EVP_MD_CTX ctxLocal = ctx;
+ NativeCrypto.EVP_DigestInit_ex(ctxLocal, evp_md);
+ digestInitializedInContext = true;
+ }
+ }
+
+ @Override
+ protected synchronized void engineReset() {
+ // Reset to the same state as at the end of the <init>(long evp_md, int size). We can avoid
+ // allocating a new EVP_MD_CTX by invoking EVP_MD_CTX_cleanup on the existing one.
+ // EVP_MD_CTX_cleanup cleans up and reinitializes the EVP_MD_CTX.
+ final NativeRef.EVP_MD_CTX ctxLocal = ctx;
+ NativeCrypto.EVP_MD_CTX_cleanup(ctxLocal);
+ digestInitializedInContext = false;
+ }
+
+ @Override
+ protected int engineGetDigestLength() {
+ return size;
+ }
+
+ @Override
+ protected synchronized void engineUpdate(byte input) {
+ singleByte[0] = input;
+ engineUpdate(singleByte, 0, 1);
+ }
+
+ @Override
+ protected synchronized void engineUpdate(byte[] input, int offset, int len) {
+ ensureDigestInitializedInContext();
+ NativeCrypto.EVP_DigestUpdate(ctx, input, offset, len);
+ }
+
+ @Override
+ protected synchronized void engineUpdate(ByteBuffer input) {
+ // Optimization: Avoid copying/allocation for direct buffers because their contents are
+ // stored as a contiguous region in memory and thus can be efficiently accessed from native
+ // code.
+
+ if (!input.hasRemaining()) {
+ return;
+ }
+
+ if (!input.isDirect()) {
+ super.engineUpdate(input);
+ return;
+ }
+
+ long baseAddress = NativeCrypto.getDirectBufferAddress(input);
+ if (baseAddress == 0) {
+ // Direct buffer's contents can't be accessed from JNI -- superclass's implementation
+ // is good enough to handle this.
+ super.engineUpdate(input);
+ return;
+ }
+
+ // Digest the contents between Buffer's position and limit (remaining() number of bytes)
+ int position = input.position();
+ if (position < 0) {
+ throw new RuntimeException("Negative position");
+ }
+ long ptr = baseAddress + position;
+ int len = input.remaining();
+ if (len < 0) {
+ throw new RuntimeException("Negative remaining amount");
+ }
+
+ ensureDigestInitializedInContext();
+ NativeCrypto.EVP_DigestUpdateDirect(ctx, ptr, len);
+ input.position(position + len);
+ }
+
+ @Override
+ protected synchronized byte[] engineDigest() {
+ ensureDigestInitializedInContext();
+ final byte[] result = new byte[size];
+ NativeCrypto.EVP_DigestFinal_ex(ctx, result, 0);
+
+ // Optimized reset path:
+ // 1. No need to wipe EVP_MD_CTX because EVP_DigestFinal_ex has already cleansed any
+ // sensitive state from it.
+ // 2. Require EVP_DigestInit_ex to be invoked before this MessageDigestSpi starts computing
+ // a new digest.
+ digestInitializedInContext = false;
+
+ return result;
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class MD5 extends OpenSSLMessageDigestJDK {
+ @libcore.api.IntraCoreApi
+ public MD5() throws NoSuchAlgorithmException {
+ super(EvpMdRef.MD5.EVP_MD, EvpMdRef.MD5.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA1 extends OpenSSLMessageDigestJDK {
+ @libcore.api.IntraCoreApi
+ public SHA1() throws NoSuchAlgorithmException {
+ super(EvpMdRef.SHA1.EVP_MD, EvpMdRef.SHA1.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA224 extends OpenSSLMessageDigestJDK {
+ @libcore.api.IntraCoreApi
+ public SHA224() throws NoSuchAlgorithmException {
+ super(EvpMdRef.SHA224.EVP_MD, EvpMdRef.SHA224.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA256 extends OpenSSLMessageDigestJDK {
+ @libcore.api.IntraCoreApi
+ public SHA256() throws NoSuchAlgorithmException {
+ super(EvpMdRef.SHA256.EVP_MD, EvpMdRef.SHA256.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA384 extends OpenSSLMessageDigestJDK {
+ @libcore.api.IntraCoreApi
+ public SHA384() throws NoSuchAlgorithmException {
+ super(EvpMdRef.SHA384.EVP_MD, EvpMdRef.SHA384.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA512 extends OpenSSLMessageDigestJDK {
+ @libcore.api.IntraCoreApi
+ public SHA512() throws NoSuchAlgorithmException {
+ super(EvpMdRef.SHA512.EVP_MD, EvpMdRef.SHA512.SIZE_BYTES);
+ }
+ }
+
+ @Override
+ public Object clone() {
+ NativeRef.EVP_MD_CTX ctxCopy = new NativeRef.EVP_MD_CTX(NativeCrypto.EVP_MD_CTX_create());
+ // EVP_MD_CTX_copy_ex requires that the digest struct of source EVP_MD_CTX is initialized.
+ // There's no need to invoke EVP_MD_CTX_copy_ex when the digest struct isn't initialized.
+ if (digestInitializedInContext) {
+ NativeCrypto.EVP_MD_CTX_copy_ex(ctxCopy, ctx);
+ }
+ return new OpenSSLMessageDigestJDK(evp_md, size, ctxCopy, digestInitializedInContext);
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLProvider.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLProvider.java
new file mode 100644
index 0000000..5396aa6
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLProvider.java
@@ -0,0 +1,636 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.Provider;
+
+/**
+ * Provider that uses BoringSSL to perform the actual cryptographic operations.
+ * <p>
+ * Every algorithm should have its IANA assigned OID as an alias. See the following URLs for each
+ * type: <ul> <li><a
+ * href="http://www.iana.org/assignments/hash-function-text-names/hash-function-text-names.xml">Hash
+ * functions</a></li> <li><a href="http://www.iana.org/assignments/dssc/dssc.xml">Signature
+ * algorithms</a></li> <li><a
+ * href="http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html">NIST cryptographic
+ * algorithms</a></li>
+ * </ul>
+ * @hide This class is not part of the Android public SDK API
+ */
+@libcore.api.IntraCoreApi
+@libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+@Internal
+public final class OpenSSLProvider extends Provider {
+ private static final long serialVersionUID = 2996752495318905136L;
+
+ private static final String PREFIX = OpenSSLProvider.class.getPackage().getName() + ".";
+
+ private static final String STANDARD_EC_PRIVATE_KEY_INTERFACE_CLASS_NAME =
+ "java.security.interfaces.ECPrivateKey";
+ private static final String STANDARD_XEC_PRIVATE_KEY_INTERFACE_CLASS_NAME =
+ "java.security.interfaces.XECPrivateKey";
+ private static final String STANDARD_RSA_PRIVATE_KEY_INTERFACE_CLASS_NAME =
+ "java.security.interfaces.RSAPrivateKey";
+ private static final String STANDARD_RSA_PUBLIC_KEY_INTERFACE_CLASS_NAME =
+ "java.security.interfaces.RSAPublicKey";
+
+ @android.compat.annotation.UnsupportedAppUsage
+ @libcore.api.IntraCoreApi
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public OpenSSLProvider() {
+ this(Platform.getDefaultProviderName());
+ }
+
+ @SuppressWarnings("deprecation")
+ public OpenSSLProvider(String providerName) {
+ this(providerName, Platform.provideTrustManagerByDefault(), "TLSv1.3");
+ }
+
+ OpenSSLProvider(String providerName, boolean includeTrustManager, String defaultTlsProtocol) {
+ super(providerName, 1.0, "Android's OpenSSL-backed security provider");
+
+ // Ensure that the native library has been loaded.
+ NativeCrypto.checkAvailability();
+
+ // Make sure the platform is initialized.
+ Platform.setup();
+
+ /* === SSL Contexts === */
+ String classOpenSSLContextImpl = PREFIX + "OpenSSLContextImpl";
+ String tls12SSLContextSuffix = "$TLSv12";
+ String tls13SSLContextSuffix = "$TLSv13";
+ String defaultSSLContextSuffix;
+ switch (defaultTlsProtocol) {
+ case "TLSv1.2":
+ defaultSSLContextSuffix = tls12SSLContextSuffix;
+ break;
+ case "TLSv1.3":
+ defaultSSLContextSuffix = tls13SSLContextSuffix;
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Choice of default protocol is unsupported: " + defaultTlsProtocol);
+ }
+ // Keep SSL as an alias to TLS
+ put("SSLContext.SSL", classOpenSSLContextImpl + defaultSSLContextSuffix);
+ put("SSLContext.TLS", classOpenSSLContextImpl + defaultSSLContextSuffix);
+ put("SSLContext.TLSv1", classOpenSSLContextImpl + "$TLSv1");
+ put("SSLContext.TLSv1.1", classOpenSSLContextImpl + "$TLSv11");
+ put("SSLContext.TLSv1.2", classOpenSSLContextImpl + tls12SSLContextSuffix);
+ put("SSLContext.TLSv1.3", classOpenSSLContextImpl + tls13SSLContextSuffix);
+ put("SSLContext.Default", PREFIX + "DefaultSSLContextImpl" + defaultSSLContextSuffix);
+
+ if (includeTrustManager) {
+ put("TrustManagerFactory.PKIX", TrustManagerFactoryImpl.class.getName());
+ put("Alg.Alias.TrustManagerFactory.X509", "PKIX");
+ }
+
+ put("KeyManagerFactory.PKIX", KeyManagerFactoryImpl.class.getName());
+ put("Alg.Alias.KeyManagerFactory.X509", "PKIX");
+
+ /* === AlgorithmParameters === */
+ put("AlgorithmParameters.AES", PREFIX + "IvParameters$AES");
+ put("Alg.Alias.AlgorithmParameters.2.16.840.1.101.3.4.1.2", "AES");
+ put("Alg.Alias.AlgorithmParameters.2.16.840.1.101.3.4.1.22", "AES");
+ put("Alg.Alias.AlgorithmParameters.2.16.840.1.101.3.4.1.42", "AES");
+
+ put("AlgorithmParameters.ChaCha20", PREFIX + "IvParameters$ChaCha20");
+
+ put("AlgorithmParameters.DESEDE", PREFIX + "IvParameters$DESEDE");
+ put("Alg.Alias.AlgorithmParameters.TDEA", "DESEDE");
+ put("Alg.Alias.AlgorithmParameters.1.2.840.113549.3.7", "DESEDE");
+
+ put("AlgorithmParameters.GCM", PREFIX + "GCMParameters");
+ put("Alg.Alias.AlgorithmParameters.2.16.840.1.101.3.4.1.6", "GCM");
+ put("Alg.Alias.AlgorithmParameters.2.16.840.1.101.3.4.1.26", "GCM");
+ put("Alg.Alias.AlgorithmParameters.2.16.840.1.101.3.4.1.46", "GCM");
+ put("AlgorithmParameters.OAEP", PREFIX + "OAEPParameters");
+ put("AlgorithmParameters.PSS", PREFIX + "PSSParameters");
+ put("AlgorithmParameters.EC", PREFIX + "ECParameters");
+
+ /* === Message Digests === */
+ put("MessageDigest.SHA-1", PREFIX + "OpenSSLMessageDigestJDK$SHA1");
+ put("Alg.Alias.MessageDigest.SHA1", "SHA-1");
+ put("Alg.Alias.MessageDigest.SHA", "SHA-1");
+ put("Alg.Alias.MessageDigest.1.3.14.3.2.26", "SHA-1");
+
+ put("MessageDigest.SHA-224", PREFIX + "OpenSSLMessageDigestJDK$SHA224");
+ put("Alg.Alias.MessageDigest.SHA224", "SHA-224");
+ put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.4", "SHA-224");
+
+ put("MessageDigest.SHA-256", PREFIX + "OpenSSLMessageDigestJDK$SHA256");
+ put("Alg.Alias.MessageDigest.SHA256", "SHA-256");
+ put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.1", "SHA-256");
+
+ put("MessageDigest.SHA-384", PREFIX + "OpenSSLMessageDigestJDK$SHA384");
+ put("Alg.Alias.MessageDigest.SHA384", "SHA-384");
+ put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.2", "SHA-384");
+
+ put("MessageDigest.SHA-512", PREFIX + "OpenSSLMessageDigestJDK$SHA512");
+ put("Alg.Alias.MessageDigest.SHA512", "SHA-512");
+ put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.3", "SHA-512");
+
+ // iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) md5(5)
+ put("MessageDigest.MD5", PREFIX + "OpenSSLMessageDigestJDK$MD5");
+ put("Alg.Alias.MessageDigest.1.2.840.113549.2.5", "MD5");
+
+ /* == KeyGenerators == */
+ put("KeyGenerator.ARC4", PREFIX + "KeyGeneratorImpl$ARC4");
+ put("Alg.Alias.KeyGenerator.RC4", "ARC4");
+ put("Alg.Alias.KeyGenerator.1.2.840.113549.3.4", "ARC4");
+
+ put("KeyGenerator.AES", PREFIX + "KeyGeneratorImpl$AES");
+
+ put("KeyGenerator.ChaCha20", PREFIX + "KeyGeneratorImpl$ChaCha20");
+
+ put("KeyGenerator.DESEDE", PREFIX + "KeyGeneratorImpl$DESEDE");
+ put("Alg.Alias.KeyGenerator.TDEA", "DESEDE");
+
+ put("KeyGenerator.HmacMD5", PREFIX + "KeyGeneratorImpl$HmacMD5");
+ put("Alg.Alias.KeyGenerator.1.3.6.1.5.5.8.1.1", "HmacMD5");
+ put("Alg.Alias.KeyGenerator.HMAC-MD5", "HmacMD5");
+ put("Alg.Alias.KeyGenerator.HMAC/MD5", "HmacMD5");
+
+ put("KeyGenerator.HmacSHA1", PREFIX + "KeyGeneratorImpl$HmacSHA1");
+ put("Alg.Alias.KeyGenerator.1.2.840.113549.2.7", "HmacSHA1");
+ put("Alg.Alias.KeyGenerator.1.3.6.1.5.5.8.1.2", "HmacSHA1");
+ put("Alg.Alias.KeyGenerator.HMAC-SHA1", "HmacSHA1");
+ put("Alg.Alias.KeyGenerator.HMAC/SHA1", "HmacSHA1");
+
+ put("KeyGenerator.HmacSHA224", PREFIX + "KeyGeneratorImpl$HmacSHA224");
+ put("Alg.Alias.KeyGenerator.1.2.840.113549.2.8", "HmacSHA224");
+ put("Alg.Alias.KeyGenerator.HMAC-SHA224", "HmacSHA224");
+ put("Alg.Alias.KeyGenerator.HMAC/SHA224", "HmacSHA224");
+
+ put("KeyGenerator.HmacSHA256", PREFIX + "KeyGeneratorImpl$HmacSHA256");
+ put("Alg.Alias.KeyGenerator.1.2.840.113549.2.9", "HmacSHA256");
+ put("Alg.Alias.KeyGenerator.2.16.840.1.101.3.4.2.1", "HmacSHA256");
+ put("Alg.Alias.KeyGenerator.HMAC-SHA256", "HmacSHA256");
+ put("Alg.Alias.KeyGenerator.HMAC/SHA256", "HmacSHA256");
+
+ put("KeyGenerator.HmacSHA384", PREFIX + "KeyGeneratorImpl$HmacSHA384");
+ put("Alg.Alias.KeyGenerator.1.2.840.113549.2.10", "HmacSHA384");
+ put("Alg.Alias.KeyGenerator.HMAC-SHA384", "HmacSHA384");
+ put("Alg.Alias.KeyGenerator.HMAC/SHA384", "HmacSHA384");
+
+ put("KeyGenerator.HmacSHA512", PREFIX + "KeyGeneratorImpl$HmacSHA512");
+ put("Alg.Alias.KeyGenerator.1.2.840.113549.2.11", "HmacSHA512");
+ put("Alg.Alias.KeyGenerator.HMAC-SHA512", "HmacSHA512");
+ put("Alg.Alias.KeyGenerator.HMAC/SHA512", "HmacSHA512");
+
+ /* == KeyPairGenerators == */
+ put("KeyPairGenerator.RSA", PREFIX + "OpenSSLRSAKeyPairGenerator");
+ put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1.1", "RSA");
+ put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1.7", "RSA");
+ put("Alg.Alias.KeyPairGenerator.2.5.8.1.1", "RSA");
+
+ put("KeyPairGenerator.EC", PREFIX + "OpenSSLECKeyPairGenerator");
+ put("Alg.Alias.KeyPairGenerator.1.2.840.10045.2.1", "EC");
+ put("Alg.Alias.KeyPairGenerator.1.3.133.16.840.63.0.2", "EC");
+
+ put("KeyPairGenerator.XDH", PREFIX + "OpenSSLXDHKeyPairGenerator");
+ put("Alg.Alias.KeyPairGenerator.1.3.101.110", "XDH");
+
+ /* == KeyFactory == */
+ put("KeyFactory.RSA", PREFIX + "OpenSSLRSAKeyFactory");
+ put("Alg.Alias.KeyFactory.1.2.840.113549.1.1.1", "RSA");
+ put("Alg.Alias.KeyFactory.1.2.840.113549.1.1.7", "RSA");
+ put("Alg.Alias.KeyFactory.2.5.8.1.1", "RSA");
+
+ put("KeyFactory.EC", PREFIX + "OpenSSLECKeyFactory");
+ put("Alg.Alias.KeyFactory.1.2.840.10045.2.1", "EC");
+ put("Alg.Alias.KeyFactory.1.3.133.16.840.63.0.2", "EC");
+
+ put("KeyFactory.XDH", PREFIX + "OpenSSLXDHKeyFactory");
+ put("Alg.Alias.KeyFactory.1.3.101.110", "XDH");
+
+ /* == SecretKeyFactory == */
+ put("SecretKeyFactory.DESEDE", PREFIX + "DESEDESecretKeyFactory");
+ put("Alg.Alias.SecretKeyFactory.TDEA", "DESEDE");
+
+ /* == KeyAgreement == */
+ putECDHKeyAgreementImplClass("OpenSSLECDHKeyAgreement");
+ putXDHKeyAgreementImplClass("OpenSSLXDHKeyAgreement");
+
+ /* == Signatures == */
+ putSignatureImplClass("MD5withRSA", "OpenSSLSignature$MD5RSA");
+ put("Alg.Alias.Signature.MD5withRSAEncryption", "MD5withRSA");
+ put("Alg.Alias.Signature.MD5/RSA", "MD5withRSA");
+ put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA");
+ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.4", "MD5withRSA");
+ put("Alg.Alias.Signature.1.2.840.113549.2.5with1.2.840.113549.1.1.1", "MD5withRSA");
+
+ putSignatureImplClass("SHA1withRSA", "OpenSSLSignature$SHA1RSA");
+ put("Alg.Alias.Signature.SHA1withRSAEncryption", "SHA1withRSA");
+ put("Alg.Alias.Signature.SHA1/RSA", "SHA1withRSA");
+ put("Alg.Alias.Signature.SHA-1/RSA", "SHA1withRSA");
+ put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA");
+ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "SHA1withRSA");
+ put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.1", "SHA1withRSA");
+ put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.5", "SHA1withRSA");
+ put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1withRSA");
+ put("Alg.Alias.Signature.OID.1.3.14.3.2.29", "SHA1withRSA");
+
+ putSignatureImplClass("SHA224withRSA", "OpenSSLSignature$SHA224RSA");
+ put("Alg.Alias.Signature.SHA224withRSAEncryption", "SHA224withRSA");
+ put("Alg.Alias.Signature.SHA224/RSA", "SHA224withRSA");
+ put("Alg.Alias.Signature.1.2.840.113549.1.1.14", "SHA224withRSA");
+ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.14", "SHA224withRSA");
+ put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.113549.1.1.1",
+ "SHA224withRSA");
+ put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.113549.1.1.14",
+ "SHA224withRSA");
+
+ putSignatureImplClass("SHA256withRSA", "OpenSSLSignature$SHA256RSA");
+ put("Alg.Alias.Signature.SHA256withRSAEncryption", "SHA256withRSA");
+ put("Alg.Alias.Signature.SHA256/RSA", "SHA256withRSA");
+ put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA");
+ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.11", "SHA256withRSA");
+ put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.113549.1.1.1",
+ "SHA256withRSA");
+ put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.113549.1.1.11",
+ "SHA256withRSA");
+
+ putSignatureImplClass("SHA384withRSA", "OpenSSLSignature$SHA384RSA");
+ put("Alg.Alias.Signature.SHA384withRSAEncryption", "SHA384withRSA");
+ put("Alg.Alias.Signature.SHA384/RSA", "SHA384withRSA");
+ put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384withRSA");
+ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.12", "SHA384withRSA");
+ put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.2with1.2.840.113549.1.1.1",
+ "SHA384withRSA");
+
+ putSignatureImplClass("SHA512withRSA", "OpenSSLSignature$SHA512RSA");
+ put("Alg.Alias.Signature.SHA512withRSAEncryption", "SHA512withRSA");
+ put("Alg.Alias.Signature.SHA512/RSA", "SHA512withRSA");
+ put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512withRSA");
+ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.13", "SHA512withRSA");
+ put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.3with1.2.840.113549.1.1.1",
+ "SHA512withRSA");
+
+ putRAWRSASignatureImplClass("OpenSSLSignatureRawRSA");
+
+ putSignatureImplClass("NONEwithECDSA", "OpenSSLSignatureRawECDSA");
+
+ putSignatureImplClass("SHA1withECDSA", "OpenSSLSignature$SHA1ECDSA");
+ put("Alg.Alias.Signature.ECDSA", "SHA1withECDSA");
+ put("Alg.Alias.Signature.ECDSAwithSHA1", "SHA1withECDSA");
+ // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA1(1)
+ put("Alg.Alias.Signature.1.2.840.10045.4.1", "SHA1withECDSA");
+ put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10045.2.1", "SHA1withECDSA");
+
+ // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA2(3)
+ putSignatureImplClass("SHA224withECDSA", "OpenSSLSignature$SHA224ECDSA");
+ put("Alg.Alias.Signature.SHA224/ECDSA", "SHA224withECDSA");
+ // ecdsa-with-SHA224(1)
+ put("Alg.Alias.Signature.1.2.840.10045.4.3.1", "SHA224withECDSA");
+ put("Alg.Alias.Signature.OID.1.2.840.10045.4.3.1", "SHA224withECDSA");
+ put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.10045.2.1", "SHA224withECDSA");
+
+ // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA2(3)
+ putSignatureImplClass("SHA256withECDSA", "OpenSSLSignature$SHA256ECDSA");
+ put("Alg.Alias.Signature.SHA256/ECDSA", "SHA256withECDSA");
+ // ecdsa-with-SHA256(2)
+ put("Alg.Alias.Signature.1.2.840.10045.4.3.2", "SHA256withECDSA");
+ put("Alg.Alias.Signature.OID.1.2.840.10045.4.3.2", "SHA256withECDSA");
+ put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.10045.2.1", "SHA256withECDSA");
+
+ putSignatureImplClass("SHA384withECDSA", "OpenSSLSignature$SHA384ECDSA");
+ put("Alg.Alias.Signature.SHA384/ECDSA", "SHA384withECDSA");
+ // ecdsa-with-SHA384(3)
+ put("Alg.Alias.Signature.1.2.840.10045.4.3.3", "SHA384withECDSA");
+ put("Alg.Alias.Signature.OID.1.2.840.10045.4.3.3", "SHA384withECDSA");
+ put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.2with1.2.840.10045.2.1", "SHA384withECDSA");
+
+ putSignatureImplClass("SHA512withECDSA", "OpenSSLSignature$SHA512ECDSA");
+ put("Alg.Alias.Signature.SHA512/ECDSA", "SHA512withECDSA");
+ // ecdsa-with-SHA512(4)
+ put("Alg.Alias.Signature.1.2.840.10045.4.3.4", "SHA512withECDSA");
+ put("Alg.Alias.Signature.OID.1.2.840.10045.4.3.4", "SHA512withECDSA");
+ put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.3with1.2.840.10045.2.1", "SHA512withECDSA");
+
+ putSignatureImplClass("SHA1withRSA/PSS", "OpenSSLSignature$SHA1RSAPSS");
+ put("Alg.Alias.Signature.SHA1withRSAandMGF1", "SHA1withRSA/PSS");
+
+ putSignatureImplClass("SHA224withRSA/PSS", "OpenSSLSignature$SHA224RSAPSS");
+ put("Alg.Alias.Signature.SHA224withRSAandMGF1", "SHA224withRSA/PSS");
+
+ putSignatureImplClass("SHA256withRSA/PSS", "OpenSSLSignature$SHA256RSAPSS");
+ put("Alg.Alias.Signature.SHA256withRSAandMGF1", "SHA256withRSA/PSS");
+
+ putSignatureImplClass("SHA384withRSA/PSS", "OpenSSLSignature$SHA384RSAPSS");
+ put("Alg.Alias.Signature.SHA384withRSAandMGF1", "SHA384withRSA/PSS");
+
+ putSignatureImplClass("SHA512withRSA/PSS", "OpenSSLSignature$SHA512RSAPSS");
+ put("Alg.Alias.Signature.SHA512withRSAandMGF1", "SHA512withRSA/PSS");
+
+ /* === SecureRandom === */
+ /*
+ * We have to specify SHA1PRNG because various documentation mentions
+ * that algorithm by name instead of just recommending calling
+ * "new SecureRandom()"
+ */
+ put("SecureRandom.SHA1PRNG", PREFIX + "OpenSSLRandom");
+ put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
+
+ /* === Cipher === */
+ putRSACipherImplClass("RSA/ECB/NoPadding", "OpenSSLCipherRSA$Raw");
+ put("Alg.Alias.Cipher.RSA/None/NoPadding", "RSA/ECB/NoPadding");
+ putRSACipherImplClass("RSA/ECB/PKCS1Padding", "OpenSSLCipherRSA$PKCS1");
+ put("Alg.Alias.Cipher.RSA/None/PKCS1Padding", "RSA/ECB/PKCS1Padding");
+
+ putRSACipherImplClass("RSA/ECB/OAEPPadding", "OpenSSLCipherRSA$OAEP$SHA1");
+ put("Alg.Alias.Cipher.RSA/None/OAEPPadding", "RSA/ECB/OAEPPadding");
+ putRSACipherImplClass("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", "OpenSSLCipherRSA$OAEP$SHA1");
+ put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-1AndMGF1Padding",
+ "RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
+ putRSACipherImplClass(
+ "RSA/ECB/OAEPWithSHA-224AndMGF1Padding", "OpenSSLCipherRSA$OAEP$SHA224");
+ put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-224AndMGF1Padding",
+ "RSA/ECB/OAEPWithSHA-224AndMGF1Padding");
+ putRSACipherImplClass(
+ "RSA/ECB/OAEPWithSHA-256AndMGF1Padding", "OpenSSLCipherRSA$OAEP$SHA256");
+ put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-256AndMGF1Padding",
+ "RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
+ putRSACipherImplClass(
+ "RSA/ECB/OAEPWithSHA-384AndMGF1Padding", "OpenSSLCipherRSA$OAEP$SHA384");
+ put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-384AndMGF1Padding",
+ "RSA/ECB/OAEPWithSHA-384AndMGF1Padding");
+ putRSACipherImplClass(
+ "RSA/ECB/OAEPWithSHA-512AndMGF1Padding", "OpenSSLCipherRSA$OAEP$SHA512");
+ put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-512AndMGF1Padding",
+ "RSA/ECB/OAEPWithSHA-512AndMGF1Padding");
+
+ /*
+ * OpenSSL only supports a subset of modes, so we'll name them
+ * explicitly here.
+ *
+ * Moreover, OpenSSL only supports PKCS#7 padding. PKCS#5 padding
+ * is also supported because it's a special case of PKCS#7 for 64-bit
+ * blocks. PKCS#5 technically supports only 64-bit blocks and won't
+ * produce the same result as PKCS#7 for blocks that are not 64 bits
+ * long. However, everybody assumes PKCS#7 when they say PKCS#5. For
+ * example, lots of code uses PKCS#5 with AES whose blocks are longer
+ * than 64 bits. We solve this confusion by making PKCS7Padding an
+ * alias for PKCS5Padding.
+ */
+ putSymmetricCipherImplClass("AES/ECB/NoPadding", "OpenSSLEvpCipherAES$AES$ECB$NoPadding");
+ putSymmetricCipherImplClass(
+ "AES/ECB/PKCS5Padding", "OpenSSLEvpCipherAES$AES$ECB$PKCS5Padding");
+ put("Alg.Alias.Cipher.AES/ECB/PKCS7Padding", "AES/ECB/PKCS5Padding");
+ putSymmetricCipherImplClass("AES/CBC/NoPadding", "OpenSSLEvpCipherAES$AES$CBC$NoPadding");
+ putSymmetricCipherImplClass(
+ "AES/CBC/PKCS5Padding", "OpenSSLEvpCipherAES$AES$CBC$PKCS5Padding");
+ put("Alg.Alias.Cipher.AES/CBC/PKCS7Padding", "AES/CBC/PKCS5Padding");
+ putSymmetricCipherImplClass("AES/CTR/NoPadding", "OpenSSLEvpCipherAES$AES$CTR");
+
+ putSymmetricCipherImplClass(
+ "AES_128/ECB/NoPadding", "OpenSSLEvpCipherAES$AES_128$ECB$NoPadding");
+ putSymmetricCipherImplClass(
+ "AES_128/ECB/PKCS5Padding", "OpenSSLEvpCipherAES$AES_128$ECB$PKCS5Padding");
+ put("Alg.Alias.Cipher.AES_128/ECB/PKCS7Padding", "AES_128/ECB/PKCS5Padding");
+ putSymmetricCipherImplClass(
+ "AES_128/CBC/NoPadding", "OpenSSLEvpCipherAES$AES_128$CBC$NoPadding");
+ putSymmetricCipherImplClass(
+ "AES_128/CBC/PKCS5Padding", "OpenSSLEvpCipherAES$AES_128$CBC$PKCS5Padding");
+ put("Alg.Alias.Cipher.AES_128/CBC/PKCS7Padding", "AES_128/CBC/PKCS5Padding");
+
+ put("Alg.Alias.Cipher.PBEWithHmacSHA1AndAES_128", "AES_128/CBC/PKCS5PADDING");
+ put("Alg.Alias.Cipher.PBEWithHmacSHA224AndAES_128", "AES_128/CBC/PKCS5PADDING");
+ put("Alg.Alias.Cipher.PBEWithHmacSHA256AndAES_128", "AES_128/CBC/PKCS5PADDING");
+ put("Alg.Alias.Cipher.PBEWithHmacSHA384AndAES_128", "AES_128/CBC/PKCS5PADDING");
+ put("Alg.Alias.Cipher.PBEWithHmacSHA512AndAES_128", "AES_128/CBC/PKCS5PADDING");
+
+ putSymmetricCipherImplClass(
+ "AES_256/ECB/NoPadding", "OpenSSLEvpCipherAES$AES_256$ECB$NoPadding");
+ putSymmetricCipherImplClass(
+ "AES_256/ECB/PKCS5Padding", "OpenSSLEvpCipherAES$AES_256$ECB$PKCS5Padding");
+ put("Alg.Alias.Cipher.AES_256/ECB/PKCS7Padding", "AES_256/ECB/PKCS5Padding");
+ putSymmetricCipherImplClass(
+ "AES_256/CBC/NoPadding", "OpenSSLEvpCipherAES$AES_256$CBC$NoPadding");
+ putSymmetricCipherImplClass(
+ "AES_256/CBC/PKCS5Padding", "OpenSSLEvpCipherAES$AES_256$CBC$PKCS5Padding");
+ put("Alg.Alias.Cipher.AES_256/CBC/PKCS7Padding", "AES_256/CBC/PKCS5Padding");
+
+ put("Alg.Alias.Cipher.PBEWithHmacSHA1AndAES_256", "AES_256/CBC/PKCS5PADDING");
+ put("Alg.Alias.Cipher.PBEWithHmacSHA224AndAES_256", "AES_256/CBC/PKCS5PADDING");
+ put("Alg.Alias.Cipher.PBEWithHmacSHA256AndAES_256", "AES_256/CBC/PKCS5PADDING");
+ put("Alg.Alias.Cipher.PBEWithHmacSHA384AndAES_256", "AES_256/CBC/PKCS5PADDING");
+ put("Alg.Alias.Cipher.PBEWithHmacSHA512AndAES_256", "AES_256/CBC/PKCS5PADDING");
+
+ putSymmetricCipherImplClass("DESEDE/CBC/NoPadding", "OpenSSLEvpCipherDESEDE$CBC$NoPadding");
+ putSymmetricCipherImplClass(
+ "DESEDE/CBC/PKCS5Padding", "OpenSSLEvpCipherDESEDE$CBC$PKCS5Padding");
+ put("Alg.Alias.Cipher.DESEDE/CBC/PKCS7Padding", "DESEDE/CBC/PKCS5Padding");
+
+ putSymmetricCipherImplClass("ARC4", "OpenSSLEvpCipherARC4");
+ put("Alg.Alias.Cipher.ARCFOUR", "ARC4");
+ put("Alg.Alias.Cipher.RC4", "ARC4");
+ put("Alg.Alias.Cipher.1.2.840.113549.3.4", "ARC4");
+ put("Alg.Alias.Cipher.OID.1.2.840.113549.3.4", "ARC4");
+
+ putSymmetricCipherImplClass("AES/GCM/NoPadding", "OpenSSLAeadCipherAES$GCM");
+ put("Alg.Alias.Cipher.GCM", "AES/GCM/NoPadding");
+ put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.6", "AES/GCM/NoPadding");
+ put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.26", "AES/GCM/NoPadding");
+ put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.46", "AES/GCM/NoPadding");
+ putSymmetricCipherImplClass("AES_128/GCM/NoPadding", "OpenSSLAeadCipherAES$GCM$AES_128");
+ putSymmetricCipherImplClass("AES_256/GCM/NoPadding", "OpenSSLAeadCipherAES$GCM$AES_256");
+
+ putSymmetricCipherImplClass("AES/GCM-SIV/NoPadding", "OpenSSLAeadCipherAES$GCM_SIV");
+ putSymmetricCipherImplClass(
+ "AES_128/GCM-SIV/NoPadding", "OpenSSLAeadCipherAES$GCM_SIV$AES_128");
+ putSymmetricCipherImplClass(
+ "AES_256/GCM-SIV/NoPadding", "OpenSSLAeadCipherAES$GCM_SIV$AES_256");
+
+ putSymmetricCipherImplClass("ChaCha20",
+ "OpenSSLCipherChaCha20");
+ putSymmetricCipherImplClass("ChaCha20/Poly1305/NoPadding", "OpenSSLAeadCipherChaCha20");
+ put("Alg.Alias.Cipher.ChaCha20-Poly1305", "ChaCha20/Poly1305/NoPadding");
+
+ /* === Mac === */
+
+ putMacImplClass("HmacMD5", "OpenSSLMac$HmacMD5");
+ put("Alg.Alias.Mac.1.3.6.1.5.5.8.1.1", "HmacMD5");
+ put("Alg.Alias.Mac.HMAC-MD5", "HmacMD5");
+ put("Alg.Alias.Mac.HMAC/MD5", "HmacMD5");
+
+ // PKCS#2 - iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2)
+ // http://www.oid-info.com/get/1.2.840.113549.2
+
+ // HMAC-SHA-1 PRF (7)
+ putMacImplClass("HmacSHA1", "OpenSSLMac$HmacSHA1");
+ put("Alg.Alias.Mac.1.2.840.113549.2.7", "HmacSHA1");
+ put("Alg.Alias.Mac.1.3.6.1.5.5.8.1.2", "HmacSHA1");
+ put("Alg.Alias.Mac.HMAC-SHA1", "HmacSHA1");
+ put("Alg.Alias.Mac.HMAC/SHA1", "HmacSHA1");
+
+ // id-hmacWithSHA224 (8)
+ putMacImplClass("HmacSHA224", "OpenSSLMac$HmacSHA224");
+ put("Alg.Alias.Mac.1.2.840.113549.2.8", "HmacSHA224");
+ put("Alg.Alias.Mac.HMAC-SHA224", "HmacSHA224");
+ put("Alg.Alias.Mac.HMAC/SHA224", "HmacSHA224");
+ put("Alg.Alias.Mac.PBEWITHHMACSHA224", "HmacSHA224");
+
+ // id-hmacWithSHA256 (9)
+ putMacImplClass("HmacSHA256", "OpenSSLMac$HmacSHA256");
+ put("Alg.Alias.Mac.1.2.840.113549.2.9", "HmacSHA256");
+ put("Alg.Alias.Mac.2.16.840.1.101.3.4.2.1", "HmacSHA256");
+ put("Alg.Alias.Mac.HMAC-SHA256", "HmacSHA256");
+ put("Alg.Alias.Mac.HMAC/SHA256", "HmacSHA256");
+ put("Alg.Alias.Mac.PBEWITHHMACSHA256", "HmacSHA256");
+
+ // id-hmacWithSHA384 (10)
+ putMacImplClass("HmacSHA384", "OpenSSLMac$HmacSHA384");
+ put("Alg.Alias.Mac.1.2.840.113549.2.10", "HmacSHA384");
+ put("Alg.Alias.Mac.HMAC-SHA384", "HmacSHA384");
+ put("Alg.Alias.Mac.HMAC/SHA384", "HmacSHA384");
+ put("Alg.Alias.Mac.PBEWITHHMACSHA384", "HmacSHA384");
+
+ // id-hmacWithSHA384 (11)
+ putMacImplClass("HmacSHA512", "OpenSSLMac$HmacSHA512");
+ put("Alg.Alias.Mac.1.2.840.113549.2.11", "HmacSHA512");
+ put("Alg.Alias.Mac.HMAC-SHA512", "HmacSHA512");
+ put("Alg.Alias.Mac.HMAC/SHA512", "HmacSHA512");
+ put("Alg.Alias.Mac.PBEWITHHMACSHA512", "HmacSHA512");
+
+ putMacImplClass("AESCMAC", "OpenSSLMac$AesCmac");
+
+ /* === Certificate === */
+
+ put("CertificateFactory.X509", PREFIX + "OpenSSLX509CertificateFactory");
+ put("Alg.Alias.CertificateFactory.X.509", "X509");
+ }
+
+ private void putMacImplClass(String algorithm, String className) {
+ // Accept only keys for which any of the following is true:
+ // * the key is from this provider (subclass of OpenSSLKeyHolder),
+ // * the key provides its key material in "RAW" encoding via Key.getEncoded.
+ String supportedKeyClasses = PREFIX + "OpenSSLKeyHolder";
+ String supportedKeyFormats = "RAW";
+ putImplClassWithKeyConstraints(
+ "Mac." + algorithm,
+ PREFIX + className,
+ supportedKeyClasses,
+ supportedKeyFormats);
+ }
+
+ private void putSymmetricCipherImplClass(String transformation, String className) {
+ // Accept only keys for which any of the following is true:
+ // * the key provides its key material in "RAW" encoding via Key.getEncoded.
+ String supportedKeyClasses = null; // ignored -- filtered based on encoding format only
+ String supportedKeyFormats = "RAW";
+ putImplClassWithKeyConstraints(
+ "Cipher." + transformation,
+ PREFIX + className,
+ supportedKeyClasses,
+ supportedKeyFormats);
+ }
+
+ private void putRSACipherImplClass(String transformation, String className) {
+ // Accept only keys for which any of the following is true:
+ // * the key is instance of OpenSSLRSAPrivateKey, RSAPrivateKey, OpenSSLRSAPublicKey, or
+ // RSAPublicKey.
+ String supportedKeyClasses = PREFIX + "OpenSSLRSAPrivateKey"
+ + "|" + STANDARD_RSA_PRIVATE_KEY_INTERFACE_CLASS_NAME
+ + "|" + PREFIX + "OpenSSLRSAPublicKey"
+ + "|" + STANDARD_RSA_PUBLIC_KEY_INTERFACE_CLASS_NAME;
+ String supportedKeyFormats = null; // ignored -- filtered based on class only
+ putImplClassWithKeyConstraints(
+ "Cipher." + transformation,
+ PREFIX + className,
+ supportedKeyClasses,
+ supportedKeyFormats);
+ }
+
+ private void putSignatureImplClass(String algorithm, String className) {
+ // Accept only keys for which any of the following is true:
+ // * the key is from this provider (subclass of OpenSSLKeyHolder),
+ // * the key provides its key material in "PKCS#8" or "X.509" encodings via Key.getEncoded.
+ // * the key is a transparent private key (subclass of RSAPrivateKey or ECPrivateKey). For
+ // some reason this provider's Signature implementation does not unconditionally accept
+ // transparent public keys -- it only accepts them if they provide their key material in
+ // encoded form (see above).
+ String supportedKeyClasses = PREFIX + "OpenSSLKeyHolder"
+ + "|" + STANDARD_RSA_PRIVATE_KEY_INTERFACE_CLASS_NAME
+ + "|" + STANDARD_EC_PRIVATE_KEY_INTERFACE_CLASS_NAME
+ + "|" + STANDARD_RSA_PUBLIC_KEY_INTERFACE_CLASS_NAME;
+ String supportedKeyFormats = "PKCS#8|X.509";
+ putImplClassWithKeyConstraints(
+ "Signature." + algorithm,
+ PREFIX + className,
+ supportedKeyClasses,
+ supportedKeyFormats);
+ }
+
+ private void putRAWRSASignatureImplClass(String className) {
+ // Accept only keys for which any of the following is true:
+ // * the key is instance of OpenSSLRSAPrivateKey, RSAPrivateKey, OpenSSLRSAPublicKey, or
+ // RSAPublicKey.
+ String supportedKeyClasses = PREFIX + "OpenSSLRSAPrivateKey"
+ + "|" + STANDARD_RSA_PRIVATE_KEY_INTERFACE_CLASS_NAME
+ + "|" + PREFIX + "OpenSSLRSAPublicKey"
+ + "|" + STANDARD_RSA_PUBLIC_KEY_INTERFACE_CLASS_NAME;
+ String supportedKeyFormats = null; // ignored -- filtered based on class only
+ putImplClassWithKeyConstraints(
+ "Signature.NONEwithRSA",
+ PREFIX + className,
+ supportedKeyClasses,
+ supportedKeyFormats);
+ }
+
+ private void putECDHKeyAgreementImplClass(String className) {
+ // Accept only keys for which any of the following is true:
+ // * the key is from this provider (subclass of OpenSSLKeyHolder),
+ // * the key provides its key material in "PKCS#8" encoding via Key.getEncoded.
+ // * the key is a transparent EC private key (subclass of ECPrivateKey).
+ String supportedKeyClasses = PREFIX + "OpenSSLKeyHolder"
+ + "|" + STANDARD_EC_PRIVATE_KEY_INTERFACE_CLASS_NAME;
+ String supportedKeyFormats = "PKCS#8";
+ putImplClassWithKeyConstraints(
+ "KeyAgreement.ECDH",
+ PREFIX + className,
+ supportedKeyClasses,
+ supportedKeyFormats);
+ }
+
+ private void putXDHKeyAgreementImplClass(String className) {
+ // Accept only keys for which any of the following is true:
+ // * the key is from this provider (subclass of OpenSSLKeyHolder),
+ // * the key provides its key material in "PKCS#8" encoding via Key.getEncoded.
+ // * the key is a transparent XEC private key (subclass of XECPrivateKey).
+ String supportedKeyClasses = PREFIX + "OpenSSLKeyHolder"
+ + "|" + STANDARD_XEC_PRIVATE_KEY_INTERFACE_CLASS_NAME + "|" + PREFIX
+ + "OpenSSLX25519PrivateKey";
+ String supportedKeyFormats = "PKCS#8";
+ putImplClassWithKeyConstraints(
+ "KeyAgreement.XDH", PREFIX + className, supportedKeyClasses, supportedKeyFormats);
+ }
+
+ private void putImplClassWithKeyConstraints(String typeAndAlgName,
+ String fullyQualifiedClassName,
+ String supportedKeyClasses,
+ String supportedKeyFormats) {
+ put(typeAndAlgName, fullyQualifiedClassName);
+ if (supportedKeyClasses != null) {
+ put(typeAndAlgName + " SupportedKeyClasses", supportedKeyClasses);
+ }
+ if (supportedKeyFormats != null) {
+ put(typeAndAlgName + " SupportedKeyFormats", supportedKeyFormats);
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAKeyFactory.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAKeyFactory.java
new file mode 100644
index 0000000..adaadd4
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAKeyFactory.java
@@ -0,0 +1,256 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+/**
+ * An implementation of {@link java.security.KeyFactory} which uses BoringSSL to perform all the
+ * operations.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class OpenSSLRSAKeyFactory extends KeyFactorySpi {
+ public OpenSSLRSAKeyFactory() {}
+
+ @Override
+ protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException {
+ if (keySpec == null) {
+ throw new InvalidKeySpecException("keySpec == null");
+ }
+
+ if (keySpec instanceof RSAPublicKeySpec) {
+ return new OpenSSLRSAPublicKey((RSAPublicKeySpec) keySpec);
+ } else if (keySpec instanceof X509EncodedKeySpec) {
+ return OpenSSLKey.getPublicKey((X509EncodedKeySpec) keySpec, NativeConstants.EVP_PKEY_RSA);
+ }
+ throw new InvalidKeySpecException("Must use RSAPublicKeySpec or X509EncodedKeySpec; was "
+ + keySpec.getClass().getName());
+ }
+
+ @Override
+ protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException {
+ if (keySpec == null) {
+ throw new InvalidKeySpecException("keySpec == null");
+ }
+
+ if (keySpec instanceof RSAPrivateCrtKeySpec) {
+ return new OpenSSLRSAPrivateCrtKey((RSAPrivateCrtKeySpec) keySpec);
+ } else if (keySpec instanceof RSAPrivateKeySpec) {
+ return new OpenSSLRSAPrivateKey((RSAPrivateKeySpec) keySpec);
+ } else if (keySpec instanceof PKCS8EncodedKeySpec) {
+ return OpenSSLKey.getPrivateKey((PKCS8EncodedKeySpec) keySpec,
+ NativeConstants.EVP_PKEY_RSA);
+ }
+ throw new InvalidKeySpecException("Must use RSAPublicKeySpec or PKCS8EncodedKeySpec; was "
+ + keySpec.getClass().getName());
+ }
+
+ @Override
+ protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
+ throws InvalidKeySpecException {
+ if (key == null) {
+ throw new InvalidKeySpecException("key == null");
+ }
+
+ if (keySpec == null) {
+ throw new InvalidKeySpecException("keySpec == null");
+ }
+
+ if (!"RSA".equals(key.getAlgorithm())) {
+ throw new InvalidKeySpecException("Key must be a RSA key");
+ }
+
+ if (key instanceof RSAPublicKey && RSAPublicKeySpec.class.isAssignableFrom(keySpec)) {
+ RSAPublicKey rsaKey = (RSAPublicKey) key;
+ @SuppressWarnings("unchecked")
+ T result = (T) new RSAPublicKeySpec(rsaKey.getModulus(), rsaKey.getPublicExponent());
+ return result;
+ } else if (key instanceof PublicKey && RSAPublicKeySpec.class.isAssignableFrom(keySpec)) {
+ final byte[] encoded = key.getEncoded();
+ if (!"X.509".equals(key.getFormat()) || encoded == null) {
+ throw new InvalidKeySpecException("Not a valid X.509 encoding");
+ }
+ RSAPublicKey rsaKey =
+ (RSAPublicKey) engineGeneratePublic(new X509EncodedKeySpec(encoded));
+ @SuppressWarnings("unchecked")
+ T result = (T) new RSAPublicKeySpec(rsaKey.getModulus(), rsaKey.getPublicExponent());
+ return result;
+ } else if (key instanceof RSAPrivateCrtKey
+ && RSAPrivateCrtKeySpec.class.isAssignableFrom(keySpec)) {
+ RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) key;
+ @SuppressWarnings("unchecked")
+ T result = (T) new RSAPrivateCrtKeySpec(rsaKey.getModulus(), rsaKey.getPublicExponent(),
+ rsaKey.getPrivateExponent(), rsaKey.getPrimeP(), rsaKey.getPrimeQ(),
+ rsaKey.getPrimeExponentP(), rsaKey.getPrimeExponentQ(),
+ rsaKey.getCrtCoefficient());
+ return result;
+ } else if (key instanceof RSAPrivateCrtKey
+ && RSAPrivateKeySpec.class.isAssignableFrom(keySpec)) {
+ RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) key;
+ @SuppressWarnings("unchecked")
+ T result = (T) new RSAPrivateKeySpec(rsaKey.getModulus(), rsaKey.getPrivateExponent());
+ return result;
+ } else if (key instanceof RSAPrivateKey
+ && RSAPrivateKeySpec.class.isAssignableFrom(keySpec)) {
+ RSAPrivateKey rsaKey = (RSAPrivateKey) key;
+ @SuppressWarnings("unchecked")
+ T result = (T) new RSAPrivateKeySpec(rsaKey.getModulus(), rsaKey.getPrivateExponent());
+ return result;
+ } else if (key instanceof PrivateKey
+ && RSAPrivateCrtKeySpec.class.isAssignableFrom(keySpec)) {
+ final byte[] encoded = key.getEncoded();
+ if (!"PKCS#8".equals(key.getFormat()) || encoded == null) {
+ throw new InvalidKeySpecException("Not a valid PKCS#8 encoding");
+ }
+ RSAPrivateKey privKey =
+ (RSAPrivateKey) engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
+ if (privKey instanceof RSAPrivateCrtKey) {
+ RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) privKey;
+ @SuppressWarnings("unchecked")
+ T result = (T) new RSAPrivateCrtKeySpec(rsaKey.getModulus(),
+ rsaKey.getPublicExponent(), rsaKey.getPrivateExponent(), rsaKey.getPrimeP(),
+ rsaKey.getPrimeQ(), rsaKey.getPrimeExponentP(), rsaKey.getPrimeExponentQ(),
+ rsaKey.getCrtCoefficient());
+ return result;
+ } else {
+ throw new InvalidKeySpecException("Encoded key is not an RSAPrivateCrtKey");
+ }
+ } else if (key instanceof PrivateKey && RSAPrivateKeySpec.class.isAssignableFrom(keySpec)) {
+ final byte[] encoded = key.getEncoded();
+ if (!"PKCS#8".equals(key.getFormat()) || encoded == null) {
+ throw new InvalidKeySpecException("Not a valid PKCS#8 encoding");
+ }
+ RSAPrivateKey rsaKey =
+ (RSAPrivateKey) engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
+ @SuppressWarnings("unchecked")
+ T result = (T) new RSAPrivateKeySpec(rsaKey.getModulus(), rsaKey.getPrivateExponent());
+ return result;
+ } else if (key instanceof PrivateKey
+ && PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) {
+ final byte[] encoded = key.getEncoded();
+ if (!"PKCS#8".equals(key.getFormat())) {
+ throw new InvalidKeySpecException("Encoding type must be PKCS#8; was "
+ + key.getFormat());
+ } else if (encoded == null) {
+ throw new InvalidKeySpecException("Key is not encodable");
+ }
+ @SuppressWarnings("unchecked") T result = (T) new PKCS8EncodedKeySpec(encoded);
+ return result;
+ } else if (key instanceof PublicKey && X509EncodedKeySpec.class.isAssignableFrom(keySpec)) {
+ final byte[] encoded = key.getEncoded();
+ if (!"X.509".equals(key.getFormat())) {
+ throw new InvalidKeySpecException("Encoding type must be X.509; was "
+ + key.getFormat());
+ } else if (encoded == null) {
+ throw new InvalidKeySpecException("Key is not encodable");
+ }
+ @SuppressWarnings("unchecked") T result = (T) new X509EncodedKeySpec(encoded);
+ return result;
+ } else {
+ throw new InvalidKeySpecException("Unsupported key type and key spec combination; key="
+ + key.getClass().getName() + ", keySpec=" + keySpec.getName());
+ }
+ }
+
+ @Override
+ protected Key engineTranslateKey(Key key) throws InvalidKeyException {
+ if (key == null) {
+ throw new InvalidKeyException("key == null");
+ }
+
+ if ((key instanceof OpenSSLRSAPublicKey) || (key instanceof OpenSSLRSAPrivateKey)) {
+ return key;
+ } else if (key instanceof RSAPublicKey) {
+ RSAPublicKey rsaKey = (RSAPublicKey) key;
+
+ try {
+ return engineGeneratePublic(new RSAPublicKeySpec(rsaKey.getModulus(),
+ rsaKey.getPublicExponent()));
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e);
+ }
+ } else if (key instanceof RSAPrivateCrtKey) {
+ RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) key;
+ BigInteger modulus = rsaKey.getModulus();
+ BigInteger publicExponent = rsaKey.getPublicExponent();
+ BigInteger privateExponent = rsaKey.getPrivateExponent();
+ BigInteger primeP = rsaKey.getPrimeP();
+ BigInteger primeQ = rsaKey.getPrimeQ();
+ BigInteger primeExponentP = rsaKey.getPrimeExponentP();
+ BigInteger primeExponentQ = rsaKey.getPrimeExponentQ();
+ BigInteger crtCoefficient = rsaKey.getCrtCoefficient();
+
+ try {
+ return engineGeneratePrivate(new RSAPrivateCrtKeySpec(modulus, publicExponent,
+ privateExponent, primeP, primeQ, primeExponentP, primeExponentQ,
+ crtCoefficient));
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e);
+ }
+ } else if (key instanceof RSAPrivateKey) {
+ RSAPrivateKey rsaKey = (RSAPrivateKey) key;
+ BigInteger modulus = rsaKey.getModulus();
+ BigInteger privateExponent = rsaKey.getPrivateExponent();
+
+ try {
+ return engineGeneratePrivate(new RSAPrivateKeySpec(modulus, privateExponent));
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e);
+ }
+ } else if ((key instanceof PrivateKey) && "PKCS#8".equals(key.getFormat())) {
+ byte[] encoded = key.getEncoded();
+ if (encoded == null) {
+ throw new InvalidKeyException("Key does not support encoding");
+ }
+ try {
+ return engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e);
+ }
+ } else if ((key instanceof PublicKey) && "X.509".equals(key.getFormat())) {
+ byte[] encoded = key.getEncoded();
+ if (encoded == null) {
+ throw new InvalidKeyException("Key does not support encoding");
+ }
+ try {
+ return engineGeneratePublic(new X509EncodedKeySpec(encoded));
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e);
+ }
+ } else {
+ throw new InvalidKeyException("Key must be an RSA public or private key; was "
+ + key.getClass().getName());
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAKeyPairGenerator.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAKeyPairGenerator.java
new file mode 100644
index 0000000..3fe1156
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAKeyPairGenerator.java
@@ -0,0 +1,83 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGeneratorSpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.RSAKeyGenParameterSpec;
+
+/**
+ * An implementation of {@link java.security.KeyPairGenerator} which uses BoringSSL to perform all
+ * the operations.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class OpenSSLRSAKeyPairGenerator extends KeyPairGeneratorSpi {
+ /**
+ * Default modulus size is 0x10001 (65537)
+ */
+ private byte[] publicExponent = new byte[] {
+ 0x01, 0x00, 0x01
+ };
+
+ /**
+ * Default RSA key size 2048 bits.
+ */
+ private int modulusBits = 2048;
+
+ public OpenSSLRSAKeyPairGenerator() {}
+
+ @Override
+ public KeyPair generateKeyPair() {
+ final OpenSSLKey key = new OpenSSLKey(NativeCrypto.RSA_generate_key_ex(modulusBits,
+ publicExponent));
+
+ PrivateKey privKey = OpenSSLRSAPrivateKey.getInstance(key);
+ PublicKey pubKey = new OpenSSLRSAPublicKey(key);
+
+ return new KeyPair(pubKey, privKey);
+ }
+
+ @Override
+ public void initialize(int keysize, SecureRandom random) {
+ this.modulusBits = keysize;
+ }
+
+ @Override
+ public void initialize(AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidAlgorithmParameterException {
+ if (!(params instanceof RSAKeyGenParameterSpec)) {
+ throw new InvalidAlgorithmParameterException("Only RSAKeyGenParameterSpec supported");
+ }
+
+ RSAKeyGenParameterSpec spec = (RSAKeyGenParameterSpec) params;
+
+ final BigInteger publicExponent = spec.getPublicExponent();
+ if (publicExponent != null) {
+ this.publicExponent = publicExponent.toByteArray();
+ }
+
+ this.modulusBits = spec.getKeysize();
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPrivateCrtKey.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPrivateCrtKey.java
new file mode 100644
index 0000000..5981738
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPrivateCrtKey.java
@@ -0,0 +1,299 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPrivateCrtKeySpec;
+
+/**
+ * An implementation of {@link java.security.PrivateKey} for RSA keys which uses BoringSSL to
+ * perform all the operations.
+ */
+final class OpenSSLRSAPrivateCrtKey extends OpenSSLRSAPrivateKey implements RSAPrivateCrtKey {
+ private static final long serialVersionUID = 3785291944868707197L;
+
+ private BigInteger publicExponent;
+
+ private BigInteger primeP;
+
+ private BigInteger primeQ;
+
+ private BigInteger primeExponentP;
+
+ private BigInteger primeExponentQ;
+
+ private BigInteger crtCoefficient;
+
+ OpenSSLRSAPrivateCrtKey(OpenSSLKey key) {
+ super(key);
+ }
+
+ OpenSSLRSAPrivateCrtKey(OpenSSLKey key, byte[][] params) {
+ super(key, params);
+ }
+
+ OpenSSLRSAPrivateCrtKey(RSAPrivateCrtKeySpec rsaKeySpec) throws InvalidKeySpecException {
+ super(init(rsaKeySpec));
+ }
+
+ private static OpenSSLKey init(RSAPrivateCrtKeySpec rsaKeySpec) throws InvalidKeySpecException {
+ BigInteger modulus = rsaKeySpec.getModulus();
+ BigInteger privateExponent = rsaKeySpec.getPrivateExponent();
+
+ if (modulus == null) {
+ throw new InvalidKeySpecException("modulus == null");
+ } else if (privateExponent == null) {
+ throw new InvalidKeySpecException("privateExponent == null");
+ }
+
+ try {
+ /*
+ * OpenSSL uses the public modulus to do RSA blinding. If
+ * the public modulus is not available, the call to
+ * EVP_PKEY_new_RSA will turn off blinding for this key
+ * instance.
+ */
+ final BigInteger publicExponent = rsaKeySpec.getPublicExponent();
+ final BigInteger primeP = rsaKeySpec.getPrimeP();
+ final BigInteger primeQ = rsaKeySpec.getPrimeQ();
+ final BigInteger primeExponentP = rsaKeySpec.getPrimeExponentP();
+ final BigInteger primeExponentQ = rsaKeySpec.getPrimeExponentQ();
+ final BigInteger crtCoefficient = rsaKeySpec.getCrtCoefficient();
+
+ return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
+ modulus.toByteArray(),
+ publicExponent == null ? null : publicExponent.toByteArray(),
+ privateExponent.toByteArray(),
+ primeP == null ? null : primeP.toByteArray(),
+ primeQ == null ? null : primeQ.toByteArray(),
+ primeExponentP == null ? null : primeExponentP.toByteArray(),
+ primeExponentQ == null ? null : primeExponentQ.toByteArray(),
+ crtCoefficient == null ? null : crtCoefficient.toByteArray()));
+ } catch (Exception e) {
+ throw new InvalidKeySpecException(e);
+ }
+ }
+
+ static OpenSSLKey getInstance(RSAPrivateCrtKey rsaPrivateKey) throws InvalidKeyException {
+ /**
+ * If the key is not encodable (PKCS11-like key), then wrap it and use
+ * JNI upcalls to satisfy requests.
+ */
+ if (rsaPrivateKey.getFormat() == null) {
+ return wrapPlatformKey(rsaPrivateKey);
+ }
+
+ BigInteger modulus = rsaPrivateKey.getModulus();
+ BigInteger privateExponent = rsaPrivateKey.getPrivateExponent();
+
+ if (modulus == null) {
+ throw new InvalidKeyException("modulus == null");
+ } else if (privateExponent == null) {
+ throw new InvalidKeyException("privateExponent == null");
+ }
+
+ try {
+ /*
+ * OpenSSL uses the public modulus to do RSA blinding. If
+ * the public modulus is not available, the call to
+ * EVP_PKEY_new_RSA will turn off blinding for this key
+ * instance.
+ */
+ final BigInteger publicExponent = rsaPrivateKey.getPublicExponent();
+ final BigInteger primeP = rsaPrivateKey.getPrimeP();
+ final BigInteger primeQ = rsaPrivateKey.getPrimeQ();
+ final BigInteger primeExponentP = rsaPrivateKey.getPrimeExponentP();
+ final BigInteger primeExponentQ = rsaPrivateKey.getPrimeExponentQ();
+ final BigInteger crtCoefficient = rsaPrivateKey.getCrtCoefficient();
+
+ return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
+ modulus.toByteArray(),
+ publicExponent == null ? null : publicExponent.toByteArray(),
+ privateExponent.toByteArray(),
+ primeP == null ? null : primeP.toByteArray(),
+ primeQ == null ? null : primeQ.toByteArray(),
+ primeExponentP == null ? null : primeExponentP.toByteArray(),
+ primeExponentQ == null ? null : primeExponentQ.toByteArray(),
+ crtCoefficient == null ? null : crtCoefficient.toByteArray()));
+ } catch (Exception e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
+ @Override
+ synchronized void readParams(byte[][] params) {
+ super.readParams(params);
+ // params[0] read in super.readParams
+ if (params[1] != null) {
+ publicExponent = new BigInteger(params[1]);
+ }
+ // params[2] read in super.readParams
+ if (params[3] != null) {
+ primeP = new BigInteger(params[3]);
+ }
+ if (params[4] != null) {
+ primeQ = new BigInteger(params[4]);
+ }
+ if (params[5] != null) {
+ primeExponentP = new BigInteger(params[5]);
+ }
+ if (params[6] != null) {
+ primeExponentQ = new BigInteger(params[6]);
+ }
+ if (params[7] != null) {
+ crtCoefficient = new BigInteger(params[7]);
+ }
+ }
+
+ @Override
+ public BigInteger getPublicExponent() {
+ ensureReadParams();
+ return publicExponent;
+ }
+
+ @Override
+ public BigInteger getPrimeP() {
+ ensureReadParams();
+ return primeP;
+ }
+
+ @Override
+ public BigInteger getPrimeQ() {
+ ensureReadParams();
+ return primeQ;
+ }
+
+ @Override
+ public BigInteger getPrimeExponentP() {
+ ensureReadParams();
+ return primeExponentP;
+ }
+
+ @Override
+ public BigInteger getPrimeExponentQ() {
+ ensureReadParams();
+ return primeExponentQ;
+ }
+
+ @Override
+ public BigInteger getCrtCoefficient() {
+ ensureReadParams();
+ return crtCoefficient;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (o instanceof OpenSSLRSAPrivateKey) {
+ OpenSSLRSAPrivateKey other = (OpenSSLRSAPrivateKey) o;
+ return getOpenSSLKey().equals(other.getOpenSSLKey());
+ }
+
+ if (o instanceof RSAPrivateCrtKey) {
+ ensureReadParams();
+ RSAPrivateCrtKey other = (RSAPrivateCrtKey) o;
+
+ if (getOpenSSLKey().isHardwareBacked()) {
+ return getModulus().equals(other.getModulus())
+ && publicExponent.equals(other.getPublicExponent());
+ } else {
+ return getModulus().equals(other.getModulus())
+ && publicExponent.equals(other.getPublicExponent())
+ && getPrivateExponent().equals(other.getPrivateExponent())
+ && primeP.equals(other.getPrimeP()) && primeQ.equals(other.getPrimeQ())
+ && primeExponentP.equals(other.getPrimeExponentP())
+ && primeExponentQ.equals(other.getPrimeExponentQ())
+ && crtCoefficient.equals(other.getCrtCoefficient());
+ }
+ } else if (o instanceof RSAPrivateKey) {
+ ensureReadParams();
+ RSAPrivateKey other = (RSAPrivateKey) o;
+
+ if (getOpenSSLKey().isHardwareBacked()) {
+ return getModulus().equals(other.getModulus());
+ } else {
+ return getModulus().equals(other.getModulus())
+ && getPrivateExponent().equals(other.getPrivateExponent());
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ int hashCode = super.hashCode();
+ if (publicExponent != null) {
+ hashCode ^= publicExponent.hashCode();
+ }
+ return hashCode;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("OpenSSLRSAPrivateCrtKey{");
+
+ ensureReadParams();
+ sb.append("modulus=");
+ sb.append(getModulus().toString(16));
+
+ if (publicExponent != null) {
+ sb.append(',');
+ sb.append("publicExponent=");
+ sb.append(publicExponent.toString(16));
+ }
+
+ sb.append('}');
+ return sb.toString();
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+
+ key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
+ modulus.toByteArray(),
+ publicExponent == null ? null : publicExponent.toByteArray(),
+ privateExponent.toByteArray(),
+ primeP == null ? null : primeP.toByteArray(),
+ primeQ == null ? null : primeQ.toByteArray(),
+ primeExponentP == null ? null : primeExponentP.toByteArray(),
+ primeExponentQ == null ? null : primeExponentQ.toByteArray(),
+ crtCoefficient == null ? null : crtCoefficient.toByteArray()));
+ fetchedParams = true;
+ }
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ if (getOpenSSLKey().isHardwareBacked()) {
+ throw new NotSerializableException("Hardware backed keys cannot be serialized");
+ }
+
+ ensureReadParams();
+ stream.defaultWriteObject();
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPrivateKey.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPrivateKey.java
new file mode 100644
index 0000000..0170d1b
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPrivateKey.java
@@ -0,0 +1,291 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.RSAKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPrivateKeySpec;
+
+/**
+ * An implementation of {@link java.security.PrivateKey} for RSA keys which uses BoringSSL to
+ * perform all the operations.
+ */
+class OpenSSLRSAPrivateKey implements RSAPrivateKey, OpenSSLKeyHolder {
+ private static final long serialVersionUID = 4872170254439578735L;
+
+ transient OpenSSLKey key;
+
+ transient boolean fetchedParams;
+
+ BigInteger modulus;
+
+ BigInteger privateExponent;
+
+ OpenSSLRSAPrivateKey(OpenSSLKey key) {
+ this.key = key;
+ }
+
+ OpenSSLRSAPrivateKey(OpenSSLKey key, byte[][] params) {
+ this(key);
+ readParams(params);
+ fetchedParams = true;
+ }
+
+ @Override
+ public OpenSSLKey getOpenSSLKey() {
+ return key;
+ }
+
+ public OpenSSLRSAPrivateKey(RSAPrivateKeySpec rsaKeySpec) throws InvalidKeySpecException {
+ this(init(rsaKeySpec));
+ }
+
+ private static OpenSSLKey init(RSAPrivateKeySpec rsaKeySpec) throws InvalidKeySpecException {
+ final BigInteger modulus = rsaKeySpec.getModulus();
+ final BigInteger privateExponent = rsaKeySpec.getPrivateExponent();
+
+ if (modulus == null) {
+ throw new InvalidKeySpecException("modulus == null");
+ } else if (privateExponent == null) {
+ throw new InvalidKeySpecException("privateExponent == null");
+ }
+
+ try {
+ return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
+ modulus.toByteArray(),
+ null,
+ privateExponent.toByteArray(),
+ null,
+ null,
+ null,
+ null,
+ null));
+ } catch (Exception e) {
+ throw new InvalidKeySpecException(e);
+ }
+ }
+
+ static OpenSSLRSAPrivateKey getInstance(OpenSSLKey key) {
+ byte[][] params = NativeCrypto.get_RSA_private_params(key.getNativeRef());
+ if (params[1] != null) {
+ return new OpenSSLRSAPrivateCrtKey(key, params);
+ }
+ return new OpenSSLRSAPrivateKey(key, params);
+ }
+
+ static OpenSSLKey wrapPlatformKey(RSAPrivateKey rsaPrivateKey)
+ throws InvalidKeyException {
+ OpenSSLKey wrapper = Platform.wrapRsaKey(rsaPrivateKey);
+ if (wrapper != null) {
+ return wrapper;
+ }
+ return new OpenSSLKey(NativeCrypto.getRSAPrivateKeyWrapper(rsaPrivateKey, rsaPrivateKey
+ .getModulus().toByteArray()), true);
+ }
+
+ /**
+ * Wraps the provided private key for use in the TLS/SSL stack only. Sign/decrypt operations
+ * using the key will be delegated to the {@code Signature}/{@code Cipher} implementation of the
+ * provider which accepts the key.
+ */
+ static OpenSSLKey wrapJCAPrivateKeyForTLSStackOnly(PrivateKey privateKey,
+ PublicKey publicKey) throws InvalidKeyException {
+ BigInteger modulus = null;
+ if (privateKey instanceof RSAKey) {
+ modulus = ((RSAKey) privateKey).getModulus();
+ } else if (publicKey instanceof RSAKey) {
+ modulus = ((RSAKey) publicKey).getModulus();
+ }
+ if (modulus == null) {
+ throw new InvalidKeyException("RSA modulus not available. Private: " + privateKey
+ + ", public: " + publicKey);
+ }
+ return new OpenSSLKey(
+ NativeCrypto.getRSAPrivateKeyWrapper(privateKey, modulus.toByteArray()), true);
+ }
+
+ static OpenSSLKey getInstance(RSAPrivateKey rsaPrivateKey) throws InvalidKeyException {
+ /**
+ * If the key is not encodable (PKCS11-like key), then wrap it and use
+ * JNI upcalls to satisfy requests.
+ */
+ if (rsaPrivateKey.getFormat() == null) {
+ return wrapPlatformKey(rsaPrivateKey);
+ }
+
+ final BigInteger modulus = rsaPrivateKey.getModulus();
+ final BigInteger privateExponent = rsaPrivateKey.getPrivateExponent();
+
+ if (modulus == null) {
+ throw new InvalidKeyException("modulus == null");
+ } else if (privateExponent == null) {
+ throw new InvalidKeyException("privateExponent == null");
+ }
+
+ try {
+ return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
+ modulus.toByteArray(),
+ null,
+ privateExponent.toByteArray(),
+ null,
+ null,
+ null,
+ null,
+ null));
+ } catch (Exception e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
+ synchronized final void ensureReadParams() {
+ if (fetchedParams) {
+ return;
+ }
+ readParams(NativeCrypto.get_RSA_private_params(key.getNativeRef()));
+ fetchedParams = true;
+ }
+
+ void readParams(byte[][] params) {
+ if (params[0] == null) {
+ throw new NullPointerException("modulus == null");
+ } else if (params[2] == null && !key.isHardwareBacked()) {
+ throw new NullPointerException("privateExponent == null");
+ }
+
+ modulus = new BigInteger(params[0]);
+
+ // ENGINE-based keys are not guaranteed to have a private exponent.
+ if (params[2] != null) {
+ privateExponent = new BigInteger(params[2]);
+ }
+ }
+
+ @Override
+ public final BigInteger getPrivateExponent() {
+ if (key.isHardwareBacked()) {
+ throw new UnsupportedOperationException("Private exponent cannot be extracted");
+ }
+ ensureReadParams();
+ return privateExponent;
+ }
+
+ @Override
+ public final BigInteger getModulus() {
+ ensureReadParams();
+ return modulus;
+ }
+
+ @Override
+ public final byte[] getEncoded() {
+ if (key.isHardwareBacked()) {
+ return null;
+ }
+ return NativeCrypto.EVP_marshal_private_key(key.getNativeRef());
+ }
+
+ @Override
+ public final String getFormat() {
+ if (key.isHardwareBacked()) {
+ return null;
+ }
+ return "PKCS#8";
+ }
+
+ @Override
+ public final String getAlgorithm() {
+ return "RSA";
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (o instanceof OpenSSLRSAPrivateKey) {
+ OpenSSLRSAPrivateKey other = (OpenSSLRSAPrivateKey) o;
+ return key.equals(other.getOpenSSLKey());
+ }
+
+ if (o instanceof RSAPrivateKey) {
+ ensureReadParams();
+ RSAPrivateKey other = (RSAPrivateKey) o;
+
+ return modulus.equals(other.getModulus())
+ && privateExponent.equals(other.getPrivateExponent());
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ ensureReadParams();
+ int hash = 1;
+
+ hash = hash * 3 + modulus.hashCode();
+ if (privateExponent != null) {
+ hash = hash * 7 + privateExponent.hashCode();
+ }
+
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("OpenSSLRSAPrivateKey{");
+
+ ensureReadParams();
+ sb.append("modulus=");
+ sb.append(modulus.toString(16));
+
+ return sb.toString();
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+
+ key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
+ modulus.toByteArray(),
+ null,
+ privateExponent.toByteArray(),
+ null,
+ null,
+ null,
+ null,
+ null));
+ fetchedParams = true;
+ }
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ if (key.isHardwareBacked()) {
+ throw new NotSerializableException("Hardware backed keys can not be serialized");
+ }
+ ensureReadParams();
+ stream.defaultWriteObject();
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPublicKey.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPublicKey.java
new file mode 100644
index 0000000..8821fd0
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPublicKey.java
@@ -0,0 +1,196 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPublicKeySpec;
+
+/**
+ * An implementation of {@link java.security.PublicKey} for RSA keys which uses BoringSSL to
+ * perform all the operations.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class OpenSSLRSAPublicKey implements RSAPublicKey, OpenSSLKeyHolder {
+ private static final long serialVersionUID = 123125005824688292L;
+
+ private transient OpenSSLKey key;
+
+ private BigInteger publicExponent;
+
+ private BigInteger modulus;
+
+ private transient boolean fetchedParams;
+
+ OpenSSLRSAPublicKey(OpenSSLKey key) {
+ this.key = key;
+ }
+
+ @Override
+ public OpenSSLKey getOpenSSLKey() {
+ return key;
+ }
+
+ OpenSSLRSAPublicKey(RSAPublicKeySpec spec) throws InvalidKeySpecException {
+ try {
+ key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
+ spec.getModulus().toByteArray(),
+ spec.getPublicExponent().toByteArray(),
+ null,
+ null,
+ null,
+ null,
+ null,
+ null));
+ } catch (Exception e) {
+ throw new InvalidKeySpecException(e);
+ }
+ }
+
+ static OpenSSLKey getInstance(RSAPublicKey rsaPublicKey) throws InvalidKeyException {
+ try {
+ return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
+ rsaPublicKey.getModulus().toByteArray(),
+ rsaPublicKey.getPublicExponent().toByteArray(),
+ null,
+ null,
+ null,
+ null,
+ null,
+ null));
+ } catch (Exception e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return "RSA";
+ }
+
+ @Override
+ public String getFormat() {
+ return "X.509";
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return NativeCrypto.EVP_marshal_public_key(key.getNativeRef());
+ }
+
+ private synchronized void ensureReadParams() {
+ if (fetchedParams) {
+ return;
+ }
+
+ byte[][] params = NativeCrypto.get_RSA_public_params(key.getNativeRef());
+ modulus = new BigInteger(params[0]);
+ publicExponent = new BigInteger(params[1]);
+
+ fetchedParams = true;
+ }
+
+ @Override
+ public BigInteger getModulus() {
+ ensureReadParams();
+ return modulus;
+ }
+
+ @Override
+ public BigInteger getPublicExponent() {
+ ensureReadParams();
+ return publicExponent;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (o instanceof OpenSSLRSAPublicKey) {
+ OpenSSLRSAPublicKey other = (OpenSSLRSAPublicKey) o;
+
+ /*
+ * We can shortcut the true case, but it still may be equivalent but
+ * different copies.
+ */
+ if (key.equals(other.getOpenSSLKey())) {
+ return true;
+ }
+ }
+
+ if (!(o instanceof RSAPublicKey)) {
+ return false;
+ }
+
+ ensureReadParams();
+
+ RSAPublicKey other = (RSAPublicKey) o;
+ return modulus.equals(other.getModulus())
+ && publicExponent.equals(other.getPublicExponent());
+ }
+
+ @Override
+ public int hashCode() {
+ ensureReadParams();
+
+ return modulus.hashCode() ^ publicExponent.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ ensureReadParams();
+
+ final StringBuilder sb = new StringBuilder("OpenSSLRSAPublicKey{");
+ sb.append("modulus=");
+ sb.append(modulus.toString(16));
+ sb.append(',');
+ sb.append("publicExponent=");
+ sb.append(publicExponent.toString(16));
+ sb.append('}');
+
+ return sb.toString();
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+
+ key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
+ modulus.toByteArray(),
+ publicExponent.toByteArray(),
+ null,
+ null,
+ null,
+ null,
+ null,
+ null));
+ fetchedParams = true;
+ }
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ ensureReadParams();
+ stream.defaultWriteObject();
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRandom.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRandom.java
new file mode 100644
index 0000000..0c7b404
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRandom.java
@@ -0,0 +1,54 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.Serializable;
+import java.security.SecureRandomSpi;
+
+/**
+ * Implements {@link java.security.SecureRandom} using BoringSSL's RAND interface.
+ * @hide This class is not part of the Android public SDK API
+ */
+@libcore.api.IntraCoreApi
+@Internal
+public final class OpenSSLRandom extends SecureRandomSpi implements Serializable {
+ private static final long serialVersionUID = 8506210602917522861L;
+
+ @android.compat.annotation.UnsupportedAppUsage
+ @libcore.api.IntraCoreApi
+ public OpenSSLRandom() {}
+
+ @Override
+ protected void engineSetSeed(byte[] seed) {
+ if (seed == null) {
+ throw new NullPointerException("seed == null");
+ }
+ }
+
+ @Override
+ protected void engineNextBytes(byte[] bytes) {
+ NativeCrypto.RAND_bytes(bytes);
+ }
+
+ @Override
+ protected byte[] engineGenerateSeed(int numBytes) {
+ byte[] output = new byte[numBytes];
+ NativeCrypto.RAND_bytes(output);
+ return output;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLServerSocketFactoryImpl.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLServerSocketFactoryImpl.java
new file mode 100644
index 0000000..b066bac
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLServerSocketFactoryImpl.java
@@ -0,0 +1,111 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2007 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.security.KeyManagementException;
+import javax.net.ServerSocketFactory;
+import javax.net.ssl.SSLServerSocketFactory;
+
+/**
+ * An implementation of {@link SSLServerSocketFactory} using BoringSSL.
+ *
+ * <p/>This name of this class cannot change in order to maintain backward-compatibility with GMS
+ * core {@code ProviderInstallerImpl}
+ */
+final class OpenSSLServerSocketFactoryImpl extends SSLServerSocketFactory {
+ private static boolean useEngineSocketByDefault = SSLUtils.USE_ENGINE_SOCKET_BY_DEFAULT;
+
+ private SSLParametersImpl sslParameters;
+ private IOException instantiationException;
+ private boolean useEngineSocket = useEngineSocketByDefault;
+
+ OpenSSLServerSocketFactoryImpl() {
+ try {
+ this.sslParameters = SSLParametersImpl.getDefault();
+ this.sslParameters.setUseClientMode(false);
+ } catch (KeyManagementException e) {
+ instantiationException = new IOException("Delayed instantiation exception:");
+ instantiationException.initCause(e);
+ }
+ }
+
+ OpenSSLServerSocketFactoryImpl(SSLParametersImpl sslParameters) {
+ this.sslParameters = (SSLParametersImpl) sslParameters.clone();
+ this.sslParameters.setUseClientMode(false);
+ }
+
+ /**
+ * Configures the default socket type to be created for the default and all new instances.
+ */
+ static void setUseEngineSocketByDefault(boolean useEngineSocket) {
+ useEngineSocketByDefault = useEngineSocket;
+ // The default SSLServerSocketFactory may already have been created, so also change its
+ // setting.
+ ServerSocketFactory defaultFactory = SSLServerSocketFactory.getDefault();
+ if (defaultFactory instanceof OpenSSLServerSocketFactoryImpl) {
+ ((OpenSSLServerSocketFactoryImpl) defaultFactory).setUseEngineSocket(useEngineSocket);
+ }
+ }
+
+ /**
+ * Configures the socket to be created for this instance. If not called,
+ * {@link #useEngineSocketByDefault} will be used.
+ */
+ void setUseEngineSocket(boolean useEngineSocket) {
+ this.useEngineSocket = useEngineSocket;
+ }
+
+ @Override
+ public String[] getDefaultCipherSuites() {
+ return sslParameters.getEnabledCipherSuites();
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return NativeCrypto.getSupportedCipherSuites();
+ }
+
+ @Override
+ public ServerSocket createServerSocket() throws IOException {
+ return new ConscryptServerSocket((SSLParametersImpl) sslParameters.clone())
+ .setUseEngineSocket(useEngineSocket);
+ }
+
+ @Override
+ public ServerSocket createServerSocket(int port) throws IOException {
+ return new ConscryptServerSocket(port, (SSLParametersImpl) sslParameters.clone())
+ .setUseEngineSocket(useEngineSocket);
+ }
+
+ @Override
+ public ServerSocket createServerSocket(int port, int backlog) throws IOException {
+ return new ConscryptServerSocket(port, backlog, (SSLParametersImpl) sslParameters.clone())
+ .setUseEngineSocket(useEngineSocket);
+ }
+
+ @Override
+ public ServerSocket createServerSocket(int port, int backlog, InetAddress iAddress)
+ throws IOException {
+ return new ConscryptServerSocket(
+ port, backlog, iAddress, (SSLParametersImpl) sslParameters.clone())
+ .setUseEngineSocket(useEngineSocket);
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSignature.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSignature.java
new file mode 100644
index 0000000..cf48e9b
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSignature.java
@@ -0,0 +1,543 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2008 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.nio.ByteBuffer;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.ProviderException;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PSSParameterSpec;
+
+/**
+ * Implements the subset of the JDK Signature interface needed for
+ * signature verification using OpenSSL.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class OpenSSLSignature extends SignatureSpi {
+ private enum EngineType {
+ RSA, EC,
+ }
+
+ private NativeRef.EVP_MD_CTX ctx;
+
+ /**
+ * The current OpenSSL key we're operating on.
+ */
+ private OpenSSLKey key;
+
+ /**
+ * Holds the type of the Java algorithm.
+ */
+ private final EngineType engineType;
+
+ /**
+ * Digest algorithm (reference to {@code EVP_MD}).
+ */
+ private final long evpMdRef;
+
+ /**
+ * Holds a dummy buffer for writing single bytes to the digest.
+ */
+ private final byte[] singleByte = new byte[1];
+
+ /**
+ * True when engine is initialized to signing.
+ */
+ private boolean signing;
+
+ /**
+ * Public key algorithm context (reference to {@code EVP_PKEY_CTX}).
+ */
+ private long evpPkeyCtx;
+
+ /**
+ * Creates a new OpenSSLSignature instance for the given algorithm name.
+ *
+ * @param evpMdRef digest algorithm ({@code EVP_MD} reference).
+ */
+ private OpenSSLSignature(long evpMdRef, EngineType engineType) {
+ this.engineType = engineType;
+ this.evpMdRef = evpMdRef;
+ }
+
+ private void resetContext() throws InvalidAlgorithmParameterException {
+ NativeRef.EVP_MD_CTX ctxLocal = new NativeRef.EVP_MD_CTX(NativeCrypto.EVP_MD_CTX_create());
+ if (signing) {
+ evpPkeyCtx = NativeCrypto.EVP_DigestSignInit(ctxLocal, evpMdRef, key.getNativeRef());
+ } else {
+ evpPkeyCtx = NativeCrypto.EVP_DigestVerifyInit(ctxLocal, evpMdRef, key.getNativeRef());
+ }
+ configureEVP_PKEY_CTX(evpPkeyCtx);
+ this.ctx = ctxLocal;
+ }
+
+ /**
+ * Configures the public key algorithm context ({@code EVP_PKEY_CTX}) associated with this
+ * operation.
+ *
+ * <p>The default implementation does nothing.
+ *
+ * @param ctx reference to the context ({@code EVP_PKEY_CTX}).
+ */
+ protected void configureEVP_PKEY_CTX(long ctx) throws InvalidAlgorithmParameterException {}
+
+ @Override
+ protected void engineUpdate(byte input) {
+ singleByte[0] = input;
+ engineUpdate(singleByte, 0, 1);
+ }
+
+ @Override
+ protected void engineUpdate(byte[] input, int offset, int len) {
+ final NativeRef.EVP_MD_CTX ctxLocal = ctx;
+ if (signing) {
+ NativeCrypto.EVP_DigestSignUpdate(ctxLocal, input, offset, len);
+ } else {
+ NativeCrypto.EVP_DigestVerifyUpdate(ctxLocal, input, offset, len);
+ }
+ }
+
+ @Override
+ protected void engineUpdate(ByteBuffer input) {
+ // Optimization: Avoid copying/allocation for direct buffers because their contents are
+ // stored as a contiguous region in memory and thus can be efficiently accessed from native
+ // code.
+
+ if (!input.hasRemaining()) {
+ return;
+ }
+
+ if (!input.isDirect()) {
+ super.engineUpdate(input);
+ return;
+ }
+
+ long baseAddress = NativeCrypto.getDirectBufferAddress(input);
+ if (baseAddress == 0) {
+ // Direct buffer's contents can't be accessed from JNI -- superclass's implementation
+ // is good enough to handle this.
+ super.engineUpdate(input);
+ return;
+ }
+
+ // Process the contents between Buffer's position and limit (remaining() number of bytes)
+ int position = input.position();
+ if (position < 0) {
+ throw new RuntimeException("Negative position");
+ }
+ long ptr = baseAddress + position;
+ int len = input.remaining();
+ if (len < 0) {
+ throw new RuntimeException("Negative remaining amount");
+ }
+
+ final NativeRef.EVP_MD_CTX ctxLocal = ctx;
+ if (signing) {
+ NativeCrypto.EVP_DigestSignUpdateDirect(ctxLocal, ptr, len);
+ } else {
+ NativeCrypto.EVP_DigestVerifyUpdateDirect(ctxLocal, ptr, len);
+ }
+ input.position(position + len);
+ }
+
+ @Deprecated
+ @Override
+ protected Object engineGetParameter(String param) throws InvalidParameterException {
+ return null;
+ }
+
+ private void checkEngineType(OpenSSLKey pkey) throws InvalidKeyException {
+ final int pkeyType = NativeCrypto.EVP_PKEY_type(pkey.getNativeRef());
+
+ switch (engineType) {
+ case RSA:
+ if (pkeyType != NativeConstants.EVP_PKEY_RSA) {
+ throw new InvalidKeyException("Signature initialized as " + engineType
+ + " (not RSA)");
+ }
+ break;
+ case EC:
+ if (pkeyType != NativeConstants.EVP_PKEY_EC) {
+ throw new InvalidKeyException("Signature initialized as " + engineType
+ + " (not EC)");
+ }
+ break;
+ default:
+ throw new InvalidKeyException("Key must be of type " + engineType);
+ }
+ }
+
+ private void initInternal(OpenSSLKey newKey, boolean signing) throws InvalidKeyException {
+ checkEngineType(newKey);
+ key = newKey;
+
+ this.signing = signing;
+ try {
+ resetContext();
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
+ @Override
+ protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException {
+ initInternal(OpenSSLKey.fromPrivateKey(privateKey), true);
+ }
+
+ @Override
+ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
+ initInternal(OpenSSLKey.fromPublicKey(publicKey), false);
+ }
+
+ @Deprecated
+ @Override
+ protected void engineSetParameter(String param, Object value) throws InvalidParameterException {
+ }
+
+ @Override
+ @SuppressWarnings("Finally")
+ protected byte[] engineSign() throws SignatureException {
+ final NativeRef.EVP_MD_CTX ctxLocal = ctx;
+ try {
+ return NativeCrypto.EVP_DigestSignFinal(ctxLocal);
+ } catch (Exception ex) {
+ throw new SignatureException(ex);
+ } finally {
+ /*
+ * Java expects the digest context to be reset completely after sign
+ * calls.
+ */
+ try {
+ resetContext();
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new AssertionError("Reset of context failed after it was successful once");
+ }
+ }
+ }
+
+ @Override
+ @SuppressWarnings("Finally")
+ protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
+ final NativeRef.EVP_MD_CTX ctxLocal = ctx;
+ try {
+ return NativeCrypto.EVP_DigestVerifyFinal(ctxLocal, sigBytes, 0, sigBytes.length);
+ } catch (Exception ex) {
+ throw new SignatureException(ex);
+ } finally {
+ /*
+ * Java expects the digest context to be reset completely after
+ * verify calls.
+ */
+ try {
+ resetContext();
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new AssertionError("Reset of context failed after it was successful once");
+ }
+ }
+ }
+
+ /**
+ * Returns the public key algorithm context ({@code EVP_PKEY_CTX} reference) associated with
+ * this operation or {@code 0} if operation hasn't been initialized.
+ */
+ protected final long getEVP_PKEY_CTX() {
+ return evpPkeyCtx;
+ }
+
+ /**
+ * Base class for {@code RSASSA-PKCS1-v1_5} signatures.
+ */
+ abstract static class RSAPKCS1Padding extends OpenSSLSignature {
+ RSAPKCS1Padding(long evpMdRef) {
+ super(evpMdRef, EngineType.RSA);
+ }
+
+ @Override
+ protected final void configureEVP_PKEY_CTX(long ctx)
+ throws InvalidAlgorithmParameterException {
+ NativeCrypto.EVP_PKEY_CTX_set_rsa_padding(ctx, NativeConstants.RSA_PKCS1_PADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class MD5RSA extends RSAPKCS1Padding {
+ public MD5RSA() {
+ super(EvpMdRef.MD5.EVP_MD);
+ }
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA1RSA extends RSAPKCS1Padding {
+ public SHA1RSA() {
+ super(EvpMdRef.SHA1.EVP_MD);
+ }
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA224RSA extends RSAPKCS1Padding {
+ public SHA224RSA() {
+ super(EvpMdRef.SHA224.EVP_MD);
+ }
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA256RSA extends RSAPKCS1Padding {
+ public SHA256RSA() {
+ super(EvpMdRef.SHA256.EVP_MD);
+ }
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA384RSA extends RSAPKCS1Padding {
+ public SHA384RSA() {
+ super(EvpMdRef.SHA384.EVP_MD);
+ }
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA512RSA extends RSAPKCS1Padding {
+ public SHA512RSA() {
+ super(EvpMdRef.SHA512.EVP_MD);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA1ECDSA extends OpenSSLSignature {
+ public SHA1ECDSA() {
+ super(EvpMdRef.SHA1.EVP_MD, EngineType.EC);
+ }
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA224ECDSA extends OpenSSLSignature {
+ public SHA224ECDSA() {
+ super(EvpMdRef.SHA224.EVP_MD, EngineType.EC);
+ }
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA256ECDSA extends OpenSSLSignature {
+ public SHA256ECDSA() {
+ super(EvpMdRef.SHA256.EVP_MD, EngineType.EC);
+ }
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA384ECDSA extends OpenSSLSignature {
+ public SHA384ECDSA() {
+ super(EvpMdRef.SHA384.EVP_MD, EngineType.EC);
+ }
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA512ECDSA extends OpenSSLSignature {
+ public SHA512ECDSA() {
+ super(EvpMdRef.SHA512.EVP_MD, EngineType.EC);
+ }
+ }
+
+ /**
+ * Base class for {@code RSASSA-PSS} signatures.
+ */
+ abstract static class RSAPSSPadding extends OpenSSLSignature {
+ private static final int TRAILER_FIELD_BC_ID = 1;
+
+ private final String contentDigestAlgorithm;
+
+ private String mgf1DigestAlgorithm;
+ private long mgf1EvpMdRef;
+ private int saltSizeBytes;
+
+ RSAPSSPadding(
+ long contentDigestEvpMdRef, String contentDigestAlgorithm, int saltSizeBytes) {
+ super(contentDigestEvpMdRef, EngineType.RSA);
+ this.contentDigestAlgorithm = contentDigestAlgorithm;
+ this.mgf1DigestAlgorithm = contentDigestAlgorithm;
+ this.mgf1EvpMdRef = contentDigestEvpMdRef;
+ this.saltSizeBytes = saltSizeBytes;
+ }
+
+ @Override
+ protected final void configureEVP_PKEY_CTX(long ctx)
+ throws InvalidAlgorithmParameterException {
+ NativeCrypto.EVP_PKEY_CTX_set_rsa_padding(ctx, NativeConstants.RSA_PKCS1_PSS_PADDING);
+ NativeCrypto.EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, mgf1EvpMdRef);
+ NativeCrypto.EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, saltSizeBytes);
+ }
+
+ @Override
+ protected final void engineSetParameter(AlgorithmParameterSpec params)
+ throws InvalidAlgorithmParameterException {
+ if (!(params instanceof PSSParameterSpec)) {
+ throw new InvalidAlgorithmParameterException(
+ "Unsupported parameter: " + params + ". Only "
+ + PSSParameterSpec.class.getName() + " supported");
+ }
+ PSSParameterSpec spec = (PSSParameterSpec) params;
+ String specContentDigest = EvpMdRef
+ .getJcaDigestAlgorithmStandardName(spec.getDigestAlgorithm());
+ if (specContentDigest == null) {
+ throw new InvalidAlgorithmParameterException(
+ "Unsupported content digest algorithm: " + spec.getDigestAlgorithm());
+ } else if (!contentDigestAlgorithm.equalsIgnoreCase(specContentDigest)) {
+ throw new InvalidAlgorithmParameterException(
+ "Changing content digest algorithm not supported");
+ }
+
+ String specMgfAlgorithm = spec.getMGFAlgorithm();
+ if (!EvpMdRef.MGF1_ALGORITHM_NAME.equalsIgnoreCase(specMgfAlgorithm)
+ && !EvpMdRef.MGF1_OID.equals(specMgfAlgorithm)) {
+ throw new InvalidAlgorithmParameterException(
+ "Unsupported MGF algorithm: " + specMgfAlgorithm + ". Only "
+ + EvpMdRef.MGF1_ALGORITHM_NAME + " supported");
+ }
+
+ AlgorithmParameterSpec mgfSpec = spec.getMGFParameters();
+ if (!(mgfSpec instanceof MGF1ParameterSpec)) {
+ throw new InvalidAlgorithmParameterException(
+ "Unsupported MGF parameters: " + mgfSpec + ". Only "
+ + MGF1ParameterSpec.class.getName() + " supported");
+ }
+ MGF1ParameterSpec specMgf1Spec = (MGF1ParameterSpec) spec.getMGFParameters();
+
+ String specMgf1Digest = EvpMdRef
+ .getJcaDigestAlgorithmStandardName(specMgf1Spec.getDigestAlgorithm());
+ if (specMgf1Digest == null) {
+ throw new InvalidAlgorithmParameterException(
+ "Unsupported MGF1 digest algorithm: " + specMgf1Spec.getDigestAlgorithm());
+ }
+ long specMgf1EvpMdRef;
+ try {
+ specMgf1EvpMdRef = EvpMdRef
+ .getEVP_MDByJcaDigestAlgorithmStandardName(specMgf1Digest);
+ } catch (NoSuchAlgorithmException e) {
+ throw new ProviderException("Failed to obtain EVP_MD for " + specMgf1Digest, e);
+ }
+
+ int specSaltSizeBytes = spec.getSaltLength();
+ if (specSaltSizeBytes < 0) {
+ throw new InvalidAlgorithmParameterException(
+ "Salt length must be non-negative: " + specSaltSizeBytes);
+ }
+
+ int specTrailer = spec.getTrailerField();
+ if (specTrailer != TRAILER_FIELD_BC_ID) {
+ throw new InvalidAlgorithmParameterException(
+ "Unsupported trailer field: " + specTrailer + ". Only "
+ + TRAILER_FIELD_BC_ID + " supported");
+ }
+
+ this.mgf1DigestAlgorithm = specMgf1Digest;
+ this.mgf1EvpMdRef = specMgf1EvpMdRef;
+ this.saltSizeBytes = specSaltSizeBytes;
+
+ long ctx = getEVP_PKEY_CTX();
+ if (ctx != 0) {
+ configureEVP_PKEY_CTX(ctx);
+ }
+ }
+
+ @Override
+ protected final AlgorithmParameters engineGetParameters() {
+ try {
+ AlgorithmParameters result = AlgorithmParameters.getInstance("PSS");
+ result.init(
+ new PSSParameterSpec(
+ contentDigestAlgorithm,
+ EvpMdRef.MGF1_ALGORITHM_NAME,
+ new MGF1ParameterSpec(mgf1DigestAlgorithm),
+ saltSizeBytes,
+ TRAILER_FIELD_BC_ID));
+ return result;
+ } catch (NoSuchAlgorithmException e) {
+ throw new ProviderException("Failed to create PSS AlgorithmParameters", e);
+ } catch (InvalidParameterSpecException e) {
+ throw new ProviderException("Failed to create PSS AlgorithmParameters", e);
+ }
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA1RSAPSS extends RSAPSSPadding {
+ public SHA1RSAPSS() {
+ super(EvpMdRef.SHA1.EVP_MD, EvpMdRef.SHA1.JCA_NAME, EvpMdRef.SHA1.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA224RSAPSS extends RSAPSSPadding {
+ public SHA224RSAPSS() {
+ super(EvpMdRef.SHA224.EVP_MD, EvpMdRef.SHA224.JCA_NAME, EvpMdRef.SHA224.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA256RSAPSS extends RSAPSSPadding {
+ public SHA256RSAPSS() {
+ super(EvpMdRef.SHA256.EVP_MD, EvpMdRef.SHA256.JCA_NAME, EvpMdRef.SHA256.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA384RSAPSS extends RSAPSSPadding {
+ public SHA384RSAPSS() {
+ super(EvpMdRef.SHA384.EVP_MD, EvpMdRef.SHA384.JCA_NAME, EvpMdRef.SHA384.SIZE_BYTES);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class SHA512RSAPSS extends RSAPSSPadding {
+ public SHA512RSAPSS() {
+ super(EvpMdRef.SHA512.EVP_MD, EvpMdRef.SHA512.JCA_NAME, EvpMdRef.SHA512.SIZE_BYTES);
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSignatureRawECDSA.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSignatureRawECDSA.java
new file mode 100644
index 0000000..d48abd0
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSignatureRawECDSA.java
@@ -0,0 +1,136 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.android.org.conscrypt;
+
+import java.io.ByteArrayOutputStream;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+
+/**
+ * Implements the JDK Signature interface needed for RAW ECDSA signature
+ * generation and verification using BoringSSL.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class OpenSSLSignatureRawECDSA extends SignatureSpi {
+ /**
+ * The current OpenSSL key we're operating on.
+ */
+ private OpenSSLKey key;
+
+ /**
+ * Buffer to hold value to be signed or verified.
+ */
+ private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ public OpenSSLSignatureRawECDSA() {}
+
+ @Override
+ protected void engineUpdate(byte input) {
+ buffer.write(input);
+ }
+
+ @Override
+ protected void engineUpdate(byte[] input, int offset, int len) {
+ buffer.write(input, offset, len);
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ protected Object engineGetParameter(String param) throws InvalidParameterException {
+ return null;
+ }
+
+ private static OpenSSLKey verifyKey(OpenSSLKey key) throws InvalidKeyException {
+ int pkeyType = NativeCrypto.EVP_PKEY_type(key.getNativeRef());
+ if (pkeyType != NativeConstants.EVP_PKEY_EC) {
+ throw new InvalidKeyException("Non-EC key used to initialize EC signature.");
+ }
+ return key;
+ }
+
+ @Override
+ protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException {
+ key = verifyKey(OpenSSLKey.fromPrivateKey(privateKey));
+ }
+
+ @Override
+ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
+ key = verifyKey(OpenSSLKey.fromPublicKey(publicKey));
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ protected void engineSetParameter(String param, Object value) throws InvalidParameterException {
+ }
+
+ @Override
+ protected byte[] engineSign() throws SignatureException {
+ if (key == null) {
+ // This can't actually happen, but you never know...
+ throw new SignatureException("No key provided");
+ }
+
+ int output_size = NativeCrypto.ECDSA_size(key.getNativeRef());
+ byte[] outputBuffer = new byte[output_size];
+ try {
+ int bytes_written =
+ NativeCrypto.ECDSA_sign(buffer.toByteArray(), outputBuffer, key.getNativeRef());
+ if (bytes_written < 0) {
+ throw new SignatureException("Could not compute signature.");
+ }
+ // There's no guarantee that the signature will be ECDSA_size bytes long,
+ // that's just the maximum possible length of a signature. Only return the bytes
+ // that were actually produced.
+ if (bytes_written != output_size) {
+ byte[] newBuffer = new byte[bytes_written];
+ System.arraycopy(outputBuffer, 0, newBuffer, 0, bytes_written);
+ outputBuffer = newBuffer;
+ }
+ return outputBuffer;
+ } catch (Exception ex) {
+ throw new SignatureException(ex);
+ } finally {
+ buffer.reset();
+ }
+ }
+
+ @Override
+ protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
+ if (key == null) {
+ // This can't actually happen, but you never know...
+ throw new SignatureException("No key provided");
+ }
+
+ try {
+ int result =
+ NativeCrypto.ECDSA_verify(buffer.toByteArray(), sigBytes, key.getNativeRef());
+ if (result == -1) {
+ throw new SignatureException("Could not verify signature.");
+ }
+ return result == 1;
+ } catch (Exception ex) {
+ throw new SignatureException(ex);
+ } finally {
+ buffer.reset();
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSignatureRawRSA.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSignatureRawRSA.java
new file mode 100644
index 0000000..c18bcf1
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSignatureRawRSA.java
@@ -0,0 +1,201 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+/**
+ * Implements the JDK Signature interface needed for RAW RSA signature
+ * generation and verification using BoringSSL.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class OpenSSLSignatureRawRSA extends SignatureSpi {
+ /**
+ * The current OpenSSL key we're operating on.
+ */
+ private OpenSSLKey key;
+
+ /**
+ * Buffer to hold value to be signed or verified.
+ */
+ private byte[] inputBuffer;
+
+ /**
+ * Current offset in input buffer.
+ */
+ private int inputOffset;
+
+ /**
+ * Provides a flag to specify when the input is too long.
+ */
+ private boolean inputIsTooLong;
+
+ public OpenSSLSignatureRawRSA() {}
+
+ @Override
+ protected void engineUpdate(byte input) {
+ final int oldOffset = inputOffset++;
+
+ if (inputOffset > inputBuffer.length) {
+ inputIsTooLong = true;
+ return;
+ }
+
+ inputBuffer[oldOffset] = input;
+ }
+
+ @Override
+ protected void engineUpdate(byte[] input, int offset, int len) {
+ final int oldOffset = inputOffset;
+ inputOffset += len;
+
+ if (inputOffset > inputBuffer.length) {
+ inputIsTooLong = true;
+ return;
+ }
+
+ System.arraycopy(input, offset, inputBuffer, oldOffset, len);
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ protected Object engineGetParameter(String param) throws InvalidParameterException {
+ return null;
+ }
+
+ @Override
+ protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException {
+ if (privateKey instanceof OpenSSLRSAPrivateKey) {
+ OpenSSLRSAPrivateKey rsaPrivateKey = (OpenSSLRSAPrivateKey) privateKey;
+ key = rsaPrivateKey.getOpenSSLKey();
+ } else if (privateKey instanceof RSAPrivateCrtKey) {
+ RSAPrivateCrtKey rsaPrivateKey = (RSAPrivateCrtKey) privateKey;
+ key = OpenSSLRSAPrivateCrtKey.getInstance(rsaPrivateKey);
+ } else if (privateKey instanceof RSAPrivateKey) {
+ RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;
+ key = OpenSSLRSAPrivateKey.getInstance(rsaPrivateKey);
+ } else {
+ throw new InvalidKeyException("Need RSA private key");
+ }
+
+ // Allocate buffer according to RSA modulus size.
+ int maxSize = NativeCrypto.RSA_size(key.getNativeRef());
+ inputBuffer = new byte[maxSize];
+ inputOffset = 0;
+ }
+
+ @Override
+ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
+ if (publicKey instanceof OpenSSLRSAPublicKey) {
+ OpenSSLRSAPublicKey rsaPublicKey = (OpenSSLRSAPublicKey) publicKey;
+ key = rsaPublicKey.getOpenSSLKey();
+ } else if (publicKey instanceof RSAPublicKey) {
+ RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
+ key = OpenSSLRSAPublicKey.getInstance(rsaPublicKey);
+ } else {
+ throw new InvalidKeyException("Need RSA public key");
+ }
+
+ // Allocate buffer according to RSA modulus size.
+ int maxSize = NativeCrypto.RSA_size(key.getNativeRef());
+ inputBuffer = new byte[maxSize];
+ inputOffset = 0;
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ protected void engineSetParameter(String param, Object value) throws InvalidParameterException {
+ }
+
+ @Override
+ protected byte[] engineSign() throws SignatureException {
+ if (key == null) {
+ // This can't actually happen, but you never know...
+ throw new SignatureException("Need RSA private key");
+ }
+
+ if (inputIsTooLong) {
+ throw new SignatureException("input length " + inputOffset + " != "
+ + inputBuffer.length + " (modulus size)");
+ }
+
+ byte[] outputBuffer = new byte[inputBuffer.length];
+ try {
+ NativeCrypto.RSA_private_encrypt(inputOffset, inputBuffer, outputBuffer,
+ key.getNativeRef(), NativeConstants.RSA_PKCS1_PADDING);
+ return outputBuffer;
+ } catch (Exception ex) {
+ throw new SignatureException(ex);
+ } finally {
+ inputOffset = 0;
+ }
+ }
+
+ @Override
+ protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
+ if (key == null) {
+ // This can't actually happen, but you never know...
+ throw new SignatureException("Need RSA public key");
+ }
+
+ if (inputIsTooLong) {
+ return false;
+ }
+
+ // We catch this case here instead of BoringSSL so we can throw an
+ // exception that matches other implementations.
+ if (sigBytes.length > inputBuffer.length) {
+ throw new SignatureException("Input signature length is too large: " + sigBytes.length
+ + " > " + inputBuffer.length);
+ }
+
+ byte[] outputBuffer = new byte[inputBuffer.length];
+ try {
+ final int resultSize;
+ try {
+ resultSize = NativeCrypto.RSA_public_decrypt(sigBytes.length, sigBytes,
+ outputBuffer, key.getNativeRef(), NativeConstants.RSA_PKCS1_PADDING);
+ } catch (SignatureException e) {
+ throw e;
+ } catch (Exception e) {
+ return false;
+ }
+ /* Make this constant time by comparing every byte. */
+ boolean matches = (resultSize == inputOffset);
+ for (int i = 0; i < resultSize; i++) {
+ if (inputBuffer[i] != outputBuffer[i]) {
+ matches = false;
+ }
+ }
+ return matches;
+ } catch (Exception ex) {
+ throw new SignatureException(ex);
+ } finally {
+ inputOffset = 0;
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSocketFactoryImpl.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSocketFactoryImpl.java
new file mode 100644
index 0000000..e7891ae
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSocketFactoryImpl.java
@@ -0,0 +1,178 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2007 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.Platform.createEngineSocket;
+import static com.android.org.conscrypt.Platform.createFileDescriptorSocket;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.security.KeyManagementException;
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * An implementation of {@link SSLSocketFactory} based on BoringSSL.
+ *
+ * <p/>This name of this class cannot change in order to maintain backward-compatibility with GMS
+ * core {@code ProviderInstallerImpl}
+ */
+final class OpenSSLSocketFactoryImpl extends SSLSocketFactory {
+ private static boolean useEngineSocketByDefault = SSLUtils.USE_ENGINE_SOCKET_BY_DEFAULT;
+
+ @android.compat.annotation.UnsupportedAppUsage private final SSLParametersImpl sslParameters;
+ private final IOException instantiationException;
+ private boolean useEngineSocket = useEngineSocketByDefault;
+
+ @android.compat.annotation.UnsupportedAppUsage
+ OpenSSLSocketFactoryImpl() {
+ SSLParametersImpl sslParametersLocal = null;
+ IOException instantiationExceptionLocal = null;
+ try {
+ sslParametersLocal = SSLParametersImpl.getDefault();
+ } catch (KeyManagementException e) {
+ instantiationExceptionLocal = new IOException("Delayed instantiation exception:", e);
+ }
+ this.sslParameters = sslParametersLocal;
+ this.instantiationException = instantiationExceptionLocal;
+ }
+
+ OpenSSLSocketFactoryImpl(SSLParametersImpl sslParameters) {
+ this.sslParameters = sslParameters;
+ this.instantiationException = null;
+ }
+
+ /**
+ * Configures the default socket type to be created for the default and all new instances.
+ */
+ static void setUseEngineSocketByDefault(boolean useEngineSocket) {
+ useEngineSocketByDefault = useEngineSocket;
+ // The default SSLSocketFactory may already have been created, so also change its setting.
+ SocketFactory defaultFactory = SSLSocketFactory.getDefault();
+ if (defaultFactory instanceof OpenSSLSocketFactoryImpl) {
+ ((OpenSSLSocketFactoryImpl) defaultFactory).setUseEngineSocket(useEngineSocket);
+ }
+ }
+
+ /**
+ * Configures the socket to be created for this instance. If not called,
+ * {@link #useEngineSocketByDefault} will be used.
+ */
+ void setUseEngineSocket(boolean useEngineSocket) {
+ this.useEngineSocket = useEngineSocket;
+ }
+
+ @Override
+ public String[] getDefaultCipherSuites() {
+ return sslParameters.getEnabledCipherSuites();
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return NativeCrypto.getSupportedCipherSuites();
+ }
+
+ @Override
+ public Socket createSocket() throws IOException {
+ if (instantiationException != null) {
+ throw instantiationException;
+ }
+ if (useEngineSocket) {
+ return createEngineSocket((SSLParametersImpl) sslParameters.clone());
+ } else {
+ return createFileDescriptorSocket((SSLParametersImpl) sslParameters.clone());
+ }
+ }
+
+ @Override
+ public Socket createSocket(String hostname, int port) throws IOException, UnknownHostException {
+ if (useEngineSocket) {
+ return createEngineSocket(
+ hostname, port, (SSLParametersImpl) sslParameters.clone());
+ } else {
+ return createFileDescriptorSocket(
+ hostname, port, (SSLParametersImpl) sslParameters.clone());
+ }
+ }
+
+ @Override
+ public Socket createSocket(String hostname, int port, InetAddress localHost, int localPort)
+ throws IOException, UnknownHostException {
+ if (useEngineSocket) {
+ return createEngineSocket(hostname, port, localHost,
+ localPort, (SSLParametersImpl) sslParameters.clone());
+ } else {
+ return createFileDescriptorSocket(hostname, port, localHost,
+ localPort, (SSLParametersImpl) sslParameters.clone());
+ }
+ }
+
+ @Override
+ public Socket createSocket(InetAddress address, int port) throws IOException {
+ if (useEngineSocket) {
+ return createEngineSocket(
+ address, port, (SSLParametersImpl) sslParameters.clone());
+ } else {
+ return createFileDescriptorSocket(
+ address, port, (SSLParametersImpl) sslParameters.clone());
+ }
+ }
+
+ @Override
+ public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
+ int localPort) throws IOException {
+ if (useEngineSocket) {
+ return createEngineSocket(address, port, localAddress,
+ localPort, (SSLParametersImpl) sslParameters.clone());
+ } else {
+ return createFileDescriptorSocket(address, port, localAddress,
+ localPort, (SSLParametersImpl) sslParameters.clone());
+ }
+ }
+
+ @Override
+ public Socket createSocket(Socket socket, String hostname, int port, boolean autoClose)
+ throws IOException {
+ Preconditions.checkNotNull(socket, "socket");
+ if (!socket.isConnected()) {
+ throw new SocketException("Socket is not connected.");
+ }
+
+ if (!useEngineSocket && hasFileDescriptor(socket)) {
+ return createFileDescriptorSocket(
+ socket, hostname, port, autoClose, (SSLParametersImpl) sslParameters.clone());
+ } else {
+ return createEngineSocket(
+ socket, hostname, port, autoClose, (SSLParametersImpl) sslParameters.clone());
+ }
+ }
+
+ private boolean hasFileDescriptor(Socket s) {
+ try {
+ // If socket has a file descriptor we can use it directly
+ // otherwise we need to use the engine.
+ Platform.getFileDescriptor(s);
+ return true;
+ } catch (RuntimeException re) {
+ return false;
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSocketImpl.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSocketImpl.java
new file mode 100644
index 0000000..420d934
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSocketImpl.java
@@ -0,0 +1,199 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2007 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.security.PrivateKey;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+
+/**
+ * Public shim allowing us to stay backward-compatible with legacy applications which were using
+ * Conscrypt's extended socket API before the introduction of the {@link Conscrypt} class.
+ * @hide This class is not part of the Android public SDK API
+ */
+@libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+@Internal
+public abstract class OpenSSLSocketImpl extends AbstractConscryptSocket {
+ OpenSSLSocketImpl() throws IOException {
+ }
+
+ OpenSSLSocketImpl(String hostname, int port) throws IOException {
+ super(hostname, port);
+ }
+
+ OpenSSLSocketImpl(InetAddress address, int port) throws IOException {
+ super(address, port);
+ }
+
+ OpenSSLSocketImpl(String hostname, int port, InetAddress clientAddress, int clientPort)
+ throws IOException {
+ super(hostname, port, clientAddress, clientPort);
+ }
+
+ OpenSSLSocketImpl(InetAddress address, int port, InetAddress clientAddress,
+ int clientPort)
+ throws IOException {
+ super(address, port, clientAddress, clientPort);
+ }
+
+ OpenSSLSocketImpl(Socket socket, String hostname, int port, boolean autoClose)
+ throws IOException {
+ super(socket, hostname, port, autoClose);
+ }
+
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ @Override
+ public String getHostname() {
+ return super.getHostname();
+ }
+
+ @android.compat.annotation.
+ UnsupportedAppUsage(maxTargetSdk = dalvik.annotation.compat.VersionCodes.Q,
+ publicAlternatives = "Use {@code javax.net.ssl.SSLParameters#setServerNames}.")
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ @Override
+ public void
+ setHostname(String hostname) {
+ super.setHostname(hostname);
+ }
+
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ @Override
+ public String getHostnameOrIP() {
+ return super.getHostnameOrIP();
+ }
+
+ @Override
+ public FileDescriptor getFileDescriptor$() {
+ return super.getFileDescriptor$();
+ }
+
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ @Override
+ public void setSoWriteTimeout(int writeTimeoutMilliseconds) throws SocketException {
+ super.setSoWriteTimeout(writeTimeoutMilliseconds);
+ }
+
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ @Override
+ public int getSoWriteTimeout() throws SocketException {
+ return super.getSoWriteTimeout();
+ }
+
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ @Override
+ public void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketException {
+ super.setHandshakeTimeout(handshakeTimeoutMilliseconds);
+ }
+
+ @Override
+ public abstract SSLSession getHandshakeSession();
+
+ @android.compat.annotation.
+ UnsupportedAppUsage(maxTargetSdk = dalvik.annotation.compat.VersionCodes.Q,
+ publicAlternatives = "Use {@link android.net.ssl.SSLSockets#setUseSessionTickets}.")
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ @Override
+ public abstract void
+ setUseSessionTickets(boolean useSessionTickets);
+
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ @Override
+ public abstract void setChannelIdEnabled(boolean enabled);
+
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ @Override
+ public abstract byte[] getChannelId() throws SSLException;
+
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ @Override
+ public abstract void setChannelIdPrivateKey(PrivateKey privateKey);
+
+ /**
+ * @deprecated NPN is not supported
+ */
+ @android.compat.annotation.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ @Override
+ @Deprecated
+ public final byte[] getNpnSelectedProtocol() {
+ return super.getNpnSelectedProtocol();
+ }
+
+ /**
+ * @deprecated NPN is not supported
+ */
+ @android.compat.annotation.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ @Override
+ @Deprecated
+ public final void setNpnProtocols(byte[] npnProtocols) {
+ super.setNpnProtocols(npnProtocols);
+ }
+
+ /**
+ * @deprecated use {@link #setApplicationProtocols(String[])} instead.
+ */
+ @android.compat.annotation.
+ UnsupportedAppUsage(maxTargetSdk = dalvik.annotation.compat.VersionCodes.Q,
+ publicAlternatives =
+ "Use {@code javax.net.ssl.SSLParameters#setApplicationProtocols(java.lang.String[])}.")
+ @Override
+ @Deprecated
+ public final void
+ setAlpnProtocols(String[] alpnProtocols) {
+ setApplicationProtocols(alpnProtocols == null ? EmptyArray.STRING : alpnProtocols);
+ }
+
+ /**
+ * @deprecated use {@link #getApplicationProtocol()} instead.
+ */
+ @android.compat.annotation.
+ UnsupportedAppUsage(maxTargetSdk = dalvik.annotation.compat.VersionCodes.Q,
+ publicAlternatives = "Use {@code javax.net.ssl.SSLSocket#getApplicationProtocol()}.")
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ @Override
+ @Deprecated
+ public final byte[]
+ getAlpnSelectedProtocol() {
+ return SSLUtils.toProtocolBytes(getApplicationProtocol());
+ }
+
+ /**
+ * @deprecated Use {@link #setAlpnProtocols(String[])} instead.
+ */
+ @android.compat.annotation.
+ UnsupportedAppUsage(maxTargetSdk = dalvik.annotation.compat.VersionCodes.Q,
+ publicAlternatives =
+ "Use {@code javax.net.ssl.SSLParameters#setApplicationProtocols(java.lang.String[])}.")
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ @Override
+ @Deprecated
+ public final void
+ setAlpnProtocols(byte[] protocols) {
+ setApplicationProtocols(SSLUtils.decodeProtocols(protocols == null ? EmptyArray.BYTE : protocols));
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX25519Key.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX25519Key.java
new file mode 100644
index 0000000..00e7f91
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX25519Key.java
@@ -0,0 +1,11 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface OpenSSLX25519Key {
+ int X25519_KEY_SIZE_BYTES = 32;
+
+ byte[] getU();
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX25519PrivateKey.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX25519PrivateKey.java
new file mode 100644
index 0000000..08bda04
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX25519PrivateKey.java
@@ -0,0 +1,111 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt;
+
+import java.security.PrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class OpenSSLX25519PrivateKey implements OpenSSLX25519Key, PrivateKey {
+ private static final long serialVersionUID = -3136201500221850916L;
+ private static final byte[] PKCS8_PREAMBLE = new byte[]{
+ 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x04, 0x22, 0x04, 0x20,
+ };
+
+ private static final byte[] PKCS8_PREAMBLE_WITH_NULL = new byte[] {
+ 0x30, 0x30, 0x02, 0x01, 0x00, 0x30, 0x07, 0x06, 0x03, 0x2B, 0x65, 0x6E, 0x05, 0x00, 0x04, 0x22, 0x04, 0x20,
+ };
+
+ private byte[] uCoordinate;
+
+ public OpenSSLX25519PrivateKey(PKCS8EncodedKeySpec keySpec) throws InvalidKeySpecException {
+ byte[] encoded = keySpec.getEncoded();
+ if (encoded == null || !"PKCS#8".equals(keySpec.getFormat())) {
+ throw new InvalidKeySpecException("Key must be encoded in PKCS#8 format");
+ }
+
+ int preambleLength = matchesPreamble(PKCS8_PREAMBLE, encoded) | matchesPreamble(PKCS8_PREAMBLE_WITH_NULL, encoded);
+ if (preambleLength == 0) {
+ throw new InvalidKeySpecException("Key size is not correct size");
+ }
+
+ uCoordinate = Arrays.copyOfRange(encoded, PKCS8_PREAMBLE.length, encoded.length);
+ }
+
+ private static int matchesPreamble(byte[] preamble, byte[] encoded) {
+ if (encoded.length != (preamble.length + X25519_KEY_SIZE_BYTES)) {
+ return 0;
+ }
+ int cmp = 0;
+ for (int i = 0; i < preamble.length; i++) {
+ cmp |= encoded[i] ^ preamble[i];
+ }
+ if (cmp != 0) {
+ return 0;
+ }
+ return preamble.length;
+ }
+
+ public OpenSSLX25519PrivateKey(byte[] coordinateBytes) {
+ uCoordinate = coordinateBytes.clone();
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return "XDH";
+ }
+
+ @Override
+ public String getFormat() {
+ return "PKCS#8";
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ if (uCoordinate == null) {
+ throw new IllegalStateException("key is destroyed");
+ }
+
+ byte[] encoded = Arrays.copyOf(PKCS8_PREAMBLE, PKCS8_PREAMBLE.length + uCoordinate.length);
+ System.arraycopy(uCoordinate, 0, encoded, PKCS8_PREAMBLE.length, uCoordinate.length);
+ return encoded;
+ }
+
+ @Override
+ public byte[] getU() {
+ if (uCoordinate == null) {
+ throw new IllegalStateException("key is destroyed");
+ }
+
+ return uCoordinate.clone();
+ }
+
+ @Override
+ public void destroy() {
+ if (uCoordinate != null) {
+ Arrays.fill(uCoordinate, (byte) 0);
+ uCoordinate = null;
+ }
+ }
+
+ @Override
+ public boolean isDestroyed() {
+ return uCoordinate == null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof OpenSSLX25519PrivateKey)) return false;
+ OpenSSLX25519PrivateKey that = (OpenSSLX25519PrivateKey) o;
+ return Arrays.equals(uCoordinate, that.uCoordinate);
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(uCoordinate);
+ }
+}
\ No newline at end of file
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX25519PublicKey.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX25519PublicKey.java
new file mode 100644
index 0000000..b064ce7
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX25519PublicKey.java
@@ -0,0 +1,107 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt;
+
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class OpenSSLX25519PublicKey implements OpenSSLX25519Key, PublicKey {
+ private static final long serialVersionUID = 453861992373478445L;
+
+ private static final byte[] X509_PREAMBLE = new byte[] {
+ 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00,
+ };
+
+ private static final byte[] X509_PREAMBLE_WITH_NULL = new byte[] {
+ 0x30, 0x2C, 0x30, 0x07, 0x06, 0x03, 0x2B, 0x65, 0x6E, 0x05, 0x00, 0x03, 0x21, 0x00,
+ };
+
+ private final byte[] uCoordinate;
+
+ public OpenSSLX25519PublicKey(X509EncodedKeySpec keySpec) throws InvalidKeySpecException {
+ byte[] encoded = keySpec.getEncoded();
+ if (encoded == null || !"X.509".equals(keySpec.getFormat())) {
+ throw new InvalidKeySpecException("Encoding must be in X.509 format");
+ }
+
+ int preambleLength = matchesPreamble(X509_PREAMBLE, encoded) | matchesPreamble(X509_PREAMBLE_WITH_NULL, encoded);
+ if (preambleLength == 0) {
+ throw new InvalidKeySpecException("Key size is not correct size");
+ }
+
+ uCoordinate = Arrays.copyOfRange(encoded, preambleLength, encoded.length);
+ }
+
+ private static int matchesPreamble(byte[] preamble, byte[] encoded) {
+ if (encoded.length != (preamble.length + X25519_KEY_SIZE_BYTES)) {
+ return 0;
+ }
+ int cmp = 0;
+ for (int i = 0; i < preamble.length; i++) {
+ cmp |= encoded[i] ^ preamble[i];
+ }
+ if (cmp != 0) {
+ return 0;
+ }
+ return preamble.length;
+ }
+
+ public OpenSSLX25519PublicKey(byte[] coordinateBytes) {
+ uCoordinate = coordinateBytes.clone();
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return "XDH";
+ }
+
+ @Override
+ public String getFormat() {
+ return "X.509";
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ if (uCoordinate == null) {
+ throw new IllegalStateException("key is destroyed");
+ }
+
+ byte[] encoded = Arrays.copyOf(X509_PREAMBLE, X509_PREAMBLE.length + X25519_KEY_SIZE_BYTES);
+ System.arraycopy(uCoordinate, 0, encoded, X509_PREAMBLE.length, uCoordinate.length);
+ return encoded;
+ }
+
+ @Override
+ public byte[] getU() {
+ if (uCoordinate == null) {
+ throw new IllegalStateException("key is destroyed");
+ }
+
+ return uCoordinate.clone();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (uCoordinate == null) {
+ throw new IllegalStateException("key is destroyed");
+ }
+
+ if (this == o) return true;
+ if (!(o instanceof OpenSSLX25519PublicKey)) return false;
+ OpenSSLX25519PublicKey that = (OpenSSLX25519PublicKey) o;
+ return Arrays.equals(uCoordinate, that.uCoordinate);
+ }
+
+ @Override
+ public int hashCode() {
+ if (uCoordinate == null) {
+ throw new IllegalStateException("key is destroyed");
+ }
+
+ return Arrays.hashCode(uCoordinate);
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CRL.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CRL.java
new file mode 100644
index 0000000..f0fb680
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CRL.java
@@ -0,0 +1,426 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2013 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.
+ */
+
+package com.android.org.conscrypt;
+
+import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TimeZone;
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * An implementation of {@link X509CRL} based on BoringSSL.
+ */
+final class OpenSSLX509CRL extends X509CRL {
+ private final long mContext;
+ private final Date thisUpdate;
+ private final Date nextUpdate;
+
+ private OpenSSLX509CRL(long ctx) throws ParsingException {
+ mContext = ctx;
+ // The legacy X509 OpenSSL APIs don't validate ASN1_TIME structures until access, so
+ // parse them here because this is the only time we're allowed to throw ParsingException
+ thisUpdate = toDate(NativeCrypto.X509_CRL_get_lastUpdate(mContext, this));
+ nextUpdate = toDate(NativeCrypto.X509_CRL_get_nextUpdate(mContext, this));
+ }
+
+ // Package-visible because it's also used by OpenSSLX509CRLEntry
+ static Date toDate(long asn1time) throws ParsingException {
+ Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ calendar.set(Calendar.MILLISECOND, 0);
+ NativeCrypto.ASN1_TIME_to_Calendar(asn1time, calendar);
+ return calendar.getTime();
+ }
+
+ static OpenSSLX509CRL fromX509DerInputStream(InputStream is) throws ParsingException {
+ final OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is, true);
+
+ try {
+ final long crlCtx = NativeCrypto.d2i_X509_CRL_bio(bis.getBioContext());
+ if (crlCtx == 0) {
+ return null;
+ }
+ return new OpenSSLX509CRL(crlCtx);
+ } catch (Exception e) {
+ throw new ParsingException(e);
+ } finally {
+ bis.release();
+ }
+ }
+
+ static List<OpenSSLX509CRL> fromPkcs7DerInputStream(InputStream is)
+ throws ParsingException {
+ OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is, true);
+
+ final long[] certRefs;
+ try {
+ certRefs = NativeCrypto.d2i_PKCS7_bio(bis.getBioContext(), NativeCrypto.PKCS7_CRLS);
+ } catch (Exception e) {
+ throw new ParsingException(e);
+ } finally {
+ bis.release();
+ }
+
+ final List<OpenSSLX509CRL> certs = new ArrayList<>(certRefs.length);
+ for (long certRef : certRefs) {
+ if (certRef == 0) {
+ continue;
+ }
+ certs.add(new OpenSSLX509CRL(certRef));
+ }
+ return certs;
+ }
+
+ static OpenSSLX509CRL fromX509PemInputStream(InputStream is) throws ParsingException {
+ final OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is, true);
+
+ try {
+ final long crlCtx = NativeCrypto.PEM_read_bio_X509_CRL(bis.getBioContext());
+ if (crlCtx == 0) {
+ return null;
+ }
+ return new OpenSSLX509CRL(crlCtx);
+ } catch (Exception e) {
+ throw new ParsingException(e);
+ } finally {
+ bis.release();
+ }
+ }
+
+ static List<OpenSSLX509CRL> fromPkcs7PemInputStream(InputStream is)
+ throws ParsingException {
+ OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is, true);
+
+ final long[] certRefs;
+ try {
+ certRefs = NativeCrypto.PEM_read_bio_PKCS7(bis.getBioContext(),
+ NativeCrypto.PKCS7_CRLS);
+ } catch (Exception e) {
+ throw new ParsingException(e);
+ } finally {
+ bis.release();
+ }
+
+ final List<OpenSSLX509CRL> certs = new ArrayList<>(certRefs.length);
+ for (long certRef : certRefs) {
+ if (certRef == 0) {
+ continue;
+ }
+ certs.add(new OpenSSLX509CRL(certRef));
+ }
+ return certs;
+ }
+
+ @Override
+ public Set<String> getCriticalExtensionOIDs() {
+ String[] critOids =
+ NativeCrypto.get_X509_CRL_ext_oids(mContext, this, NativeCrypto.EXTENSION_TYPE_CRITICAL);
+
+ /*
+ * This API has a special case that if there are no extensions, we
+ * should return null. So if we have no critical extensions, we'll check
+ * non-critical extensions.
+ */
+ if ((critOids.length == 0)
+ && (NativeCrypto.get_X509_CRL_ext_oids(mContext, this,
+ NativeCrypto.EXTENSION_TYPE_NON_CRITICAL).length == 0)) {
+ return null;
+ }
+
+ return new HashSet<>(Arrays.asList(critOids));
+ }
+
+ @Override
+ public byte[] getExtensionValue(String oid) {
+ return NativeCrypto.X509_CRL_get_ext_oid(mContext, this, oid);
+ }
+
+ @Override
+ public Set<String> getNonCriticalExtensionOIDs() {
+ String[] nonCritOids =
+ NativeCrypto.get_X509_CRL_ext_oids(mContext, this,
+ NativeCrypto.EXTENSION_TYPE_NON_CRITICAL);
+
+ /*
+ * This API has a special case that if there are no extensions, we
+ * should return null. So if we have no non-critical extensions, we'll
+ * check critical extensions.
+ */
+ if ((nonCritOids.length == 0)
+ && (NativeCrypto.get_X509_CRL_ext_oids(mContext, this,
+ NativeCrypto.EXTENSION_TYPE_CRITICAL).length == 0)) {
+ return null;
+ }
+
+ return new HashSet<>(Arrays.asList(nonCritOids));
+ }
+
+ @Override
+ public boolean hasUnsupportedCriticalExtension() {
+ final String[] criticalOids =
+ NativeCrypto.get_X509_CRL_ext_oids(mContext, this, NativeCrypto.EXTENSION_TYPE_CRITICAL);
+ for (String oid : criticalOids) {
+ final long extensionRef = NativeCrypto.X509_CRL_get_ext(mContext, this, oid);
+ if (NativeCrypto.X509_supported_extension(extensionRef) != 1) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public byte[] getEncoded() throws CRLException {
+ return NativeCrypto.i2d_X509_CRL(mContext, this);
+ }
+
+ private void verifyOpenSSL(OpenSSLKey pkey)
+ throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ try {
+ NativeCrypto.X509_CRL_verify(mContext, this, pkey.getNativeRef());
+ } catch (BadPaddingException | IllegalBlockSizeException e) {
+ throw new SignatureException(e);
+ }
+ }
+
+ private void verifyInternal(PublicKey key, String sigProvider)
+ throws NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException,
+ SignatureException {
+ String sigAlg = getSigAlgName();
+ if (sigAlg == null) {
+ sigAlg = getSigAlgOID();
+ }
+
+ final Signature sig;
+ if (sigProvider == null) {
+ sig = Signature.getInstance(sigAlg);
+ } else {
+ sig = Signature.getInstance(sigAlg, sigProvider);
+ }
+
+ sig.initVerify(key);
+ sig.update(getTBSCertList());
+ if (!sig.verify(getSignature())) {
+ throw new SignatureException("signature did not verify");
+ }
+ }
+
+ @Override
+ public void verify(PublicKey key) throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException {
+ if (key instanceof OpenSSLKeyHolder) {
+ OpenSSLKey pkey = ((OpenSSLKeyHolder) key).getOpenSSLKey();
+ verifyOpenSSL(pkey);
+ return;
+ }
+
+ verifyInternal(key, null);
+ }
+
+ @Override
+ public void verify(PublicKey key, String sigProvider) throws CRLException,
+ NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException,
+ SignatureException {
+ verifyInternal(key, sigProvider);
+ }
+
+ @Override
+ public int getVersion() {
+ return (int) NativeCrypto.X509_CRL_get_version(mContext, this) + 1;
+ }
+
+ @Override
+ public Principal getIssuerDN() {
+ return getIssuerX500Principal();
+ }
+
+ @Override
+ public X500Principal getIssuerX500Principal() {
+ final byte[] issuer = NativeCrypto.X509_CRL_get_issuer_name(mContext, this);
+ return new X500Principal(issuer);
+ }
+
+ @Override
+ public Date getThisUpdate() {
+ return (Date) thisUpdate.clone();
+ }
+
+ @Override
+ public Date getNextUpdate() {
+ return (Date) nextUpdate.clone();
+ }
+
+ @Override
+ public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) {
+ final long revokedRef = NativeCrypto.X509_CRL_get0_by_serial(mContext, this,
+ serialNumber.toByteArray());
+ if (revokedRef == 0) {
+ return null;
+ }
+ try {
+ return new OpenSSLX509CRLEntry(NativeCrypto.X509_REVOKED_dup(revokedRef));
+ } catch (ParsingException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public X509CRLEntry getRevokedCertificate(X509Certificate certificate) {
+ if (certificate instanceof OpenSSLX509Certificate) {
+ OpenSSLX509Certificate osslCert = (OpenSSLX509Certificate) certificate;
+ final long x509RevokedRef = NativeCrypto.X509_CRL_get0_by_cert(mContext, this,
+ osslCert.getContext(), osslCert);
+
+ if (x509RevokedRef == 0) {
+ return null;
+ }
+
+ try {
+ return new OpenSSLX509CRLEntry(NativeCrypto.X509_REVOKED_dup(x509RevokedRef));
+ } catch (ParsingException e) {
+ return null;
+ }
+ }
+
+ return getRevokedCertificate(certificate.getSerialNumber());
+ }
+
+ @Override
+ public Set<? extends X509CRLEntry> getRevokedCertificates() {
+ final long[] entryRefs = NativeCrypto.X509_CRL_get_REVOKED(mContext, this);
+ if (entryRefs == null || entryRefs.length == 0) {
+ return null;
+ }
+
+ final Set<OpenSSLX509CRLEntry> crlSet = new HashSet<>();
+ for (long entryRef : entryRefs) {
+ try {
+ crlSet.add(new OpenSSLX509CRLEntry(entryRef));
+ } catch (ParsingException e) {
+ // Skip this entry
+ }
+ }
+
+ return crlSet;
+ }
+
+ @Override
+ public byte[] getTBSCertList() {
+ return NativeCrypto.get_X509_CRL_crl_enc(mContext, this);
+ }
+
+ @Override
+ public byte[] getSignature() {
+ return NativeCrypto.get_X509_CRL_signature(mContext, this);
+ }
+
+ @Override
+ public String getSigAlgName() {
+ String oid = getSigAlgOID();
+ String algName = OidData.oidToAlgorithmName(oid);
+ if (algName != null) {
+ return algName;
+ }
+ algName = Platform.oidToAlgorithmName(oid);
+ if (algName != null) {
+ return algName;
+ }
+ return oid;
+ }
+
+ @Override
+ public String getSigAlgOID() {
+ return NativeCrypto.get_X509_CRL_sig_alg_oid(mContext, this);
+ }
+
+ @Override
+ public byte[] getSigAlgParams() {
+ return NativeCrypto.get_X509_CRL_sig_alg_parameter(mContext, this);
+ }
+
+ @Override
+ public boolean isRevoked(Certificate cert) {
+ if (!(cert instanceof X509Certificate)) {
+ return false;
+ }
+
+ final OpenSSLX509Certificate osslCert;
+ if (cert instanceof OpenSSLX509Certificate) {
+ osslCert = (OpenSSLX509Certificate) cert;
+ } else {
+ try {
+ osslCert = OpenSSLX509Certificate.fromX509DerInputStream(new ByteArrayInputStream(
+ cert.getEncoded()));
+ } catch (Exception e) {
+ throw new RuntimeException("cannot convert certificate", e);
+ }
+ }
+
+ final long x509RevokedRef = NativeCrypto.X509_CRL_get0_by_cert(mContext, this,
+ osslCert.getContext(), osslCert);
+
+ return x509RevokedRef != 0;
+ }
+
+ @Override
+ public String toString() {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ final long bioCtx = NativeCrypto.create_BIO_OutputStream(os);
+ try {
+ NativeCrypto.X509_CRL_print(bioCtx, mContext, this);
+ return os.toString();
+ } finally {
+ NativeCrypto.BIO_free_all(bioCtx);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ protected void finalize() throws Throwable {
+ try {
+ if (mContext != 0) {
+ NativeCrypto.X509_CRL_free(mContext, this);
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CRLEntry.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CRLEntry.java
new file mode 100644
index 0000000..d8c5d9e
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CRLEntry.java
@@ -0,0 +1,138 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2013 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRLEntry;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+
+/**
+ * An implementation of {@link X509CRLEntry} based on BoringSSL.
+ */
+final class OpenSSLX509CRLEntry extends X509CRLEntry {
+ private final long mContext;
+ private final Date revocationDate;
+
+ OpenSSLX509CRLEntry(long ctx) throws ParsingException {
+ mContext = ctx;
+ // The legacy X509 OpenSSL APIs don't validate ASN1_TIME structures until access, so
+ // parse them here because this is the only time we're allowed to throw ParsingException
+ revocationDate = OpenSSLX509CRL.toDate(NativeCrypto.get_X509_REVOKED_revocationDate(mContext));
+ }
+
+ @Override
+ public Set<String> getCriticalExtensionOIDs() {
+ String[] critOids =
+ NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_CRITICAL);
+
+ /*
+ * This API has a special case that if there are no extensions, we
+ * should return null. So if we have no critical extensions, we'll check
+ * non-critical extensions.
+ */
+ if ((critOids.length == 0)
+ && (NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_NON_CRITICAL).length == 0)) {
+ return null;
+ }
+
+ return new HashSet<String>(Arrays.asList(critOids));
+ }
+
+ @Override
+ public byte[] getExtensionValue(String oid) {
+ return NativeCrypto.X509_REVOKED_get_ext_oid(mContext, oid);
+ }
+
+ @Override
+ public Set<String> getNonCriticalExtensionOIDs() {
+ String[] critOids =
+ NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_NON_CRITICAL);
+
+ /*
+ * This API has a special case that if there are no extensions, we
+ * should return null. So if we have no non-critical extensions, we'll
+ * check critical extensions.
+ */
+ if ((critOids.length == 0)
+ && (NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_CRITICAL).length == 0)) {
+ return null;
+ }
+
+ return new HashSet<String>(Arrays.asList(critOids));
+ }
+
+ @Override
+ public boolean hasUnsupportedCriticalExtension() {
+ final String[] criticalOids =
+ NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_CRITICAL);
+ for (String oid : criticalOids) {
+ final long extensionRef = NativeCrypto.X509_REVOKED_get_ext(mContext, oid);
+ if (NativeCrypto.X509_supported_extension(extensionRef) != 1) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public byte[] getEncoded() throws CRLException {
+ return NativeCrypto.i2d_X509_REVOKED(mContext);
+ }
+
+ @Override
+ public BigInteger getSerialNumber() {
+ return new BigInteger(NativeCrypto.X509_REVOKED_get_serialNumber(mContext));
+ }
+
+ @Override
+ public Date getRevocationDate() {
+ return (Date) revocationDate.clone();
+ }
+
+ @Override
+ public boolean hasExtensions() {
+ return (NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_NON_CRITICAL).length != 0)
+ || (NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_CRITICAL).length != 0);
+ }
+
+ @Override
+ public String toString() {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ long bioCtx = NativeCrypto.create_BIO_OutputStream(os);
+ try {
+ NativeCrypto.X509_REVOKED_print(bioCtx, mContext);
+ return os.toString();
+ } finally {
+ NativeCrypto.BIO_free_all(bioCtx);
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CertPath.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CertPath.java
new file mode 100644
index 0000000..eaa9f9a
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CertPath.java
@@ -0,0 +1,265 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2013 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+
+/**
+ * An implementation of {@link CertPath} based on BoringSSL.
+ */
+final class OpenSSLX509CertPath extends CertPath {
+ private static final long serialVersionUID = -3249106005255170761L;
+
+ private static final byte[] PKCS7_MARKER = new byte[] {
+ '-', '-', '-', '-', '-', 'B', 'E', 'G', 'I', 'N', ' ', 'P', 'K', 'C', 'S', '7'
+ };
+
+ private static final int PUSHBACK_SIZE = 64;
+
+ /**
+ * Supported encoding types for CerthPath. Used by the various APIs that
+ * encode this into bytes such as {@link #getEncoded()}.
+ */
+ private enum Encoding {
+ PKI_PATH("PkiPath"),
+ PKCS7("PKCS7");
+
+ private final String apiName;
+
+ Encoding(String apiName) {
+ this.apiName = apiName;
+ }
+
+ static Encoding findByApiName(String apiName) throws CertificateEncodingException {
+ for (Encoding element : values()) {
+ if (element.apiName.equals(apiName)) {
+ return element;
+ }
+ }
+
+ return null;
+ }
+ }
+
+ /** Unmodifiable list of encodings for the API. */
+ private static final List<String> ALL_ENCODINGS = Collections.unmodifiableList(Arrays
+ .asList(new String[] {
+ Encoding.PKI_PATH.apiName,
+ Encoding.PKCS7.apiName,
+ }));
+
+ private static final Encoding DEFAULT_ENCODING = Encoding.PKI_PATH;
+
+ private final List<? extends X509Certificate> mCertificates;
+
+ static Iterator<String> getEncodingsIterator() {
+ return ALL_ENCODINGS.iterator();
+ }
+
+ OpenSSLX509CertPath(List<? extends X509Certificate> certificates) {
+ super("X.509");
+
+ mCertificates = certificates;
+ }
+
+ @Override
+ public List<? extends Certificate> getCertificates() {
+ return Collections.unmodifiableList(mCertificates);
+ }
+
+ private byte[] getEncoded(Encoding encoding) throws CertificateEncodingException {
+ final OpenSSLX509Certificate[] certs = new OpenSSLX509Certificate[mCertificates.size()];
+ final long[] certRefs = new long[certs.length];
+
+ for (int i = 0, j = certs.length - 1; j >= 0; i++, j--) {
+ final X509Certificate cert = mCertificates.get(i);
+
+ if (cert instanceof OpenSSLX509Certificate) {
+ certs[j] = (OpenSSLX509Certificate) cert;
+ } else {
+ certs[j] = OpenSSLX509Certificate.fromX509Der(cert.getEncoded());
+ }
+
+ certRefs[j] = certs[j].getContext();
+ }
+
+ switch (encoding) {
+ case PKI_PATH:
+ return NativeCrypto.ASN1_seq_pack_X509(certRefs);
+ case PKCS7:
+ return NativeCrypto.i2d_PKCS7(certRefs);
+ default:
+ throw new CertificateEncodingException("Unknown encoding");
+ }
+ }
+
+ @Override
+ public byte[] getEncoded() throws CertificateEncodingException {
+ return getEncoded(DEFAULT_ENCODING);
+ }
+
+ @Override
+ public byte[] getEncoded(String encoding) throws CertificateEncodingException {
+ Encoding enc = Encoding.findByApiName(encoding);
+ if (enc == null) {
+ throw new CertificateEncodingException("Invalid encoding: " + encoding);
+ }
+
+ return getEncoded(enc);
+ }
+
+ @Override
+ public Iterator<String> getEncodings() {
+ return getEncodingsIterator();
+ }
+
+ private static CertPath fromPkiPathEncoding(InputStream inStream) throws CertificateException {
+ OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(inStream, true);
+
+ final boolean markable = inStream.markSupported();
+ if (markable) {
+ inStream.mark(PUSHBACK_SIZE);
+ }
+
+ final long[] certRefs;
+ try {
+ certRefs = NativeCrypto.ASN1_seq_unpack_X509_bio(bis.getBioContext());
+ } catch (Exception e) {
+ if (markable) {
+ try {
+ inStream.reset();
+ } catch (IOException ignored) {
+ // Ignored
+ }
+ }
+ throw new CertificateException(e);
+ } finally {
+ bis.release();
+ }
+
+ if (certRefs == null) {
+ return new OpenSSLX509CertPath(Collections.<X509Certificate> emptyList());
+ }
+
+ final List<OpenSSLX509Certificate> certs =
+ new ArrayList<OpenSSLX509Certificate>(certRefs.length);
+ for (int i = certRefs.length - 1; i >= 0; i--) {
+ if (certRefs[i] == 0) {
+ continue;
+ }
+ try {
+ certs.add(new OpenSSLX509Certificate(certRefs[i]));
+ } catch (ParsingException e) {
+ throw new CertificateParsingException(e);
+ }
+ }
+
+ return new OpenSSLX509CertPath(certs);
+ }
+
+ private static CertPath fromPkcs7Encoding(InputStream inStream) throws CertificateException {
+ try {
+ if (inStream == null || inStream.available() == 0) {
+ return new OpenSSLX509CertPath(Collections.<X509Certificate> emptyList());
+ }
+ } catch (IOException e) {
+ throw new CertificateException("Problem reading input stream", e);
+ }
+
+ final boolean markable = inStream.markSupported();
+ if (markable) {
+ inStream.mark(PUSHBACK_SIZE);
+ }
+
+ /* Attempt to see if this is a PKCS#7 bag. */
+ final PushbackInputStream pbis = new PushbackInputStream(inStream, PUSHBACK_SIZE);
+ try {
+ final byte[] buffer = new byte[PKCS7_MARKER.length];
+
+ final int len = pbis.read(buffer);
+ if (len < 0) {
+ /* No need to reset here. The stream was empty or EOF. */
+ throw new ParsingException("inStream is empty");
+ }
+ pbis.unread(buffer, 0, len);
+
+ if (len == PKCS7_MARKER.length && Arrays.equals(PKCS7_MARKER, buffer)) {
+ return new OpenSSLX509CertPath(OpenSSLX509Certificate.fromPkcs7PemInputStream(pbis));
+ }
+
+ return new OpenSSLX509CertPath(OpenSSLX509Certificate.fromPkcs7DerInputStream(pbis));
+ } catch (Exception e) {
+ if (markable) {
+ try {
+ inStream.reset();
+ } catch (IOException ignored) {
+ // Ignored
+ }
+ }
+ throw new CertificateException(e);
+ }
+ }
+
+ private static CertPath fromEncoding(InputStream inStream, Encoding encoding)
+ throws CertificateException {
+ switch (encoding) {
+ case PKI_PATH:
+ return fromPkiPathEncoding(inStream);
+ case PKCS7:
+ return fromPkcs7Encoding(inStream);
+ default:
+ throw new CertificateEncodingException("Unknown encoding");
+ }
+ }
+
+ static CertPath fromEncoding(InputStream inStream, String encoding)
+ throws CertificateException {
+ if (inStream == null) {
+ throw new CertificateException("inStream == null");
+ }
+
+ Encoding enc = Encoding.findByApiName(encoding);
+ if (enc == null) {
+ throw new CertificateException("Invalid encoding: " + encoding);
+ }
+
+ return fromEncoding(inStream, enc);
+ }
+
+ static CertPath fromEncoding(InputStream inStream) throws CertificateException {
+ if (inStream == null) {
+ throw new CertificateException("inStream == null");
+ }
+
+ return fromEncoding(inStream, DEFAULT_ENCODING);
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509Certificate.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509Certificate.java
new file mode 100644
index 0000000..6f664fc
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509Certificate.java
@@ -0,0 +1,588 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TimeZone;
+import javax.crypto.BadPaddingException;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * An implementation of {@link X509Certificate} based on BoringSSL.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class OpenSSLX509Certificate extends X509Certificate {
+ private static final long serialVersionUID = 1992239142393372128L;
+
+ @android.compat.annotation.UnsupportedAppUsage private transient final long mContext;
+ private transient Integer mHashCode;
+
+ private final Date notBefore;
+ private final Date notAfter;
+
+ OpenSSLX509Certificate(long ctx) throws ParsingException {
+ mContext = ctx;
+ // The legacy X509 OpenSSL APIs don't validate ASN1_TIME structures until access, so
+ // parse them here because this is the only time we're allowed to throw ParsingException
+ notBefore = toDate(NativeCrypto.X509_get_notBefore(mContext, this));
+ notAfter = toDate(NativeCrypto.X509_get_notAfter(mContext, this));
+ }
+
+ // A non-throwing constructor used when we have already parsed the dates
+ private OpenSSLX509Certificate(long ctx, Date notBefore, Date notAfter) {
+ mContext = ctx;
+ this.notBefore = notBefore;
+ this.notAfter = notAfter;
+ }
+
+ private static Date toDate(long asn1time) throws ParsingException {
+ Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ calendar.set(Calendar.MILLISECOND, 0);
+ NativeCrypto.ASN1_TIME_to_Calendar(asn1time, calendar);
+ return calendar.getTime();
+ }
+
+ public static OpenSSLX509Certificate fromX509DerInputStream(InputStream is)
+ throws ParsingException {
+ @SuppressWarnings("resource")
+ final OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is, true);
+
+ try {
+ final long certCtx = NativeCrypto.d2i_X509_bio(bis.getBioContext());
+ if (certCtx == 0) {
+ return null;
+ }
+ return new OpenSSLX509Certificate(certCtx);
+ } catch (Exception e) {
+ throw new ParsingException(e);
+ } finally {
+ bis.release();
+ }
+ }
+
+ public static OpenSSLX509Certificate fromX509Der(byte[] encoded)
+ throws CertificateEncodingException {
+ try {
+ return new OpenSSLX509Certificate(NativeCrypto.d2i_X509(encoded));
+ } catch (ParsingException e) {
+ throw new CertificateEncodingException(e);
+ }
+ }
+
+ public static List<OpenSSLX509Certificate> fromPkcs7DerInputStream(InputStream is)
+ throws ParsingException {
+ @SuppressWarnings("resource")
+ OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is, true);
+
+ final long[] certRefs;
+ try {
+ certRefs = NativeCrypto.d2i_PKCS7_bio(bis.getBioContext(), NativeCrypto.PKCS7_CERTS);
+ } catch (Exception e) {
+ throw new ParsingException(e);
+ } finally {
+ bis.release();
+ }
+
+ if (certRefs == null) {
+ // To avoid returning a immutable list in only one path, we create an
+ // empty list here instead of using Collections.emptyList()
+ return new ArrayList<>();
+ }
+
+ final List<OpenSSLX509Certificate> certs = new ArrayList<>(certRefs.length);
+ for (long certRef : certRefs) {
+ if (certRef == 0) {
+ continue;
+ }
+ certs.add(new OpenSSLX509Certificate(certRef));
+ }
+ return certs;
+ }
+
+ @android.compat.annotation.UnsupportedAppUsage
+ public static OpenSSLX509Certificate fromX509PemInputStream(InputStream is)
+ throws ParsingException {
+ @SuppressWarnings("resource")
+ final OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is, true);
+
+ try {
+ final long certCtx = NativeCrypto.PEM_read_bio_X509(bis.getBioContext());
+ if (certCtx == 0L) {
+ return null;
+ }
+ return new OpenSSLX509Certificate(certCtx);
+ } catch (Exception e) {
+ throw new ParsingException(e);
+ } finally {
+ bis.release();
+ }
+ }
+
+ public static List<OpenSSLX509Certificate> fromPkcs7PemInputStream(InputStream is)
+ throws ParsingException {
+ @SuppressWarnings("resource")
+ OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is, true);
+
+ final long[] certRefs;
+ try {
+ certRefs = NativeCrypto.PEM_read_bio_PKCS7(bis.getBioContext(),
+ NativeCrypto.PKCS7_CERTS);
+ } catch (Exception e) {
+ throw new ParsingException(e);
+ } finally {
+ bis.release();
+ }
+
+ final List<OpenSSLX509Certificate> certs = new ArrayList<>(certRefs.length);
+ for (long certRef : certRefs) {
+ if (certRef == 0) {
+ continue;
+ }
+ certs.add(new OpenSSLX509Certificate(certRef));
+ }
+ return certs;
+ }
+
+ public static OpenSSLX509Certificate fromCertificate(Certificate cert)
+ throws CertificateEncodingException {
+ if (cert instanceof OpenSSLX509Certificate) {
+ return (OpenSSLX509Certificate) cert;
+ } else if (cert instanceof X509Certificate) {
+ return fromX509Der(cert.getEncoded());
+ } else {
+ throw new CertificateEncodingException("Only X.509 certificates are supported");
+ }
+ }
+
+ @Override
+ public Set<String> getCriticalExtensionOIDs() {
+ String[] critOids =
+ NativeCrypto.get_X509_ext_oids(mContext, this, NativeCrypto.EXTENSION_TYPE_CRITICAL);
+
+ /*
+ * This API has a special case that if there are no extensions, we
+ * should return null. So if we have no critical extensions, we'll check
+ * non-critical extensions.
+ */
+ if ((critOids.length == 0)
+ && (NativeCrypto.get_X509_ext_oids(mContext, this,
+ NativeCrypto.EXTENSION_TYPE_NON_CRITICAL).length == 0)) {
+ return null;
+ }
+
+ return new HashSet<>(Arrays.asList(critOids));
+ }
+
+ @Override
+ public byte[] getExtensionValue(String oid) {
+ return NativeCrypto.X509_get_ext_oid(mContext, this, oid);
+ }
+
+ @Override
+ public Set<String> getNonCriticalExtensionOIDs() {
+ String[] nonCritOids =
+ NativeCrypto.get_X509_ext_oids(mContext, this, NativeCrypto.EXTENSION_TYPE_NON_CRITICAL);
+
+ /*
+ * This API has a special case that if there are no extensions, we
+ * should return null. So if we have no non-critical extensions, we'll
+ * check critical extensions.
+ */
+ if ((nonCritOids.length == 0)
+ && (NativeCrypto.get_X509_ext_oids(mContext, this,
+ NativeCrypto.EXTENSION_TYPE_CRITICAL).length == 0)) {
+ return null;
+ }
+
+ return new HashSet<>(Arrays.asList(nonCritOids));
+ }
+
+ @Override
+ public boolean hasUnsupportedCriticalExtension() {
+ return (NativeCrypto.get_X509_ex_flags(mContext, this) & NativeConstants.EXFLAG_CRITICAL) != 0;
+ }
+
+ @Override
+ @SuppressWarnings("JdkObsolete") // Needed for API compatibility
+ public void checkValidity()
+ throws CertificateExpiredException, CertificateNotYetValidException {
+ checkValidity(new Date());
+ }
+
+ @Override
+ @SuppressWarnings("JdkObsolete") // Needed for API compatibility
+ public void checkValidity(Date date)
+ throws CertificateExpiredException, CertificateNotYetValidException {
+ if (getNotBefore().compareTo(date) > 0) {
+ throw new CertificateNotYetValidException("Certificate not valid until "
+ + getNotBefore().toString() + " (compared to " + date.toString() + ")");
+ }
+
+ if (getNotAfter().compareTo(date) < 0) {
+ throw new CertificateExpiredException("Certificate expired at "
+ + getNotAfter().toString() + " (compared to " + date.toString() + ")");
+ }
+ }
+
+ @Override
+ public int getVersion() {
+ return (int) NativeCrypto.X509_get_version(mContext, this) + 1;
+ }
+
+ @Override
+ public BigInteger getSerialNumber() {
+ return new BigInteger(NativeCrypto.X509_get_serialNumber(mContext, this));
+ }
+
+ @Override
+ public Principal getIssuerDN() {
+ return getIssuerX500Principal();
+ }
+
+ @Override
+ public Principal getSubjectDN() {
+ return getSubjectX500Principal();
+ }
+
+ @Override
+ public Date getNotBefore() {
+ return (Date) notBefore.clone();
+ }
+
+ @Override
+ public Date getNotAfter() {
+ return (Date) notAfter.clone();
+ }
+
+ @Override
+ public byte[] getTBSCertificate() throws CertificateEncodingException {
+ return NativeCrypto.get_X509_tbs_cert(mContext, this);
+ }
+
+ @Override
+ public byte[] getSignature() {
+ return NativeCrypto.get_X509_signature(mContext, this);
+ }
+
+ @Override
+ public String getSigAlgName() {
+ String oid = getSigAlgOID();
+ String algName = OidData.oidToAlgorithmName(oid);
+ if (algName != null) {
+ return algName;
+ }
+ algName = Platform.oidToAlgorithmName(oid);
+ if (algName != null) {
+ return algName;
+ }
+ return oid;
+ }
+
+ @Override
+ public String getSigAlgOID() {
+ return NativeCrypto.get_X509_sig_alg_oid(mContext, this);
+ }
+
+ @Override
+ public byte[] getSigAlgParams() {
+ return NativeCrypto.get_X509_sig_alg_parameter(mContext, this);
+ }
+
+ @Override
+ public boolean[] getIssuerUniqueID() {
+ return NativeCrypto.get_X509_issuerUID(mContext, this);
+ }
+
+ @Override
+ public boolean[] getSubjectUniqueID() {
+ return NativeCrypto.get_X509_subjectUID(mContext, this);
+ }
+
+ @Override
+ public boolean[] getKeyUsage() {
+ final boolean[] kusage = NativeCrypto.get_X509_ex_kusage(mContext, this);
+ if (kusage == null) {
+ return null;
+ }
+
+ if (kusage.length >= 9) {
+ return kusage;
+ }
+
+ final boolean[] resized = new boolean[9];
+ System.arraycopy(kusage, 0, resized, 0, kusage.length);
+ return resized;
+ }
+
+ @Override
+ public int getBasicConstraints() {
+ if ((NativeCrypto.get_X509_ex_flags(mContext, this) & NativeConstants.EXFLAG_CA) == 0) {
+ return -1;
+ }
+
+ final int pathLen = NativeCrypto.get_X509_ex_pathlen(mContext, this);
+ if (pathLen == -1) {
+ return Integer.MAX_VALUE;
+ }
+
+ return pathLen;
+ }
+
+ @Override
+ public byte[] getEncoded() throws CertificateEncodingException {
+ return NativeCrypto.i2d_X509(mContext, this);
+ }
+
+ private void verifyOpenSSL(OpenSSLKey pkey) throws CertificateException, SignatureException {
+ try {
+ NativeCrypto.X509_verify(mContext, this, pkey.getNativeRef());
+ } catch (RuntimeException e) {
+ throw new CertificateException(e);
+ } catch (BadPaddingException e) {
+ throw new SignatureException();
+ }
+ }
+
+ private void verifyInternal(PublicKey key, String sigProvider)
+ throws NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException,
+ SignatureException, CertificateEncodingException {
+ final Signature sig;
+ if (sigProvider == null) {
+ sig = Signature.getInstance(getSigAlgName());
+ } else {
+ sig = Signature.getInstance(getSigAlgName(), sigProvider);
+ }
+
+ sig.initVerify(key);
+ sig.update(getTBSCertificate());
+ if (!sig.verify(getSignature())) {
+ throw new SignatureException("signature did not verify");
+ }
+ }
+
+ @Override
+ public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException {
+ if (key instanceof OpenSSLKeyHolder) {
+ OpenSSLKey pkey = ((OpenSSLKeyHolder) key).getOpenSSLKey();
+ verifyOpenSSL(pkey);
+ return;
+ }
+
+ verifyInternal(key, null);
+ }
+
+ @Override
+ public void verify(PublicKey key, String sigProvider) throws CertificateException,
+ NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException,
+ SignatureException {
+ verifyInternal(key, sigProvider);
+ }
+
+ /* @Override */
+ @SuppressWarnings("MissingOverride") // For compilation with Java 7.
+ // noinspection Override
+ public void verify(PublicKey key, Provider sigProvider)
+ throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
+ SignatureException {
+ if (key instanceof OpenSSLKeyHolder && sigProvider instanceof OpenSSLProvider) {
+ OpenSSLKey pkey = ((OpenSSLKeyHolder) key).getOpenSSLKey();
+ verifyOpenSSL(pkey);
+ return;
+ }
+
+ final Signature sig;
+ if (sigProvider == null) {
+ sig = Signature.getInstance(getSigAlgName());
+ } else {
+ sig = Signature.getInstance(getSigAlgName(), sigProvider);
+ }
+
+ sig.initVerify(key);
+ sig.update(getTBSCertificate());
+ if (!sig.verify(getSignature())) {
+ throw new SignatureException("signature did not verify");
+ }
+ }
+
+ @Override
+ public String toString() {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ long bioCtx = NativeCrypto.create_BIO_OutputStream(os);
+ try {
+ NativeCrypto.X509_print_ex(bioCtx, mContext, this, 0, 0);
+ return os.toString();
+ } finally {
+ NativeCrypto.BIO_free_all(bioCtx);
+ }
+ }
+
+ @Override
+ public PublicKey getPublicKey() {
+ /* First try to generate the key from supported OpenSSL key types. */
+ try {
+ OpenSSLKey pkey = new OpenSSLKey(NativeCrypto.X509_get_pubkey(mContext, this));
+ return pkey.getPublicKey();
+ } catch (NoSuchAlgorithmException | InvalidKeyException ignored) {
+ // Ignored
+ }
+
+ /* Try generating the key using other Java providers. */
+ String oid = NativeCrypto.get_X509_pubkey_oid(mContext, this);
+ byte[] encoded = NativeCrypto.i2d_X509_PUBKEY(mContext, this);
+ try {
+ KeyFactory kf = KeyFactory.getInstance(oid);
+ return kf.generatePublic(new X509EncodedKeySpec(encoded));
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException ignored) {
+ // Ignored
+ }
+
+ /*
+ * We couldn't find anything else, so just return a nearly-unusable
+ * X.509-encoded key.
+ */
+ return new X509PublicKey(oid, encoded);
+ }
+
+ @Override
+ public X500Principal getIssuerX500Principal() {
+ final byte[] issuer = NativeCrypto.X509_get_issuer_name(mContext, this);
+ return new X500Principal(issuer);
+ }
+
+ @Override
+ public X500Principal getSubjectX500Principal() {
+ final byte[] subject = NativeCrypto.X509_get_subject_name(mContext, this);
+ return new X500Principal(subject);
+ }
+
+ @Override
+ public List<String> getExtendedKeyUsage() {
+ String[] extUsage = NativeCrypto.get_X509_ex_xkusage(mContext, this);
+ if (extUsage == null) {
+ return null;
+ }
+
+ return Arrays.asList(extUsage);
+ }
+
+ private static Collection<List<?>> alternativeNameArrayToList(Object[][] altNameArray) {
+ if (altNameArray == null) {
+ return null;
+ }
+
+ Collection<List<?>> coll = new ArrayList<>(altNameArray.length);
+ for (Object[] objects : altNameArray) {
+ coll.add(Collections.unmodifiableList(Arrays.asList(objects)));
+ }
+
+ return Collections.unmodifiableCollection(coll);
+ }
+
+ @Override
+ public Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException {
+ return alternativeNameArrayToList(NativeCrypto.get_X509_GENERAL_NAME_stack(mContext, this,
+ NativeCrypto.GN_STACK_SUBJECT_ALT_NAME));
+ }
+
+ @Override
+ public Collection<List<?>> getIssuerAlternativeNames() throws CertificateParsingException {
+ return alternativeNameArrayToList(NativeCrypto.get_X509_GENERAL_NAME_stack(mContext, this,
+ NativeCrypto.GN_STACK_ISSUER_ALT_NAME));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof OpenSSLX509Certificate) {
+ OpenSSLX509Certificate o = (OpenSSLX509Certificate) other;
+
+ return NativeCrypto.X509_cmp(mContext, this, o.mContext, o) == 0;
+ }
+
+ return super.equals(other);
+ }
+
+ @Override
+ public int hashCode() {
+ if (mHashCode != null) {
+ return mHashCode;
+ }
+ mHashCode = super.hashCode();
+ return mHashCode;
+ }
+
+ /**
+ * Returns the raw pointer to the X509 context for use in JNI calls. The
+ * life cycle of this native pointer is managed by the
+ * {@code OpenSSLX509Certificate} instance and must not be destroyed or
+ * freed by users of this API.
+ */
+ public long getContext() {
+ return mContext;
+ }
+
+ /**
+ * Returns a re-encoded TBSCertificate with the extension identified by oid removed.
+ */
+ public byte[] getTBSCertificateWithoutExtension(String oid) {
+ return NativeCrypto.get_X509_tbs_cert_without_ext(mContext, this, oid);
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ protected void finalize() throws Throwable {
+ try {
+ if (mContext != 0) {
+ NativeCrypto.X509_free(mContext, this);
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CertificateFactory.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CertificateFactory.java
new file mode 100644
index 0000000..1907738
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CertificateFactory.java
@@ -0,0 +1,371 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactorySpi;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * An implementation of {@link java.security.cert.CertificateFactory} based on BoringSSL.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class OpenSSLX509CertificateFactory extends CertificateFactorySpi {
+ private static final byte[] PKCS7_MARKER = new byte[] {
+ '-', '-', '-', '-', '-', 'B', 'E', 'G', 'I', 'N', ' ', 'P', 'K', 'C', 'S', '7'
+ };
+
+ private static final int PUSHBACK_SIZE = 64;
+
+ static class ParsingException extends Exception {
+ private static final long serialVersionUID = 8390802697728301325L;
+
+ ParsingException(String message) {
+ super(message);
+ }
+
+ ParsingException(Exception cause) {
+ super(cause);
+ }
+
+ ParsingException(String message, Exception cause) {
+ super(message, cause);
+ }
+ }
+
+ private static boolean isMaybePkcs7(byte[] header) {
+ // The outer tag must be SEQUENCE.
+ if (header.length < 2 || header[0] != 0x30) {
+ return false;
+ }
+
+ // Bytes are signed in Java.
+ int lengthByte = header[1] & 0xff;
+
+ // Skip the length prefix to find the tag of the first child of SEQUENCE. This function is
+ // intentionally lax and does not attempt to parse the length itself. It is only necessary
+ // to return true on PKCS#7 inputs and false on X.509 inputs. Other structures can go either
+ // way.
+ int idx = 2;
+ if (lengthByte <= 0x80) {
+ // Short-form or indefinite length.
+ } else if (lengthByte == 0x81) {
+ idx += 1;
+ } else if (lengthByte == 0x82) {
+ idx += 2;
+ } else if (lengthByte == 0x83) {
+ idx += 3;
+ } else if (lengthByte == 0x84) {
+ idx += 4;
+ } else {
+ // BoringSSL stops at 4-byte lengths. A 5-byte length would require a 4GiB input.
+ return false;
+ }
+
+ // The first element of a PKCS#7 structure is OBJECT IDENTIFIER, which has tag 6. The first
+ // element of an X.509 structure is never OBJECT IDENTIFIER.
+ return idx < header.length && header[idx] == 0x06;
+ }
+
+ /**
+ * The code for X509 Certificates and CRL is pretty much the same. We use
+ * this abstract class to share the code between them. This makes it ugly,
+ * but it's already written in this language anyway.
+ */
+ private static abstract class Parser<T> {
+ T generateItem(InputStream inStream) throws ParsingException {
+ if (inStream == null) {
+ throw new ParsingException("inStream == null");
+ }
+
+ final boolean markable = inStream.markSupported();
+ if (markable) {
+ inStream.mark(PKCS7_MARKER.length);
+ }
+
+ final PushbackInputStream pbis = new PushbackInputStream(inStream, PUSHBACK_SIZE);
+ try {
+ final byte[] buffer = new byte[PKCS7_MARKER.length];
+
+ final int len = pbis.read(buffer);
+ if (len < 0) {
+ /* No need to reset here. The stream was empty or EOF. */
+ throw new ParsingException("inStream is empty");
+ }
+ pbis.unread(buffer, 0, len);
+
+ if (buffer[0] == '-') {
+ return fromX509PemInputStream(pbis);
+ }
+
+ if (isMaybePkcs7(buffer)) {
+ List<? extends T> certs = fromPkcs7DerInputStream(pbis);
+ if (certs.size() == 0) {
+ return null;
+ }
+ return certs.get(0);
+ } else {
+ return fromX509DerInputStream(pbis);
+ }
+ } catch (Exception e) {
+ if (markable) {
+ try {
+ inStream.reset();
+ } catch (IOException ignored) {
+ // If resetting the stream fails, there's not much we can do
+ }
+ }
+ throw new ParsingException(e);
+ }
+ }
+
+ Collection<? extends T> generateItems(InputStream inStream)
+ throws ParsingException {
+ if (inStream == null) {
+ throw new ParsingException("inStream == null");
+ }
+
+ final boolean markable = inStream.markSupported();
+ if (markable) {
+ inStream.mark(PUSHBACK_SIZE);
+ }
+
+ /* Attempt to see if this is a PKCS#7 bag. */
+ final PushbackInputStream pbis = new PushbackInputStream(inStream, PUSHBACK_SIZE);
+ try {
+ final byte[] buffer = new byte[PKCS7_MARKER.length];
+
+ final int len = pbis.read(buffer);
+ if (len < 0) {
+ // No need to reset here. The stream was empty or EOF so we return an empty
+ // list, making it mutable for consistency with the other code paths.
+ return new ArrayList<>();
+ }
+ pbis.unread(buffer, 0, len);
+
+ if (len == PKCS7_MARKER.length && Arrays.equals(PKCS7_MARKER, buffer)) {
+ return fromPkcs7PemInputStream(pbis);
+ }
+
+ if (isMaybePkcs7(buffer)) {
+ return fromPkcs7DerInputStream(pbis);
+ }
+ } catch (Exception e) {
+ if (markable) {
+ try {
+ inStream.reset();
+ } catch (IOException ignored) {
+ // If resetting the stream fails, there's not much we can do
+ }
+ }
+ throw new ParsingException(e);
+ }
+
+ /*
+ * It wasn't, so just try to keep grabbing certificates until we
+ * can't anymore.
+ */
+ final List<T> coll = new ArrayList<T>();
+ T c;
+ do {
+ /*
+ * If this stream supports marking, try to mark here in case
+ * there is an error during certificate generation.
+ */
+ if (markable) {
+ inStream.mark(PUSHBACK_SIZE);
+ }
+
+ try {
+ c = generateItem(pbis);
+ coll.add(c);
+ } catch (ParsingException e) {
+ /*
+ * If this stream supports marking, attempt to reset it to
+ * the mark before the failure.
+ */
+ if (markable) {
+ try {
+ inStream.reset();
+ } catch (IOException ignored) {
+ // If resetting the stream fails, there's not much we can do
+ }
+ }
+
+ c = null;
+ }
+ } while (c != null);
+
+ return coll;
+ }
+
+ protected abstract T fromX509PemInputStream(InputStream pbis) throws ParsingException;
+
+ protected abstract T fromX509DerInputStream(InputStream pbis) throws ParsingException;
+
+ protected abstract List<? extends T> fromPkcs7PemInputStream(InputStream is)
+ throws ParsingException;
+
+ protected abstract List<? extends T> fromPkcs7DerInputStream(InputStream is)
+ throws ParsingException;
+ }
+
+ private Parser<OpenSSLX509Certificate> certificateParser =
+ new Parser<OpenSSLX509Certificate>() {
+ @Override
+ public OpenSSLX509Certificate fromX509PemInputStream(InputStream is)
+ throws ParsingException {
+ return OpenSSLX509Certificate.fromX509PemInputStream(is);
+ }
+
+ @Override
+ public OpenSSLX509Certificate fromX509DerInputStream(InputStream is)
+ throws ParsingException {
+ return OpenSSLX509Certificate.fromX509DerInputStream(is);
+ }
+
+ @Override
+ public List<? extends OpenSSLX509Certificate>
+ fromPkcs7PemInputStream(InputStream is) throws ParsingException {
+ return OpenSSLX509Certificate.fromPkcs7PemInputStream(is);
+ }
+
+ @Override
+ public List<? extends OpenSSLX509Certificate>
+ fromPkcs7DerInputStream(InputStream is) throws ParsingException {
+ return OpenSSLX509Certificate.fromPkcs7DerInputStream(is);
+ }
+ };
+
+ private Parser<OpenSSLX509CRL> crlParser =
+ new Parser<OpenSSLX509CRL>() {
+ @Override
+ public OpenSSLX509CRL fromX509PemInputStream(InputStream is)
+ throws ParsingException {
+ return OpenSSLX509CRL.fromX509PemInputStream(is);
+ }
+
+ @Override
+ public OpenSSLX509CRL fromX509DerInputStream(InputStream is)
+ throws ParsingException {
+ return OpenSSLX509CRL.fromX509DerInputStream(is);
+ }
+
+ @Override
+ public List<? extends OpenSSLX509CRL> fromPkcs7PemInputStream(InputStream is)
+ throws ParsingException {
+ return OpenSSLX509CRL.fromPkcs7PemInputStream(is);
+ }
+
+ @Override
+ public List<? extends OpenSSLX509CRL> fromPkcs7DerInputStream(InputStream is)
+ throws ParsingException {
+ return OpenSSLX509CRL.fromPkcs7DerInputStream(is);
+ }
+ };
+
+ public OpenSSLX509CertificateFactory() {}
+
+ @Override
+ public Certificate engineGenerateCertificate(InputStream inStream) throws CertificateException {
+ try {
+ return certificateParser.generateItem(inStream);
+ } catch (ParsingException e) {
+ throw new CertificateException(e);
+ }
+ }
+
+ @Override
+ public Collection<? extends Certificate> engineGenerateCertificates(
+ InputStream inStream) throws CertificateException {
+ try {
+ return certificateParser.generateItems(inStream);
+ } catch (ParsingException e) {
+ throw new CertificateException(e);
+ }
+ }
+
+ @Override
+ public CRL engineGenerateCRL(InputStream inStream) throws CRLException {
+ try {
+ return crlParser.generateItem(inStream);
+ } catch (ParsingException e) {
+ throw new CRLException(e);
+ }
+ }
+
+ @Override
+ public Collection<? extends CRL> engineGenerateCRLs(InputStream inStream) throws CRLException {
+ if (inStream == null) {
+ return Collections.emptyList();
+ }
+
+ try {
+ return crlParser.generateItems(inStream);
+ } catch (ParsingException e) {
+ throw new CRLException(e);
+ }
+ }
+
+ @Override
+ public Iterator<String> engineGetCertPathEncodings() {
+ return OpenSSLX509CertPath.getEncodingsIterator();
+ }
+
+ @Override
+ public CertPath engineGenerateCertPath(InputStream inStream) throws CertificateException {
+ return OpenSSLX509CertPath.fromEncoding(inStream);
+ }
+
+ @Override
+ public CertPath engineGenerateCertPath(InputStream inStream, String encoding)
+ throws CertificateException {
+ return OpenSSLX509CertPath.fromEncoding(inStream, encoding);
+ }
+
+ @Override
+ public CertPath engineGenerateCertPath(List<? extends Certificate> certificates)
+ throws CertificateException {
+ final List<X509Certificate> filtered = new ArrayList<X509Certificate>(certificates.size());
+ for (int i = 0; i < certificates.size(); i++) {
+ final Certificate c = certificates.get(i);
+
+ if (!(c instanceof X509Certificate)) {
+ throw new CertificateException("Certificate not X.509 type at index " + i);
+ }
+
+ filtered.add((X509Certificate) c);
+ }
+
+ return new OpenSSLX509CertPath(filtered);
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLXDHKeyAgreement.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLXDHKeyAgreement.java
new file mode 100644
index 0000000..0ee62dd
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLXDHKeyAgreement.java
@@ -0,0 +1,68 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2013 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * Elliptic Curve Diffie-Hellman key agreement backed by the OpenSSL engine.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class OpenSSLXDHKeyAgreement extends OpenSSLBaseDHKeyAgreement<byte[]> {
+ public OpenSSLXDHKeyAgreement() {
+ }
+
+ @Override
+ protected byte[] convertPublicKey(PublicKey key) throws InvalidKeyException {
+ if (!(key instanceof OpenSSLX25519PublicKey)) {
+ throw new InvalidKeyException("Only OpenSSLX25519PublicKey accepted");
+ }
+
+ return ((OpenSSLX25519PublicKey) key).getU();
+ }
+
+ @Override
+ protected byte[] convertPrivateKey(PrivateKey key) throws InvalidKeyException {
+ if (!(key instanceof OpenSSLX25519PrivateKey)) {
+ throw new InvalidKeyException("Only OpenSSLX25519PublicKey accepted");
+ }
+
+ return ((OpenSSLX25519PrivateKey) key).getU();
+ }
+
+ @Override
+ protected int computeKey(byte[] buffer, byte[] theirPublicKey, byte[] ourPrivateKey) throws InvalidKeyException {
+ if (!NativeCrypto.X25519(
+ buffer,
+ ourPrivateKey,
+ theirPublicKey)) {
+ throw new InvalidKeyException("Error running X25519");
+ }
+
+ return OpenSSLX25519Key.X25519_KEY_SIZE_BYTES;
+ }
+
+ @Override
+ protected int getOutputSize(byte[] key) {
+ // We only support X25519 which is 32-byte (256-bit)
+ return OpenSSLX25519Key.X25519_KEY_SIZE_BYTES;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLXDHKeyFactory.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLXDHKeyFactory.java
new file mode 100644
index 0000000..e8a815f
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLXDHKeyFactory.java
@@ -0,0 +1,217 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2013 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+/**
+ * An implementation of a {@link KeyFactorySpi} for EC keys based on BoringSSL.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class OpenSSLXDHKeyFactory extends KeyFactorySpi {
+
+ public OpenSSLXDHKeyFactory() {}
+
+ @Override
+ protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException {
+ if (keySpec == null) {
+ throw new InvalidKeySpecException("keySpec == null");
+ }
+
+ if (keySpec instanceof X509EncodedKeySpec) {
+ return new OpenSSLX25519PublicKey((X509EncodedKeySpec) keySpec);
+ }
+ throw new InvalidKeySpecException("Must use ECPublicKeySpec or X509EncodedKeySpec; was "
+ + keySpec.getClass().getName());
+ }
+
+ @Override
+ protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException {
+ if (keySpec == null) {
+ throw new InvalidKeySpecException("keySpec == null");
+ }
+
+ if (keySpec instanceof PKCS8EncodedKeySpec) {
+ return new OpenSSLX25519PrivateKey((PKCS8EncodedKeySpec) keySpec);
+ }
+ throw new InvalidKeySpecException("Must use ECPrivateKeySpec or PKCS8EncodedKeySpec; was "
+ + keySpec.getClass().getName());
+ }
+
+ @Override
+ protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
+ throws InvalidKeySpecException {
+ if (key == null) {
+ throw new InvalidKeySpecException("key == null");
+ }
+
+ if (keySpec == null) {
+ throw new InvalidKeySpecException("keySpec == null");
+ }
+
+ if (!"XDH".equals(key.getAlgorithm())) {
+ throw new InvalidKeySpecException("Key must be an XDH key");
+ }
+
+ Class<?> publicKeySpec = getJavaPublicKeySpec();
+ Class<?> privateKeySpec = getJavaPrivateKeySpec();
+
+ if (publicKeySpec != null && key instanceof PublicKey && publicKeySpec.isAssignableFrom(keySpec)) {
+ final byte[] encoded = key.getEncoded();
+ if (!"X.509".equals(key.getFormat()) || encoded == null) {
+ throw new InvalidKeySpecException("Not a valid X.509 encoding");
+ }
+ OpenSSLX25519PublicKey publicKey = (OpenSSLX25519PublicKey) engineGeneratePublic(new X509EncodedKeySpec(encoded));
+ @SuppressWarnings("unchecked")
+ T result = (T) constructJavaPublicKeySpec(publicKeySpec, publicKey);
+ return result;
+ } else if (privateKeySpec != null && key instanceof PrivateKey && privateKeySpec.isAssignableFrom(keySpec)) {
+ final byte[] encoded = key.getEncoded();
+ if (!"PKCS#8".equals(key.getFormat()) || encoded == null) {
+ throw new InvalidKeySpecException("Not a valid PKCS#8 encoding");
+ }
+ OpenSSLX25519PrivateKey privateKey = (OpenSSLX25519PrivateKey) engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
+ @SuppressWarnings("unchecked")
+ T result = (T) constructJavaPrivateKeySpec(privateKeySpec, privateKey);
+ return result;
+ } else if (key instanceof PrivateKey && PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) {
+ final byte[] encoded = key.getEncoded();
+ if (!"PKCS#8".equals(key.getFormat())) {
+ throw new InvalidKeySpecException("Encoding type must be PKCS#8; was "
+ + key.getFormat());
+ } else if (encoded == null) {
+ throw new InvalidKeySpecException("Key is not encodable");
+ }
+ @SuppressWarnings("unchecked") T result = (T) new PKCS8EncodedKeySpec(encoded);
+ return result;
+ } else if (key instanceof PublicKey && X509EncodedKeySpec.class.isAssignableFrom(keySpec)) {
+ final byte[] encoded = key.getEncoded();
+ if (!"X.509".equals(key.getFormat())) {
+ throw new InvalidKeySpecException("Encoding type must be X.509; was "
+ + key.getFormat());
+ } else if (encoded == null) {
+ throw new InvalidKeySpecException("Key is not encodable");
+ }
+ @SuppressWarnings("unchecked") T result = (T) new X509EncodedKeySpec(encoded);
+ return result;
+ }
+
+ throw new InvalidKeySpecException("Unsupported key type and key spec combination; key="
+ + key.getClass().getName() + ", keySpec=" + keySpec.getName());
+ }
+
+ @Override
+ protected Key engineTranslateKey(Key key) throws InvalidKeyException {
+ if (key == null) {
+ throw new InvalidKeyException("key == null");
+ }
+ if ((key instanceof OpenSSLX25519PublicKey) || (key instanceof OpenSSLX25519PrivateKey)) {
+ return key;
+ } else if ((key instanceof PrivateKey) && "PKCS#8".equals(key.getFormat())) {
+ byte[] encoded = key.getEncoded();
+ if (encoded == null) {
+ throw new InvalidKeyException("Key does not support encoding");
+ }
+ try {
+ return engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e);
+ }
+ } else if ((key instanceof PublicKey) && "X.509".equals(key.getFormat())) {
+ byte[] encoded = key.getEncoded();
+ if (encoded == null) {
+ throw new InvalidKeyException("Key does not support encoding");
+ }
+ try {
+ return engineGeneratePublic(new X509EncodedKeySpec(encoded));
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e);
+ }
+ } else {
+ throw new InvalidKeyException("Key must be EC public or private key; was "
+ + key.getClass().getName());
+ }
+ }
+
+ private static Class<?> getJavaPrivateKeySpec() {
+ try {
+ return Class.forName("java.security.spec.XECPrivateKeySpec");
+ } catch (ClassNotFoundException ignored) {
+ return null;
+ }
+ }
+
+ private static Class<?> getJavaPublicKeySpec() {
+ try {
+ return Class.forName("java.security.spec.XECPublicKeySpec");
+ } catch (ClassNotFoundException ignored) {
+ return null;
+ }
+ }
+
+ private KeySpec constructJavaPrivateKeySpec(Class<?> privateKeySpec, OpenSSLX25519PrivateKey privateKey) throws InvalidKeySpecException {
+ if (privateKeySpec == null) {
+ throw new InvalidKeySpecException("Could not find java.security.spec.XECPrivateKeySpec");
+ }
+
+ try {
+ Constructor<?> c = privateKeySpec.getConstructor(AlgorithmParameterSpec.class, byte[].class);
+ @SuppressWarnings("unchecked")
+ KeySpec result = (KeySpec) c.newInstance(new OpenSSLXECParameterSpec(OpenSSLXECParameterSpec.X25519), privateKey.getU());
+ return result;
+ } catch (NoSuchMethodException e) {
+ throw new InvalidKeySpecException("Could not find java.security.spec.XECPrivateKeySpec", e);
+ } catch (InstantiationException e) {
+ throw new InvalidKeySpecException("Could not find java.security.spec.XECPrivateKeySpec", e);
+ } catch (IllegalAccessException e) {
+ throw new InvalidKeySpecException("Could not find java.security.spec.XECPrivateKeySpec", e);
+ } catch (InvocationTargetException e) {
+ throw new InvalidKeySpecException("Could not find java.security.spec.XECPrivateKeySpec", e);
+ }
+ }
+
+ private KeySpec constructJavaPublicKeySpec(Class<?> publicKeySpec, OpenSSLX25519PublicKey publicKey) throws InvalidKeySpecException {
+ try {
+ Constructor<?> c = publicKeySpec.getConstructor(AlgorithmParameterSpec.class, BigInteger.class);
+ @SuppressWarnings("unchecked")
+ KeySpec result = (KeySpec) c.newInstance(new OpenSSLXECParameterSpec(OpenSSLXECParameterSpec.X25519), new BigInteger(1, publicKey.getU()));
+ return result;
+ } catch (NoSuchMethodException e) {
+ throw new InvalidKeySpecException("Could not find java.security.spec.XECPublicKeySpec", e);
+ } catch (InstantiationException e) {
+ throw new InvalidKeySpecException("Could not find java.security.spec.XECPublicKeySpec", e);
+ } catch (IllegalAccessException e) {
+ throw new InvalidKeySpecException("Could not find java.security.spec.XECPublicKeySpec", e);
+ } catch (InvocationTargetException e) {
+ throw new InvalidKeySpecException("Could not find java.security.spec.XECPublicKeySpec", e);
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLXDHKeyPairGenerator.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLXDHKeyPairGenerator.java
new file mode 100644
index 0000000..1672a78
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLXDHKeyPairGenerator.java
@@ -0,0 +1,59 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * An implementation of {@link KeyPairGenerator} for XDH keys which uses BoringSSL to perform all the
+ * operations. This only supports X25519 keys.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class OpenSSLXDHKeyPairGenerator extends KeyPairGenerator {
+ private static final String ALGORITHM = "XDH";
+
+ public OpenSSLXDHKeyPairGenerator() {
+ super(ALGORITHM);
+ }
+
+ @Override
+ public KeyPair generateKeyPair() {
+ byte[] publicKeyBytes = new byte[OpenSSLX25519Key.X25519_KEY_SIZE_BYTES];
+ byte[] privateKeyBytes = new byte[OpenSSLX25519Key.X25519_KEY_SIZE_BYTES];
+
+ NativeCrypto.X25519_keypair(publicKeyBytes, privateKeyBytes);
+
+ return new KeyPair(new OpenSSLX25519PublicKey(publicKeyBytes), new OpenSSLX25519PrivateKey(privateKeyBytes));
+ }
+
+ @Override
+ public void initialize(int keysize, SecureRandom random) {
+ }
+
+ @Override
+ public void initialize(AlgorithmParameterSpec param, SecureRandom random)
+ throws InvalidAlgorithmParameterException {
+ throw new InvalidAlgorithmParameterException(
+ "No AlgorithmParameterSpec classes are supported");
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLXECParameterSpec.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLXECParameterSpec.java
new file mode 100644
index 0000000..d8f3746
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLXECParameterSpec.java
@@ -0,0 +1,22 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * Parameter markers to assist in future compatibility should other XEC curves be supported.
+ */
+@Internal
+class OpenSSLXECParameterSpec implements AlgorithmParameterSpec {
+ public static final String X25519 = "1.3.101.110";
+
+ private final String oid;
+
+ public OpenSSLXECParameterSpec(String oid) {
+ this.oid = oid;
+ }
+
+ public String getOid() {
+ return oid;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/PSKKeyManager.java b/repackaged/common/src/main/java/com/android/org/conscrypt/PSKKeyManager.java
new file mode 100644
index 0000000..0243cb6
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/PSKKeyManager.java
@@ -0,0 +1,177 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2014 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.net.Socket;
+import javax.crypto.SecretKey;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLEngine;
+
+/**
+ * Provider of key material for pre-shared key (PSK) key exchange used in TLS-PSK cipher suites.
+ *
+ * <h3>Overview of TLS-PSK</h3>
+ *
+ * <p>TLS-PSK is a set of TLS/SSL cipher suites which rely on a symmetric pre-shared key (PSK) to
+ * secure the TLS/SSL connection and mutually authenticate its peers. These cipher suites may be
+ * a more natural fit compared to conventional public key based cipher suites in some scenarios
+ * where communication between peers is bootstrapped via a separate step (for example, a pairing
+ * step) and requires both peers to authenticate each other. In such scenarios a symmetric key (PSK)
+ * can be exchanged during the bootstrapping step, removing the need to generate and exchange public
+ * key pairs and X.509 certificates.</p>
+ *
+ * <p>When a TLS-PSK cipher suite is used, both peers have to use the same key for the TLS/SSL
+ * handshake to succeed. Thus, both peers are implicitly authenticated by a successful handshake.
+ * This removes the need to use a {@code TrustManager} in conjunction with this {@code KeyManager}.
+ * </p>
+ *
+ * <h3>Supporting multiple keys</h3>
+ *
+ * <p>A peer may have multiple keys to choose from. To help choose the right key, during the
+ * handshake the server can provide a <em>PSK identity hint</em> to the client, and the client can
+ * provide a <em>PSK identity</em> to the server. The contents of these two pieces of information
+ * are specific to application-level protocols.</p>
+ *
+ * <p><em>NOTE: Both the PSK identity hint and the PSK identity are transmitted in cleartext.
+ * Moreover, these data are received and processed prior to peer having been authenticated. Thus,
+ * they must not contain or leak key material or other sensitive information, and should be
+ * treated (e.g., parsed) with caution, as untrusted data.</em></p>
+ *
+ * <p>The high-level flow leading to peers choosing a key during TLS/SSL handshake is as follows:
+ * <ol>
+ * <li>Server receives a handshake request from client.
+ * <li>Server replies, optionally providing a PSK identity hint to client.</li>
+ * <li>Client chooses the key.</li>
+ * <li>Client provides a PSK identity of the chosen key to server.</li>
+ * <li>Server chooses the key.</li>
+ * </ol></p>
+ *
+ * <p>In the flow above, either peer can signal that they do not have a suitable key, in which case
+ * the the handshake will be aborted immediately. This may enable a network attacker who does not
+ * know the key to learn which PSK identity hints or PSK identities are supported. If this is a
+ * concern then a randomly generated key should be used in the scenario where no key is available.
+ * This will lead to the handshake aborting later, due to key mismatch -- same as in the scenario
+ * where a key is available -- making it appear to the attacker that all PSK identity hints and PSK
+ * identities are supported.</p>
+ *
+ * <h3>Maximum sizes</h3>
+ *
+ * <p>The maximum supported sizes are as follows:
+ * <ul>
+ * <li>256 bytes for keys (see {@link #MAX_KEY_LENGTH_BYTES}),</li>
+ * <li>128 bytes for PSK identity and PSK identity hint (in modified UTF-8 representation) (see
+ * {@link #MAX_IDENTITY_LENGTH_BYTES} and {@link #MAX_IDENTITY_HINT_LENGTH_BYTES}).</li>
+ * </ul></p>
+ *
+ * <h3>Example</h3>
+ * The following example illustrates how to create an {@code SSLContext} which enables the use of
+ * TLS-PSK in {@code SSLSocket}, {@code SSLServerSocket} and {@code SSLEngine} instances obtained
+ * from it.
+ * <pre>
+ * PSKKeyManager myPskKeyManager = ...;
+ *
+ * SSLContext sslContext = SSLContext.getInstance("TLS");
+ * sslContext.init(
+ * new KeyManager[] {myPskKeyManager},
+ * new TrustManager[0], // No TrustManagers needed for TLS-PSK
+ * null // Use the default source of entropy
+ * );
+ *
+ * SSLSocket sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket(...);
+ * </pre>
+ *
+ * @deprecated This abstraction is deprecated because it does not work with TLS 1.3.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Deprecated
+@Internal
+public interface PSKKeyManager extends KeyManager {
+
+ /**
+ * Maximum supported length (in bytes) for PSK identity hint (in modified UTF-8 representation).
+ */
+ int MAX_IDENTITY_HINT_LENGTH_BYTES = 128;
+
+ /** Maximum supported length (in bytes) for PSK identity (in modified UTF-8 representation). */
+ int MAX_IDENTITY_LENGTH_BYTES = 128;
+
+ /** Maximum supported length (in bytes) for PSK key. */
+ int MAX_KEY_LENGTH_BYTES = 256;
+
+ /**
+ * Gets the PSK identity hint to report to the client to help agree on the PSK for the provided
+ * socket.
+ *
+ * @return PSK identity hint to be provided to the client or {@code null} to provide no hint.
+ */
+ String chooseServerKeyIdentityHint(Socket socket);
+
+ /**
+ * Gets the PSK identity hint to report to the client to help agree on the PSK for the provided
+ * engine.
+ *
+ * @return PSK identity hint to be provided to the client or {@code null} to provide no hint.
+ */
+ String chooseServerKeyIdentityHint(SSLEngine engine);
+
+ /**
+ * Gets the PSK identity to report to the server to help agree on the PSK for the provided
+ * socket.
+ *
+ * @param identityHint identity hint provided by the server or {@code null} if none provided.
+ *
+ * @return PSK identity to provide to the server. {@code null} is permitted but will be
+ * converted into an empty string.
+ */
+ String chooseClientKeyIdentity(String identityHint, Socket socket);
+
+ /**
+ * Gets the PSK identity to report to the server to help agree on the PSK for the provided
+ * engine.
+ *
+ * @param identityHint identity hint provided by the server or {@code null} if none provided.
+ *
+ * @return PSK identity to provide to the server. {@code null} is permitted but will be
+ * converted into an empty string.
+ */
+ String chooseClientKeyIdentity(String identityHint, SSLEngine engine);
+
+ /**
+ * Gets the PSK to use for the provided socket.
+ *
+ * @param identityHint identity hint provided by the server to help select the key or
+ * {@code null} if none provided.
+ * @param identity identity provided by the client to help select the key.
+ *
+ * @return key or {@code null} to signal to peer that no suitable key is available and to abort
+ * the handshake.
+ */
+ SecretKey getKey(String identityHint, String identity, Socket socket);
+
+ /**
+ * Gets the PSK to use for the provided engine.
+ *
+ * @param identityHint identity hint provided by the server to help select the key or
+ * {@code null} if none provided.
+ * @param identity identity provided by the client to help select the key.
+ *
+ * @return key or {@code null} to signal to peer that no suitable key is available and to abort
+ * the handshake.
+ */
+ SecretKey getKey(String identityHint, String identity, SSLEngine engine);
+}
\ No newline at end of file
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/PSSParameters.java b/repackaged/common/src/main/java/com/android/org/conscrypt/PSSParameters.java
new file mode 100644
index 0000000..554de86
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/PSSParameters.java
@@ -0,0 +1,158 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.IOException;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PSSParameterSpec;
+
+/**
+ * AlgorithmParameters implementation for PSS. The only supported encoding format is ASN.1
+ * (with X.509 accepted as an alias), as specified in RFC 4055 section 3.1.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class PSSParameters extends AlgorithmParametersSpi {
+
+ private PSSParameterSpec spec = PSSParameterSpec.DEFAULT;
+
+ public PSSParameters() {}
+
+ @Override
+ protected void engineInit(AlgorithmParameterSpec algorithmParameterSpec)
+ throws InvalidParameterSpecException {
+ if (algorithmParameterSpec instanceof PSSParameterSpec) {
+ this.spec = (PSSParameterSpec) algorithmParameterSpec;
+ } else {
+ throw new InvalidParameterSpecException("Only PSSParameterSpec is supported");
+ }
+ }
+
+ @Override
+ protected void engineInit(byte[] bytes) throws IOException {
+ long readRef = 0;
+ long seqRef = 0;
+ try {
+ readRef = NativeCrypto.asn1_read_init(bytes);
+ seqRef = NativeCrypto.asn1_read_sequence(readRef);
+ int saltLength = 20;
+ String hash = OAEPParameters.readHash(seqRef);
+ String mgfHash = OAEPParameters.readMgfHash(seqRef);
+ if (NativeCrypto.asn1_read_next_tag_is(seqRef, 2)) {
+ long saltRef = 0;
+ try {
+ saltRef = NativeCrypto.asn1_read_tagged(seqRef);
+ saltLength = (int) NativeCrypto.asn1_read_uint64(saltRef);
+ } finally {
+ NativeCrypto.asn1_read_free(saltRef);
+ }
+ }
+ if (NativeCrypto.asn1_read_next_tag_is(seqRef, 3)) {
+ long trailerField;
+ long trailerRef = 0;
+ try {
+ trailerRef = NativeCrypto.asn1_read_tagged(seqRef);
+ trailerField = (int) NativeCrypto.asn1_read_uint64(trailerRef);
+ } finally {
+ NativeCrypto.asn1_read_free(trailerRef);
+ }
+ // 1 is the only legal value for trailerField
+ if (trailerField != 1) {
+ throw new IOException("Error reading ASN.1 encoding");
+ }
+ }
+
+ if (!NativeCrypto.asn1_read_is_empty(seqRef)
+ || !NativeCrypto.asn1_read_is_empty(readRef)) {
+ throw new IOException("Error reading ASN.1 encoding");
+ }
+ this.spec = new PSSParameterSpec(hash, "MGF1", new MGF1ParameterSpec(mgfHash),
+ saltLength, 1);
+ } finally {
+ NativeCrypto.asn1_read_free(seqRef);
+ NativeCrypto.asn1_read_free(readRef);
+ }
+ }
+
+ @Override
+ protected void engineInit(byte[] bytes, String format) throws IOException {
+ if ((format == null) || format.equals("ASN.1") || format.equals("X.509")) {
+ engineInit(bytes);
+ } else {
+ throw new IOException("Unsupported format: " + format);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected <T extends AlgorithmParameterSpec> T engineGetParameterSpec(Class<T> aClass)
+ throws InvalidParameterSpecException {
+ if ((aClass != null) && aClass == PSSParameterSpec.class) {
+ return (T) spec;
+ } else {
+ throw new InvalidParameterSpecException("Unsupported class: " + aClass);
+ }
+ }
+
+ @Override
+ protected byte[] engineGetEncoded() throws IOException {
+ long cbbRef = 0;
+ long seqRef = 0;
+ try {
+ cbbRef = NativeCrypto.asn1_write_init();
+ seqRef = NativeCrypto.asn1_write_sequence(cbbRef);
+ OAEPParameters.writeHashAndMgfHash(seqRef, spec.getDigestAlgorithm(),
+ (MGF1ParameterSpec) spec.getMGFParameters());
+ // Implementations are prohibited from writing the default value for any of the fields
+ if (spec.getSaltLength() != 20) {
+ long tagRef = 0;
+ try {
+ tagRef = NativeCrypto.asn1_write_tag(seqRef, 2);
+ NativeCrypto.asn1_write_uint64(tagRef, spec.getSaltLength());
+ } finally {
+ NativeCrypto.asn1_write_flush(seqRef);
+ NativeCrypto.asn1_write_free(tagRef);
+ }
+ }
+ // 1 is the only legal value for trailerField and the default, so ignore it
+ return NativeCrypto.asn1_write_finish(cbbRef);
+ } catch (IOException e) {
+ NativeCrypto.asn1_write_cleanup(cbbRef);
+ throw e;
+ } finally {
+ NativeCrypto.asn1_write_free(seqRef);
+ NativeCrypto.asn1_write_free(cbbRef);
+ }
+ }
+
+ @Override
+ protected byte[] engineGetEncoded(String format) throws IOException {
+ if ((format == null) || format.equals("ASN.1") || format.equals("X.509")) {
+ return engineGetEncoded();
+ }
+ throw new IOException("Unsupported format: " + format);
+ }
+
+ @Override
+ protected String engineToString() {
+ return "Conscrypt PSS AlgorithmParameters";
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/PeerInfoProvider.java b/repackaged/common/src/main/java/com/android/org/conscrypt/PeerInfoProvider.java
new file mode 100644
index 0000000..d180425
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/PeerInfoProvider.java
@@ -0,0 +1,79 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.android.org.conscrypt;
+
+/**
+ * A provider for the peer host and port information.
+ */
+abstract class PeerInfoProvider {
+ private static final PeerInfoProvider NULL_PEER_INFO_PROVIDER = new PeerInfoProvider() {
+ @Override
+ String getHostname() {
+ return null;
+ }
+
+ @Override
+ public String getHostnameOrIP() {
+ return null;
+ }
+
+ @Override
+ public int getPort() {
+ return -1;
+ }
+ };
+
+ /**
+ * Returns the hostname supplied during engine/socket creation. No DNS resolution is
+ * attempted before returning the hostname.
+ */
+ abstract String getHostname();
+
+ /**
+ * This method attempts to create a textual representation of the peer host or IP. Does
+ * not perform a reverse DNS lookup. This is typically used during session creation.
+ */
+ abstract String getHostnameOrIP();
+
+ /**
+ * Gets the port of the peer.
+ */
+ abstract int getPort();
+
+ static PeerInfoProvider nullProvider() {
+ return NULL_PEER_INFO_PROVIDER;
+ }
+
+ static PeerInfoProvider forHostAndPort(final String host, final int port) {
+ return new PeerInfoProvider() {
+ @Override
+ String getHostname() {
+ return host;
+ }
+
+ @Override
+ public String getHostnameOrIP() {
+ return host;
+ }
+
+ @Override
+ public int getPort() {
+ return port;
+ }
+ };
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/Preconditions.java b/repackaged/common/src/main/java/com/android/org/conscrypt/Preconditions.java
new file mode 100644
index 0000000..801cc0f
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/Preconditions.java
@@ -0,0 +1,109 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+/**
+ * Static convenience methods that help a method or constructor check whether it was invoked
+ * correctly (that is, whether its <i>preconditions</i> were met).
+ */
+final class Preconditions {
+ private Preconditions() {}
+
+ /**
+ * Ensures that an object reference passed as a parameter to the calling method is not null.
+ *
+ * @param reference an object reference
+ * @param errorMessage the exception message to use if the check fails.
+ * @return the non-null reference that was validated
+ * @throws NullPointerException if {@code reference} is null
+ */
+ static <T> T checkNotNull(T reference, String errorMessage) {
+ if (reference == null) {
+ throw new NullPointerException(errorMessage);
+ }
+ return reference;
+ }
+
+ /**
+ * Ensures the truth of an expression involving one or more parameters to the calling method.
+ *
+ * @param condition to condition to be tested
+ * @param errorMessage the exception message to use if the check fails.
+ * @throws IllegalArgumentException if the condition is {@code false}
+ */
+ static void checkArgument(boolean condition, String errorMessage) {
+ if (!condition) {
+ throw new IllegalArgumentException(errorMessage);
+ }
+ }
+
+ /**
+ * Ensures the truth of an expression involving one or more parameters to the calling method.
+ *
+ * @param condition to condition to be tested
+ * @param errorMessageTemplate the format string to be passed to {@link String#format(String,
+ * Object...)}
+ * @param arg the format argument to be passed to {@link String#format(String, Object...)}
+ * @throws IllegalArgumentException if the condition is {@code false}
+ */
+ static void checkArgument(boolean condition, String errorMessageTemplate, Object arg) {
+ if (!condition) {
+ throw new IllegalArgumentException(String.format(errorMessageTemplate, arg));
+ }
+ }
+
+ /**
+ * Ensures that {@code start} and {@code end} specify a valid <i>positions</i> in an array, list
+ * or string of size {@code size}, and are in order. A position index may range from zero to
+ * {@code size}, inclusive.
+ *
+ * @param start a user-supplied index identifying a starting position in an array, list or string
+ * @param end a user-supplied index identifying a ending position in an array, list or string
+ * @param size the size of that array, list or string
+ * @throws IndexOutOfBoundsException if either index is negative or is greater than {@code size},
+ * or if {@code end} is less than {@code start}
+ * @throws IllegalArgumentException if {@code size} is negative
+ */
+ static void checkPositionIndexes(int start, int end, int size) {
+ // Carefully optimized for execution by hotspot (explanatory comment above)
+ if (start < 0 || end < start || end > size) {
+ throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size));
+ }
+ }
+
+ private static String badPositionIndexes(int start, int end, int size) {
+ if (start < 0 || start > size) {
+ return badPositionIndex(start, size, "start index");
+ }
+ if (end < 0 || end > size) {
+ return badPositionIndex(end, size, "end index");
+ }
+ // end < start
+ return String.format("end index (%s) must not be less than start index (%s)", end, start);
+ }
+
+ private static String badPositionIndex(int index, int size, String desc) {
+ if (index < 0) {
+ return String.format("%s (%s) must not be negative", desc, index);
+ } else if (size < 0) {
+ throw new IllegalArgumentException("negative size: " + size);
+ } else { // index > size
+ return String.format("%s (%s) must not be greater than size (%s)", desc, index, size);
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/SSLClientSessionCache.java b/repackaged/common/src/main/java/com/android/org/conscrypt/SSLClientSessionCache.java
new file mode 100644
index 0000000..1fd3c96
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/SSLClientSessionCache.java
@@ -0,0 +1,55 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt;
+
+import javax.net.ssl.SSLSession;
+
+/**
+ * A persistent {@link javax.net.ssl.SSLSession} cache used by
+ * {@link javax.net.ssl.SSLSessionContext} to share client-side SSL sessions
+ * across processes. For example, this cache enables applications to
+ * persist and reuse sessions across restarts.
+ *
+ * <p>The {@code SSLSessionContext} implementation converts
+ * {@code SSLSession}s into raw bytes and vice versa. The exact makeup of the
+ * session data is dependent upon the caller's implementation and is opaque to
+ * the {@code SSLClientSessionCache} implementation.
+ * @hide This class is not part of the Android public SDK API
+ */
+@libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+public interface SSLClientSessionCache {
+ /**
+ * Gets data from a pre-existing session for a given server host and port.
+ *
+ * @param host from {@link javax.net.ssl.SSLSession#getPeerHost()}
+ * @param port from {@link javax.net.ssl.SSLSession#getPeerPort()}
+ * @return the session data or null if none is cached
+ * @throws NullPointerException if host is null
+ */
+ byte[] getSessionData(String host, int port);
+
+ /**
+ * Stores session data for the given session.
+ *
+ * @param session to cache data for
+ * @param sessionData to cache
+ * @throws NullPointerException if session, result of
+ * {@code session.getPeerHost()} or data is null
+ */
+ void putSessionData(SSLSession session, byte[] sessionData);
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/SSLNullSession.java b/repackaged/common/src/main/java/com/android/org/conscrypt/SSLNullSession.java
new file mode 100644
index 0000000..fd1311a
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/SSLNullSession.java
@@ -0,0 +1,188 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.List;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+
+/**
+ * This is returned in the place of a {@link SSLSession} when no TLS connection could be negotiated,
+ * but one was requested from a method that can't throw an exception such as {@link
+ * javax.net.ssl.SSLSocket#getSession()} before {@link javax.net.ssl.SSLSocket#startHandshake()} is
+ * called.
+ */
+final class SSLNullSession implements ConscryptSession, Cloneable {
+ static final String INVALID_CIPHER = "SSL_NULL_WITH_NULL_NULL";
+
+ /*
+ * Holds default instances so class preloading doesn't create an instance of
+ * it.
+ */
+ private static class DefaultHolder {
+ static final SSLNullSession NULL_SESSION = new SSLNullSession();
+ }
+
+ private long creationTime;
+ private long lastAccessedTime;
+
+ static ConscryptSession getNullSession() {
+ return DefaultHolder.NULL_SESSION;
+ }
+
+ private SSLNullSession() {
+ creationTime = System.currentTimeMillis();
+ lastAccessedTime = creationTime;
+ }
+
+ @Override
+ public String getRequestedServerName() {
+ return null;
+ }
+
+ @Override
+ public List<byte[]> getStatusResponses() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public byte[] getPeerSignedCertificateTimestamp() {
+ return EmptyArray.BYTE;
+ }
+
+ @Override
+ public int getApplicationBufferSize() {
+ return NativeConstants.SSL3_RT_MAX_PLAIN_LENGTH;
+ }
+
+ @Override
+ public String getApplicationProtocol() {
+ return null;
+ }
+
+ @Override
+ public String getCipherSuite() {
+ return INVALID_CIPHER;
+ }
+
+ @Override
+ public long getCreationTime() {
+ return creationTime;
+ }
+
+ @Override
+ public byte[] getId() {
+ return EmptyArray.BYTE;
+ }
+
+ @Override
+ public long getLastAccessedTime() {
+ return lastAccessedTime;
+ }
+
+ @Override
+ public Certificate[] getLocalCertificates() {
+ return null;
+ }
+
+ @Override
+ public Principal getLocalPrincipal() {
+ return null;
+ }
+
+ @Override
+ public int getPacketBufferSize() {
+ return NativeConstants.SSL3_RT_MAX_PACKET_SIZE;
+ }
+
+ @Override
+ @SuppressWarnings("deprecation") // Public API
+ public javax.security.cert.X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ throw new SSLPeerUnverifiedException("No peer certificate");
+ }
+
+ @Override
+ public X509Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ throw new SSLPeerUnverifiedException("No peer certificate");
+ }
+
+ @Override
+ public String getPeerHost() {
+ return null;
+ }
+
+ @Override
+ public int getPeerPort() {
+ return -1;
+ }
+
+ @Override
+ public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+ throw new SSLPeerUnverifiedException("No peer certificate");
+ }
+
+ @Override
+ public String getProtocol() {
+ return "NONE";
+ }
+
+ @Override
+ public SSLSessionContext getSessionContext() {
+ return null;
+ }
+
+ @Override
+ public Object getValue(String name) {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ExternalSession.");
+ }
+
+ @Override
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ExternalSession.");
+ }
+
+ @Override
+ public void invalidate() {
+ }
+
+ @Override
+ public boolean isValid() {
+ return false;
+ }
+
+ @Override
+ public void putValue(String name, Object value) {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ExternalSession.");
+ }
+
+ @Override
+ public void removeValue(String name) {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ExternalSession.");
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/SSLParametersImpl.java b/repackaged/common/src/main/java/com/android/org/conscrypt/SSLParametersImpl.java
new file mode 100644
index 0000000..af73a43
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/SSLParametersImpl.java
@@ -0,0 +1,723 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.AlgorithmConstraints;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Set;
+import javax.crypto.SecretKey;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SNIMatcher;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * The instances of this class encapsulate all the info
+ * about enabled cipher suites and protocols,
+ * as well as the information about client/server mode of
+ * ssl socket, whether it require/want client authentication or not,
+ * and controls whether new SSL sessions may be established by this
+ * socket or not.
+ */
+final class SSLParametersImpl implements Cloneable {
+
+ // default source of X.509 certificate based authentication keys
+ private static volatile X509KeyManager defaultX509KeyManager;
+ // default source of X.509 certificate based authentication trust decisions
+ private static volatile X509TrustManager defaultX509TrustManager;
+ // default SSL parameters
+ private static volatile SSLParametersImpl defaultParameters;
+
+ // client session context contains the set of reusable
+ // client-side SSL sessions
+ private final ClientSessionContext clientSessionContext;
+ // server session context contains the set of reusable
+ // server-side SSL sessions
+ private final ServerSessionContext serverSessionContext;
+ // source of X.509 certificate based authentication keys or null if not provided
+ private final X509KeyManager x509KeyManager;
+ // source of Pre-Shared Key (PSK) authentication keys or null if not provided.
+ @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
+ private final PSKKeyManager pskKeyManager;
+ // source of X.509 certificate based authentication trust decisions or null if not provided
+ @android.compat.annotation.UnsupportedAppUsage private final X509TrustManager x509TrustManager;
+
+ // protocols enabled for SSL connection
+ String[] enabledProtocols;
+ // set to indicate when obsolete protocols are filtered
+ boolean isEnabledProtocolsFiltered;
+ // The TLS 1.0-1.2 cipher suites enabled for the SSL connection. TLS 1.3 cipher suites
+ // cannot be customized, so for simplicity this field never contains any TLS 1.3 suites.
+ String[] enabledCipherSuites;
+
+ // if the peer with this parameters tuned to work in client mode
+ private boolean client_mode = true;
+ // if the peer with this parameters tuned to require client authentication
+ private boolean need_client_auth = false;
+ // if the peer with this parameters tuned to request client authentication
+ private boolean want_client_auth = false;
+ // if the peer with this parameters allowed to cteate new SSL session
+ private boolean enable_session_creation = true;
+ // Endpoint identification algorithm (e.g., HTTPS)
+ private String endpointIdentificationAlgorithm;
+ // Whether to use the local cipher suites order
+ private boolean useCipherSuitesOrder;
+ private Collection<SNIMatcher> sniMatchers;
+ private AlgorithmConstraints algorithmConstraints;
+
+ // client-side only, bypasses the property based configuration, used for tests
+ private boolean ctVerificationEnabled;
+
+ // server-side only. SCT and OCSP data to send to clients which request it
+ byte[] sctExtension;
+ byte[] ocspResponse;
+
+ byte[] applicationProtocols = EmptyArray.BYTE;
+ ApplicationProtocolSelectorAdapter applicationProtocolSelector;
+ boolean useSessionTickets;
+ private Boolean useSni;
+
+ /**
+ * Whether the TLS Channel ID extension is enabled. This field is
+ * server-side only.
+ */
+ boolean channelIdEnabled;
+
+ /**
+ * Initializes the parameters. Naturally this constructor is used
+ * in SSLContextImpl.engineInit method which directly passes its
+ * parameters. In other words this constructor holds all
+ * the functionality provided by SSLContext.init method.
+ * See {@link javax.net.ssl.SSLContext#init(KeyManager[],TrustManager[],
+ * SecureRandom)} for more information
+ */
+ SSLParametersImpl(KeyManager[] kms, TrustManager[] tms,
+ SecureRandom sr, ClientSessionContext clientSessionContext,
+ ServerSessionContext serverSessionContext, String[] protocols)
+ throws KeyManagementException {
+ this.serverSessionContext = serverSessionContext;
+ this.clientSessionContext = clientSessionContext;
+
+ // initialize key managers
+ if (kms == null) {
+ x509KeyManager = getDefaultX509KeyManager();
+ // There's no default PSK key manager
+ pskKeyManager = null;
+ } else {
+ x509KeyManager = findFirstX509KeyManager(kms);
+ pskKeyManager = findFirstPSKKeyManager(kms);
+ }
+
+ // initialize x509TrustManager
+ if (tms == null) {
+ x509TrustManager = getDefaultX509TrustManager();
+ } else {
+ x509TrustManager = findFirstX509TrustManager(tms);
+ }
+
+ // initialize the list of cipher suites and protocols enabled by default
+ enabledProtocols = NativeCrypto.checkEnabledProtocols(
+ protocols == null ? NativeCrypto.DEFAULT_PROTOCOLS : protocols).clone();
+ boolean x509CipherSuitesNeeded = (x509KeyManager != null) || (x509TrustManager != null);
+ boolean pskCipherSuitesNeeded = pskKeyManager != null;
+ enabledCipherSuites = getDefaultCipherSuites(
+ x509CipherSuitesNeeded, pskCipherSuitesNeeded);
+
+ // We ignore the SecureRandom passed in by the caller. The native code below
+ // directly accesses /dev/urandom, which makes it irrelevant.
+ }
+
+ // Copy constructor for the purposes of changing the final fields
+ @SuppressWarnings("deprecation") // for PSKKeyManager
+ private SSLParametersImpl(ClientSessionContext clientSessionContext,
+ ServerSessionContext serverSessionContext, X509KeyManager x509KeyManager,
+ PSKKeyManager pskKeyManager, X509TrustManager x509TrustManager,
+ SSLParametersImpl sslParams) {
+ this.clientSessionContext = clientSessionContext;
+ this.serverSessionContext = serverSessionContext;
+ this.x509KeyManager = x509KeyManager;
+ this.pskKeyManager = pskKeyManager;
+ this.x509TrustManager = x509TrustManager;
+
+ this.enabledProtocols =
+ (sslParams.enabledProtocols == null) ? null : sslParams.enabledProtocols.clone();
+ this.isEnabledProtocolsFiltered = sslParams.isEnabledProtocolsFiltered;
+ this.enabledCipherSuites = (sslParams.enabledCipherSuites == null)
+ ? null
+ : sslParams.enabledCipherSuites.clone();
+ this.client_mode = sslParams.client_mode;
+ this.need_client_auth = sslParams.need_client_auth;
+ this.want_client_auth = sslParams.want_client_auth;
+ this.enable_session_creation = sslParams.enable_session_creation;
+ this.endpointIdentificationAlgorithm = sslParams.endpointIdentificationAlgorithm;
+ this.useCipherSuitesOrder = sslParams.useCipherSuitesOrder;
+ this.ctVerificationEnabled = sslParams.ctVerificationEnabled;
+ this.sctExtension =
+ (sslParams.sctExtension == null) ? null : sslParams.sctExtension.clone();
+ this.ocspResponse =
+ (sslParams.ocspResponse == null) ? null : sslParams.ocspResponse.clone();
+ this.applicationProtocols = (sslParams.applicationProtocols == null)
+ ? null
+ : sslParams.applicationProtocols.clone();
+ this.applicationProtocolSelector = sslParams.applicationProtocolSelector;
+ this.useSessionTickets = sslParams.useSessionTickets;
+ this.useSni = sslParams.useSni;
+ this.channelIdEnabled = sslParams.channelIdEnabled;
+ }
+
+ @android.compat.annotation.UnsupportedAppUsage
+ static SSLParametersImpl getDefault() throws KeyManagementException {
+ SSLParametersImpl result = defaultParameters;
+ if (result == null) {
+ // single-check idiom
+ defaultParameters = result = new SSLParametersImpl(null,
+ null,
+ null,
+ new ClientSessionContext(),
+ new ServerSessionContext(),
+ null);
+ }
+ return (SSLParametersImpl) result.clone();
+ }
+
+ /**
+ * Returns the appropriate session context.
+ */
+ AbstractSessionContext getSessionContext() {
+ return client_mode ? clientSessionContext : serverSessionContext;
+ }
+
+ /**
+ * @return client session context
+ */
+ ClientSessionContext getClientSessionContext() {
+ return clientSessionContext;
+ }
+
+ /**
+ * @return X.509 key manager or {@code null} for none.
+ */
+ X509KeyManager getX509KeyManager() {
+ return x509KeyManager;
+ }
+
+ /**
+ * @return Pre-Shared Key (PSK) key manager or {@code null} for none.
+ */
+ @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
+ PSKKeyManager getPSKKeyManager() {
+ return pskKeyManager;
+ }
+
+ /**
+ * @return X.509 trust manager or {@code null} for none.
+ */
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ X509TrustManager getX509TrustManager() {
+ return x509TrustManager;
+ }
+
+ /**
+ * @return the names of enabled cipher suites
+ */
+ String[] getEnabledCipherSuites() {
+ if (Arrays.asList(enabledProtocols).contains(NativeCrypto.SUPPORTED_PROTOCOL_TLSV1_3)) {
+ return SSLUtils.concat(
+ NativeCrypto.SUPPORTED_TLS_1_3_CIPHER_SUITES, enabledCipherSuites);
+ }
+ return enabledCipherSuites.clone();
+ }
+
+ /**
+ * Sets the enabled cipher suites after filtering through OpenSSL.
+ */
+ void setEnabledCipherSuites(String[] cipherSuites) {
+ // Filter out any TLS 1.3 cipher suites the user may have passed. Our TLS 1.3 suites
+ // are always enabled, no matter what the user requests, so we only store the 1.0-1.2
+ // suites in enabledCipherSuites.
+ enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(
+ filterFromCipherSuites(cipherSuites,
+ NativeCrypto.SUPPORTED_TLS_1_3_CIPHER_SUITES_SET));
+ }
+
+ /**
+ * @return the set of enabled protocols
+ */
+ String[] getEnabledProtocols() {
+ return enabledProtocols.clone();
+ }
+
+ /**
+ * Sets the list of available protocols for use in SSL connection.
+ * @throws IllegalArgumentException if {@code protocols == null}
+ */
+ @android.compat.annotation.UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
+ void setEnabledProtocols(String[] protocols) {
+ if (protocols == null) {
+ throw new IllegalArgumentException("protocols == null");
+ }
+ String[] filteredProtocols =
+ filterFromProtocols(protocols, NativeCrypto.OBSOLETE_PROTOCOL_SSLV3);
+ isEnabledProtocolsFiltered = protocols.length != filteredProtocols.length;
+ enabledProtocols = NativeCrypto.checkEnabledProtocols(filteredProtocols).clone();
+ }
+
+ /**
+ * Sets the list of ALPN protocols.
+ *
+ * @param protocols the list of ALPN protocols
+ */
+ void setApplicationProtocols(String[] protocols) {
+ this.applicationProtocols = SSLUtils.encodeProtocols(protocols);
+ }
+
+ String[] getApplicationProtocols() {
+ return SSLUtils.decodeProtocols(applicationProtocols);
+ }
+
+ /**
+ * Used for server-mode only. Sets or clears the application-provided ALPN protocol selector.
+ * If set, will override the protocol list provided by {@link #setApplicationProtocols(String[])}.
+ */
+ void setApplicationProtocolSelector(ApplicationProtocolSelectorAdapter applicationProtocolSelector) {
+ this.applicationProtocolSelector = applicationProtocolSelector;
+ }
+
+ /**
+ * Returns the application protocol (ALPN) selector for this socket.
+ */
+ ApplicationProtocolSelectorAdapter getApplicationProtocolSelector() {
+ return applicationProtocolSelector;
+ }
+
+ /**
+ * Tunes the peer holding this parameters to work in client mode.
+ * @param mode if the peer is configured to work in client mode
+ */
+ void setUseClientMode(boolean mode) {
+ client_mode = mode;
+ }
+
+ /**
+ * Returns the value indicating if the parameters configured to work
+ * in client mode.
+ */
+ boolean getUseClientMode() {
+ return client_mode;
+ }
+
+ /**
+ * Tunes the peer holding this parameters to require client authentication
+ */
+ void setNeedClientAuth(boolean need) {
+ need_client_auth = need;
+ // reset the want_client_auth setting
+ want_client_auth = false;
+ }
+
+ /**
+ * Returns the value indicating if the peer with this parameters tuned
+ * to require client authentication
+ */
+ boolean getNeedClientAuth() {
+ return need_client_auth;
+ }
+
+ /**
+ * Tunes the peer holding this parameters to request client authentication
+ */
+ void setWantClientAuth(boolean want) {
+ want_client_auth = want;
+ // reset the need_client_auth setting
+ need_client_auth = false;
+ }
+
+ /**
+ * Returns the value indicating if the peer with this parameters
+ * tuned to request client authentication
+ */
+ boolean getWantClientAuth() {
+ return want_client_auth;
+ }
+
+ /**
+ * Allows/disallows the peer holding this parameters to
+ * create new SSL session
+ */
+ void setEnableSessionCreation(boolean flag) {
+ enable_session_creation = flag;
+ }
+
+ /**
+ * Returns the value indicating if the peer with this parameters
+ * allowed to cteate new SSL session
+ */
+ boolean getEnableSessionCreation() {
+ return enable_session_creation;
+ }
+
+ void setUseSessionTickets(boolean useSessionTickets) {
+ this.useSessionTickets = useSessionTickets;
+ }
+
+ /**
+ * Whether connections using this SSL connection should use the TLS
+ * extension Server Name Indication (SNI).
+ */
+ void setUseSni(boolean flag) {
+ useSni = flag;
+ }
+
+ /**
+ * Returns whether connections using this SSL connection should use the TLS
+ * extension Server Name Indication (SNI).
+ */
+ boolean getUseSni() {
+ return useSni != null ? useSni : isSniEnabledByDefault();
+ }
+
+ /**
+ * For testing only.
+ */
+ void setCTVerificationEnabled(boolean enabled) {
+ ctVerificationEnabled = enabled;
+ }
+
+ /**
+ * For testing only.
+ */
+ void setSCTExtension(byte[] extension) {
+ sctExtension = extension;
+ }
+
+ /**
+ * For testing only.
+ */
+ void setOCSPResponse(byte[] response) {
+ ocspResponse = response;
+ }
+
+ byte[] getOCSPResponse() {
+ return ocspResponse;
+ }
+
+ /**
+ * This filters {@code obsoleteProtocol} from the list of {@code protocols}
+ * down to help with app compatibility.
+ */
+ private static String[] filterFromProtocols(String[] protocols, String obsoleteProtocol) {
+ if (protocols.length == 1 && obsoleteProtocol.equals(protocols[0])) {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ ArrayList<String> newProtocols = new ArrayList<String>();
+ for (String protocol : protocols) {
+ if (!obsoleteProtocol.equals(protocol)) {
+ newProtocols.add(protocol);
+ }
+ }
+ return newProtocols.toArray(EMPTY_STRING_ARRAY);
+ }
+
+ private static String[] filterFromCipherSuites(String[] cipherSuites, Set<String> toRemove) {
+ if (cipherSuites == null || cipherSuites.length == 0) {
+ return cipherSuites;
+ }
+ ArrayList<String> newCipherSuites = new ArrayList<String>(cipherSuites.length);
+ for (String cipherSuite : cipherSuites) {
+ if (!toRemove.contains(cipherSuite)) {
+ newCipherSuites.add(cipherSuite);
+ }
+ }
+ return newCipherSuites.toArray(EMPTY_STRING_ARRAY);
+ }
+
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+ /**
+ * Returns whether Server Name Indication (SNI) is enabled by default for
+ * sockets. For more information on SNI, see RFC 6066 section 3.
+ */
+ private boolean isSniEnabledByDefault() {
+ try {
+ String enableSNI = System.getProperty("jsse.enableSNIExtension", "true");
+ if ("true".equalsIgnoreCase(enableSNI)) {
+ return true;
+ } else if ("false".equalsIgnoreCase(enableSNI)) {
+ return false;
+ } else {
+ throw new RuntimeException(
+ "Can only set \"jsse.enableSNIExtension\" to \"true\" or \"false\"");
+ }
+ } catch (SecurityException e) {
+ return true;
+ }
+ }
+
+ /**
+ * For abstracting the X509KeyManager calls between
+ * {@link X509KeyManager#chooseClientAlias(String[], java.security.Principal[], java.net.Socket)}
+ * and
+ * {@link X509ExtendedKeyManager#chooseEngineClientAlias(String[], java.security.Principal[], javax.net.ssl.SSLEngine)}
+ */
+ interface AliasChooser {
+ String chooseClientAlias(X509KeyManager keyManager, X500Principal[] issuers,
+ String[] keyTypes);
+
+ String chooseServerAlias(X509KeyManager keyManager, String keyType);
+ }
+
+ /**
+ * For abstracting the {@code PSKKeyManager} calls between those taking an {@code SSLSocket} and
+ * those taking an {@code SSLEngine}.
+ */
+ @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
+ interface PSKCallbacks {
+ String chooseServerPSKIdentityHint(PSKKeyManager keyManager);
+ String chooseClientPSKIdentity(PSKKeyManager keyManager, String identityHint);
+ SecretKey getPSKKey(PSKKeyManager keyManager, String identityHint, String identity);
+ }
+
+ /**
+ * Returns the clone of this object.
+ * @return the clone.
+ */
+ @Override
+ protected Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ SSLParametersImpl cloneWithTrustManager(X509TrustManager newTrustManager) {
+ return new SSLParametersImpl(clientSessionContext, serverSessionContext, x509KeyManager,
+ pskKeyManager, newTrustManager, this);
+ }
+
+ private static X509KeyManager getDefaultX509KeyManager() throws KeyManagementException {
+ X509KeyManager result = defaultX509KeyManager;
+ if (result == null) {
+ // single-check idiom
+ defaultX509KeyManager = result = createDefaultX509KeyManager();
+ }
+ return result;
+ }
+ private static X509KeyManager createDefaultX509KeyManager() throws KeyManagementException {
+ try {
+ String algorithm = KeyManagerFactory.getDefaultAlgorithm();
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
+ kmf.init(null, null);
+ KeyManager[] kms = kmf.getKeyManagers();
+ X509KeyManager result = findFirstX509KeyManager(kms);
+ if (result == null) {
+ throw new KeyManagementException("No X509KeyManager among default KeyManagers: "
+ + Arrays.toString(kms));
+ }
+ return result;
+ } catch (NoSuchAlgorithmException e) {
+ throw new KeyManagementException(e);
+ } catch (KeyStoreException e) {
+ throw new KeyManagementException(e);
+ } catch (UnrecoverableKeyException e) {
+ throw new KeyManagementException(e);
+ }
+ }
+
+ /**
+ * Finds the first {@link X509KeyManager} element in the provided array.
+ *
+ * @return the first {@code X509KeyManager} or {@code null} if not found.
+ */
+ private static X509KeyManager findFirstX509KeyManager(KeyManager[] kms) {
+ for (KeyManager km : kms) {
+ if (km instanceof X509KeyManager) {
+ return (X509KeyManager)km;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Finds the first {@link PSKKeyManager} element in the provided array.
+ *
+ * @return the first {@code PSKKeyManager} or {@code null} if not found.
+ */
+ @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
+ private static PSKKeyManager findFirstPSKKeyManager(KeyManager[] kms) {
+ for (KeyManager km : kms) {
+ if (km instanceof PSKKeyManager) {
+ return (PSKKeyManager)km;
+ } else if (km != null) {
+ try {
+ return DuckTypedPSKKeyManager.getInstance(km);
+ } catch (NoSuchMethodException ignored) {
+ // This PSKKeyManager doesn't support the required methods, go to the next
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the default X.509 trust manager.
+ */
+ @android.compat.annotation.UnsupportedAppUsage
+ static X509TrustManager getDefaultX509TrustManager() throws KeyManagementException {
+ X509TrustManager result = defaultX509TrustManager;
+ if (result == null) {
+ // single-check idiom
+ defaultX509TrustManager = result = createDefaultX509TrustManager();
+ }
+ return result;
+ }
+
+ private static X509TrustManager createDefaultX509TrustManager()
+ throws KeyManagementException {
+ try {
+ String algorithm = TrustManagerFactory.getDefaultAlgorithm();
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
+ tmf.init((KeyStore) null);
+ TrustManager[] tms = tmf.getTrustManagers();
+ X509TrustManager trustManager = findFirstX509TrustManager(tms);
+ if (trustManager == null) {
+ throw new KeyManagementException(
+ "No X509TrustManager in among default TrustManagers: "
+ + Arrays.toString(tms));
+ }
+ return trustManager;
+ } catch (NoSuchAlgorithmException e) {
+ throw new KeyManagementException(e);
+ } catch (KeyStoreException e) {
+ throw new KeyManagementException(e);
+ }
+ }
+
+ /**
+ * Finds the first {@link X509TrustManager} element in the provided array.
+ *
+ * @return the first {@code X509ExtendedTrustManager} or
+ * {@code X509TrustManager} or {@code null} if not found.
+ */
+ private static X509TrustManager findFirstX509TrustManager(TrustManager[] tms) {
+ for (TrustManager tm : tms) {
+ if (tm instanceof X509TrustManager) {
+ return (X509TrustManager) tm;
+ }
+ }
+ return null;
+ }
+
+ String getEndpointIdentificationAlgorithm() {
+ return endpointIdentificationAlgorithm;
+ }
+
+ void setEndpointIdentificationAlgorithm(String endpointIdentificationAlgorithm) {
+ this.endpointIdentificationAlgorithm = endpointIdentificationAlgorithm;
+ }
+
+ boolean getUseCipherSuitesOrder() {
+ return useCipherSuitesOrder;
+ }
+
+ Collection<SNIMatcher> getSNIMatchers() {
+ if (sniMatchers == null) {
+ return null;
+ }
+ return new ArrayList<>(sniMatchers);
+ }
+
+ void setSNIMatchers(Collection<SNIMatcher> sniMatchers) {
+ this.sniMatchers = sniMatchers != null ? new ArrayList<>(sniMatchers) : null;
+ }
+
+ AlgorithmConstraints getAlgorithmConstraints() {
+ return algorithmConstraints;
+ }
+
+ void setAlgorithmConstraints(AlgorithmConstraints algorithmConstraints) {
+ this.algorithmConstraints = algorithmConstraints;
+ }
+
+ void setUseCipherSuitesOrder(boolean useCipherSuitesOrder) {
+ this.useCipherSuitesOrder = useCipherSuitesOrder;
+ }
+
+ private static String[] getDefaultCipherSuites(
+ boolean x509CipherSuitesNeeded,
+ boolean pskCipherSuitesNeeded) {
+ if (x509CipherSuitesNeeded) {
+ // X.509 based cipher suites need to be listed.
+ if (pskCipherSuitesNeeded) {
+ // Both X.509 and PSK based cipher suites need to be listed. Because TLS-PSK is not
+ // normally used, we assume that when PSK cipher suites are requested here they
+ // should be preferred over other cipher suites. Thus, we give PSK cipher suites
+ // higher priority than X.509 cipher suites.
+ // NOTE: There are cipher suites that use both X.509 and PSK (e.g., those based on
+ // RSA_PSK key exchange). However, these cipher suites are not currently supported.
+ return SSLUtils.concat(
+ NativeCrypto.DEFAULT_PSK_CIPHER_SUITES,
+ NativeCrypto.DEFAULT_X509_CIPHER_SUITES,
+ new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV});
+ } else {
+ // Only X.509 cipher suites need to be listed.
+ return SSLUtils.concat(
+ NativeCrypto.DEFAULT_X509_CIPHER_SUITES,
+ new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV});
+ }
+ } else if (pskCipherSuitesNeeded) {
+ // Only PSK cipher suites need to be listed.
+ return SSLUtils.concat(
+ NativeCrypto.DEFAULT_PSK_CIPHER_SUITES,
+ new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV});
+ } else {
+ // Neither X.509 nor PSK cipher suites need to be listed.
+ return new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV};
+ }
+ }
+
+ /**
+ * Check if SCT verification is enforced for a given hostname.
+ */
+ boolean isCTVerificationEnabled(String hostname) {
+ if (hostname == null) {
+ return false;
+ }
+
+ // Bypass the check. This is used for testing only
+ if (ctVerificationEnabled) {
+ return true;
+ }
+ return Platform.isCTVerificationRequired(hostname);
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/SSLServerSessionCache.java b/repackaged/common/src/main/java/com/android/org/conscrypt/SSLServerSessionCache.java
new file mode 100644
index 0000000..39fbbe9
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/SSLServerSessionCache.java
@@ -0,0 +1,53 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt;
+
+import javax.net.ssl.SSLSession;
+
+/**
+ * A persistent {@link javax.net.ssl.SSLSession} cache used by
+ * {@link javax.net.ssl.SSLSessionContext} to share server-side SSL sessions
+ * across processes. For example, this cache enables one server to resume
+ * a session started by a different server based on a session ID provided
+ * by the client.
+ *
+ * <p>The {@code SSLSessionContext} implementation converts
+ * {@code SSLSession}s into raw bytes and vice versa. The exact makeup of the
+ * session data is dependent upon the caller's implementation and is opaque to
+ * the {@code SSLServerSessionCache} implementation.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface SSLServerSessionCache {
+ /**
+ * Gets the session data for given session ID.
+ *
+ * @param id from {@link javax.net.ssl.SSLSession#getId()}
+ * @return the session data or null if none is cached
+ * @throws NullPointerException if id is null
+ */
+ byte[] getSessionData(byte[] id);
+
+ /**
+ * Stores session data for the given session.
+ *
+ * @param session to cache data for
+ * @param sessionData to cache
+ * @throws NullPointerException if session or data is null
+ */
+ void putSessionData(SSLSession session, byte[] sessionData);
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/SSLUtils.java b/repackaged/common/src/main/java/com/android/org/conscrypt/SSLUtils.java
new file mode 100644
index 0000000..daf6607
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/SSLUtils.java
@@ -0,0 +1,576 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+/*
+ * Copyright 2016 The Netty Project
+ *
+ * The Netty Project licenses this file to you 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.NativeConstants.SSL3_RT_ALERT;
+import static com.android.org.conscrypt.NativeConstants.SSL3_RT_APPLICATION_DATA;
+import static com.android.org.conscrypt.NativeConstants.SSL3_RT_CHANGE_CIPHER_SPEC;
+import static com.android.org.conscrypt.NativeConstants.SSL3_RT_HANDSHAKE;
+import static com.android.org.conscrypt.NativeConstants.SSL3_RT_HEADER_LENGTH;
+import static com.android.org.conscrypt.NativeConstants.SSL3_RT_MAX_PACKET_SIZE;
+import static java.lang.Math.min;
+import static java.nio.charset.StandardCharsets.US_ASCII;
+
+import java.io.ByteArrayInputStream;
+import java.nio.ByteBuffer;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+
+/**
+ * Utility methods for SSL packet processing. Copied from the Netty project.
+ * <p>
+ * This is a public class to allow testing to occur on Android via CTS.
+ */
+final class SSLUtils {
+ static final boolean USE_ENGINE_SOCKET_BY_DEFAULT = Boolean.parseBoolean(
+ System.getProperty("com.android.org.conscrypt.useEngineSocketByDefault", "true"));
+ private static final int MAX_PROTOCOL_LENGTH = 255;
+
+ // TODO(nathanmittler): Should these be in NativeConstants?
+ enum SessionType {
+ /**
+ * Identifies OpenSSL sessions.
+ */
+ OPEN_SSL(1),
+
+ /**
+ * Identifies OpenSSL sessions with OCSP stapled data.
+ */
+ OPEN_SSL_WITH_OCSP(2),
+
+ /**
+ * Identifies OpenSSL sessions with TLS SCT data.
+ */
+ OPEN_SSL_WITH_TLS_SCT(3);
+
+ SessionType(int value) {
+ this.value = value;
+ }
+
+ static boolean isSupportedType(int type) {
+ return type == OPEN_SSL.value || type == OPEN_SSL_WITH_OCSP.value
+ || type == OPEN_SSL_WITH_TLS_SCT.value;
+ }
+
+ final int value;
+ }
+
+ /**
+ * States for SSL engines.
+ */
+ static final class EngineStates {
+ private EngineStates() {}
+
+ /**
+ * The engine is constructed, but the initial handshake hasn't been started
+ */
+ static final int STATE_NEW = 0;
+
+ /**
+ * The client/server mode of the engine has been set.
+ */
+ static final int STATE_MODE_SET = 1;
+
+ /**
+ * The handshake has been started
+ */
+ static final int STATE_HANDSHAKE_STARTED = 2;
+
+ /**
+ * Listeners of the handshake have been notified of completion but the handshake call
+ * hasn't returned.
+ */
+ static final int STATE_HANDSHAKE_COMPLETED = 3;
+
+ /**
+ * The handshake call returned but the listeners have not yet been notified. This is expected
+ * behaviour in cut-through mode, where SSL_do_handshake returns before the handshake is
+ * complete. We can now start writing data to the socket.
+ */
+ static final int STATE_READY_HANDSHAKE_CUT_THROUGH = 4;
+
+ /**
+ * The handshake call has returned and the listeners have been notified. Ready to begin
+ * writing data.
+ */
+ static final int STATE_READY = 5;
+
+ /**
+ * The inbound direction of the engine has been closed.
+ */
+ static final int STATE_CLOSED_INBOUND = 6;
+
+ /**
+ * The outbound direction of the engine has been closed.
+ */
+ static final int STATE_CLOSED_OUTBOUND = 7;
+
+ /**
+ * The engine has been closed.
+ */
+ static final int STATE_CLOSED = 8;
+ }
+
+ /**
+ * This is the maximum overhead when encrypting plaintext as defined by
+ * <a href="https://www.ietf.org/rfc/rfc5246.txt">rfc5264</a>,
+ * <a href="https://www.ietf.org/rfc/rfc5289.txt">rfc5289</a>, and the BoringSSL
+ * implementation itself.
+ * <p>
+ * Please note that we use a padding of 16 here as BoringSSL uses PKCS#5 which uses 16 bytes
+ * while the spec itself allow up to 255 bytes. 16 bytes is the max for PKCS#5 (which handles it
+ * the same way as PKCS#7) as we use a block size of 16. See <a
+ * href="https://tools.ietf.org/html/rfc5652#section-6.3">rfc5652#section-6.3</a>.
+ * <p>
+ * 16 (IV) + 48 (MAC) + 1 (Padding_length field) + 15 (Padding)
+ * + 1 (ContentType in TLSCiphertext) + 2 (ProtocolVersion) + 2 (Length)
+ * + 1 (ContentType in TLSInnerPlaintext)
+ */
+ private static final int MAX_ENCRYPTION_OVERHEAD_LENGTH = 15 + 48 + 1 + 16 + 1 + 2 + 2 + 1;
+
+ private static final int MAX_ENCRYPTION_OVERHEAD_DIFF =
+ Integer.MAX_VALUE - MAX_ENCRYPTION_OVERHEAD_LENGTH;
+
+ /** Key type: RSA certificate. */
+ private static final String KEY_TYPE_RSA = "RSA";
+
+ /** Key type: Elliptic Curve certificate. */
+ private static final String KEY_TYPE_EC = "EC";
+
+ static X509Certificate[] decodeX509CertificateChain(byte[][] certChain)
+ throws java.security.cert.CertificateException {
+ CertificateFactory certificateFactory = getCertificateFactory();
+ int numCerts = certChain.length;
+ X509Certificate[] decodedCerts = new X509Certificate[numCerts];
+ for (int i = 0; i < numCerts; i++) {
+ decodedCerts[i] = decodeX509Certificate(certificateFactory, certChain[i]);
+ }
+ return decodedCerts;
+ }
+
+ private static CertificateFactory getCertificateFactory() {
+ try {
+ return CertificateFactory.getInstance("X.509");
+ } catch (java.security.cert.CertificateException e) {
+ return null;
+ }
+ }
+
+ private static X509Certificate decodeX509Certificate(CertificateFactory certificateFactory,
+ byte[] bytes) throws java.security.cert.CertificateException {
+ if (certificateFactory != null) {
+ return (X509Certificate) certificateFactory.generateCertificate(
+ new ByteArrayInputStream(bytes));
+ }
+ return OpenSSLX509Certificate.fromX509Der(bytes);
+ }
+
+ /**
+ * Returns key type constant suitable for calling X509KeyManager.chooseServerAlias or
+ * X509ExtendedKeyManager.chooseEngineServerAlias. Returns {@code null} for key exchanges that
+ * do not use X.509 for server authentication.
+ */
+ static String getServerX509KeyType(long sslCipherNative) {
+ String kx_name = NativeCrypto.SSL_CIPHER_get_kx_name(sslCipherNative);
+ if (kx_name.equals("RSA") || kx_name.equals("DHE_RSA") || kx_name.equals("ECDHE_RSA")) {
+ return KEY_TYPE_RSA;
+ } else if (kx_name.equals("ECDHE_ECDSA")) {
+ return KEY_TYPE_EC;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Similar to getServerKeyType, but returns value given TLS
+ * ClientCertificateType byte values from a CertificateRequest
+ * message for use with X509KeyManager.chooseClientAlias or
+ * X509ExtendedKeyManager.chooseEngineClientAlias.
+ * <p>
+ * Visible for testing.
+ */
+ static String getClientKeyType(byte clientCertificateType) {
+ // See also
+ // https://www.ietf.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-2
+ switch (clientCertificateType) {
+ case NativeConstants.TLS_CT_RSA_SIGN:
+ return KEY_TYPE_RSA; // RFC rsa_sign
+ case NativeConstants.TLS_CT_ECDSA_SIGN:
+ return KEY_TYPE_EC; // RFC ecdsa_sign
+ default:
+ return null;
+ }
+ }
+
+ static String getClientKeyTypeFromSignatureAlg(int signatureAlg) {
+ // See also
+ // https://www.ietf.org/assignments/tls-parameters/tls-parameters.xml#tls-signaturescheme
+ switch (NativeCrypto.SSL_get_signature_algorithm_key_type(signatureAlg)) {
+ case NativeConstants.EVP_PKEY_RSA:
+ return KEY_TYPE_RSA;
+ case NativeConstants.EVP_PKEY_EC:
+ return KEY_TYPE_EC;
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Gets the supported key types for client certificates based on the
+ * {@code ClientCertificateType} values provided by the server.
+ *
+ * @param clientCertificateTypes
+ * {@code ClientCertificateType} values provided by the server.
+ * See https://www.ietf.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-2.
+ * @param signatureAlgs
+ * {@code SignatureScheme} values provided by the server.
+ * See https://www.ietf.org/assignments/tls-parameters/tls-parameters.xml#tls-signaturescheme
+ * @return supported key types that can be used in {@code X509KeyManager.chooseClientAlias} and
+ * {@code X509ExtendedKeyManager.chooseEngineClientAlias}. If the inputs imply a preference
+ * order, the returned set will have an iteration order that respects that preference order,
+ * otherwise it will be in an arbitrary order.
+ *
+ * Visible for testing.
+ */
+ static Set<String> getSupportedClientKeyTypes(byte[] clientCertificateTypes,
+ int[] signatureAlgs) {
+ Set<String> fromClientCerts = new HashSet<>(clientCertificateTypes.length);
+ for (byte keyTypeCode : clientCertificateTypes) {
+ String keyType = SSLUtils.getClientKeyType(keyTypeCode);
+ if (keyType == null) {
+ // Unsupported client key type -- ignore
+ continue;
+ }
+ fromClientCerts.add(keyType);
+ }
+ // Signature algorithms are listed in preference order
+ Set<String> fromSigAlgs = new LinkedHashSet<>(signatureAlgs.length);
+ for (int signatureAlg : signatureAlgs) {
+ String keyType = SSLUtils.getClientKeyTypeFromSignatureAlg(signatureAlg);
+ if (keyType == null) {
+ // Unsupported client key type -- ignore
+ continue;
+ }
+ fromSigAlgs.add(keyType);
+ }
+ // If both are specified, the key needs to meet both sets of requirements. Otherwise,
+ // just meet the set of requirements that were specified. See RFC 5246, section 7.4.4.
+ // (In TLS 1.3, certificate_types is no longer used and is never present.)
+ if (clientCertificateTypes.length > 0 && signatureAlgs.length > 0) {
+ fromSigAlgs.retainAll(fromClientCerts);
+ return fromSigAlgs;
+ } else if (signatureAlgs.length > 0) {
+ return fromSigAlgs;
+ } else {
+ return fromClientCerts;
+ }
+ }
+
+ static byte[][] encodeSubjectX509Principals(X509Certificate[] certificates)
+ throws CertificateEncodingException {
+ byte[][] principalBytes = new byte[certificates.length][];
+ for (int i = 0; i < certificates.length; i++) {
+ principalBytes[i] = certificates[i].getSubjectX500Principal().getEncoded();
+ }
+ return principalBytes;
+ }
+
+ /**
+ * Converts the peer certificates into a cert chain.
+ */
+ @SuppressWarnings("deprecation") // Used in public Conscrypt APIs
+ static javax.security.cert.X509Certificate[] toCertificateChain(X509Certificate[] certificates)
+ throws SSLPeerUnverifiedException {
+ try {
+ javax.security.cert.X509Certificate[] chain =
+ new javax.security.cert.X509Certificate[certificates.length];
+
+ for (int i = 0; i < certificates.length; i++) {
+ byte[] encoded = certificates[i].getEncoded();
+ chain[i] = javax.security.cert.X509Certificate.getInstance(encoded);
+ }
+ return chain;
+ } catch (CertificateEncodingException | javax.security.cert.CertificateException e) {
+ SSLPeerUnverifiedException exception = new SSLPeerUnverifiedException(e.getMessage());
+ exception.initCause(e);
+ throw exception;
+ }
+ }
+
+ /**
+ * Calculates the minimum bytes required in the encrypted output buffer for the given number of
+ * plaintext source bytes.
+ */
+ static int calculateOutNetBufSize(int pendingBytes) {
+ return min(SSL3_RT_MAX_PACKET_SIZE,
+ MAX_ENCRYPTION_OVERHEAD_LENGTH + min(MAX_ENCRYPTION_OVERHEAD_DIFF, pendingBytes));
+ }
+
+ /**
+ * Wraps the given exception if it's not already a {@link SSLHandshakeException}.
+ */
+ static SSLHandshakeException toSSLHandshakeException(Throwable e) {
+ if (e instanceof SSLHandshakeException) {
+ return (SSLHandshakeException) e;
+ }
+
+ return (SSLHandshakeException) new SSLHandshakeException(e.getMessage()).initCause(e);
+ }
+
+ /**
+ * Wraps the given exception if it's not already a {@link SSLException}.
+ */
+ static SSLException toSSLException(Throwable e) {
+ if (e instanceof SSLException) {
+ return (SSLException) e;
+ }
+ return new SSLException(e);
+ }
+
+ static String toProtocolString(byte[] bytes) {
+ if (bytes == null) {
+ return null;
+ }
+ return new String(bytes, US_ASCII);
+ }
+
+ static byte[] toProtocolBytes(String protocol) {
+ if (protocol == null) {
+ return null;
+ }
+ return protocol.getBytes(US_ASCII);
+ }
+
+ /**
+ * Decodes the given list of protocols into {@link String}s.
+ * @param protocols the encoded protocol list
+ * @return the decoded protocols or {@link EmptyArray#BYTE} if {@code protocols} is
+ * empty.
+ * @throws NullPointerException if protocols is {@code null}.
+ */
+ static String[] decodeProtocols(byte[] protocols) {
+ if (protocols.length == 0) {
+ return EmptyArray.STRING;
+ }
+
+ int numProtocols = 0;
+ for (int i = 0; i < protocols.length;) {
+ int protocolLength = protocols[i];
+ if (protocolLength < 0 || protocolLength > protocols.length - i) {
+ throw new IllegalArgumentException(
+ "Protocol has invalid length (" + protocolLength + " at position " + i
+ + "): " + (protocols.length < 50
+ ? Arrays.toString(protocols) : protocols.length + " byte array"));
+ }
+
+ numProtocols++;
+ i += 1 + protocolLength;
+ }
+
+ String[] decoded = new String[numProtocols];
+ for (int i = 0, d = 0; i < protocols.length;) {
+ int protocolLength = protocols[i];
+ decoded[d++] = protocolLength > 0
+ ? new String(protocols, i + 1, protocolLength, US_ASCII)
+ : "";
+ i += 1 + protocolLength;
+ }
+
+ return decoded;
+ }
+
+ /**
+ * Encodes a list of protocols into the wire-format (length-prefixed 8-bit strings).
+ * Requires that all strings be encoded with US-ASCII.
+ *
+ * @param protocols the list of protocols to be encoded
+ * @return the encoded form of the protocol list.
+ * @throws IllegalArgumentException if protocols is {@code null}, or if any element is
+ * {@code null} or an empty string.
+ */
+ static byte[] encodeProtocols(String[] protocols) {
+ if (protocols == null) {
+ throw new IllegalArgumentException("protocols array must be non-null");
+ }
+
+ if (protocols.length == 0) {
+ return EmptyArray.BYTE;
+ }
+
+ // Calculate the encoded length.
+ int length = 0;
+ for (int i = 0; i < protocols.length; ++i) {
+ String protocol = protocols[i];
+ if (protocol == null) {
+ throw new IllegalArgumentException("protocol[" + i + "] is null");
+ }
+ int protocolLength = protocols[i].length();
+
+ // Verify that the length is valid here, so that we don't attempt to allocate an array
+ // below if the threshold is violated.
+ if (protocolLength == 0 || protocolLength > MAX_PROTOCOL_LENGTH) {
+ throw new IllegalArgumentException(
+ "protocol[" + i + "] has invalid length: " + protocolLength);
+ }
+
+ // Include a 1-byte prefix for each protocol.
+ length += 1 + protocolLength;
+ }
+
+ byte[] data = new byte[length];
+ for (int dataIndex = 0, i = 0; i < protocols.length; ++i) {
+ String protocol = protocols[i];
+ int protocolLength = protocol.length();
+
+ // Add the length prefix.
+ data[dataIndex++] = (byte) protocolLength;
+ for (int ci = 0; ci < protocolLength; ++ci) {
+ char c = protocol.charAt(ci);
+ if (c > Byte.MAX_VALUE) {
+ // Enforce US-ASCII
+ throw new IllegalArgumentException("Protocol contains invalid character: "
+ + c + "(protocol=" + protocol + ")");
+ }
+ data[dataIndex++] = (byte) c;
+ }
+ }
+ return data;
+ }
+
+ /**
+ * Return how many bytes can be read out of the encrypted data. Be aware that this method will
+ * not increase the readerIndex of the given {@link ByteBuffer}.
+ *
+ * @param buffers The {@link ByteBuffer}s to read from. Be aware that they must have at least
+ * {@link com.android.org.conscrypt.NativeConstants#SSL3_RT_HEADER_LENGTH} bytes to read,
+ * otherwise it will throw an {@link IllegalArgumentException}.
+ * @return length The length of the encrypted packet that is included in the buffer. This will
+ * return {@code -1} if the given {@link ByteBuffer} is not encrypted at all.
+ * @throws IllegalArgumentException Is thrown if the given {@link ByteBuffer} has not at least
+ * {@link com.android.org.conscrypt.NativeConstants#SSL3_RT_HEADER_LENGTH} bytes to read.
+ */
+ static int getEncryptedPacketLength(ByteBuffer[] buffers, int offset) {
+ ByteBuffer buffer = buffers[offset];
+
+ // Check if everything we need is in one ByteBuffer. If so we can make use of the fast-path.
+ if (buffer.remaining() >= SSL3_RT_HEADER_LENGTH) {
+ return getEncryptedPacketLength(buffer);
+ }
+
+ // We need to copy 5 bytes into a temporary buffer so we can parse out the packet length
+ // easily.
+ ByteBuffer tmp = ByteBuffer.allocate(SSL3_RT_HEADER_LENGTH);
+ do {
+ buffer = buffers[offset++];
+ int pos = buffer.position();
+ int limit = buffer.limit();
+ if (buffer.remaining() > tmp.remaining()) {
+ buffer.limit(pos + tmp.remaining());
+ }
+ try {
+ tmp.put(buffer);
+ } finally {
+ // Restore the original indices.
+ buffer.limit(limit);
+ buffer.position(pos);
+ }
+ } while (tmp.hasRemaining());
+
+ // Done, flip the buffer so we can read from it.
+ tmp.flip();
+ return getEncryptedPacketLength(tmp);
+ }
+
+ private static int getEncryptedPacketLength(ByteBuffer buffer) {
+ int pos = buffer.position();
+ // SSLv3 or TLS - Check ContentType
+ switch (unsignedByte(buffer.get(pos))) {
+ case SSL3_RT_CHANGE_CIPHER_SPEC:
+ case SSL3_RT_ALERT:
+ case SSL3_RT_HANDSHAKE:
+ case SSL3_RT_APPLICATION_DATA:
+ break;
+ default:
+ // SSLv2 or bad data
+ return -1;
+ }
+
+ // SSLv3 or TLS - Check ProtocolVersion
+ int majorVersion = unsignedByte(buffer.get(pos + 1));
+ if (majorVersion != 3) {
+ // Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data)
+ return -1;
+ }
+
+ // SSLv3 or TLS
+ int packetLength = unsignedShort(buffer.getShort(pos + 3)) + SSL3_RT_HEADER_LENGTH;
+ if (packetLength <= SSL3_RT_HEADER_LENGTH) {
+ // Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data)
+ return -1;
+ }
+ return packetLength;
+ }
+
+ private static short unsignedByte(byte b) {
+ return (short) (b & 0xFF);
+ }
+
+ private static int unsignedShort(short s) {
+ return s & 0xFFFF;
+ }
+
+ static String[] concat(String[]... arrays) {
+ int resultLength = 0;
+ for (String[] array : arrays) {
+ resultLength += array.length;
+ }
+ String[] result = new String[resultLength];
+ int resultOffset = 0;
+ for (String[] array : arrays) {
+ System.arraycopy(array, 0, result, resultOffset, array.length);
+ resultOffset += array.length;
+ }
+ return result;
+ }
+
+ private SSLUtils() {}
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ServerSessionContext.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ServerSessionContext.java
new file mode 100644
index 0000000..1be9883
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ServerSessionContext.java
@@ -0,0 +1,89 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt;
+
+import javax.net.ssl.SSLContext;
+
+/**
+ * Caches server sessions. Indexes by session ID. Users typically look up
+ * sessions using the ID provided by an SSL client.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class ServerSessionContext extends AbstractSessionContext {
+ private SSLServerSessionCache persistentCache;
+
+ ServerSessionContext() {
+ super(100);
+
+ // TODO make sure SSL_CTX does not automaticaly clear sessions we want it to cache
+ // SSL_CTX_set_session_cache_mode(sslCtxNativePointer, SSL_SESS_CACHE_NO_AUTO_CLEAR);
+
+ // TODO remove SSL_CTX session cache limit so we can manage it
+ // SSL_CTX_sess_set_cache_size(sslCtxNativePointer, 0);
+
+ // TODO override trimToSize and removeEldestEntry to use
+ // SSL_CTX_sessions to remove from native cache
+
+ // Set a trivial session id context. OpenSSL uses this to make
+ // sure you don't reuse sessions externalized with i2d_SSL_SESSION
+ // between apps. However our sessions are either in memory or
+ // exported to a app's SSLServerSessionCache.
+ NativeCrypto.SSL_CTX_set_session_id_context(sslCtxNativePointer, this, new byte[] { ' ' });
+ }
+
+ /**
+ * Applications should not use this method. Instead use {@link
+ * Conscrypt#setServerSessionCache(SSLContext, SSLServerSessionCache)}.
+ */
+ public void setPersistentCache(SSLServerSessionCache persistentCache) {
+ this.persistentCache = persistentCache;
+ }
+
+ @Override
+ NativeSslSession getSessionFromPersistentCache(byte[] sessionId) {
+ if (persistentCache != null) {
+ byte[] data = persistentCache.getSessionData(sessionId);
+ if (data != null) {
+ NativeSslSession session = NativeSslSession.newInstance(this, data, null, -1);
+ if (session != null && session.isValid()) {
+ cacheSession(session);
+ return session;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ void onBeforeAddSession(NativeSslSession session) {
+ // TODO: Do this in background thread.
+ if (persistentCache != null) {
+ byte[] data = session.toBytes();
+ if (data != null) {
+ persistentCache.putSessionData(session.toSSLSession(), data);
+ }
+ }
+ }
+
+ @Override
+ void onBeforeRemoveSession(NativeSslSession session) {
+ // Do nothing.
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/SessionSnapshot.java b/repackaged/common/src/main/java/com/android/org/conscrypt/SessionSnapshot.java
new file mode 100644
index 0000000..5950080
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/SessionSnapshot.java
@@ -0,0 +1,199 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSessionContext;
+
+/**
+ * A snapshot of the content of another {@link ConscryptSession}. This copies everything over
+ * except for the certificates.
+ */
+final class SessionSnapshot implements ConscryptSession {
+ private final SSLSessionContext sessionContext;
+ private final byte[] id;
+ private final String requestedServerName;
+ private final List<byte[]> statusResponses;
+ private final byte[] peerTlsSctData;
+ private final long creationTime;
+ private final long lastAccessedTime;
+ private final String cipherSuite;
+ private final String protocol;
+ private final String peerHost;
+ private final String applicationProtocol;
+ private final int peerPort;
+
+ SessionSnapshot(ConscryptSession session) {
+ sessionContext = session.getSessionContext();
+ id = session.getId();
+ requestedServerName = session.getRequestedServerName();
+ statusResponses = session.getStatusResponses();
+ peerTlsSctData = session.getPeerSignedCertificateTimestamp();
+ creationTime = session.getCreationTime();
+ lastAccessedTime = session.getLastAccessedTime();
+ cipherSuite = session.getCipherSuite();
+ protocol = session.getProtocol();
+ peerHost = session.getPeerHost();
+ peerPort = session.getPeerPort();
+ applicationProtocol = session.getApplicationProtocol();
+ }
+
+ @Override
+ public String getRequestedServerName() {
+ return requestedServerName;
+ }
+
+ @Override
+ public List<byte[]> getStatusResponses() {
+ List<byte[]> ret = new ArrayList<>(statusResponses.size());
+ for (byte[] resp : statusResponses) {
+ ret.add(resp.clone());
+ }
+ return ret;
+ }
+
+ @Override
+ public byte[] getPeerSignedCertificateTimestamp() {
+ return peerTlsSctData != null ? peerTlsSctData.clone() : null;
+ }
+
+ @Override
+ public byte[] getId() {
+ return id;
+ }
+
+ @Override
+ public SSLSessionContext getSessionContext() {
+ return sessionContext;
+ }
+
+ @Override
+ public long getCreationTime() {
+ return creationTime;
+ }
+
+ @Override
+ public long getLastAccessedTime() {
+ return lastAccessedTime;
+ }
+
+ @Override
+ public void invalidate() {
+ // Do nothing.
+ }
+
+ @Override
+ public boolean isValid() {
+ return false;
+ }
+
+ @Override
+ public void putValue(String s, Object o) {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ExternalSession.");
+ }
+
+ @Override
+ public Object getValue(String s) {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ExternalSession.");
+ }
+
+ @Override
+ public void removeValue(String s) {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ExternalSession.");
+ }
+
+ @Override
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ExternalSession.");
+ }
+
+ @Override
+ public X509Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ throw new SSLPeerUnverifiedException("No peer certificates");
+ }
+
+ @Override
+ public Certificate[] getLocalCertificates() {
+ return null;
+ }
+
+ @Override
+ @SuppressWarnings("deprecation") // Public API
+ public javax.security.cert.X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ if (!Platform.isJavaxCertificateSupported()) {
+ throw new UnsupportedOperationException("Use getPeerCertificates() instead");
+ }
+
+ throw new SSLPeerUnverifiedException("No peer certificates");
+ }
+
+ @Override
+ public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+ throw new SSLPeerUnverifiedException("No peer certificates");
+ }
+
+ @Override
+ public Principal getLocalPrincipal() {
+ return null;
+ }
+
+ @Override
+ public String getCipherSuite() {
+ return cipherSuite;
+ }
+
+ @Override
+ public String getProtocol() {
+ return protocol;
+ }
+
+ @Override
+ public String getPeerHost() {
+ return peerHost;
+ }
+
+ @Override
+ public int getPeerPort() {
+ return peerPort;
+ }
+
+ @Override
+ public int getPacketBufferSize() {
+ return NativeConstants.SSL3_RT_MAX_PACKET_SIZE;
+ }
+
+ @Override
+ public int getApplicationBufferSize() {
+ return NativeConstants.SSL3_RT_MAX_PLAIN_LENGTH;
+ }
+
+ @Override
+ public String getApplicationProtocol() {
+ return applicationProtocol;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ShortBufferWithoutStackTraceException.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ShortBufferWithoutStackTraceException.java
new file mode 100644
index 0000000..d01ca64
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ShortBufferWithoutStackTraceException.java
@@ -0,0 +1,43 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package com.android.org.conscrypt;
+
+import javax.crypto.ShortBufferException;
+
+/**
+ * This class basically does the same thing the ShortBufferException class does
+ * except not filling in stack trace in the exception to save CPU-time for it
+ * in an environment where this can be thrown many times. e.g. OpenJDK 8.
+ */
+@Internal
+final class ShortBufferWithoutStackTraceException extends ShortBufferException {
+ private static final long serialVersionUID = 676150236007842683L;
+
+ public ShortBufferWithoutStackTraceException() {
+ super();
+ }
+
+ public ShortBufferWithoutStackTraceException(String msg) {
+ super(msg);
+ }
+
+ @Override
+ public synchronized Throwable fillInStackTrace() {
+ return this;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/TEST_MAPPING b/repackaged/common/src/main/java/com/android/org/conscrypt/TEST_MAPPING
new file mode 100644
index 0000000..317e347
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsLibcoreTestCases",
+ "options": [
+ {
+ "include-filter": "com.android.org.conscrypt"
+ },
+ {
+ "include-filter": "libcore.java.security"
+ }
+ ]
+ }
+ ]
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/TrustManagerFactoryImpl.java b/repackaged/common/src/main/java/com/android/org/conscrypt/TrustManagerFactoryImpl.java
new file mode 100644
index 0000000..438b73f
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/TrustManagerFactoryImpl.java
@@ -0,0 +1,90 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+// License from Apache Harmony:
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import javax.net.ssl.ManagerFactoryParameters;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactorySpi;
+
+/**
+ *
+ * TrustManagerFactory service provider interface implementation.
+ *
+ * @see javax.net.ssl.TrustManagerFactorySpi
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class TrustManagerFactoryImpl extends TrustManagerFactorySpi {
+
+ private KeyStore keyStore;
+
+ /**
+ * @see javax.net.ssl.TrustManagerFactorySpi#engineInit(KeyStore)
+ */
+ @Override
+ public void engineInit(KeyStore ks) throws KeyStoreException {
+ if (ks != null) {
+ keyStore = ks;
+ } else {
+ keyStore = Platform.getDefaultCertKeyStore();
+ }
+ }
+
+ /**
+ * @see javax.net.ssl#engineInit(ManagerFactoryParameters)
+ */
+ @Override
+ public void engineInit(ManagerFactoryParameters spec)
+ throws InvalidAlgorithmParameterException {
+ throw new InvalidAlgorithmParameterException(
+ "ManagerFactoryParameters not supported");
+ }
+
+ /**
+ * @see javax.net.ssl#engineGetTrustManagers()
+ */
+ @Override
+ public TrustManager[] engineGetTrustManagers() {
+ if (keyStore == null) {
+ throw new IllegalStateException(
+ "TrustManagerFactory is not initialized");
+ }
+ return new TrustManager[] { new TrustManagerImpl(keyStore) };
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/TrustManagerImpl.java b/repackaged/common/src/main/java/com/android/org/conscrypt/TrustManagerImpl.java
new file mode 100644
index 0000000..76c8efd
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/TrustManagerImpl.java
@@ -0,0 +1,1047 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+// License from Apache Harmony:
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package com.android.org.conscrypt;
+
+import com.android.org.conscrypt.ct.CTLogStore;
+import com.android.org.conscrypt.ct.CTPolicy;
+import com.android.org.conscrypt.ct.CTVerificationResult;
+import com.android.org.conscrypt.ct.CTVerifier;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.Socket;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.PKIXParameters;
+import java.security.cert.PKIXRevocationChecker;
+import java.security.cert.PKIXRevocationChecker.Option;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Logger;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.X509ExtendedTrustManager;
+
+/**
+ *
+ * TrustManager implementation. The implementation is based on CertPathValidator
+ * PKIX and CertificateFactory X509 implementations. This implementations should
+ * be provided by some certification provider.
+ *
+ * @see javax.net.ssl.X509ExtendedTrustManager
+ * @hide This class is not part of the Android public SDK API
+ */
+@libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+@Internal
+public final class TrustManagerImpl extends X509ExtendedTrustManager {
+ private static final Logger logger = Logger.getLogger(TrustManagerImpl.class.getName());
+
+ /**
+ * Comparator used for ordering trust anchors during certificate path building.
+ */
+ private static final TrustAnchorComparator TRUST_ANCHOR_COMPARATOR =
+ new TrustAnchorComparator();
+
+ private static final Set<Option> REVOCATION_CHECK_OPTIONS = revocationOptions();
+
+ private static ConscryptHostnameVerifier defaultHostnameVerifier;
+
+ /**
+ * The AndroidCAStore if non-null, null otherwise.
+ */
+ private final KeyStore rootKeyStore;
+
+ /**
+ * The CertPinManager, which validates the chain against a host-to-pin mapping
+ */
+ private CertPinManager pinManager;
+
+ /**
+ * The backing store for the AndroidCAStore if non-null. This will
+ * be null when the rootKeyStore is null, implying we are not
+ * using the AndroidCAStore.
+ */
+ private final ConscryptCertStore trustedCertificateStore;
+
+ private final CertPathValidator validator;
+
+ /**
+ * An index of TrustAnchor instances that we've seen.
+ */
+ private final TrustedCertificateIndex trustedCertificateIndex;
+
+ /**
+ * An index of intermediate certificates that we've seen. These certificates are NOT implicitly
+ * trusted and must still form a valid chain to an anchor.
+ */
+ private final TrustedCertificateIndex intermediateIndex;
+
+ /**
+ * This is lazily initialized in the AndroidCAStore case since it
+ * forces us to bring all the CAs into memory. In the
+ * non-AndroidCAStore, we initialize this as part of the
+ * constructor.
+ */
+ private final X509Certificate[] acceptedIssuers;
+
+ private final Exception err;
+ private final CertificateFactory factory;
+ private final CertBlocklist blocklist;
+ private CTVerifier ctVerifier;
+ private CTPolicy ctPolicy;
+
+ private ConscryptHostnameVerifier hostnameVerifier;
+
+ // Forces CT verification to always to done. For tests.
+ private boolean ctEnabledOverride;
+
+ /**
+ * Creates X509TrustManager based on a keystore
+ */
+ @android.compat.annotation.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public TrustManagerImpl(KeyStore keyStore) {
+ this(keyStore, null);
+ }
+
+ public TrustManagerImpl(KeyStore keyStore, CertPinManager manager) {
+ this(keyStore, manager, null);
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public TrustManagerImpl(
+ KeyStore keyStore, CertPinManager manager, ConscryptCertStore certStore) {
+ this(keyStore, manager, certStore, null);
+ }
+
+ public TrustManagerImpl(KeyStore keyStore, CertPinManager manager, ConscryptCertStore certStore,
+ CertBlocklist blocklist) {
+ this(keyStore, manager, certStore, blocklist, null, null, null);
+ }
+
+ /**
+ * For testing only.
+ */
+ public TrustManagerImpl(KeyStore keyStore, CertPinManager manager, ConscryptCertStore certStore,
+ CertBlocklist blocklist, CTLogStore ctLogStore, CTVerifier ctVerifier,
+ CTPolicy ctPolicy) {
+ CertPathValidator validatorLocal = null;
+ CertificateFactory factoryLocal = null;
+ KeyStore rootKeyStoreLocal = null;
+ ConscryptCertStore trustedCertificateStoreLocal = null;
+ TrustedCertificateIndex trustedCertificateIndexLocal = null;
+ X509Certificate[] acceptedIssuersLocal = null;
+ Exception errLocal = null;
+ try {
+ validatorLocal = CertPathValidator.getInstance("PKIX");
+ factoryLocal = CertificateFactory.getInstance("X509");
+
+ // if we have an AndroidCAStore, we will lazily load CAs
+ if ("AndroidCAStore".equals(keyStore.getType())
+ && Platform.supportsConscryptCertStore()) {
+ rootKeyStoreLocal = keyStore;
+ trustedCertificateStoreLocal =
+ (certStore != null) ? certStore : Platform.newDefaultCertStore();
+ acceptedIssuersLocal = null;
+ trustedCertificateIndexLocal = new TrustedCertificateIndex();
+ } else {
+ rootKeyStoreLocal = null;
+ trustedCertificateStoreLocal = certStore;
+ acceptedIssuersLocal = acceptedIssuers(keyStore);
+ trustedCertificateIndexLocal
+ = new TrustedCertificateIndex(trustAnchors(acceptedIssuersLocal));
+ }
+
+ } catch (Exception e) {
+ errLocal = e;
+ }
+
+ if (blocklist == null) {
+ blocklist = Platform.newDefaultBlocklist();
+ }
+ if (ctLogStore == null) {
+ ctLogStore = Platform.newDefaultLogStore();
+ }
+
+ if (ctPolicy == null) {
+ ctPolicy = Platform.newDefaultPolicy(ctLogStore);
+ }
+
+ this.pinManager = manager;
+ this.rootKeyStore = rootKeyStoreLocal;
+ this.trustedCertificateStore = trustedCertificateStoreLocal;
+ this.validator = validatorLocal;
+ this.factory = factoryLocal;
+ this.trustedCertificateIndex = trustedCertificateIndexLocal;
+ this.intermediateIndex = new TrustedCertificateIndex();
+ this.acceptedIssuers = acceptedIssuersLocal;
+ this.err = errLocal;
+ this.blocklist = blocklist;
+ this.ctVerifier = new CTVerifier(ctLogStore);
+ this.ctPolicy = ctPolicy;
+ }
+
+ @SuppressWarnings("JdkObsolete") // KeyStore#aliases is the only API available
+ private static X509Certificate[] acceptedIssuers(KeyStore ks) {
+ try {
+ // Note that unlike the PKIXParameters code to create a Set of
+ // TrustAnchors from a KeyStore, this version takes from both
+ // TrustedCertificateEntry and PrivateKeyEntry, not just
+ // TrustedCertificateEntry, which is why TrustManagerImpl
+ // cannot just use an PKIXParameters(KeyStore)
+ // constructor.
+
+ // TODO remove duplicates if same cert is found in both a
+ // PrivateKeyEntry and TrustedCertificateEntry
+ List<X509Certificate> trusted = new ArrayList<X509Certificate>();
+ for (Enumeration<String> en = ks.aliases(); en.hasMoreElements();) {
+ final String alias = en.nextElement();
+ final X509Certificate cert = (X509Certificate) ks.getCertificate(alias);
+ if (cert != null) {
+ trusted.add(cert);
+ }
+ }
+ return trusted.toArray(new X509Certificate[trusted.size()]);
+ } catch (KeyStoreException e) {
+ return new X509Certificate[0];
+ }
+ }
+
+ private static Set<TrustAnchor> trustAnchors(X509Certificate[] certs) {
+ Set<TrustAnchor> trustAnchors = new HashSet<TrustAnchor>(certs.length);
+ for (X509Certificate cert : certs) {
+ trustAnchors.add(new TrustAnchor(cert, null));
+ }
+ return trustAnchors;
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ checkTrusted(chain, authType, null, null, true /* client auth */);
+ }
+
+ /**
+ * For backward compatibility with older Android API that used String for the hostname only.
+ */
+ public List<X509Certificate> checkClientTrusted(X509Certificate[] chain, String authType,
+ String hostname) throws CertificateException {
+ return checkTrusted(chain, null /* ocspData */, null /* tlsSctData */, authType, hostname,
+ true);
+ }
+
+ private static SSLSession getHandshakeSessionOrThrow(SSLSocket sslSocket)
+ throws CertificateException {
+ SSLSession session = sslSocket.getHandshakeSession();
+ if (session == null) {
+ throw new CertificateException("Not in handshake; no session available");
+ }
+ return session;
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket)
+ throws CertificateException {
+ SSLSession session = null;
+ SSLParameters parameters = null;
+ if (socket instanceof SSLSocket) {
+ SSLSocket sslSocket = (SSLSocket) socket;
+ session = getHandshakeSessionOrThrow(sslSocket);
+ parameters = sslSocket.getSSLParameters();
+ }
+ checkTrusted(chain, authType, session, parameters, true /* client auth */);
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
+ throws CertificateException {
+ SSLSession session = engine.getHandshakeSession();
+ if (session == null) {
+ throw new CertificateException("Not in handshake; no session available");
+ }
+ checkTrusted(chain, authType, session, engine.getSSLParameters(), true /* client auth */);
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ checkTrusted(chain, authType, null, null, false /* client auth */);
+ }
+
+ /**
+ * For backward compatibility with older Android API that used String for the hostname only.
+ */
+ @android.compat.annotation.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public List<X509Certificate> checkServerTrusted(
+ X509Certificate[] chain, String authType, String hostname) throws CertificateException {
+ return checkTrusted(chain, null /* ocspData */, null /* tlsSctData */, authType, hostname,
+ false);
+ }
+
+ /**
+ * Returns the full trusted certificate chain found from {@code certs}.
+ *
+ * Throws {@link CertificateException} when no trusted chain can be found from {@code certs}.
+ */
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public List<X509Certificate> getTrustedChainForServer(
+ X509Certificate[] certs, String authType, Socket socket) throws CertificateException {
+ SSLSession session = null;
+ SSLParameters parameters = null;
+ if (socket instanceof SSLSocket) {
+ SSLSocket sslSocket = (SSLSocket) socket;
+ session = getHandshakeSessionOrThrow(sslSocket);
+ parameters = sslSocket.getSSLParameters();
+ }
+ return checkTrusted(certs, authType, session, parameters, false /* client auth */);
+ }
+
+ /**
+ * Returns the full trusted certificate chain found from {@code certs}.
+ *
+ * Throws {@link CertificateException} when no trusted chain can be found from {@code certs}.
+ */
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public List<X509Certificate> getTrustedChainForServer(X509Certificate[] certs, String authType,
+ SSLEngine engine) throws CertificateException {
+ SSLSession session = engine.getHandshakeSession();
+ if (session == null) {
+ throw new CertificateException("Not in handshake; no session available");
+ }
+ return checkTrusted(certs, authType, session, engine.getSSLParameters(),
+ false /* client auth */);
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket)
+ throws CertificateException {
+ getTrustedChainForServer(chain, authType, socket);
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
+ throws CertificateException {
+ getTrustedChainForServer(chain, authType, engine);
+ }
+
+ /**
+ * Validates whether a server is trusted. If session is given and non-null
+ * it also checks if chain is pinned appropriately for that peer host. If
+ * null, it does not check for pinned certs. The return value is a list of
+ * the certificates used for making the trust decision.
+ */
+ public List<X509Certificate> checkServerTrusted(X509Certificate[] chain, String authType,
+ SSLSession session) throws CertificateException {
+ return checkTrusted(chain, authType, session, null, false /* client auth */);
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public void handleTrustStorageUpdate() {
+ if (acceptedIssuers == null) {
+ trustedCertificateIndex.reset();
+ } else {
+ trustedCertificateIndex.reset(trustAnchors(acceptedIssuers));
+ }
+ }
+
+ private List<X509Certificate> checkTrusted(X509Certificate[] certs, String authType,
+ SSLSession session, SSLParameters parameters, boolean clientAuth)
+ throws CertificateException {
+ byte[] ocspData = null;
+ byte[] tlsSctData = null;
+ String hostname = null;
+ if (session != null) {
+ hostname = session.getPeerHost();
+ ocspData = getOcspDataFromSession(session);
+ tlsSctData = getTlsSctDataFromSession(session);
+ }
+
+ if (session != null && parameters != null) {
+ String identificationAlgorithm = parameters.getEndpointIdentificationAlgorithm();
+ if ("HTTPS".equalsIgnoreCase(identificationAlgorithm)) {
+ ConscryptHostnameVerifier verifier = getHttpsVerifier();
+ if (!verifier.verify(certs, hostname, session)) {
+ throw new CertificateException("No subjectAltNames on the certificate match");
+ }
+ }
+ }
+ return checkTrusted(certs, ocspData, tlsSctData, authType, hostname, clientAuth);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static byte[] getOcspDataFromSession(SSLSession session) {
+ List<byte[]> ocspResponses = null;
+ if (session instanceof ConscryptSession) {
+ ConscryptSession opensslSession = (ConscryptSession) session;
+ ocspResponses = opensslSession.getStatusResponses();
+ } else {
+ Method m_getResponses;
+ try {
+ m_getResponses = session.getClass().getDeclaredMethod("getStatusResponses");
+ m_getResponses.setAccessible(true);
+ Object rawResponses = m_getResponses.invoke(session);
+ if (rawResponses instanceof List) {
+ ocspResponses = (List<byte[]>) rawResponses;
+ }
+ } catch (NoSuchMethodException | SecurityException | IllegalAccessException
+ | IllegalArgumentException ignored) {
+ // Method not available, fall through and return null
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e.getCause());
+ }
+ }
+
+ if (ocspResponses == null || ocspResponses.isEmpty()) {
+ return null;
+ }
+
+ return ocspResponses.get(0);
+ }
+
+ private byte[] getTlsSctDataFromSession(SSLSession session) {
+ if (session instanceof ConscryptSession) {
+ ConscryptSession opensslSession = (ConscryptSession) session;
+ return opensslSession.getPeerSignedCertificateTimestamp();
+ }
+
+ byte[] data = null;
+ try {
+ Method m_getTlsSctData = session.getClass().getDeclaredMethod("getPeerSignedCertificateTimestamp");
+ m_getTlsSctData.setAccessible(true);
+ Object rawData = m_getTlsSctData.invoke(session);
+ if (rawData instanceof byte[]) {
+ data = (byte[]) rawData;
+ }
+ } catch (NoSuchMethodException | SecurityException | IllegalAccessException
+ | IllegalArgumentException ignored) {
+ // Method not available, fall through and return null
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e.getCause());
+ }
+ return data;
+ }
+
+ private List<X509Certificate> checkTrusted(X509Certificate[] certs, byte[] ocspData,
+ byte[] tlsSctData, String authType, String host, boolean clientAuth)
+ throws CertificateException {
+ if (certs == null || certs.length == 0 || authType == null || authType.length() == 0) {
+ throw new IllegalArgumentException("null or zero-length parameter");
+ }
+ if (err != null) {
+ throw new CertificateException(err);
+ }
+ Set<X509Certificate> used = new HashSet<X509Certificate>();
+ ArrayList<X509Certificate> untrustedChain = new ArrayList<X509Certificate>();
+ ArrayList<TrustAnchor> trustedChain = new ArrayList<TrustAnchor>();
+ // Initialize the chain to contain the leaf certificate. This potentially could be a trust
+ // anchor. If the leaf is a trust anchor we still continue with path building to build the
+ // complete trusted chain for additional validation such as certificate pinning.
+ X509Certificate leaf = certs[0];
+ TrustAnchor leafAsAnchor = findTrustAnchorBySubjectAndPublicKey(leaf);
+ if (leafAsAnchor != null) {
+ trustedChain.add(leafAsAnchor);
+ used.add(leafAsAnchor.getTrustedCert());
+ } else {
+ untrustedChain.add(leaf);
+ }
+ used.add(leaf);
+ return checkTrustedRecursive(certs, ocspData, tlsSctData, host, clientAuth,
+ untrustedChain, trustedChain, used);
+ }
+
+ /**
+ * Recursively build certificate chains until a valid chain is found or all possible paths are
+ * exhausted.
+ *
+ * The chain is built in two sections, the complete trusted path is the the combination of
+ * {@code untrustedChain} and {@code trustAnchorChain}. The chain begins at the leaf
+ * certificate and ends in the final trusted root certificate.
+ *
+ * @param certs the bag of certs provided by the peer. No order is assumed.
+ * @param host the host being connected to.
+ * @param clientAuth if a client is being authorized instead of a server.
+ * @param untrustedChain the untrusted section of the chain built so far. Must be mutable.
+ * @param trustAnchorChain the trusted section of the chain built so far. Must be mutable.
+ * @param used the set certificates used so far in path building. Must be mutable.
+ *
+ * @return The entire valid chain starting with the leaf certificate. This is the
+ * concatenation of untrustedChain and trustAnchorChain.
+ *
+ * @throws CertificateException If no valid chain could be constructed. Note that there may be
+ * multiple reasons why no valid chain exists and there is no guarantee that the most severe is
+ * reported in this exception. As such applications MUST NOT use the specifics of this error
+ * for trust decisions (e.g. showing the user a click through page based on the specific error).
+ */
+ private List<X509Certificate> checkTrustedRecursive(X509Certificate[] certs, byte[] ocspData,
+ byte[] tlsSctData, String host, boolean clientAuth,
+ ArrayList<X509Certificate> untrustedChain, ArrayList<TrustAnchor> trustAnchorChain,
+ Set<X509Certificate> used) throws CertificateException {
+ CertificateException lastException = null;
+ X509Certificate current;
+ if (trustAnchorChain.isEmpty()) {
+ current = untrustedChain.get(untrustedChain.size() - 1);
+ } else {
+ current = trustAnchorChain.get(trustAnchorChain.size() - 1).getTrustedCert();
+ }
+
+ // Check that the certificate isn't blocklisted.
+ checkBlocklist(current);
+
+ // 1. If the current certificate in the chain is self-signed verify the chain as is.
+ if (current.getIssuerDN().equals(current.getSubjectDN())) {
+ return verifyChain(untrustedChain, trustAnchorChain, host, clientAuth, ocspData,
+ tlsSctData);
+ }
+
+ // 2. Try building a chain via any trust anchors that issued the current certificate.
+ // Note that we do not stop at the first trust anchor since it is possible that the trust
+ // anchor is not self-signed and its issuer may be needed for additional validation such as
+ // certificate pinning. In the common case the first trust anchor will be self-signed or
+ // its issuer's certificate will be missing.
+ Set<TrustAnchor> anchors = findAllTrustAnchorsByIssuerAndSignature(current);
+ boolean seenIssuer = false;
+ for (TrustAnchor anchor : sortPotentialAnchors(anchors)) {
+ X509Certificate anchorCert = anchor.getTrustedCert();
+ // Avoid using certificates that have already been used.
+ if (used.contains(anchorCert)) {
+ continue;
+ }
+ seenIssuer = true;
+ used.add(anchorCert);
+ trustAnchorChain.add(anchor);
+ try {
+ return checkTrustedRecursive(certs, ocspData, tlsSctData, host, clientAuth,
+ untrustedChain, trustAnchorChain, used);
+ } catch (CertificateException ex) {
+ lastException = ex;
+ }
+ // Could not form a valid chain via this certificate, remove it from this chain.
+ trustAnchorChain.remove(trustAnchorChain.size() - 1);
+ used.remove(anchorCert);
+ }
+
+ // 3. If we were unable to find additional trusted issuers, verify the current chain.
+ // This may happen if the root of trust is not self-signed and the issuer is not
+ // present in the trusted set.
+ if (!trustAnchorChain.isEmpty()) {
+ if (!seenIssuer) {
+ return verifyChain(untrustedChain, trustAnchorChain, host, clientAuth, ocspData,
+ tlsSctData);
+ }
+
+ // Otherwise all chains based on the current trust anchor were rejected, fail.
+ throw lastException;
+ }
+
+ // 4. Use the certificates provided by the peer to grow the chain.
+ // Ignore the first certificate, as that is the leaf certificate.
+ for (int i = 1; i < certs.length; i++) {
+ X509Certificate candidateIssuer = certs[i];
+ // Avoid using certificates that have already been used.
+ if (used.contains(candidateIssuer)) {
+ continue;
+ }
+ if (current.getIssuerDN().equals(candidateIssuer.getSubjectDN())) {
+ // Check the strength and validity of the certificate to prune bad certificates
+ // early.
+ try {
+ candidateIssuer.checkValidity();
+ ChainStrengthAnalyzer.checkCert(candidateIssuer);
+ } catch (CertificateException ex) {
+ lastException = new CertificateException("Unacceptable certificate: "
+ + candidateIssuer.getSubjectX500Principal(), ex);
+ continue;
+ }
+ used.add(candidateIssuer);
+ untrustedChain.add(candidateIssuer);
+ try {
+ return checkTrustedRecursive(certs, ocspData, tlsSctData, host, clientAuth,
+ untrustedChain, trustAnchorChain, used);
+ } catch (CertificateException ex) {
+ lastException = ex;
+ }
+ // Could not form a valid chain via this certificate, remove it from this chain.
+ used.remove(candidateIssuer);
+ untrustedChain.remove(untrustedChain.size() - 1);
+ }
+ }
+
+ // 5. Finally try the cached intermediates to handle server that failed to send them.
+ Set<TrustAnchor> intermediateAnchors =
+ intermediateIndex.findAllByIssuerAndSignature(current);
+ for (TrustAnchor intermediate : sortPotentialAnchors(intermediateAnchors)) {
+ X509Certificate intermediateCert = intermediate.getTrustedCert();
+ // Avoid using certificates that have already been used.
+ if (used.contains(intermediateCert)) {
+ continue;
+ }
+ used.add(intermediateCert);
+ untrustedChain.add(intermediateCert);
+ try {
+ return checkTrustedRecursive(certs, ocspData, tlsSctData, host, clientAuth,
+ untrustedChain, trustAnchorChain, used);
+ } catch (CertificateException ex) {
+ lastException = ex;
+ }
+ // Could not form a valid chain via this certificate, remove it from this chain.
+ untrustedChain.remove(untrustedChain.size() - 1);
+ used.remove(intermediateCert);
+ }
+
+ // 6. We were unable to build a valid chain, throw the last error encountered.
+ if (lastException != null) {
+ throw lastException;
+ }
+
+ // 7. If no errors were encountered above then verifyChain was never called because it was
+ // not possible to build a valid chain to a trusted certificate.
+ CertPath certPath = factory.generateCertPath(untrustedChain);
+ throw new CertificateException(new CertPathValidatorException(
+ "Trust anchor for certification path not found.", null, certPath, -1));
+ }
+
+ private List<X509Certificate> verifyChain(List<X509Certificate> untrustedChain,
+ List<TrustAnchor> trustAnchorChain, String host, boolean clientAuth, byte[] ocspData,
+ byte[] tlsSctData)
+ throws CertificateException {
+ try {
+ // build the cert path from the list of certs sans trust anchors
+ // TODO: check whether this is slow and should be replaced by a minimalistic CertPath impl
+ // since we already have built the path.
+ CertPath certPath = factory.generateCertPath(untrustedChain);
+
+ // Check that there are at least some trust anchors
+ if (trustAnchorChain.isEmpty()) {
+ throw new CertificateException(new CertPathValidatorException(
+ "Trust anchor for certification path not found.", null, certPath, -1));
+ }
+
+ List<X509Certificate> wholeChain = new ArrayList<X509Certificate>();
+ wholeChain.addAll(untrustedChain);
+ for (TrustAnchor anchor : trustAnchorChain) {
+ wholeChain.add(anchor.getTrustedCert());
+ }
+
+ if (pinManager != null) {
+ pinManager.checkChainPinning(host, wholeChain);
+ }
+ // Check whole chain against the blocklist
+ for (X509Certificate cert : wholeChain) {
+ checkBlocklist(cert);
+ }
+
+ // Check CT (if required).
+ if (!clientAuth &&
+ (ctEnabledOverride || (host != null && Platform
+ .isCTVerificationRequired(host)))) {
+ checkCT(host, wholeChain, ocspData, tlsSctData);
+ }
+
+ if (untrustedChain.isEmpty()) {
+ // The chain consists of only trust anchors, skip the validator
+ return wholeChain;
+ }
+
+ ChainStrengthAnalyzer.check(untrustedChain);
+
+ // Validate the untrusted part of the chain
+ try {
+ Set<TrustAnchor> anchorSet = new HashSet<TrustAnchor>();
+ // We know that untrusted chains to the first trust anchor, only add that.
+ anchorSet.add(trustAnchorChain.get(0));
+ PKIXParameters params = new PKIXParameters(anchorSet);
+ params.setRevocationEnabled(false);
+ X509Certificate endPointCert = untrustedChain.get(0);
+ setOcspResponses(params, endPointCert, ocspData);
+ params.addCertPathChecker(
+ new ExtendedKeyUsagePKIXCertPathChecker(clientAuth, endPointCert));
+ validator.validate(certPath, params);
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new CertificateException("Chain validation failed", e);
+ } catch (CertPathValidatorException e) {
+ throw new CertificateException("Chain validation failed", e);
+ }
+ // Add intermediate CAs to the index to tolerate sites
+ // that assume that the browser will have cached these.
+ // http://b/3404902
+ for (int i = 1; i < untrustedChain.size(); i++) {
+ intermediateIndex.index(untrustedChain.get(i));
+ }
+ return wholeChain;
+ } catch (CertificateException e) {
+ logger.fine("Rejected candidate cert chain due to error: " + e.getMessage());
+ throw e;
+ }
+ }
+
+ private void checkBlocklist(X509Certificate cert) throws CertificateException {
+ if (blocklist != null && blocklist.isPublicKeyBlockListed(cert.getPublicKey())) {
+ throw new CertificateException("Certificate blocklisted by public key: " + cert);
+ }
+ }
+
+ private void checkCT(String host, List<X509Certificate> chain, byte[] ocspData, byte[] tlsData)
+ throws CertificateException {
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, tlsData, ocspData);
+
+ if (!ctPolicy.doesResultConformToPolicy(result, host,
+ chain.toArray(new X509Certificate[chain.size()]))) {
+ throw new CertificateException(
+ "Certificate chain does not conform to required transparency policy.");
+ }
+ }
+
+ /**
+ * Sets the OCSP response data that was possibly stapled to the TLS response.
+ */
+ private void setOcspResponses(PKIXParameters params, X509Certificate cert, byte[] ocspData) {
+ if (ocspData == null) {
+ return;
+ }
+
+ PKIXRevocationChecker revChecker = null;
+ List<PKIXCertPathChecker> checkers =
+ new ArrayList<PKIXCertPathChecker>(params.getCertPathCheckers());
+ for (PKIXCertPathChecker checker : checkers) {
+ if (checker instanceof PKIXRevocationChecker) {
+ revChecker = (PKIXRevocationChecker) checker;
+ break;
+ }
+ }
+
+ if (revChecker == null) {
+ // Only new CertPathValidatorSpi instances will support the
+ // revocation checker API.
+ try {
+ revChecker = (PKIXRevocationChecker) validator.getRevocationChecker();
+ } catch (UnsupportedOperationException e) {
+ return;
+ }
+
+ checkers.add(revChecker);
+
+ /*
+ * If we add a new revocation checker, we should set the option for
+ * end-entity verification only. Otherwise the CertPathValidator will
+ * throw an exception when it can't verify the entire chain. We
+ * also set the option to prevent falling back from OCSP to CRL download.
+ */
+ revChecker.setOptions(REVOCATION_CHECK_OPTIONS);
+ }
+
+ revChecker.setOcspResponses(Collections.singletonMap(cert, ocspData));
+ params.setCertPathCheckers(checkers);
+ }
+
+ /**
+ * Sort potential anchors so that the most preferred for use come first.
+ *
+ * @see CertificatePriorityComparator
+ */
+ private static Collection<TrustAnchor> sortPotentialAnchors(Set<TrustAnchor> anchors) {
+ if (anchors.size() <= 1) {
+ return anchors;
+ }
+ List<TrustAnchor> sortedAnchors = new ArrayList<TrustAnchor>(anchors);
+ Collections.sort(sortedAnchors, TRUST_ANCHOR_COMPARATOR);
+ return sortedAnchors;
+ }
+
+
+ /**
+ * Comparator for sorting {@link TrustAnchor}s using a {@link CertificatePriorityComparator}.
+ */
+ private static class TrustAnchorComparator implements Comparator<TrustAnchor> {
+ private static final CertificatePriorityComparator CERT_COMPARATOR =
+ new CertificatePriorityComparator();
+ @Override
+ public int compare(TrustAnchor lhs, TrustAnchor rhs) {
+ X509Certificate lhsCert = lhs.getTrustedCert();
+ X509Certificate rhsCert = rhs.getTrustedCert();
+ return CERT_COMPARATOR.compare(lhsCert, rhsCert);
+ }
+ }
+
+ private static Set<Option> revocationOptions() {
+ Set<Option> options = new HashSet<>();
+ options.add(Option.ONLY_END_ENTITY); // Only check end entity
+ options.add(Option.NO_FALLBACK); // Don't fall back from OCSP to CRL download
+ return Collections.unmodifiableSet(options);
+ }
+
+ /**
+ * If an EKU extension is present in the end-entity certificate,
+ * it MUST contain an appropriate key usage. For servers, this
+ * includes anyExtendedKeyUsage, serverAuth, or the historical
+ * Server Gated Cryptography options of nsSGC or msSGC. For
+ * clients, this includes anyExtendedKeyUsage and clientAuth.
+ */
+ private static class ExtendedKeyUsagePKIXCertPathChecker extends PKIXCertPathChecker {
+
+ private static final String EKU_OID = "2.5.29.37";
+
+ private static final String EKU_anyExtendedKeyUsage = "2.5.29.37.0";
+ private static final String EKU_clientAuth = "1.3.6.1.5.5.7.3.2";
+ private static final String EKU_serverAuth = "1.3.6.1.5.5.7.3.1";
+ private static final String EKU_nsSGC = "2.16.840.1.113730.4.1";
+ private static final String EKU_msSGC = "1.3.6.1.4.1.311.10.3.3";
+
+ private static final Set<String> SUPPORTED_EXTENSIONS
+ = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(EKU_OID)));
+
+ private final boolean clientAuth;
+ private final X509Certificate leaf;
+
+ private ExtendedKeyUsagePKIXCertPathChecker(boolean clientAuth, X509Certificate leaf) {
+ this.clientAuth = clientAuth;
+ this.leaf = leaf;
+ }
+
+ @Override
+ public void init(boolean forward) throws CertPathValidatorException {
+ }
+
+ @Override
+ public boolean isForwardCheckingSupported() {
+ return true;
+ }
+
+ @Override
+ public Set<String> getSupportedExtensions() {
+ return SUPPORTED_EXTENSIONS;
+ }
+
+ @SuppressWarnings("ReferenceEquality")
+ @Override
+ public void check(Certificate c, Collection<String> unresolvedCritExts)
+ throws CertPathValidatorException {
+ // We only want to validate the EKU on the leaf certificate.
+ if (c != leaf) {
+ return;
+ }
+ List<String> ekuOids;
+ try {
+ ekuOids = leaf.getExtendedKeyUsage();
+ } catch (CertificateParsingException e) {
+ // A malformed EKU is bad news, consider it fatal.
+ throw new CertPathValidatorException(e);
+ }
+ // We are here to check EKU, but there is none.
+ if (ekuOids == null) {
+ return;
+ }
+
+ boolean goodExtendedKeyUsage = false;
+ for (String ekuOid : ekuOids) {
+ // anyExtendedKeyUsage for clients and servers
+ if (ekuOid.equals(EKU_anyExtendedKeyUsage)) {
+ goodExtendedKeyUsage = true;
+ break;
+ }
+
+ // clients
+ if (clientAuth) {
+ if (ekuOid.equals(EKU_clientAuth)) {
+ goodExtendedKeyUsage = true;
+ break;
+ }
+ continue;
+ }
+
+ // servers
+ if (ekuOid.equals(EKU_serverAuth)) {
+ goodExtendedKeyUsage = true;
+ break;
+ }
+ if (ekuOid.equals(EKU_nsSGC)) {
+ goodExtendedKeyUsage = true;
+ break;
+ }
+ if (ekuOid.equals(EKU_msSGC)) {
+ goodExtendedKeyUsage = true;
+ break;
+ }
+ }
+ if (goodExtendedKeyUsage) {
+ // Mark extendedKeyUsage as resolved if present.
+ unresolvedCritExts.remove(EKU_OID);
+ } else {
+ throw new CertPathValidatorException("End-entity certificate does not have a valid "
+ + "extendedKeyUsage.");
+ }
+ }
+ }
+
+ /**
+ * Find all possible issuing trust anchors of {@code cert}.
+ */
+ private Set<TrustAnchor> findAllTrustAnchorsByIssuerAndSignature(X509Certificate cert) {
+ Set<TrustAnchor> indexedAnchors =
+ trustedCertificateIndex.findAllByIssuerAndSignature(cert);
+ if (!indexedAnchors.isEmpty() || trustedCertificateStore == null) {
+ return indexedAnchors;
+ }
+ Set<X509Certificate> storeAnchors = trustedCertificateStore.findAllIssuers(cert);
+ if (storeAnchors.isEmpty()) {
+ return indexedAnchors;
+ }
+ Set<TrustAnchor> result = new HashSet<TrustAnchor>(storeAnchors.size());
+ for (X509Certificate storeCert : storeAnchors) {
+ result.add(trustedCertificateIndex.index(storeCert));
+ }
+ return result;
+ }
+
+ /**
+ * Check the trustedCertificateIndex for the cert to see if it is
+ * already trusted and failing that check the KeyStore if it is
+ * available.
+ */
+ private TrustAnchor findTrustAnchorBySubjectAndPublicKey(X509Certificate cert) {
+ TrustAnchor trustAnchor = trustedCertificateIndex.findBySubjectAndPublicKey(cert);
+ if (trustAnchor != null) {
+ return trustAnchor;
+ }
+ if (trustedCertificateStore == null) {
+ // not trusted and no TrustedCertificateStore to check.
+ return null;
+ }
+ // probe KeyStore for a cert. AndroidCAStore stores its
+ // contents hashed by cert subject on the filesystem to make
+ // this faster than scanning all key store entries.
+ X509Certificate systemCert = trustedCertificateStore.getTrustAnchor(cert);
+ if (systemCert != null) {
+ // Don't index the system certificate here, that way the only place that adds anchors to
+ // the index are findAllTrustAnchorsByIssuerAndSignature.
+ // This allows findAllTrustAnchorsByIssuerAndSignature to avoid checking the
+ // TrustedCertificateStore if the TrustedCertificateIndex contains any issuers for the
+ // certificate because it will have cached all certificates contained in the
+ // TrustedCertificateStore.
+ return new TrustAnchor(systemCert, null);
+ }
+ return null;
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return (acceptedIssuers != null) ? acceptedIssuers.clone() : acceptedIssuers(rootKeyStore);
+ }
+
+ /**
+ * Set the default hostname verifier that will be used for HTTPS endpoint identification. If
+ * {@code null} (the default), endpoint identification will use the default hostname verifier
+ * set in {@link HttpsURLConnection#setDefaultHostnameVerifier(javax.net.ssl.HostnameVerifier)}.
+ */
+ synchronized static void setDefaultHostnameVerifier(ConscryptHostnameVerifier verifier) {
+ defaultHostnameVerifier = verifier;
+ }
+
+ /**
+ * Returns the currently-set default hostname verifier.
+ *
+ * @see #setDefaultHostnameVerifier(ConscryptHostnameVerifier)
+ */
+ synchronized static ConscryptHostnameVerifier getDefaultHostnameVerifier() {
+ return defaultHostnameVerifier;
+ }
+
+ /**
+ * Set the hostname verifier that will be used for HTTPS endpoint identification. If
+ * {@code null} (the default), endpoint identification will use the default hostname verifier
+ * set in {@link #setDefaultHostnameVerifier(ConscryptHostnameVerifier)}.
+ */
+ void setHostnameVerifier(ConscryptHostnameVerifier verifier) {
+ this.hostnameVerifier = verifier;
+ }
+
+ /**
+ * Returns the currently-set hostname verifier for this instance.
+ *
+ * @see #setHostnameVerifier(ConscryptHostnameVerifier)
+ */
+ ConscryptHostnameVerifier getHostnameVerifier() {
+ return hostnameVerifier;
+ }
+
+ private ConscryptHostnameVerifier getHttpsVerifier() {
+ if (hostnameVerifier != null) {
+ return hostnameVerifier;
+ }
+ if (defaultHostnameVerifier != null) {
+ return defaultHostnameVerifier;
+ }
+ return Platform.getDefaultHostnameVerifier();
+ }
+
+ public void setCTEnabledOverride(boolean enabled) {
+ this.ctEnabledOverride = enabled;
+ }
+
+ // Replace the CTVerifier. For testing only.
+ public void setCTVerifier(CTVerifier verifier) {
+ this.ctVerifier = verifier;
+ }
+
+ // Replace the CTPolicy. For testing only.
+ public void setCTPolicy(CTPolicy policy) {
+ this.ctPolicy = policy;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/TrustedCertificateIndex.java b/repackaged/common/src/main/java/com/android/org/conscrypt/TrustedCertificateIndex.java
new file mode 100644
index 0000000..c6e199e
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/TrustedCertificateIndex.java
@@ -0,0 +1,212 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.PublicKey;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * Indexes {@code TrustAnchor} instances so they can be found in O(1)
+ * time instead of O(N).
+ * @hide This class is not part of the Android public SDK API
+ */
+@libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+@Internal
+public final class TrustedCertificateIndex {
+ private final Map<X500Principal, List<TrustAnchor>> subjectToTrustAnchors
+ = new HashMap<X500Principal, List<TrustAnchor>>();
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public TrustedCertificateIndex() {}
+
+ public TrustedCertificateIndex(Set<TrustAnchor> anchors) {
+ index(anchors);
+ }
+
+ private void index(Set<TrustAnchor> anchors) {
+ for (TrustAnchor anchor : anchors) {
+ index(anchor);
+ }
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public TrustAnchor index(X509Certificate cert) {
+ TrustAnchor anchor = new TrustAnchor(cert, null);
+ index(anchor);
+ return anchor;
+ }
+
+ public void index(TrustAnchor anchor) {
+ X500Principal subject;
+ X509Certificate cert = anchor.getTrustedCert();
+ if (cert != null) {
+ subject = cert.getSubjectX500Principal();
+ } else {
+ subject = anchor.getCA();
+ }
+
+ synchronized (subjectToTrustAnchors) {
+ List<TrustAnchor> anchors = subjectToTrustAnchors.get(subject);
+ if (anchors == null) {
+ anchors = new ArrayList<TrustAnchor>(1);
+ subjectToTrustAnchors.put(subject, anchors);
+ } else {
+ // Avoid indexing the same certificate multiple times
+ if (cert != null) {
+ for (TrustAnchor entry : anchors) {
+ if (cert.equals(entry.getTrustedCert())) {
+ return;
+ }
+ }
+ }
+ }
+ anchors.add(anchor);
+ }
+ }
+
+ public void reset() {
+ synchronized (subjectToTrustAnchors) {
+ subjectToTrustAnchors.clear();
+ }
+ }
+
+ public void reset(Set<TrustAnchor> anchors) {
+ synchronized (subjectToTrustAnchors) {
+ reset();
+ index(anchors);
+ }
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public TrustAnchor findByIssuerAndSignature(X509Certificate cert) {
+ X500Principal issuer = cert.getIssuerX500Principal();
+ synchronized (subjectToTrustAnchors) {
+ List<TrustAnchor> anchors = subjectToTrustAnchors.get(issuer);
+ if (anchors == null) {
+ return null;
+ }
+
+ for (TrustAnchor anchor : anchors) {
+ PublicKey publicKey;
+ try {
+ X509Certificate caCert = anchor.getTrustedCert();
+ if (caCert != null) {
+ publicKey = caCert.getPublicKey();
+ } else {
+ publicKey = anchor.getCAPublicKey();
+ }
+ cert.verify(publicKey);
+ return anchor;
+ } catch (Exception ignored) {
+ // Ignored
+ }
+ }
+ }
+ return null;
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public TrustAnchor findBySubjectAndPublicKey(X509Certificate cert) {
+ X500Principal subject = cert.getSubjectX500Principal();
+ synchronized (subjectToTrustAnchors) {
+ List<TrustAnchor> anchors = subjectToTrustAnchors.get(subject);
+ if (anchors == null) {
+ return null;
+ }
+ return findBySubjectAndPublicKey(cert, anchors);
+ }
+ }
+
+ private static TrustAnchor findBySubjectAndPublicKey(X509Certificate cert,
+ Collection<TrustAnchor> anchors) {
+ PublicKey certPublicKey = cert.getPublicKey();
+ for (TrustAnchor anchor : anchors) {
+ PublicKey caPublicKey;
+ try {
+ X509Certificate caCert = anchor.getTrustedCert();
+ if (caCert != null) {
+ caPublicKey = caCert.getPublicKey();
+ } else {
+ caPublicKey = anchor.getCAPublicKey();
+ }
+ if (caPublicKey.equals(certPublicKey)) {
+ return anchor;
+ } else {
+ // PublicKey.equals is not required to compare keys across providers. Fall back
+ // to checking using the encoded form.
+ if ("X.509".equals(caPublicKey.getFormat())
+ && "X.509".equals(certPublicKey.getFormat())) {
+ byte[] caPublicKeyEncoded = caPublicKey.getEncoded();
+ byte[] certPublicKeyEncoded = certPublicKey.getEncoded();
+ if (certPublicKeyEncoded != null
+ && caPublicKeyEncoded != null
+ && Arrays.equals(caPublicKeyEncoded, certPublicKeyEncoded)) {
+ return anchor;
+ }
+ }
+ }
+ } catch (Exception e) {
+ // can happen with unsupported public key types
+ }
+ }
+ return null;
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public Set<TrustAnchor> findAllByIssuerAndSignature(X509Certificate cert) {
+ X500Principal issuer = cert.getIssuerX500Principal();
+ synchronized (subjectToTrustAnchors) {
+ List<TrustAnchor> anchors = subjectToTrustAnchors.get(issuer);
+ if (anchors == null) {
+ return Collections.<TrustAnchor>emptySet();
+ }
+
+ Set<TrustAnchor> result = new HashSet<TrustAnchor>();
+ for (TrustAnchor anchor : anchors) {
+ try {
+ PublicKey publicKey;
+ X509Certificate caCert = anchor.getTrustedCert();
+ if (caCert != null) {
+ publicKey = caCert.getPublicKey();
+ } else {
+ publicKey = anchor.getCAPublicKey();
+ }
+ if (publicKey == null) {
+ continue;
+ }
+ cert.verify(publicKey);
+ result.add(anchor);
+ } catch (Exception ignored) {
+ // Ignored
+ }
+ }
+ return result;
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/X509PublicKey.java b/repackaged/common/src/main/java/com/android/org/conscrypt/X509PublicKey.java
new file mode 100644
index 0000000..c30487c
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/X509PublicKey.java
@@ -0,0 +1,88 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2013 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.PublicKey;
+import java.util.Arrays;
+
+/**
+ * A simple but useless key class that holds X.509 public key information when
+ * the appropriate KeyFactory for the key algorithm is not available.
+ */
+final class X509PublicKey implements PublicKey {
+ private static final long serialVersionUID = -8610156854731664298L;
+
+ private final String algorithm;
+
+ private final byte[] encoded;
+
+ @android.compat.annotation.UnsupportedAppUsage
+ X509PublicKey(String algorithm, byte[] encoded) {
+ this.algorithm = algorithm;
+ this.encoded = encoded;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ @Override
+ public String getFormat() {
+ return "X.509";
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return encoded;
+ }
+
+ @Override
+ public String toString() {
+ return "X509PublicKey [algorithm=" + algorithm + ", encoded=" + Arrays.toString(encoded)
+ + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((algorithm == null) ? 0 : algorithm.hashCode());
+ result = prime * result + Arrays.hashCode(encoded);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ X509PublicKey other = (X509PublicKey) obj;
+ if (algorithm == null) {
+ if (other.algorithm != null)
+ return false;
+ } else if (!algorithm.equals(other.algorithm))
+ return false;
+ if (!Arrays.equals(encoded, other.encoded))
+ return false;
+ return true;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTConstants.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTConstants.java
new file mode 100644
index 0000000..f25a414
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTConstants.java
@@ -0,0 +1,48 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt.ct;
+
+import com.android.org.conscrypt.Internal;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class CTConstants {
+ public static final String X509_SCT_LIST_OID = "1.3.6.1.4.1.11129.2.4.2";
+ public static final String OCSP_SCT_LIST_OID = "1.3.6.1.4.1.11129.2.4.5";
+
+ public static final int VERSION_LENGTH = 1;
+ public static final int LOGID_LENGTH = 32;
+ public static final int TIMESTAMP_LENGTH = 8;
+ public static final int EXTENSIONS_LENGTH_BYTES = 2;
+
+ public static final int HASH_ALGORITHM_LENGTH = 1;
+ public static final int SIGNATURE_ALGORITHM_LENGTH = 1;
+ public static final int SIGNATURE_LENGTH_BYTES = 2;
+
+ public static final int SIGNATURE_TYPE_LENGTH = 1;
+ public static final int LOG_ENTRY_TYPE_LENGTH = 2;
+ public static final int CERTIFICATE_LENGTH_BYTES = 3;
+
+ public static final int SERIALIZED_SCT_LENGTH_BYTES = 2;
+ public static final int SCT_LIST_LENGTH_BYTES = 2;
+
+ public static final int ISSUER_KEY_HASH_LENGTH = 32;
+}
+
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTLogInfo.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTLogInfo.java
new file mode 100644
index 0000000..348f5cc
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTLogInfo.java
@@ -0,0 +1,147 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt.ct;
+
+import java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.Arrays;
+import com.android.org.conscrypt.Internal;
+
+/**
+ * Properties about a Certificate Transparency Log.
+ * This object stores information about a CT log, its public key, description and URL.
+ * It allows verification of SCTs against the log's public key.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class CTLogInfo {
+ private final byte[] logId;
+ private final PublicKey publicKey;
+ private final String description;
+ private final String url;
+
+ public CTLogInfo(PublicKey publicKey, String description, String url) {
+ try {
+ this.logId = MessageDigest.getInstance("SHA-256")
+ .digest(publicKey.getEncoded());
+ } catch (NoSuchAlgorithmException e) {
+ // SHA-256 is guaranteed to be available
+ throw new RuntimeException(e);
+ }
+
+ this.publicKey = publicKey;
+ this.description = description;
+ this.url = url;
+ }
+
+ /**
+ * Get the log's ID, that is the SHA-256 hash of it's public key
+ */
+ public byte[] getID() {
+ return logId;
+ }
+
+ public PublicKey getPublicKey() {
+ return publicKey;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof CTLogInfo)) {
+ return false;
+ }
+
+ CTLogInfo that = (CTLogInfo)other;
+ return
+ this.publicKey.equals(that.publicKey) &&
+ this.description.equals(that.description) &&
+ this.url.equals(that.url);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 1;
+ hash = hash * 31 + publicKey.hashCode();
+ hash = hash * 31 + description.hashCode();
+ hash = hash * 31 + url.hashCode();
+
+ return hash;
+ }
+
+ /**
+ * Verify the signature of a signed certificate timestamp for the given certificate entry
+ * against the log's public key.
+ *
+ * @return the result of the verification
+ */
+ public VerifiedSCT.Status verifySingleSCT(SignedCertificateTimestamp sct,
+ CertificateEntry entry) {
+ if (!Arrays.equals(sct.getLogID(), getID())) {
+ return VerifiedSCT.Status.UNKNOWN_LOG;
+ }
+
+ byte[] toVerify;
+ try {
+ toVerify = sct.encodeTBS(entry);
+ } catch (SerializationException e) {
+ return VerifiedSCT.Status.INVALID_SCT;
+ }
+
+ Signature signature;
+ try {
+ String algorithm = sct.getSignature().getAlgorithm();
+ signature = Signature.getInstance(algorithm);
+ } catch (NoSuchAlgorithmException e) {
+ return VerifiedSCT.Status.INVALID_SCT;
+ }
+
+ try {
+ signature.initVerify(publicKey);
+ } catch (InvalidKeyException e) {
+ return VerifiedSCT.Status.INVALID_SCT;
+ }
+
+ try {
+ signature.update(toVerify);
+ if (!signature.verify(sct.getSignature().getSignature())) {
+ return VerifiedSCT.Status.INVALID_SIGNATURE;
+ }
+ return VerifiedSCT.Status.VALID;
+ } catch (SignatureException e) {
+ // This only happens if the signature is not initialized,
+ // but we call initVerify just before, so it should never do
+ throw new RuntimeException(e);
+ }
+ }
+}
+
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTLogStore.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTLogStore.java
new file mode 100644
index 0000000..0f6b715
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTLogStore.java
@@ -0,0 +1,29 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt.ct;
+
+import com.android.org.conscrypt.Internal;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public interface CTLogStore {
+ CTLogInfo getKnownLog(byte[] logId);
+}
+
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTPolicy.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTPolicy.java
new file mode 100644
index 0000000..9057e7a
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTPolicy.java
@@ -0,0 +1,30 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt.ct;
+
+import java.security.cert.X509Certificate;
+import com.android.org.conscrypt.Internal;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public interface CTPolicy {
+ boolean doesResultConformToPolicy(CTVerificationResult result, String hostname,
+ X509Certificate[] chain);
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTVerificationResult.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTVerificationResult.java
new file mode 100644
index 0000000..bfa1f59
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTVerificationResult.java
@@ -0,0 +1,49 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt.ct;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import com.android.org.conscrypt.Internal;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class CTVerificationResult {
+ private final ArrayList<VerifiedSCT> validSCTs = new ArrayList<VerifiedSCT>();
+ private final ArrayList<VerifiedSCT> invalidSCTs = new ArrayList<VerifiedSCT>();
+
+ public void add(VerifiedSCT result) {
+ if (result.status == VerifiedSCT.Status.VALID) {
+ validSCTs.add(result);
+ } else {
+ invalidSCTs.add(result);
+ }
+ }
+
+ public List<VerifiedSCT> getValidSCTs() {
+ return Collections.unmodifiableList(validSCTs);
+ }
+
+ public List<VerifiedSCT> getInvalidSCTs() {
+ return Collections.unmodifiableList(invalidSCTs);
+ }
+}
+
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTVerifier.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTVerifier.java
new file mode 100644
index 0000000..3d6945f
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTVerifier.java
@@ -0,0 +1,262 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt.ct;
+
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import com.android.org.conscrypt.Internal;
+import com.android.org.conscrypt.NativeCrypto;
+import com.android.org.conscrypt.OpenSSLX509Certificate;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class CTVerifier {
+ private final CTLogStore store;
+
+ public CTVerifier(CTLogStore store) {
+ this.store = store;
+ }
+
+ public CTVerificationResult verifySignedCertificateTimestamps(List<X509Certificate> chain,
+ byte[] tlsData, byte[] ocspData) throws CertificateEncodingException {
+ OpenSSLX509Certificate[] certs = new OpenSSLX509Certificate[chain.size()];
+ int i = 0;
+ for(X509Certificate cert : chain) {
+ certs[i++] = OpenSSLX509Certificate.fromCertificate(cert);
+ }
+ return verifySignedCertificateTimestamps(certs, tlsData, ocspData);
+ }
+
+ /**
+ * Verify a certificate chain for transparency.
+ * Signed timestamps are extracted from the leaf certificate, TLS extension, and stapled ocsp
+ * response, and verified against the list of known logs.
+ * @throws IllegalArgumentException if the chain is empty
+ */
+ public CTVerificationResult verifySignedCertificateTimestamps(OpenSSLX509Certificate[] chain,
+ byte[] tlsData, byte[] ocspData) throws CertificateEncodingException {
+ if (chain.length == 0) {
+ throw new IllegalArgumentException("Chain of certificates mustn't be empty.");
+ }
+
+ OpenSSLX509Certificate leaf = chain[0];
+
+ CTVerificationResult result = new CTVerificationResult();
+ List<SignedCertificateTimestamp> tlsScts = getSCTsFromTLSExtension(tlsData);
+ verifyExternalSCTs(tlsScts, leaf, result);
+
+ List<SignedCertificateTimestamp> ocspScts = getSCTsFromOCSPResponse(ocspData, chain);
+ verifyExternalSCTs(ocspScts, leaf, result);
+
+ List<SignedCertificateTimestamp> embeddedScts = getSCTsFromX509Extension(chain[0]);
+ verifyEmbeddedSCTs(embeddedScts, chain, result);
+ return result;
+ }
+
+ /**
+ * Verify a list of SCTs which were embedded from an X509 certificate.
+ * The result of the verification for each sct is added to {@code result}.
+ */
+ private void verifyEmbeddedSCTs(List<SignedCertificateTimestamp> scts,
+ OpenSSLX509Certificate[] chain,
+ CTVerificationResult result) {
+ // Avoid creating the cert entry if we don't need it
+ if (scts.isEmpty()) {
+ return;
+ }
+
+ CertificateEntry precertEntry = null;
+ if (chain.length >= 2) {
+ OpenSSLX509Certificate leaf = chain[0];
+ OpenSSLX509Certificate issuer = chain[1];
+
+ try {
+ precertEntry = CertificateEntry.createForPrecertificate(leaf, issuer);
+ } catch (CertificateException e) {
+ // Leave precertEntry as null, we handle it just below
+ }
+ }
+
+ if (precertEntry == null) {
+ markSCTsAsInvalid(scts, result);
+ return;
+ }
+
+ for (SignedCertificateTimestamp sct: scts) {
+ VerifiedSCT.Status status = verifySingleSCT(sct, precertEntry);
+ result.add(new VerifiedSCT(sct, status));
+ }
+ }
+
+ /**
+ * Verify a list of SCTs which were not embedded in an X509 certificate, that is received
+ * through the TLS or OCSP extensions.
+ * The result of the verification for each sct is added to {@code result}.
+ */
+ private void verifyExternalSCTs(List<SignedCertificateTimestamp> scts,
+ OpenSSLX509Certificate leaf,
+ CTVerificationResult result) {
+ // Avoid creating the cert entry if we don't need it
+ if (scts.isEmpty()) {
+ return;
+ }
+
+ CertificateEntry x509Entry;
+ try {
+ x509Entry = CertificateEntry.createForX509Certificate(leaf);
+ } catch (CertificateException e) {
+ markSCTsAsInvalid(scts, result);
+ return;
+ }
+
+ for (SignedCertificateTimestamp sct: scts) {
+ VerifiedSCT.Status status = verifySingleSCT(sct, x509Entry);
+ result.add(new VerifiedSCT(sct, status));
+ }
+ }
+
+ /**
+ * Verify a single SCT for the given Certificate Entry
+ */
+ private VerifiedSCT.Status verifySingleSCT(SignedCertificateTimestamp sct,
+ CertificateEntry certEntry) {
+ CTLogInfo log = store.getKnownLog(sct.getLogID());
+ if (log == null) {
+ return VerifiedSCT.Status.UNKNOWN_LOG;
+ }
+
+ return log.verifySingleSCT(sct, certEntry);
+ }
+
+ /**
+ * Add every SCT in {@code scts} to {@code result} with INVALID_SCT as status
+ */
+ private void markSCTsAsInvalid(List<SignedCertificateTimestamp> scts,
+ CTVerificationResult result) {
+ for (SignedCertificateTimestamp sct: scts) {
+ result.add(new VerifiedSCT(sct, VerifiedSCT.Status.INVALID_SCT));
+ }
+ }
+
+ /**
+ * Parse an encoded SignedCertificateTimestampList into a list of SignedCertificateTimestamp
+ * instances, as described by RFC6962.
+ * Individual SCTs which fail to be parsed are skipped. If the data is null, or the encompassing
+ * list fails to be parsed, an empty list is returned.
+ * @param origin used to create the SignedCertificateTimestamp instances.
+ */
+ @SuppressWarnings("MixedMutabilityReturnType")
+ private static List<SignedCertificateTimestamp> getSCTsFromSCTList(
+ byte[] data, SignedCertificateTimestamp.Origin origin) {
+ if (data == null) {
+ return Collections.emptyList();
+ }
+
+ byte[][] sctList;
+ try {
+ sctList = Serialization.readList(data, CTConstants.SCT_LIST_LENGTH_BYTES,
+ CTConstants.SERIALIZED_SCT_LENGTH_BYTES);
+ } catch (SerializationException e) {
+ return Collections.emptyList();
+ }
+
+ List<SignedCertificateTimestamp> scts = new ArrayList<SignedCertificateTimestamp>();
+ for (byte[] encodedSCT: sctList) {
+ try {
+ SignedCertificateTimestamp sct = SignedCertificateTimestamp.decode(encodedSCT, origin);
+ scts.add(sct);
+ } catch (SerializationException e) {
+ // Ignore errors
+ }
+ }
+
+ return scts;
+ }
+
+ /**
+ * Extract a list of SignedCertificateTimestamp from a TLS "signed_certificate_timestamp"
+ * extension as described by RFC6962.
+ * Individual SCTs which fail to be parsed are skipped. If the data is null, or the encompassing
+ * list fails to be parsed, an empty list is returned.
+ * @param data contents of the TLS extension to be decoded
+ */
+ private List<SignedCertificateTimestamp> getSCTsFromTLSExtension(byte[] data) {
+ return getSCTsFromSCTList(data, SignedCertificateTimestamp.Origin.TLS_EXTENSION);
+ }
+
+ /**
+ * Extract a list of SignedCertificateTimestamp contained in an OCSP response.
+ * If the data is null, or parsing the OCSP response fails, an empty list is returned.
+ * Individual SCTs which fail to be parsed are skipped.
+ * @param data contents of the OCSP response
+ * @param chain certificate chain for which to get SCTs. Must contain at least the leaf and it's
+ * issuer in order to identify the relevant SingleResponse from the OCSP response,
+ * or an empty list is returned
+ */
+ private List<SignedCertificateTimestamp> getSCTsFromOCSPResponse(byte[] data,
+ OpenSSLX509Certificate[] chain) {
+ if (data == null || chain.length < 2) {
+ return Collections.emptyList();
+ }
+
+ byte[] extData = NativeCrypto.get_ocsp_single_extension(data, CTConstants.OCSP_SCT_LIST_OID,
+ chain[0].getContext(), chain[0],
+ chain[1].getContext(), chain[1]);
+ if (extData == null) {
+ return Collections.emptyList();
+ }
+
+ try {
+ return getSCTsFromSCTList(
+ Serialization.readDEROctetString(
+ Serialization.readDEROctetString(extData)),
+ SignedCertificateTimestamp.Origin.OCSP_RESPONSE);
+ } catch (SerializationException e) {
+ return Collections.emptyList();
+ }
+ }
+
+ /**
+ * Extract a list of SignedCertificateTimestamp embedded in an X509 certificate.
+ *
+ * If the certificate does not contain any SCT extension, or the encompassing encoded list fails
+ * to be parsed, an empty list is returned. Individual SCTs which fail to be parsed are ignored.
+ */
+ private List<SignedCertificateTimestamp> getSCTsFromX509Extension(OpenSSLX509Certificate leaf) {
+ byte[] extData = leaf.getExtensionValue(CTConstants.X509_SCT_LIST_OID);
+ if (extData == null) {
+ return Collections.emptyList();
+ }
+
+ try {
+ return getSCTsFromSCTList(
+ Serialization.readDEROctetString(
+ Serialization.readDEROctetString(extData)),
+ SignedCertificateTimestamp.Origin.EMBEDDED);
+ } catch (SerializationException e) {
+ return Collections.emptyList();
+ }
+ }
+}
+
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CertificateEntry.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CertificateEntry.java
new file mode 100644
index 0000000..84dabe7
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CertificateEntry.java
@@ -0,0 +1,139 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt.ct;
+
+import java.io.OutputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import com.android.org.conscrypt.Internal;
+import com.android.org.conscrypt.OpenSSLX509Certificate;
+
+/**
+ * CertificateEntry structure.
+ * This structure describes part of the data which is signed over in SCTs.
+ * It is not defined by the RFC6962, but it is useful to have.
+ *
+ * It's definition would be :
+ * struct {
+ * LogEntryType entry_type;
+ * select(entry_type) {
+ * case x509_entry: ASN.1Cert;
+ * case precert_entry: PreCert;
+ * } signed_entry;
+ * } CertificateEntry;
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class CertificateEntry {
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public enum LogEntryType {
+ X509_ENTRY,
+ PRECERT_ENTRY
+ }
+
+ private final LogEntryType entryType;
+
+ // Only used when entryType is LOG_ENTRY_TYPE_PRECERT
+ private final byte[] issuerKeyHash;
+
+ /* If entryType == PRECERT_ENTRY, this is the encoded TBS of the precertificate.
+ If entryType == X509_ENTRY, this is the encoded leaf certificate. */
+ private final byte[] certificate;
+
+ private CertificateEntry(LogEntryType entryType, byte[] certificate, byte[] issuerKeyHash) {
+ if (entryType == LogEntryType.PRECERT_ENTRY && issuerKeyHash == null) {
+ throw new IllegalArgumentException("issuerKeyHash missing for precert entry.");
+ } else if (entryType == LogEntryType.X509_ENTRY && issuerKeyHash != null) {
+ throw new IllegalArgumentException("unexpected issuerKeyHash for X509 entry.");
+ }
+
+ if (issuerKeyHash != null && issuerKeyHash.length != CTConstants.ISSUER_KEY_HASH_LENGTH) {
+ throw new IllegalArgumentException("issuerKeyHash must be 32 bytes long");
+ }
+
+ this.entryType = entryType;
+ this.issuerKeyHash = issuerKeyHash;
+ this.certificate = certificate;
+ }
+
+ /**
+ * Creates a CertificateEntry with type PRECERT_ENTRY
+ *
+ * @throws IllegalArgumentException if issuerKeyHash isn't 32 bytes
+ */
+ public static CertificateEntry createForPrecertificate(byte[] tbsCertificate, byte[] issuerKeyHash) {
+ return new CertificateEntry(LogEntryType.PRECERT_ENTRY, tbsCertificate, issuerKeyHash);
+ }
+
+ public static CertificateEntry createForPrecertificate(OpenSSLX509Certificate leaf,
+ OpenSSLX509Certificate issuer) throws CertificateException {
+ try {
+ if (!leaf.getNonCriticalExtensionOIDs().contains(CTConstants.X509_SCT_LIST_OID)) {
+ throw new CertificateException("Certificate does not contain embedded signed timestamps");
+ }
+
+ byte[] tbs = leaf.getTBSCertificateWithoutExtension(CTConstants.X509_SCT_LIST_OID);
+
+ byte[] issuerKey = issuer.getPublicKey().getEncoded();
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+ md.update(issuerKey);
+ byte[] issuerKeyHash = md.digest();
+
+ return createForPrecertificate(tbs, issuerKeyHash);
+ } catch (NoSuchAlgorithmException e) {
+ // SHA-256 is guaranteed to be available
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static CertificateEntry createForX509Certificate(byte[] x509Certificate) {
+ return new CertificateEntry(LogEntryType.X509_ENTRY, x509Certificate, null);
+ }
+
+ public static CertificateEntry createForX509Certificate(X509Certificate cert)
+ throws CertificateEncodingException {
+ return createForX509Certificate(cert.getEncoded());
+ }
+
+ public LogEntryType getEntryType() {
+ return entryType;
+ }
+ public byte[] getCertificate() {
+ return certificate;
+ }
+ public byte[] getIssuerKeyHash() {
+ return issuerKeyHash;
+ }
+
+ /**
+ * TLS encode the CertificateEntry structure.
+ */
+ public void encode(OutputStream output) throws SerializationException {
+ Serialization.writeNumber(output, entryType.ordinal(), CTConstants.LOG_ENTRY_TYPE_LENGTH);
+ if (entryType == LogEntryType.PRECERT_ENTRY) {
+ Serialization.writeFixedBytes(output, issuerKeyHash);
+ }
+ Serialization.writeVariableBytes(output, certificate, CTConstants.CERTIFICATE_LENGTH_BYTES);
+ }
+}
+
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ct/DigitallySigned.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/DigitallySigned.java
new file mode 100644
index 0000000..ea62666
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/DigitallySigned.java
@@ -0,0 +1,136 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt.ct;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import com.android.org.conscrypt.Internal;
+
+/**
+ * DigitallySigned structure, as defined by RFC5246 Section 4.7.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class DigitallySigned {
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public enum HashAlgorithm {
+ NONE,
+ MD5,
+ SHA1,
+ SHA224,
+ SHA256,
+ SHA384,
+ SHA512;
+
+ private static HashAlgorithm[] values = values();
+ public static HashAlgorithm valueOf(int ord) {
+ try {
+ return values[ord];
+ } catch (IndexOutOfBoundsException e) {
+ throw new IllegalArgumentException("Invalid hash algorithm " + ord, e);
+ }
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public enum SignatureAlgorithm {
+ ANONYMOUS,
+ RSA,
+ DSA,
+ ECDSA;
+
+ private static SignatureAlgorithm[] values = values();
+ public static SignatureAlgorithm valueOf(int ord) {
+ try {
+ return values[ord];
+ } catch (IndexOutOfBoundsException e) {
+ throw new IllegalArgumentException("Invalid signature algorithm " + ord, e);
+ }
+ }
+ }
+
+ private final HashAlgorithm hashAlgorithm;
+ private final SignatureAlgorithm signatureAlgorithm;
+ private final byte[] signature;
+
+ public DigitallySigned(HashAlgorithm hashAlgorithm,
+ SignatureAlgorithm signatureAlgorithm,
+ byte[] signature) {
+ this.hashAlgorithm = hashAlgorithm;
+ this.signatureAlgorithm = signatureAlgorithm;
+ this.signature = signature;
+ }
+
+ public DigitallySigned(int hashAlgorithm,
+ int signatureAlgorithm,
+ byte[] signature) {
+ this(
+ HashAlgorithm.valueOf(hashAlgorithm),
+ SignatureAlgorithm.valueOf(signatureAlgorithm),
+ signature
+ );
+ }
+
+ public HashAlgorithm getHashAlgorithm() {
+ return hashAlgorithm;
+ }
+ public SignatureAlgorithm getSignatureAlgorithm() {
+ return signatureAlgorithm;
+ }
+ public byte[] getSignature() {
+ return signature;
+ }
+
+ /**
+ * Get the name of the hash and signature combination.
+ * The result can be used to as the argument to {@link java.security.Signature#getInstance}.
+ */
+ public String getAlgorithm() {
+ return String.format("%swith%s", hashAlgorithm, signatureAlgorithm);
+ }
+
+ /**
+ * Decode a TLS encoded DigitallySigned structure.
+ */
+ public static DigitallySigned decode(InputStream input)
+ throws SerializationException {
+ try {
+ return new DigitallySigned(
+ Serialization.readNumber(input, CTConstants.HASH_ALGORITHM_LENGTH),
+ Serialization.readNumber(input, CTConstants.SIGNATURE_ALGORITHM_LENGTH),
+ Serialization.readVariableBytes(input, CTConstants.SIGNATURE_LENGTH_BYTES)
+ );
+ } catch (IllegalArgumentException e) {
+ throw new SerializationException(e);
+ }
+ }
+
+ /**
+ * Decode a TLS encoded DigitallySigned structure.
+ */
+ public static DigitallySigned decode(byte[] input)
+ throws SerializationException {
+ return decode(new ByteArrayInputStream(input));
+ }
+}
+
+
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ct/Serialization.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/Serialization.java
new file mode 100644
index 0000000..4b54dbf
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/Serialization.java
@@ -0,0 +1,243 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt.ct;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import com.android.org.conscrypt.Internal;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class Serialization {
+ private Serialization() {}
+
+ private static final int DER_TAG_MASK = 0x3f;
+ private static final int DER_TAG_OCTET_STRING = 0x4;
+ private static final int DER_LENGTH_LONG_FORM_FLAG = 0x80;
+
+ public static byte[] readDEROctetString(byte[] input)
+ throws SerializationException {
+ return readDEROctetString(new ByteArrayInputStream(input));
+ }
+
+ public static byte[] readDEROctetString(InputStream input)
+ throws SerializationException {
+ int tag = readByte(input) & DER_TAG_MASK;
+ if (tag != DER_TAG_OCTET_STRING) {
+ throw new SerializationException("Wrong DER tag, expected OCTET STRING, got " + tag);
+ }
+ int length;
+ int width = readNumber(input, 1);
+ if ((width & DER_LENGTH_LONG_FORM_FLAG) != 0) {
+ length = readNumber(input, width & ~DER_LENGTH_LONG_FORM_FLAG);
+ } else {
+ length = width;
+ }
+
+ return readFixedBytes(input, length);
+ }
+
+ public static byte[][] readList(byte[] input, int listWidth, int elemWidth)
+ throws SerializationException {
+ return readList(new ByteArrayInputStream(input), listWidth, elemWidth);
+ }
+
+ /**
+ * Read a variable length vector of variable sized elements as described by RFC5246 section 4.3.
+ * The vector is prefixed by its total length, in bytes and in big endian format,
+ * so is each element contained in the vector.
+ * @param listWidth the width of the vector's length field, in bytes.
+ * @param elemWidth the width of each element's length field, in bytes.
+ * @throws SerializationException if EOF is encountered.
+ */
+ public static byte[][] readList(InputStream input, int listWidth, int elemWidth)
+ throws SerializationException {
+ ArrayList<byte[]> result = new ArrayList<byte[]>();
+ byte[] data = readVariableBytes(input, listWidth);
+ input = new ByteArrayInputStream(data);
+ try {
+ while (input.available() > 0) {
+ result.add(readVariableBytes(input, elemWidth));
+ }
+ } catch (IOException e) {
+ throw new SerializationException(e);
+ }
+ return result.toArray(new byte[result.size()][]);
+ }
+
+ /**
+ * Read a length-prefixed sequence of bytes.
+ * The length must be encoded in big endian format.
+ * @param width the width of the length prefix, in bytes.
+ * @throws SerializationException if EOF is encountered, or if {@code width} is negative or
+ * greater than 4
+ */
+ public static byte[] readVariableBytes(InputStream input, int width)
+ throws SerializationException {
+ int length = readNumber(input, width);
+ return readFixedBytes(input, length);
+ }
+
+ /**
+ * Read a fixed number of bytes from the input stream.
+ * @param length the number of bytes to read.
+ * @throws SerializationException if EOF is encountered.
+ */
+ public static byte[] readFixedBytes(InputStream input, int length)
+ throws SerializationException {
+ try {
+ if (length < 0) {
+ throw new SerializationException("Negative length: " + length);
+ }
+
+ byte[] data = new byte[length];
+ int count = input.read(data);
+ if (count < length) {
+ throw new SerializationException("Premature end of input, expected " + length +
+ " bytes, only read " + count);
+ }
+ return data;
+ } catch (IOException e) {
+ throw new SerializationException(e);
+ }
+ }
+
+ /**
+ * Read a number in big endian format from the input stream.
+ * This methods only supports a width of up to 4 bytes.
+ * @param width the width of the number, in bytes.
+ * @throws SerializationException if EOF is encountered, or if {@code width} is negative or
+ * greater than 4
+ */
+ public static int readNumber(InputStream input, int width) throws SerializationException {
+ if (width > 4 || width < 0) {
+ throw new SerializationException("Invalid width: " + width);
+ }
+
+ int result = 0;
+ for (int i = 0; i < width; i++) {
+ result = (result << 8) | (readByte(input) & 0xFF);
+ }
+
+ return result;
+ }
+
+ /**
+ * Read a number in big endian format from the input stream.
+ * This methods supports a width of up to 8 bytes.
+ * @param width the width of the number, in bytes.
+ * @throws SerializationException if EOF is encountered.
+ * @throws IllegalArgumentException if {@code width} is negative or greater than 8
+ */
+ public static long readLong(InputStream input, int width) throws SerializationException {
+ if (width > 8 || width < 0) {
+ throw new IllegalArgumentException("Invalid width: " + width);
+ }
+
+ long result = 0;
+ for (int i = 0; i < width; i++) {
+ result = (result << 8) | (readByte(input) & 0xFF);
+ }
+
+ return result;
+ }
+
+ /**
+ * Read a single byte from the input stream.
+ * @throws SerializationException if EOF is encountered.
+ */
+ public static byte readByte(InputStream input) throws SerializationException {
+ try {
+ int b = input.read();
+ if (b == -1) {
+ throw new SerializationException("Premature end of input, could not read byte.");
+ }
+ return (byte)b;
+ } catch (IOException e) {
+ throw new SerializationException(e);
+ }
+ }
+
+ /**
+ * Write length prefixed sequence of bytes to the ouput stream.
+ * The length prefix is encoded in big endian order.
+ * @param data the data to be written.
+ * @param width the width of the length prefix, in bytes.
+ * @throws SerializationException if the length of {@code data} is too large to fit in
+ * {@code width} bytes or {@code width} is negative.
+ */
+ public static void writeVariableBytes(OutputStream output, byte[] data, int width)
+ throws SerializationException {
+ writeNumber(output, data.length, width);
+ writeFixedBytes(output, data);
+ }
+
+ /**
+ * Write a fixed number sequence of bytes to the ouput stream.
+ * @param data the data to be written.
+ */
+ public static void writeFixedBytes(OutputStream output, byte[] data)
+ throws SerializationException {
+ try {
+ output.write(data);
+ } catch (IOException e) {
+ throw new SerializationException(e);
+ }
+ }
+
+ /**
+ * Write a number to the output stream.
+ * The number is encoded in big endian order.
+ * @param value the value to be written.
+ * @param width the width of the encoded number, in bytes
+ * @throws SerializationException if the number is too large to fit in {@code width} bytes or
+ * {@code width} is negative.
+ */
+ public static void writeNumber(OutputStream output, long value, int width)
+ throws SerializationException {
+ if (width < 0) {
+ throw new SerializationException("Negative width: " + width);
+ }
+ if (width < 8 && value >= (1L << (8 * width))) {
+ throw new SerializationException(
+ "Number too large, " + value + " does not fit in " + width + " bytes");
+ }
+
+ try {
+ while (width > 0) {
+ long shift = (width - 1) * 8L;
+ // Java behaves weirdly if shifting by more than the variable's size
+ if (shift < Long.SIZE) {
+ output.write((byte) ((value >> shift) & 0xFF));
+ } else {
+ output.write(0);
+ }
+
+ width--;
+ }
+ } catch (IOException e) {
+ throw new SerializationException(e);
+ }
+ }
+}
+
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ct/SerializationException.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/SerializationException.java
new file mode 100644
index 0000000..0a8eec1
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/SerializationException.java
@@ -0,0 +1,44 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt.ct;
+
+import com.android.org.conscrypt.Internal;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class SerializationException extends Exception {
+ private static final long serialVersionUID = -5317873136664833411L;
+
+ public SerializationException() {
+ }
+
+ public SerializationException(String message) {
+ super(message);
+ }
+
+ public SerializationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public SerializationException(Throwable cause) {
+ super(cause);
+ }
+}
+
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ct/SignedCertificateTimestamp.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/SignedCertificateTimestamp.java
new file mode 100644
index 0000000..218603b
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/SignedCertificateTimestamp.java
@@ -0,0 +1,147 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt.ct;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import com.android.org.conscrypt.Internal;
+
+/**
+ * SignedCertificateTimestamp structure, as defined by RFC6962 Section 3.2.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class SignedCertificateTimestamp {
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public enum Version {
+ V1
+ };
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public enum SignatureType {
+ CERTIFICATE_TIMESTAMP,
+ TREE_HASH
+ };
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public enum Origin {
+ EMBEDDED,
+ TLS_EXTENSION,
+ OCSP_RESPONSE
+ };
+
+ private final Version version;
+ private final byte[] logId;
+ private final long timestamp;
+ private final byte[] extensions;
+ private final DigitallySigned signature;
+
+ // origin is implied from the SCT's source and is not encoded in it,
+ // and affects the verification process.
+ private final Origin origin;
+
+ public SignedCertificateTimestamp(Version version, byte[] logId,
+ long timestamp, byte[] extensions,
+ DigitallySigned signature, Origin origin) {
+ this.version = version;
+ this.logId = logId;
+ this.timestamp = timestamp;
+ this.extensions = extensions;
+ this.signature = signature;
+ this.origin = origin;
+ }
+
+ public Version getVersion() {
+ return version;
+ }
+ public byte[] getLogID() {
+ return logId;
+ }
+ public long getTimestamp() {
+ return timestamp;
+ }
+ public byte[] getExtensions() {
+ return extensions;
+ }
+ public DigitallySigned getSignature() {
+ return signature;
+ }
+ public Origin getOrigin() {
+ return origin;
+ }
+
+ /**
+ * Decode a TLS encoded SignedCertificateTimestamp structure.
+ */
+ public static SignedCertificateTimestamp decode(InputStream input, Origin origin)
+ throws SerializationException {
+ int version = Serialization.readNumber(input, CTConstants.VERSION_LENGTH);
+ if (version != Version.V1.ordinal()) {
+ throw new SerializationException("Unsupported SCT version " + version);
+ }
+
+ return new SignedCertificateTimestamp(
+ Version.V1,
+ Serialization.readFixedBytes(input, CTConstants.LOGID_LENGTH),
+ Serialization.readLong(input, CTConstants.TIMESTAMP_LENGTH),
+ Serialization.readVariableBytes(input, CTConstants.EXTENSIONS_LENGTH_BYTES),
+ DigitallySigned.decode(input),
+ origin
+ );
+ }
+
+ /**
+ * Decode a TLS encoded SignedCertificateTimestamp structure.
+ */
+ public static SignedCertificateTimestamp decode(byte[] input, Origin origin)
+ throws SerializationException {
+ return decode(new ByteArrayInputStream(input), origin);
+ }
+
+ /**
+ * TLS encode the signed part of the SCT, as described by RFC6962 section 3.2.
+ */
+ public void encodeTBS(OutputStream output, CertificateEntry certEntry)
+ throws SerializationException {
+ Serialization.writeNumber(output, version.ordinal(), CTConstants.VERSION_LENGTH);
+ Serialization.writeNumber(output, SignatureType.CERTIFICATE_TIMESTAMP.ordinal(),
+ CTConstants.SIGNATURE_TYPE_LENGTH);
+ Serialization.writeNumber(output, timestamp, CTConstants.TIMESTAMP_LENGTH);
+ certEntry.encode(output);
+ Serialization.writeVariableBytes(output, extensions, CTConstants.EXTENSIONS_LENGTH_BYTES);
+ }
+
+ /**
+ * TLS encode the signed part of the SCT, as described by RFC6962 section 3.2.
+ */
+ public byte[] encodeTBS(CertificateEntry certEntry)
+ throws SerializationException {
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ encodeTBS(output, certEntry);
+ return output.toByteArray();
+ }
+}
+
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ct/TEST_MAPPING b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/TEST_MAPPING
new file mode 100644
index 0000000..e73a39a
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsLibcoreTestCases",
+ "options": [
+ {
+ "include-filter": "com.android.org.conscrypt.ct"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ct/VerifiedSCT.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/VerifiedSCT.java
new file mode 100644
index 0000000..e68a98c
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/VerifiedSCT.java
@@ -0,0 +1,46 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt.ct;
+
+import com.android.org.conscrypt.Internal;
+
+/**
+ * Verification result for a single SCT.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class VerifiedSCT {
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public enum Status {
+ VALID,
+ INVALID_SIGNATURE,
+ UNKNOWN_LOG,
+ INVALID_SCT
+ }
+
+ public final SignedCertificateTimestamp sct;
+ public final Status status;
+
+ public VerifiedSCT(SignedCertificateTimestamp sct, Status status) {
+ this.sct = sct;
+ this.status = status;
+ }
+}
+
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/io/IoUtils.java b/repackaged/common/src/main/java/com/android/org/conscrypt/io/IoUtils.java
new file mode 100644
index 0000000..e7f9830
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/io/IoUtils.java
@@ -0,0 +1,68 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.io;
+
+import java.io.Closeable;
+import java.io.InterruptedIOException;
+import java.net.Socket;
+import com.android.org.conscrypt.Internal;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class IoUtils {
+ private IoUtils() {}
+
+ /**
+ * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null.
+ */
+ public static void closeQuietly(Closeable closeable) {
+ if (closeable != null) {
+ try {
+ closeable.close();
+ } catch (RuntimeException rethrown) {
+ throw rethrown;
+ } catch (Exception ignored) {
+ // Ignored
+ }
+ }
+ }
+
+ /**
+ * Closes 'socket', ignoring any exceptions. Does nothing if 'socket' is null.
+ */
+ public static void closeQuietly(Socket socket) {
+ if (socket != null) {
+ try {
+ socket.close();
+ } catch (Exception ignored) {
+ // Ignored
+ }
+ }
+ }
+
+ public static void throwInterruptedIoException() throws InterruptedIOException {
+ // This is typically thrown in response to an
+ // InterruptedException which does not leave the thread in an
+ // interrupted state, so explicitly interrupt here.
+ Thread.currentThread().interrupt();
+ // TODO: set InterruptedIOException.bytesTransferred
+ throw new InterruptedIOException();
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/CipherSuite.java b/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/CipherSuite.java
new file mode 100644
index 0000000..ed28d69
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/CipherSuite.java
@@ -0,0 +1,89 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2020 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.
+ */
+package com.android.org.conscrypt.metrics;
+
+import com.android.org.conscrypt.Internal;
+
+/**
+ * Cipher suites to metric mapping for metrics instrumentation.
+ *
+ * Must be in sync with frameworks/base/cmds/statsd/src/atoms.proto
+ *
+ * Ids are based on IANA's database of SSL/TLS cipher suites
+ * @see https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public enum CipherSuite {
+ UNKNOWN_CIPHER_SUITE(0x0000),
+
+ // Supported but not enabled
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA(0xC00A),
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA(0xC014),
+ TLS_RSA_WITH_AES_256_CBC_SHA(0x0035),
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA(0xC009),
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA(0xC013),
+ TLS_RSA_WITH_AES_128_CBC_SHA(0x002F),
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA(0x000A),
+
+ // TLSv1.2 cipher suites
+ TLS_RSA_WITH_AES_128_GCM_SHA256(0x009C),
+ TLS_RSA_WITH_AES_256_GCM_SHA384(0x009D),
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(0xC02F),
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384(0xC030),
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256(0xC02B),
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384(0xC02C),
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256(0xCCA9),
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256(0xCCA8),
+
+ // Pre-Shared Key (PSK) cipher suites
+ TLS_PSK_WITH_AES_128_CBC_SHA(0x008C),
+ TLS_PSK_WITH_AES_256_CBC_SHA(0x008D),
+ TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA(0xC035),
+ TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA(0xC036),
+ TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256(0xCCAC),
+
+ // TLS 1.3 cipher suites
+ TLS_AES_128_GCM_SHA256(0x1301),
+ TLS_AES_256_GCM_SHA384(0x1302),
+ TLS_CHACHA20_POLY1305_SHA256(0x1303),
+
+ TLS_CIPHER_FAILED(0xFFFF),
+ ;
+
+ final short id;
+
+ public int getId() {
+ return this.id;
+ }
+
+ public static CipherSuite forName(String name) {
+ if ("SSL_RSA_WITH_3DES_EDE_CBC_SHA".equals(name)) {
+ // JCA StandardNames shenanigans.
+ return TLS_RSA_WITH_3DES_EDE_CBC_SHA;
+ }
+ try {
+ return CipherSuite.valueOf(name);
+ } catch (IllegalArgumentException e) {
+ return CipherSuite.UNKNOWN_CIPHER_SUITE;
+ }
+ }
+
+ private CipherSuite(int id) {
+ this.id = (short) id;
+ }
+}
\ No newline at end of file
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/ConscryptStatsLog.java b/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/ConscryptStatsLog.java
new file mode 100644
index 0000000..b5ebdf7
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/ConscryptStatsLog.java
@@ -0,0 +1,49 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2020 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.
+ */
+package com.android.org.conscrypt.metrics;
+
+import com.android.org.conscrypt.Internal;
+
+/**
+ * Reimplement with reflection calls the logging class,
+ * generated by frameworks/statsd.
+ * <p>
+ * In case atom is changed, generate new wrapper with stats-log-api-gen
+ * tool as shown below and add corresponding methods to ReflexiveStatsEvent's
+ * newEvent() method.
+ * <p>
+ * $ stats-log-api-gen \
+ * --java "common/src/main/java/org/conscrypt/metrics/ConscryptStatsLog.java" \
+ * --module conscrypt \
+ * --javaPackage org.conscrypt.metrics \
+ * --javaClass ConscryptStatsLog
+ * @hide This class is not part of the Android public SDK API
+ **/
+@Internal
+public final class ConscryptStatsLog {
+ public static final int TLS_HANDSHAKE_REPORTED = 317;
+
+ private ConscryptStatsLog() {}
+
+ public static void write(int atomId, boolean success, int protocol, int cipherSuite,
+ int duration, Source source) {
+ ReflexiveStatsEvent event = ReflexiveStatsEvent.buildEvent(
+ atomId, success, protocol, cipherSuite, duration, source.ordinal());
+
+ ReflexiveStatsLog.write(event);
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/OptionalMethod.java b/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/OptionalMethod.java
new file mode 100644
index 0000000..97692cd
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/OptionalMethod.java
@@ -0,0 +1,101 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2020 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.
+ */
+package com.android.org.conscrypt.metrics;
+
+import com.android.org.conscrypt.Internal;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Helper class to handle reflexive loading and invocation of methods which may be absent.
+ *
+ * @hide This class is not part of the Android public SDK API
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class OptionalMethod {
+ private final Method cachedMethod;
+
+ /**
+ * Instantiates a new OptionalMethod.
+ * <p>Does not throw any exceptions if the class or method can't be loaded, or if any parameter
+ * classes are {@code null} and instead behaves as a no-op, always returning {@code null}.
+ *
+ * @param clazz the Class to search for methods on
+ * @param methodName the name of the {@code Method} on {@code clazz}
+ * @param methodParams list of {@code Classes} of the {@code Method's} parameters
+ *
+ * @throws NullPointerException if the method name is {@code null}
+ */
+ public OptionalMethod(Class<?> clazz, String methodName, Class<?>... methodParams) {
+ this.cachedMethod = initializeMethod(clazz, methodName, methodParams);
+ }
+
+ private static Method initializeMethod(
+ Class<?> clazz, String methodName, Class<?>... methodParams) {
+ try {
+ for (Class<?> paramClass : methodParams) {
+ if (paramClass == null) {
+ return null;
+ }
+ }
+ if (clazz != null) {
+ return clazz.getMethod(checkNotNull(methodName), methodParams);
+ }
+ } catch (NoSuchMethodException ignored) {
+ // Ignored
+ }
+ return null;
+ }
+
+ public Object invokeStatic(Object... args) {
+ // no-op if failed to load method in constructor
+ if (cachedMethod == null) {
+ return null;
+ }
+ try {
+ return cachedMethod.invoke(null, args);
+ } catch (IllegalAccessException ignored) {
+ // Ignored
+ } catch (InvocationTargetException ignored) {
+ // Ignored
+ }
+ return null;
+ }
+
+ public Object invoke(Object target, Object... args) {
+ // no-op if failed to load method in constructor or target is null
+ if (cachedMethod == null || target == null) {
+ return null;
+ }
+ try {
+ return cachedMethod.invoke(target, args);
+ } catch (IllegalAccessException ignored) {
+ // Ignored
+ } catch (InvocationTargetException ignored) {
+ // Ignored
+ }
+ return null;
+ }
+
+ private static <T> T checkNotNull(T reference) {
+ if (reference == null) {
+ throw new NullPointerException();
+ }
+ return reference;
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/Protocol.java b/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/Protocol.java
new file mode 100644
index 0000000..dda1f38
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/Protocol.java
@@ -0,0 +1,66 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2020 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.
+ */
+package com.android.org.conscrypt.metrics;
+
+import com.android.org.conscrypt.Internal;
+
+/**
+ * Protocols to metric mapping for metrics instrumentation.
+ *
+ * Must be in sync with frameworks/base/cmds/statsd/src/atoms.proto
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public enum Protocol {
+ UNKNOWN_PROTO(0),
+ SSLv3(1),
+ TLSv1(2),
+ TLSv1_1(3),
+ TLSv1_2(4),
+ TLSv1_3(5),
+ TLS_PROTO_FAILED(0xFFFF),
+ ;
+
+ final byte id;
+
+ public int getId() {
+ return this.id;
+ }
+
+ public static Protocol forName(String name) {
+ switch (name) {
+ case "SSLv3":
+ return SSLv3;
+ case "TLSv1":
+ return TLSv1;
+ case "TLSv1.1":
+ return TLSv1_1;
+ case "TLSv1.2":
+ return TLSv1_2;
+ case "TLSv1.3":
+ return TLSv1_3;
+ case "TLS_PROTO_FAILED":
+ return TLS_PROTO_FAILED;
+ default:
+ return UNKNOWN_PROTO;
+ }
+ }
+
+ private Protocol(int id) {
+ this.id = (byte) id;
+ }
+}
\ No newline at end of file
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/ReflexiveStatsEvent.java b/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/ReflexiveStatsEvent.java
new file mode 100644
index 0000000..d3e0100
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/ReflexiveStatsEvent.java
@@ -0,0 +1,128 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2020 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.
+ */
+package com.android.org.conscrypt.metrics;
+
+import com.android.org.conscrypt.Internal;
+
+/**
+ * Reflection wrapper around android.util.StatsEvent.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class ReflexiveStatsEvent {
+ private static final OptionalMethod newBuilder;
+ private static final Class<?> c_statsEvent;
+
+ static {
+ c_statsEvent = initStatsEventClass();
+ newBuilder = new OptionalMethod(c_statsEvent, "newBuilder");
+ }
+
+ private static Class<?> initStatsEventClass() {
+ try {
+ return Class.forName("android.util.StatsEvent");
+ } catch (ClassNotFoundException ignored) {
+ return null;
+ }
+ }
+
+ private final Object statsEvent;
+
+ private ReflexiveStatsEvent(Object statsEvent) {
+ this.statsEvent = statsEvent;
+ }
+
+ public Object getStatsEvent() {
+ return statsEvent;
+ }
+
+ public static ReflexiveStatsEvent.Builder newBuilder() {
+ return new ReflexiveStatsEvent.Builder();
+ }
+
+ public static ReflexiveStatsEvent buildEvent(
+ int atomId, boolean success, int protocol, int cipherSuite, int duration, int source) {
+ ReflexiveStatsEvent.Builder builder = ReflexiveStatsEvent.newBuilder();
+ builder.setAtomId(atomId);
+ builder.writeBoolean(success);
+ builder.writeInt(protocol);
+ builder.writeInt(cipherSuite);
+ builder.writeInt(duration);
+ builder.writeInt(source);
+ builder.usePooledBuffer();
+ return builder.build();
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class Builder {
+ private static final Class<?> c_statsEvent_Builder;
+ private static final OptionalMethod setAtomId;
+ private static final OptionalMethod writeBoolean;
+ private static final OptionalMethod writeInt;
+ private static final OptionalMethod build;
+ private static final OptionalMethod usePooledBuffer;
+
+ static {
+ c_statsEvent_Builder = initStatsEventBuilderClass();
+ setAtomId = new OptionalMethod(c_statsEvent_Builder, "setAtomId", int.class);
+ writeBoolean = new OptionalMethod(c_statsEvent_Builder, "writeBoolean", boolean.class);
+ writeInt = new OptionalMethod(c_statsEvent_Builder, "writeInt", int.class);
+ build = new OptionalMethod(c_statsEvent_Builder, "build");
+ usePooledBuffer = new OptionalMethod(c_statsEvent_Builder, "usePooledBuffer");
+ }
+
+ private static Class<?> initStatsEventBuilderClass() {
+ try {
+ return Class.forName("android.util.StatsEvent$Builder");
+ } catch (ClassNotFoundException ignored) {
+ return null;
+ }
+ }
+
+ private final Object builder;
+
+ private Builder() {
+ this.builder = newBuilder.invokeStatic();
+ }
+
+ public Builder setAtomId(final int atomId) {
+ setAtomId.invoke(this.builder, atomId);
+ return this;
+ }
+
+ public Builder writeBoolean(final boolean value) {
+ writeBoolean.invoke(this.builder, value);
+ return this;
+ }
+
+ public Builder writeInt(final int value) {
+ writeInt.invoke(this.builder, value);
+ return this;
+ }
+
+ public void usePooledBuffer() {
+ usePooledBuffer.invoke(this.builder);
+ }
+
+ public ReflexiveStatsEvent build() {
+ Object statsEvent = build.invoke(this.builder);
+ return new ReflexiveStatsEvent(statsEvent);
+ }
+ }
+}
\ No newline at end of file
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/ReflexiveStatsLog.java b/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/ReflexiveStatsLog.java
new file mode 100644
index 0000000..8f56e30
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/ReflexiveStatsLog.java
@@ -0,0 +1,61 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2020 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.
+ */
+package com.android.org.conscrypt.metrics;
+
+import com.android.org.conscrypt.Internal;
+
+/**
+ * Reflection wrapper around android.util.StatsLog.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class ReflexiveStatsLog {
+ private static final Class<?> c_statsLog;
+ private static final Class<?> c_statsEvent;
+ private static final OptionalMethod write;
+
+ static {
+ c_statsLog = initStatsLogClass();
+ c_statsEvent = initStatsEventClass();
+ write = new OptionalMethod(c_statsLog, "write", c_statsEvent);
+ }
+
+ private static Class<?> initStatsLogClass() {
+ try {
+ return Class.forName("android.util.StatsLog");
+ } catch (ClassNotFoundException ignored) {
+ return null;
+ }
+ }
+
+ private static Class<?> initStatsEventClass() {
+ try {
+ return Class.forName("android.util.StatsEvent");
+ } catch (ClassNotFoundException ignored) {
+ return null;
+ }
+ }
+
+ private ReflexiveStatsLog() {}
+
+ public static void write(ReflexiveStatsEvent event) {
+ Object statsEvent = event.getStatsEvent();
+ if (statsEvent != null) {
+ write.invokeStatic(statsEvent);
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/Source.java b/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/Source.java
new file mode 100644
index 0000000..8eafb8c
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/metrics/Source.java
@@ -0,0 +1,33 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2022 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.
+ */
+package com.android.org.conscrypt.metrics;
+
+import com.android.org.conscrypt.Internal;
+
+/**
+ * Data Sources to metric mapping for metrics instrumentation.
+ *
+ * Must be in sync with frameworks/base/cmds/statsd/src/atoms.proto
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public enum Source {
+ SOURCE_UNKNOWN,
+ SOURCE_MAINLINE,
+ SOURCE_GMS,
+ SOURCE_UNBUNDLED;
+}
\ No newline at end of file
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/BufferUtilsTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/BufferUtilsTest.java
new file mode 100644
index 0000000..ef26e0d
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/BufferUtilsTest.java
@@ -0,0 +1,212 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2021 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import com.android.org.conscrypt.TestUtils.BufferType;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(Parameterized.class)
+public class BufferUtilsTest {
+ private static final int K64 = 64 * 1024;
+ private static final int K16 = 16 * 1024;
+
+ private static final int[][] TEST_SIZES = {
+ // All even numbers as several tests use size/2
+ { 0 },
+ { 0, 0, 0, 0 },
+ { 0, 0, 0, 2 },
+ { 2, 0, 0, 0 },
+ { 100, 200, 300 },
+ { 1000, 2000, 3000 },
+ { K16 },
+ { 0, 0, K16 },
+ { K16, 0, 0 },
+ { K64 },
+ { 0, 0, K64 },
+ { K64, 0, 0 },
+ { 100, 100, K64 },
+ { K64, 100, 100 },
+ { K64, K64, K64 },
+ };
+
+
+ @Parameters(name = "{0}")
+ public static BufferType[] data() {
+ return new BufferType[] { BufferType.HEAP, BufferType.DIRECT };
+ }
+
+ @Parameter
+ public BufferType bufferType;
+
+ @Test
+ public void checkNotNull() {
+ for (int[] sizes : TEST_SIZES) {
+ BufferUtils.checkNotNull(bufferType.newRandomBuffers(sizes));
+ }
+
+ ByteBuffer[] buffers = bufferType.newRandomBuffers(10, 10, 10, 10, 10);
+ buffers[2] = null;
+ try {
+ BufferUtils.checkNotNull(buffers);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ }
+
+ @Test
+ public void remaining() {
+ for (int[] sizes : TEST_SIZES) {
+ assertEquals(arraySum(sizes),
+ BufferUtils.remaining(bufferType.newRandomBuffers(sizes)));
+ }
+ }
+
+ @Test
+ public void consume() {
+ for (int[] sizes : TEST_SIZES) {
+ ByteBuffer[] buffers = bufferType.newRandomBuffers(sizes);
+ int totalSize = arraySum(sizes);
+
+ BufferUtils.consume(buffers, 0);
+ assertEquals(totalSize, BufferUtils.remaining(buffers));
+
+ BufferUtils.consume(buffers,totalSize / 2);
+ assertEquals(totalSize / 2, BufferUtils.remaining(buffers));
+
+ BufferUtils.consume(buffers,totalSize / 2);
+ assertEquals(0, BufferUtils.remaining(buffers));
+
+ if (totalSize > 0) {
+ try {
+ BufferUtils.consume(buffers, totalSize / 2);
+ fail("Managed to consume past end of buffer array");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ }
+ }
+ }
+
+ @Test
+ public void copyNoConsume() {
+ for (BufferType destinationType : BufferType.values()) {
+ for (int[] sizes : TEST_SIZES) {
+ ByteBuffer[] buffers = bufferType.newRandomBuffers(sizes);
+ int totalSize = arraySum(sizes);
+
+ ByteBuffer destination = destinationType.newBuffer(totalSize);
+ BufferUtils.copyNoConsume(buffers, destination, totalSize);
+ assertEquals(totalSize, BufferUtils.remaining(buffers));
+
+ assertArrayEquals(toArray(buffers), toArray(destination));
+ }
+ }
+ }
+
+ private static byte[] toArray(ByteBuffer... buffers) {
+ byte[] bytes = new byte[(int) BufferUtils.remaining(buffers)];
+ int offset = 0;
+ for (ByteBuffer buffer : buffers) {
+ int length = buffer.remaining();
+ if (length > 0) {
+ buffer.get(bytes, offset, length);
+ offset += length;
+ }
+ }
+ return bytes;
+ }
+
+ @Test
+ public void getBufferLargerThan_allSmall() {
+ ByteBuffer[] buffers = bufferType.newRandomBuffers(100, 200, 300, 400);
+
+ assertNull(BufferUtils.getBufferLargerThan(buffers, K16));
+
+ BufferUtils.consume(buffers, 300);
+ assertNull(BufferUtils.getBufferLargerThan(buffers, K16));
+ assertSame(buffers[2], BufferUtils.getBufferLargerThan(buffers, 100));
+
+ BufferUtils.consume(buffers, 300);
+ assertSame(buffers[3], BufferUtils.getBufferLargerThan(buffers, K16));
+
+ BufferUtils.consume(buffers, 200);
+ assertSame(buffers[3], BufferUtils.getBufferLargerThan(buffers, K16));
+
+ BufferUtils.consume(buffers, 200);
+ ByteBuffer buffer = BufferUtils.getBufferLargerThan(buffers, K16);
+ assertNull(buffer);
+ }
+
+ @Test
+ public void getBufferLargerThan_oneLarge() {
+ ByteBuffer[] buffers = bufferType.newRandomBuffers(100, K64, 300, 400);
+
+ assertNull(BufferUtils.getBufferLargerThan(buffers, K16));
+
+ BufferUtils.consume(buffers, 100);
+ assertSame(buffers[1], BufferUtils.getBufferLargerThan(buffers, K16));
+
+ BufferUtils.consume(buffers, 1024); // 63K remaining in buffers[1]
+ assertSame(buffers[1], BufferUtils.getBufferLargerThan(buffers, K16));
+
+ BufferUtils.consume(buffers, 60 * 1024); // 3K remaining in buffers[1]
+ assertNull(BufferUtils.getBufferLargerThan(buffers, K16));
+
+ BufferUtils.consume(buffers, 3 * 1024);
+ assertEquals(0, buffers[1].remaining());
+ assertNull(BufferUtils.getBufferLargerThan(buffers, K16));
+
+ BufferUtils.consume(buffers, 300);
+ assertSame(buffers[3], BufferUtils.getBufferLargerThan(buffers, K16));
+
+ BufferUtils.consume(buffers, 400);
+ ByteBuffer buffer = BufferUtils.getBufferLargerThan(buffers, K16);
+ assertNull(buffer);
+ }
+
+ @Test
+ public void getBufferLargerThan_onlyOneBuffer() {
+ ByteBuffer[] buffers = bufferType.newRandomBuffers(0, 0, 100, 0, 0);
+
+ assertSame(buffers[2], BufferUtils.getBufferLargerThan(buffers, K16));
+ }
+
+ private int arraySum(int[] sizes) {
+ int sum = 0;
+ for (int i : sizes) {
+ sum += i;
+ }
+ return sum;
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/CertPinManagerTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/CertPinManagerTest.java
new file mode 100644
index 0000000..a2479bb
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/CertPinManagerTest.java
@@ -0,0 +1,126 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.security.KeyStore;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.List;
+import com.android.org.conscrypt.java.security.TestKeyStore;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class CertPinManagerTest {
+ private List<X509Certificate> expectedFullChain;
+ private X509Certificate[] chain;
+
+ @Before
+ public void setUp() {
+ KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
+ X509Certificate[] certs = (X509Certificate[]) pke.getCertificateChain();
+ expectedFullChain = Arrays.asList(certs);
+ // Leave the root out of the chain
+ chain = new X509Certificate[2];
+ chain[0] = certs[0];
+ chain[1] = certs[1];
+ }
+
+ @Test
+ public void testCertPinManagerCalled() throws Exception {
+ class TestCertPinManager implements CertPinManager {
+ public boolean called = false;
+ @Override
+ public void checkChainPinning(String hostname, List<X509Certificate> chain) {
+ called = true;
+ }
+ }
+ TestCertPinManager manager = new TestCertPinManager();
+ callCheckServerTrusted(null, manager);
+ assertTrue(manager.called);
+ }
+
+ @Test
+ public void testNullPinManager() throws Exception {
+ callCheckServerTrusted(null, null);
+ }
+
+ @Test
+ public void testFailure() throws Exception {
+ CertPinManager manager = new CertPinManager() {
+ @Override
+ public void checkChainPinning(String hostname, List<X509Certificate> chain)
+ throws CertificateException {
+ throw new CertificateException("pin failure");
+ }
+ };
+ try {
+ callCheckServerTrusted(null, manager);
+ fail("Invalid chain was trusted");
+ } catch (CertificateException expected) {
+ assertEquals("pin failure", expected.getMessage());
+ }
+ }
+
+ @Test
+ public void testHostnameProvided() throws Exception {
+ final String expectedHostname = "example.com";
+ class TestCertPinManager implements CertPinManager {
+ public boolean hostnameMatched = false;
+ @Override
+ public void checkChainPinning(String hostname, List<X509Certificate> chain) {
+ hostnameMatched = expectedHostname.equals(hostname);
+ }
+ }
+ TestCertPinManager manager = new TestCertPinManager();
+ callCheckServerTrusted(expectedHostname, manager);
+ assertTrue(manager.hostnameMatched);
+ }
+
+ @Test
+ public void testFullChainProvided() throws Exception {
+ class TestCertPinManager implements CertPinManager {
+ public boolean fullChainProvided = false;
+ @Override
+ public void checkChainPinning(String hostname, List<X509Certificate> chain)
+ throws CertificateException {
+ fullChainProvided = expectedFullChain.equals(chain);
+ }
+ }
+ TestCertPinManager manager = new TestCertPinManager();
+ callCheckServerTrusted(null, manager);
+ assertTrue(manager.fullChainProvided);
+ }
+
+ private void callCheckServerTrusted(String hostname, CertPinManager manager)
+ throws CertificateException {
+ TestUtils.assumeExtendedTrustManagerAvailable();
+ TrustManagerImpl tm = new TrustManagerImpl(TestKeyStore.getClient().keyStore, manager);
+ tm.checkServerTrusted(chain, "RSA", hostname);
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/ChainStrengthAnalyzerTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/ChainStrengthAnalyzerTest.java
new file mode 100644
index 0000000..fe968b9
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/ChainStrengthAnalyzerTest.java
@@ -0,0 +1,371 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2011 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class ChainStrengthAnalyzerTest {
+
+ //openssl req -x509 -nodes -days 365 -subj '/C=US/ST=Testsota/L=Testville/CN=test.com' \
+ //-newkey rsa:2048 -sha256 -keyout k.pem -out good.pem
+ private static final String GOOD_RSA_PEM = "" +
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIDYTCCAkmgAwIBAgIJAPFX8KGuEZcgMA0GCSqGSIb3DQEBCwUAMEcxCzAJBgNV\n" +
+ "BAYTAlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVzdHZpbGxlMREw\n" +
+ "DwYDVQQDDAh0ZXN0LmNvbTAeFw0xMjEwMTUyMTQ0MTBaFw0xMzEwMTUyMTQ0MTBa\n" +
+ "MEcxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVz\n" +
+ "dHZpbGxlMREwDwYDVQQDDAh0ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n" +
+ "ADCCAQoCggEBAM44hz3eTINuAIS9OYmg6DkUIj3MItn5dgbcMEdbXrhNpeWY93ho\n" +
+ "WQFfsqcSSx28NzqKJmnX+cyinzIUfVde/qciP9P7fxRDokRsf34DJ6gXQplz6P2t\n" +
+ "s4CWjYM+WXJrvEUgLUQ3CBV0CCrtYvG1B9wYsBdAdWkVaMxTvEt7aVxcvJYzp+KU\n" +
+ "ME7HDg0PVxptvUExIskcqKVmW7i748AgBLhd0r1nFWLuH20d42Aowja0Wi19fWl2\n" +
+ "SEMErDRjG8jIPUdSoOLPVLGTktEpex51xnAaZ+I7hy6zs55dq8ua/hE/v2cXIkiQ\n" +
+ "ZXpWyvI/MaKEfeydLnNpa7J3GpH3KW93HQcCAwEAAaNQME4wHQYDVR0OBBYEFA0M\n" +
+ "RI+3hIPCSpVVArisr3Y3/sheMB8GA1UdIwQYMBaAFA0MRI+3hIPCSpVVArisr3Y3\n" +
+ "/sheMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFgUNyuy2qaJvgDO\n" +
+ "plYudTrJR38O3id1B5oKOzgTEgRrfmHHfyloY4fL5gjAGNp7vdlDKSHC2Ebo23/X\n" +
+ "Wg535MJ2296R855jaTMdkSE0+4ASpdmon1D007H0FhLyojlKVta3pqMAF1zsp0YF\n" +
+ "Mf3V/rVMDxCOnbSnqAX0+1nW8Qm4Jgrr3AAMafZk6ypq0xuNQn+sUWuIWw3Xv5Jl\n" +
+ "KehjnuKtMgVYkn2ItRNnUdhm2dQK+Phdb5Yg8WHXN/r9sZQdORg8FQS9TfQJmimB\n" +
+ "CVYuqA9Dt0JJZPuO/Pd1yAxWP4NpxX1xr3lNQ5jrTO702QA3gOrscluULLzrYR50\n" +
+ "FoAjeos=\n" +
+ "-----END CERTIFICATE-----";
+
+ //openssl ecparam -genkey -name prime256v1 -out eckey.pem && \
+ //openssl req -x509 -nodes -days 365 -subj '/C=US/ST=Testsota/L=Testville/CN=test.com' \
+ //-newkey ec:eckey.pem -sha256 -keyout k.pem -out good.pem
+ private static final String GOOD_ECDSA_PEM = "" +
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIB1jCCAXugAwIBAgIJALhpH2C1lYeaMAoGCCqGSM49BAMCMEcxCzAJBgNVBAYT\n" +
+ "AlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVzdHZpbGxlMREwDwYD\n" +
+ "VQQDDAh0ZXN0LmNvbTAeFw0xNDEwMjAyMjUyNDZaFw0xNTEwMjAyMjUyNDZaMEcx\n" +
+ "CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVzdHZp\n" +
+ "bGxlMREwDwYDVQQDDAh0ZXN0LmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA\n" +
+ "BNR++2RWKGFUm+1KTLz7qxrJclPhVNM6gqInvAz2bLo7ENsD5KqN9BbmNvT4eg3y\n" +
+ "u5i+00kiroKcm/35zhNFYamjUDBOMB0GA1UdDgQWBBRJmq9/dKkDW8n8mPzGzuo5\n" +
+ "LcYUKjAfBgNVHSMEGDAWgBRJmq9/dKkDW8n8mPzGzuo5LcYUKjAMBgNVHRMEBTAD\n" +
+ "AQH/MAoGCCqGSM49BAMCA0kAMEYCIQDgq5qudvY9zp3ZhVKEfMLbmwybiM15+wrC\n" +
+ "xp6ipl+GZgIhAKbN/YfYoYlvr6z/xPrZfCZNLEaY/E01PqvD/d91Psa8\n" +
+ "-----END CERTIFICATE-----\n";
+
+ //openssl dsaparam -genkey 1024 -out dsakey.pem && \
+ //openssl req -x509 -nodes -days 365 -subj '/C=US/ST=Testsota/L=Testville/CN=test.com' \
+ //-newkey dsa:dsakey.pem -sha256 -keyout k.pem -out good.pem
+ private static final String GOOD_DSA_PEM = "" +
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIDHTCCAtugAwIBAgIJAI4X+OBX9ap9MAsGCWCGSAFlAwQDAjBHMQswCQYDVQQG\n" +
+ "EwJVUzERMA8GA1UECAwIVGVzdHNvdGExEjAQBgNVBAcMCVRlc3R2aWxsZTERMA8G\n" +
+ "A1UEAwwIdGVzdC5jb20wHhcNMTQwOTAyMjA1MjUwWhcNMTUwOTAyMjA1MjUwWjBH\n" +
+ "MQswCQYDVQQGEwJVUzERMA8GA1UECAwIVGVzdHNvdGExEjAQBgNVBAcMCVRlc3R2\n" +
+ "aWxsZTERMA8GA1UEAwwIdGVzdC5jb20wggG2MIIBKwYHKoZIzjgEATCCAR4CgYEA\n" +
+ "2QAjoImNX+oSkLdHPDdAzRrbdGdp665OyVBORfdnQeUHbi4WDElqUefTvIWYoDpC\n" +
+ "Dvio284lhTSwXs8H2LKW3xV3AChzaNmPbGwWd4x8zxrE0OSQ+nXgbnBdhlUNUHpa\n" +
+ "AnuuD31eMIDRN6o9WJ7DgksL8aEDO9DRuKUI4TNJKtECFQCB4+ccG9JUCoRh/bnb\n" +
+ "X3cw3BV55wKBgHTmAcAt9Yu6vPdxX6NyzBMwb11kdt/3f0111WCI8nJl/+9mpRDd\n" +
+ "snuPJUzsT00/JMH+puEN2fgOq7QxlCHtgNhX+WUtRE+QFjgvqilM+o+YEWEzeLfp\n" +
+ "kWu/VfM6fV1B3jjmMsie1VNuitVVV1WOE7Pw0rq8m/yXQ5xft0ylhmLSA4GEAAKB\n" +
+ "gH2Q6/2aSPh2b+ePFTLQc20EI6oU6xcyDPKfTsSYH0nUGpr4/k02spVOpHvtUe8e\n" +
+ "1TVS0U30bzdC3bIz2fSUmeU4Kqde4IoZZ3SKjxD0jUKU4/hGuPSAMDEZfPKQIcpj\n" +
+ "UEiqYo+r1ER2u3LdSOqu5ZkYNgT4/C7tr6+NIg1Y4sNuo1AwTjAdBgNVHQ4EFgQU\n" +
+ "PfxTb9tJ6gh4KgFCR6q4Hng1P1AwHwYDVR0jBBgwFoAUPfxTb9tJ6gh4KgFCR6q4\n" +
+ "Hng1P1AwDAYDVR0TBAUwAwEB/zALBglghkgBZQMEAwIDLwAwLAIUNgv+keqfh+sd\n" +
+ "6xqIy6O1QFmjCsMCFB+MYu4K4+BrgPrrMVOnHB4MFHHo\n" +
+ "-----END CERTIFICATE-----";
+
+ //openssl req -x509 -nodes -days 365 -subj '/C=US/ST=Testsota/L=Testville/CN=test.com' \
+ //-newkey rsa:2048 -md2 -keyout k.pem -out md2.pem
+ private static final String MD2_RSA_PEM = "" +
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIDuzCCAqOgAwIBAgIJAPgJ74B13cElMA0GCSqGSIb3DQEBAgUAMEcxCzAJBgNV\n" +
+ "BAYTAlVTMREwDwYDVQQIEwhUZXN0c290YTESMBAGA1UEBxMJVGVzdHZpbGxlMREw\n" +
+ "DwYDVQQDEwh0ZXN0LmNvbTAeFw0xNDA5MDUwMTMwMDZaFw0xNTA5MDUwMTMwMDZa\n" +
+ "MEcxCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhUZXN0c290YTESMBAGA1UEBxMJVGVz\n" +
+ "dHZpbGxlMREwDwYDVQQDEwh0ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n" +
+ "ADCCAQoCggEBAMHoaqm+IagQsnbI5fg1shbV4o4RMuxdOdqq35+FUuyGHRm2iUwu\n" +
+ "0KVIX35ZGpzzfbpsOMFSy5XoRdgdG/6zEpYXTNzjGWtZQ/51cwMAVxDFAsrL7bZz\n" +
+ "9mMEbccXOBS6P4mCAVBQmPfjf6YEP9XUFSY4FeD/sfoIwvutQDbkiUKjhUnQzkSl\n" +
+ "JwnIURUqJOonzBVQV+slypYC9GMrXBT+gVq3QaQSkBwQHHr3SAhZfr8nKoxWlPUy\n" +
+ "l/uliZw9LlctlqRegzGo9m1JHHft9E4mqN4DsVfHl/43XE9DVzZwFZlJ2iJ0X2yL\n" +
+ "VXvKPTwZucdXkhl3oW6NHT/u02P9EnSTbEUCAwEAAaOBqTCBpjAdBgNVHQ4EFgQU\n" +
+ "q1g42h7XKGGPlPbgAmmWvlAC2kMwdwYDVR0jBHAwboAUq1g42h7XKGGPlPbgAmmW\n" +
+ "vlAC2kOhS6RJMEcxCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhUZXN0c290YTESMBAG\n" +
+ "A1UEBxMJVGVzdHZpbGxlMREwDwYDVQQDEwh0ZXN0LmNvbYIJAPgJ74B13cElMAwG\n" +
+ "A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQECBQADggEBAIz1S5LVYRrmRAKfEaXf0Ja8\n" +
+ "XyxGoE8BlM2WWHQoUO6HX+ixJBFueJT6kFJCH4NPKIZdTmhtKKOKBqJeHKiRom2L\n" +
+ "a+p7GEGondaO/Q+8dqx+S7LUI22CaOss72DHoGFqES37KCs9P8G1gu/5GrQVgfV/\n" +
+ "/UjESMF5/fQuFncgWfn5c6E5z7PRuYOLw3Clym1GbLUwldGeAeVqT4kcIgIKA3Rd\n" +
+ "NqMum8A2TrJlrmtxG4OlkKdpKKjPRhYPYLtPXi/g0p8heJ8/YZSwXGQHrqqOND1F\n" +
+ "fkc4rWxUev50cXXJ4qI8EM0zi3HpBqsqV6JgR8+VMA6MMxPQAWmGbBoztKv1r8U=\n" +
+ "-----END CERTIFICATE-----";
+
+ //openssl req -x509 -nodes -days 365 -subj '/C=US/ST=Testsota/L=Testville/CN=test.com' \
+ //-newkey rsa:2048 -md4 -keyout k.pem -out md4.pem
+ private static final String MD4_RSA_PEM = "" +
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIDYTCCAkmgAwIBAgIJAO2CvPpNFLqwMA0GCSqGSIb3DQEBAwUAMEcxCzAJBgNV\n" +
+ "BAYTAlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVzdHZpbGxlMREw\n" +
+ "DwYDVQQDDAh0ZXN0LmNvbTAeFw0xNDA5MDQyMjI1MzNaFw0xNTA5MDQyMjI1MzNa\n" +
+ "MEcxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVz\n" +
+ "dHZpbGxlMREwDwYDVQQDDAh0ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n" +
+ "ADCCAQoCggEBAOQHeENDnuCN08gW/CgIcIYZlD8qgHIc/QgUaHkxbMNBomiOgD8Z\n" +
+ "D1JGtrW6ucbdD66L3Zd5gAfqgGbJ8ySrVFpgXbSpVb6C0wulPZRrm9ll4sZ5BYvg\n" +
+ "zgFhY0TlrizaupZMV+XM3dce/EOYGnrqxWr6jOS7cX3D5Vb9NVE6g+GIW6XKw51Z\n" +
+ "qD+GxxZ2As0lYaZ3vc/+EbiTs/UuIUTsSQvctRkvc83e2vAPtWHX+9ztOLmpSRUP\n" +
+ "8xpganKg5JrfKlXlMXdhJipnOPcYLRMf+UD/7s13TyiQ8Qgt1/h8nirkP8mHYreM\n" +
+ "WenY9Sqrp0FPgGTZbkSnL127mUcWiq+CyasCAwEAAaNQME4wHQYDVR0OBBYEFPSg\n" +
+ "PNT/OJ5IrgrbA7Y0kNgqMp2uMB8GA1UdIwQYMBaAFPSgPNT/OJ5IrgrbA7Y0kNgq\n" +
+ "Mp2uMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEDBQADggEBADg6acU5eqHUDjvG\n" +
+ "M6L+2gMVNiTczlYItLqoibYZW88wzgxpptGKFlWzdl11TIjUaIYqZktfLAWC3Oun\n" +
+ "C564mYPZfaIJEDKNMqcVPiZa9g/8dbctmOxAAvOGdXl+5uk5xOrAsmab7/NH+ksA\n" +
+ "YRpcZntUzbqH33GcMP3CG2i8TM0xM3ZjKch+79asBD/vZmNK1BhsHy3LAE2H2HeA\n" +
+ "k+YDvaBU2yKb0RuZvUmfiySiIjyLtX9JagtHVpcnCZ6pXgCuBy60nGSeP5GQ024x\n" +
+ "GdyN37tmX7gvcazx1+uBlGtw07Uydua4868v/kgu/Ll2zY37CIY6OFi1G0mdk2Xs\n" +
+ "28zzK8s=\n" +
+ "-----END CERTIFICATE-----";
+
+ //openssl req -x509 -nodes -days 365 -subj '/C=US/ST=Testsota/L=Testville/CN=test.com' \
+ //-newkey rsa:2048 -md5 -keyout k.pem -out md5.pem
+ private static final String MD5_RSA_PEM = "" +
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIDYTCCAkmgAwIBAgIJAJsffMf2cyx0MA0GCSqGSIb3DQEBBAUAMEcxCzAJBgNV\n" +
+ "BAYTAlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVzdHZpbGxlMREw\n" +
+ "DwYDVQQDDAh0ZXN0LmNvbTAeFw0xMjEwMTUyMTQzMzZaFw0xMzEwMTUyMTQzMzZa\n" +
+ "MEcxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVz\n" +
+ "dHZpbGxlMREwDwYDVQQDDAh0ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n" +
+ "ADCCAQoCggEBAOJyiUwgf/VsdbTTdx6dsb742adeBFBY1FpSWCeQW/JVtdMephbK\n" +
+ "AA00nu8Xq3dNx9bp8AqvzeyHi/RBsZOtb2eAsOXE3RbFy28ehDTHdG34fRQNT6kp\n" +
+ "RUHw8wrUGovMVqS8j+iW8HfAy3sjArje0ygz2NIETlNQbEOifAJtY+AEfZwZE0/0\n" +
+ "IMVP4hwTmIgyReJBDmAx31clwsWZSPar9x+WQfeJ3rfy5LBCtf3RUbdgnvynBHFk\n" +
+ "FjucwoqgOOXviCWxIa0F+ZAmZJBj5+pLN/V92RXOu0c2fR3Mf68J67OJ+K4ueo1N\n" +
+ "nBhRsulWMmGqIVjYOZQxiNzWYcOVXj3DTRMCAwEAAaNQME4wHQYDVR0OBBYEFJbY\n" +
+ "TU06RuJaiMBs2vzx5y0MbaQOMB8GA1UdIwQYMBaAFJbYTU06RuJaiMBs2vzx5y0M\n" +
+ "baQOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBAFEky0jLTmKefDVX\n" +
+ "8O84KoupmQ2qQQBaQF3F5GEuhi0qJRwnmsWkCmsxPP55S67WDFp3JH+LX14UxL4T\n" +
+ "fbG2CXHt/BF1yU3Z8JBwx3bDmfUnUOAFkO3nmByb11FyZTHMzq4jp03DexWREv4q\n" +
+ "Ai5+5Xb56VECgCH/hnGqhQeFGhlZUcSXobVhAU+39L6azWELXxk1K4bpVxYFGn1N\n" +
+ "uZ+dWmb6snPKDzG6J5IIX8QIs6G8H6ptj+QNoU/qTcZEnuzMJxpqMsyq10AA+bY/\n" +
+ "VAYyXeZm3XZrtqYosDeiUdmcL0jjmyQtyOcAoVUQWj1EJuRjXg4BvI6xxRAIPWYT\n" +
+ "EDeWHJE=\n" +
+ "-----END CERTIFICATE-----";
+
+ //openssl req -x509 -nodes -days 365 -subj '/C=US/ST=Testsota/L=Testville/CN=test.com' \
+ //-newkey rsa:2048 -sha1 -keyout k.pem -out md5.pem
+ private static final String SHA1_RSA_PEM = "" +
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIDZDCCAkygAwIBAgIJALW5K4gErucTMA0GCSqGSIb3DQEBBQUAMEcxCzAJBgNV\n" +
+ "BAYTAlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVzdHZpbGxlMREw\n" +
+ "DwYDVQQDDAh0ZXN0LmNvbTAeFw0xODA0MTIxOTM1MzlaFw0xOTA0MTIxOTM1Mzla\n" +
+ "MEcxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVz\n" +
+ "dHZpbGxlMREwDwYDVQQDDAh0ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n" +
+ "ADCCAQoCggEBAMAphayEftP2twO/FpfUoERx9Y2DyaSMqvLND5Ay6wDXuLMN6qWX\n" +
+ "3ljtEJW3ZVYM2gEhRIXKKUYt0lyx5EuE0VxrNOVyncr8/SQUY2tYlCSB1LLeOzGB\n" +
+ "sYvVzEon/FUeKlRmcgae9FdqDP/t1pCwVdSxIhYxGoPt+znsbrT2UFO7yBw2WDZa\n" +
+ "P8pLP8VeryXWLyAjX2ezxBNVpxwPBsdssrMRqX2BvsZt9pVx87weBH8Mj1lnGJL2\n" +
+ "4ekfUonSEgT6hhCJv8G6PPvXvV2XWmGzjh+CyaEncoODa5a16JHVmq/BNtK6o/OB\n" +
+ "YNrne86kDCzpruA69JtSYAf9YM2TU8vy6GECAwEAAaNTMFEwHQYDVR0OBBYEFHFu\n" +
+ "2+j9+gNDXIlvtDq7P7A6JYnZMB8GA1UdIwQYMBaAFHFu2+j9+gNDXIlvtDq7P7A6\n" +
+ "JYnZMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBALnB+IOCAuWU\n" +
+ "BEC8AtPzQaBQh2MJhzIg+0HHOGldkMX6jRGRnySf31okZMr9FjLkUMEwyylZvFI1\n" +
+ "fFIdq7a070XAH1u4k/Xx7xi7R0+sfnceaLrt1nvOyhEjitLzLT/+zblMrvY+PvpF\n" +
+ "JkUNSKbd8XkSSMvV3U4bmkAZfP/LIJ8juSrNwzsfIu7IPBq+3yPFZpBR/UNH/NhP\n" +
+ "/9OmD8bLwSer9xAcWFT3JVljtaHmL3D+mP/Q1n2lsb7VhrZ4XESLN8thWxWddRC7\n" +
+ "/72ObwvnJIPGB4Knybv8qee02ZDZRKcjFp872FeIkpHMfG/G/kwQiNzvA6cmwTYQ\n" +
+ "QeVc5iP8Lqo=\n" +
+ "-----END CERTIFICATE-----";
+
+
+ //openssl ecparam -genkey -name prime256v1 -out eckey.pem && \
+ //openssl req -x509 -nodes -days 365 -subj '/C=US/ST=Testsota/L=Testville/CN=test.com' \
+ //-newkey ec:eckey.pem -sha1 -keyout k.pem -out sha1.pem
+ private static final String SHA1_ECDSA_PEM = "" +
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIB1zCCAX2gAwIBAgIJAKS+GaTWit91MAkGByqGSM49BAEwRzELMAkGA1UEBhMC\n" +
+ "VVMxETAPBgNVBAgMCFRlc3Rzb3RhMRIwEAYDVQQHDAlUZXN0dmlsbGUxETAPBgNV\n" +
+ "BAMMCHRlc3QuY29tMB4XDTE4MDQxMjE5NDAyMloXDTE5MDQxMjE5NDAyMlowRzEL\n" +
+ "MAkGA1UEBhMCVVMxETAPBgNVBAgMCFRlc3Rzb3RhMRIwEAYDVQQHDAlUZXN0dmls\n" +
+ "bGUxETAPBgNVBAMMCHRlc3QuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE\n" +
+ "VYHDIpvFu7UBWsfF9G8L5V5Cj+wIGHXIUIYp/GVri9bCTZBkLMqcoNyYKWDKDQb5\n" +
+ "sKuo/CCSo5+1dPSjy8gm8KNTMFEwHQYDVR0OBBYEFI8coJOBd83LFcwx7ypFc7F0\n" +
+ "B7clMB8GA1UdIwQYMBaAFI8coJOBd83LFcwx7ypFc7F0B7clMA8GA1UdEwEB/wQF\n" +
+ "MAMBAf8wCQYHKoZIzj0EAQNJADBGAiEAjXa+FcLuU4jRVf93c4vY8EmATcjFrb4h\n" +
+ "bKrvFxXMUpkCIQCllGWVU3j8Np8DxX0MK2Af/5h8O4zlr9DvPUpCsggaQw==\n" +
+ "-----END CERTIFICATE-----";
+
+ //openssl dsaparam -out dsakey.pem -genkey 1024 && \
+ //openssl req -x509 -nodes -days 365 -subj '/C=US/ST=Testsota/L=Testville/CN=test.com' \
+ //-newkey dsa:dsakey.pem -sha1 -keyout k.pem -out sha1.pem
+ private static final String SHA1_DSA_PEM = "" +
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIDHzCCAt2gAwIBAgIJAPO9edaSntPLMAkGByqGSM44BAMwRzELMAkGA1UEBhMC\n" +
+ "VVMxETAPBgNVBAgMCFRlc3Rzb3RhMRIwEAYDVQQHDAlUZXN0dmlsbGUxETAPBgNV\n" +
+ "BAMMCHRlc3QuY29tMB4XDTE4MDQxMjE5NTAyN1oXDTE5MDQxMjE5NTAyN1owRzEL\n" +
+ "MAkGA1UEBhMCVVMxETAPBgNVBAgMCFRlc3Rzb3RhMRIwEAYDVQQHDAlUZXN0dmls\n" +
+ "bGUxETAPBgNVBAMMCHRlc3QuY29tMIIBtzCCASwGByqGSM44BAEwggEfAoGBAMZy\n" +
+ "BYuw9s+UFLnrErRwysU2dfcY0tv4b8FIi63JtF12kTborQkyxilNtDDtBVEA0mKE\n" +
+ "13dvd8JQx2+d6LwHSiaaS2n2/XofVn61HmDNPns1zV8m9XvUX8Cqmz0+1dgyZx0Y\n" +
+ "dP+eg2BjfhfX/6tXWXMd2t2+y3sJalLh9KeC/LftAhUA2RmeKHbNMj9pC9wOj8Yj\n" +
+ "u239Q1ECgYEAhnfB/Z2S/lYc2c78PU2DcChXsj+Mp8ITUwTVg+G4+WvqGzX6FFzr\n" +
+ "9/eTrn+rPLkKDJonHW/OZyVFK2mVQ/s5xE8Wn9YDUYkNPlJ/dFB+okmhZE8hDRwF\n" +
+ "LsgtrLgJqpOEw54b37hyqdvk2vtHI+ANU+jZONRdsmWT9HZ0ryJGqY8DgYQAAoGA\n" +
+ "U8tXEXYh4oCAGLG+S7aNI73LN+a/n0r1aSJM8XuNExZus/eaXCHqEreUi/SBXVEm\n" +
+ "UJEXnsRwzLyErE24yBlQzLBoMbHqJnIOJRmxjrQ7xo9vivo53woIbxHSRdWlzfwW\n" +
+ "14yR5dSVDEVI30TTT/zAoNIWvegHXO2LCeEZ/ilLPxCjUzBRMB0GA1UdDgQWBBQB\n" +
+ "cKP86kuQ/GEG+n0NdJK7A9uBOTAfBgNVHSMEGDAWgBQBcKP86kuQ/GEG+n0NdJK7\n" +
+ "A9uBOTAPBgNVHRMBAf8EBTADAQH/MAkGByqGSM44BAMDMQAwLgIVAIIMd1qgBuGf\n" +
+ "zY7SmaNFYmeQV2qpAhUAkPFti47uD7JjdAEqJ/nFMhYcolQ=\n" +
+ "-----END CERTIFICATE-----";
+
+
+ //openssl req -x509 -nodes -days 365 -subj '/C=US/ST=Testsota/L=Testville/CN=test.com' \
+ //-newkey rsa:512 -sha256 -keyout k.pem -out short.pem
+ private static final String SHORT_RSA_PEM = "" +
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIB1zCCAYGgAwIBAgIJAOxaz9TreDNIMA0GCSqGSIb3DQEBCwUAMEcxCzAJBgNV\n" +
+ "BAYTAlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVzdHZpbGxlMREw\n" +
+ "DwYDVQQDDAh0ZXN0LmNvbTAeFw0xMjEwMTUyMTQzMjNaFw0xMzEwMTUyMTQzMjNa\n" +
+ "MEcxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVz\n" +
+ "dHZpbGxlMREwDwYDVQQDDAh0ZXN0LmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgC\n" +
+ "QQCoMgxK9HG0L+hXEht1mKq6ApN3+3lmIEVUcWQKL7EMmn9+L6rVSJyOAGwpTVG7\n" +
+ "eZ5uulC0Lkm5/bzKFSrCf1jlAgMBAAGjUDBOMB0GA1UdDgQWBBTda66RZsgUvR4e\n" +
+ "2RSsq65K1xcz0jAfBgNVHSMEGDAWgBTda66RZsgUvR4e2RSsq65K1xcz0jAMBgNV\n" +
+ "HRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA0EAZWYgoNDn6yEzcmWgsYnG3w2BT6fL\n" +
+ "Npi0+APKWkwxnEJk1kgpdeSTMgaHAphQ8qksHnSgeBAJSs2ZCQMinVPgOg==\n" +
+ "-----END CERTIFICATE-----";
+
+ //openssl dsaparam -genkey 768 -out dsakey.pem && \
+ //openssl req -x509 -nodes -days 365 -subj '/C=US/ST=Testsota/L=Testville/CN=test.com' \
+ //-newkey dsa:dsakey.pem -sha256 -keyout k.pem -out short.pem
+ private static final String SHORT_DSA_PEM = "" +
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIICuDCCAnWgAwIBAgIJAMQeQVxVNTKRMAsGCWCGSAFlAwQDAjBHMQswCQYDVQQG\n" +
+ "EwJVUzERMA8GA1UECAwIVGVzdHNvdGExEjAQBgNVBAcMCVRlc3R2aWxsZTERMA8G\n" +
+ "A1UEAwwIdGVzdC5jb20wHhcNMTQwOTAyMjAzNjQ4WhcNMTUwOTAyMjAzNjQ4WjBH\n" +
+ "MQswCQYDVQQGEwJVUzERMA8GA1UECAwIVGVzdHNvdGExEjAQBgNVBAcMCVRlc3R2\n" +
+ "aWxsZTERMA8GA1UEAwwIdGVzdC5jb20wggFQMIHoBgcqhkjOOAQBMIHcAmEApVZC\n" +
+ "vx5pcu5CjEv0n5M0PVxnX/4ZkJn8EAnkgn5P37KxDm7dIHcMw71Epd+l7hP4TLUV\n" +
+ "etW9VOu1ybo+hOMr3IGqlaMVHxL5VWk6DGFjo5ZplF5QGQt+hqFYX8agruoFAhUA\n" +
+ "xsTsmLlEe97rZm2UfNt51tXoQgECYA1dMDAfVUqfC06LJ0O5Q2RmjbkqCLfwiXvq\n" +
+ "q0LVqxQJBVzmjbWoNRdmZpzhjOfMQ2bpQwTj+M4t2YPGifQTgumUolutWGEs7jxU\n" +
+ "HcybdA8/3fqubZ/pEKrz1FhjIReuJgNjAAJgEWAocKA/8Q7pFQ7tkJDUTctU7ZUN\n" +
+ "O9eUqghBkJAaHhjq8GJ/UIoPuS8PCz19/xDZICMhbKpobi+z/sy3atZLtcrrUhN1\n" +
+ "XBgEPD6aWSP3qEBzz2a6MqL6RegDL3ldrRMjo1AwTjAdBgNVHQ4EFgQUk7IR6KN+\n" +
+ "Lb8ZlDs4v1pKtmQans0wHwYDVR0jBBgwFoAUk7IR6KN+Lb8ZlDs4v1pKtmQans0w\n" +
+ "DAYDVR0TBAUwAwEB/zALBglghkgBZQMEAwIDMAAwLQIUG9is/MhJ0qXggCtPiOdH\n" +
+ "UZSNrCgCFQDBb443MntlcWrx5gV7YRd52k0Yug==\n" +
+ "-----END CERTIFICATE-----";
+
+ //ecparam -genkey -name secp128r1 -out eckey.pem && \
+ //openssl req -x509 -nodes -days 365 -subj '/C=US/ST=Testsota/L=Testville/CN=test.com' \
+ //-newkey ec:eckey.pem -sha256 -keyout k.pem -out short.pem
+ private static final String SHORT_ECDSA_PEM = "" +
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIBkTCCAVigAwIBAgIJAKogErAsYuahMAoGCCqGSM49BAMCMEcxCzAJBgNVBAYT\n" +
+ "AlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVzdHZpbGxlMREwDwYD\n" +
+ "VQQDDAh0ZXN0LmNvbTAeFw0xNDA5MDIyMDQ1MjdaFw0xNTA5MDIyMDQ1MjdaMEcx\n" +
+ "CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVzdHZp\n" +
+ "bGxlMREwDwYDVQQDDAh0ZXN0LmNvbTA2MBAGByqGSM49AgEGBSuBBAAcAyIABE9Z\n" +
+ "bL28dyGE/sRmSUB0kqdsmkaKaC7gu+9A4CLDO5kJo1AwTjAdBgNVHQ4EFgQU7f+b\n" +
+ "vrGRimukkorDkERufEFRaj0wHwYDVR0jBBgwFoAU7f+bvrGRimukkorDkERufEFR\n" +
+ "aj0wDAYDVR0TBAUwAwEB/zAKBggqhkjOPQQDAgMnADAkAhBXRMkfHNexPXaqzJwT\n" +
+ "9eAwAhAzX+1NE+FY0kk74wH83Cz0\n" +
+ "-----END CERTIFICATE-----";
+
+
+ @Test
+ public void testMD2() throws Exception {
+ assertBad(MD2_RSA_PEM, "Weak hash check did not fail as expected");
+ }
+
+ @Test
+ public void testMD4() throws Exception {
+ assertBad(MD4_RSA_PEM, "Weak hash check did not fail as expected");
+ }
+
+ @Test
+ public void testMD5() throws Exception {
+ assertBad(MD5_RSA_PEM, "Weak hash check did not fail as expected");
+ }
+
+ @Test
+ public void testSHA1() throws Exception {
+ assertBad(SHA1_RSA_PEM, "Weak SHA1 RSA signature did not fail as expected");
+ assertBad(SHA1_ECDSA_PEM, "Weak SHA1 ECDSA signature did not fail as expected");
+ assertBad(SHA1_DSA_PEM, "Weak SHA1 DSA signature did not fail as expected");
+ }
+
+ @Test
+ public void testRsa512() throws Exception {
+ assertBad(SHORT_RSA_PEM, "Short RSA modulus check did not fail as expected");
+ }
+
+ @Test
+ public void testDsa768() throws Exception {
+ assertBad(SHORT_DSA_PEM, "Short DSA key check did not fail as expected");
+ }
+
+ @Test
+ public void testEcdsa128() throws Exception {
+ assertBad(SHORT_ECDSA_PEM, "Short EC key check did not fail as expected");
+ }
+
+ @Test
+ public void testGoodChain() throws Exception {
+ assertGood(GOOD_RSA_PEM);
+ assertGood(GOOD_DSA_PEM);
+ assertGood(GOOD_ECDSA_PEM);
+ }
+
+ private static void assertBad(String pem, String msg) throws Exception {
+ try {
+ check(createCert(pem));
+ fail(msg);
+ } catch (CertificateException expected) {
+ } catch (NoSuchAlgorithmException expected) {
+ // Some weak EC groups can no longer be parsed.
+ }
+ }
+
+ private static void assertGood(String pem) throws Exception {
+ check(createCert(pem));
+ }
+
+ private static void check(X509Certificate cert) throws Exception {
+ X509Certificate[] chain = {cert};
+ ChainStrengthAnalyzer.check(chain);
+ }
+
+ private static X509Certificate createCert(String pem) throws Exception {
+ CertificateFactory cf = CertificateFactory.getInstance("X509");
+ InputStream pemInput = new ByteArrayInputStream(pem.getBytes("UTF-8"));
+ return (X509Certificate) cf.generateCertificate(pemInput);
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/HostnameVerifierTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/HostnameVerifierTest.java
new file mode 100644
index 0000000..f3da396
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/HostnameVerifierTest.java
@@ -0,0 +1,662 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.Charset;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collection;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.security.auth.x500.X500Principal;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Tests for our hostname verifier. Most of these tests are from AOSP, which
+ * itself includes tests from the Apache HTTP Client test suite.
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(Parameterized.class)
+public final class HostnameVerifierTest {
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class FakeSSLSession extends com.android.org.conscrypt.javax.net.ssl.FakeSSLSession {
+
+ private final Certificate[] certificates;
+
+ public FakeSSLSession(Certificate... certificates) throws Exception {
+ super("FakeHost");
+ this.certificates = certificates;
+ }
+
+ @Override
+ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ if (certificates.length == 0) {
+ throw new SSLPeerUnverifiedException("peer not authenticated");
+ }
+ return certificates;
+ }
+ }
+
+ private static final Charset UTF_8 = Charset.forName("UTF-8");
+ // BEGIN Android-changed: Run tests for both default and strict verifiers. http://b/144694112
+ // private HostnameVerifier verifier = OkHostnameVerifier.INSTANCE;
+ @Parameters()
+ public static Collection<Object[]> data() {
+ // Both verifiers should behave the same in all tests except for
+ // subjectAltNameWithToplevelWildcard(), and that test is not parameterized for clarity.
+ return Arrays.asList(new Object[][] {
+ { OkHostnameVerifier.INSTANCE },
+ { OkHostnameVerifier.strictInstance() }
+ });
+ }
+
+ @Parameter
+ public OkHostnameVerifier verifier;
+ // END Android-changed: Run tests for both default and strict verifiers. http://b/144694112
+
+ @Test public void verify() throws Exception {
+ FakeSSLSession session = new FakeSSLSession();
+ X509Certificate[] certs = {};
+ assertFalse(verifier.verify(certs,"localhost", session));
+ }
+
+ @Test public void verifyCn() throws Exception {
+ // CN=foo.com
+ SSLSession session = session(""
+ + "-----BEGIN CERTIFICATE-----\n"
+ + "MIIERjCCAy6gAwIBAgIJAIz+EYMBU6aQMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD\n"
+ + "VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE\n"
+ + "ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU\n"
+ + "FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n"
+ + "ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1MzE0MVoXDTI4MTEwNTE1MzE0MVowgaQx\n"
+ + "CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0\n"
+ + "IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl\n"
+ + "cnRpZmljYXRlczEQMA4GA1UEAxMHZm9vLmNvbTElMCMGCSqGSIb3DQEJARYWanVs\n"
+ + "aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n"
+ + "ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B\n"
+ + "lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy\n"
+ + "zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY\n"
+ + "07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8\n"
+ + "BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV\n"
+ + "JTxpTKqym93whYk93l3ocEe55c0CAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgB\n"
+ + "hvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYE\n"
+ + "FJ8Ud78/OrbKOIJCSBYs2tDLXofYMB8GA1UdIwQYMBaAFHua2o+QmU5S0qzbswNS\n"
+ + "yoemDT4NMA0GCSqGSIb3DQEBBQUAA4IBAQC3jRmEya6sQCkmieULcvx8zz1euCk9\n"
+ + "fSez7BEtki8+dmfMXe3K7sH0lI8f4jJR0rbSCjpmCQLYmzC3NxBKeJOW0RcjNBpO\n"
+ + "c2JlGO9auXv2GDP4IYiXElLJ6VSqc8WvDikv0JmCCWm0Zga+bZbR/EWN5DeEtFdF\n"
+ + "815CLpJZNcYwiYwGy/CVQ7w2TnXlG+mraZOz+owr+cL6J/ZesbdEWfjoS1+cUEhE\n"
+ + "HwlNrAu8jlZ2UqSgskSWlhYdMTAP9CPHiUv9N7FcT58Itv/I4fKREINQYjDpvQcx\n"
+ + "SaTYb9dr5sB4WLNglk7zxDtM80H518VvihTcP7FHL+Gn6g4j5fkI98+S\n"
+ + "-----END CERTIFICATE-----\n");
+ // Android-changed: Ignore common name in hostname verification. http://b/70278814
+ // assertTrue(verifier.verify("foo.com", session));
+ X509Certificate[] certs = {};
+ assertFalse(verifier.verify(certs, "foo.com", session));
+ assertFalse(verifier.verify(certs, "a.foo.com", session));
+ assertFalse(verifier.verify(certs, "bar.com", session));
+ }
+
+ @Test public void verifyNonAsciiCn() throws Exception {
+ // CN=花子.co.jp
+ SSLSession session = session(""
+ + "-----BEGIN CERTIFICATE-----\n"
+ + "MIIESzCCAzOgAwIBAgIJAIz+EYMBU6aTMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD\n"
+ + "VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE\n"
+ + "ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU\n"
+ + "FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n"
+ + "ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1NDIxNVoXDTI4MTEwNTE1NDIxNVowgakx\n"
+ + "CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0\n"
+ + "IEhpbGwxFzAVBgNVBAoMDmh0dHBjb21wb25lbnRzMRowGAYDVQQLDBF0ZXN0IGNl\n"
+ + "cnRpZmljYXRlczEVMBMGA1UEAwwM6Iqx5a2QLmNvLmpwMSUwIwYJKoZIhvcNAQkB\n"
+ + "FhZqdWxpdXNkYXZpZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n"
+ + "MIIBCgKCAQEAyGOvloI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjU\n"
+ + "g4pNjYGViGjg7zhfbjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQc\n"
+ + "wHf0ZHLN6sD9m2uVSp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t\n"
+ + "7iu1JVjTuE0pcBvah2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAn\n"
+ + "AxK6q/wGqcZ3zvFBTcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArD\n"
+ + "qUYxqJUlPGlMqrKb3fCFiT3eXehwR7nlzQIDAQABo3sweTAJBgNVHRMEAjAAMCwG\n"
+ + "CWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNV\n"
+ + "HQ4EFgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLS\n"
+ + "rNuzA1LKh6YNPg0wDQYJKoZIhvcNAQEFBQADggEBALJ27i3okV/KvlDp6KMID3gd\n"
+ + "ITl68PyItzzx+SquF8gahMh016NX73z/oVZoVUNdftla8wPUB1GwIkAnGkhQ9LHK\n"
+ + "spBdbRiCj0gMmLCsX8SrjFvr7cYb2cK6J/fJe92l1tg/7Y4o7V/s4JBe/cy9U9w8\n"
+ + "a0ctuDmEBCgC784JMDtT67klRfr/2LlqWhlOEq7pUFxRLbhpquaAHSOjmIcWnVpw\n"
+ + "9BsO7qe46hidgn39hKh1WjKK2VcL/3YRsC4wUi0PBtFW6ScMCuMhgIRXSPU55Rae\n"
+ + "UIlOdPjjr1SUNWGId1rD7W16Scpwnknn310FNxFMHVI0GTGFkNdkilNCFJcIoRA=\n"
+ + "-----END CERTIFICATE-----\n");
+ // Android-changed: Ignore common name in hostname verification. http://b/70278814
+ // assertTrue(verifier.verify("\u82b1\u5b50.co.jp", session));
+ X509Certificate[] certs = {};
+ assertFalse(verifier.verify(certs, "\u82b1\u5b50.co.jp", session));
+ assertFalse(verifier.verify(certs, "a.\u82b1\u5b50.co.jp", session));
+ }
+
+ @Test public void verifySubjectAlt() throws Exception {
+ // CN=foo.com, subjectAlt=bar.com
+ SSLSession session = session(""
+ + "-----BEGIN CERTIFICATE-----\n"
+ + "MIIEXDCCA0SgAwIBAgIJAIz+EYMBU6aRMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD\n"
+ + "VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE\n"
+ + "ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU\n"
+ + "FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n"
+ + "ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1MzYyOVoXDTI4MTEwNTE1MzYyOVowgaQx\n"
+ + "CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0\n"
+ + "IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl\n"
+ + "cnRpZmljYXRlczEQMA4GA1UEAxMHZm9vLmNvbTElMCMGCSqGSIb3DQEJARYWanVs\n"
+ + "aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n"
+ + "ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B\n"
+ + "lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy\n"
+ + "zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY\n"
+ + "07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8\n"
+ + "BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV\n"
+ + "JTxpTKqym93whYk93l3ocEe55c0CAwEAAaOBkDCBjTAJBgNVHRMEAjAAMCwGCWCG\n"
+ + "SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E\n"
+ + "FgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuz\n"
+ + "A1LKh6YNPg0wEgYDVR0RBAswCYIHYmFyLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEA\n"
+ + "dQyprNZBmVnvuVWjV42sey/PTfkYShJwy1j0/jcFZR/ypZUovpiHGDO1DgL3Y3IP\n"
+ + "zVQ26uhUsSw6G0gGRiaBDe/0LUclXZoJzXX1qpS55OadxW73brziS0sxRgGrZE/d\n"
+ + "3g5kkio6IED47OP6wYnlmZ7EKP9cqjWwlnvHnnUcZ2SscoLNYs9rN9ccp8tuq2by\n"
+ + "88OyhKwGjJfhOudqfTNZcDzRHx4Fzm7UsVaycVw4uDmhEHJrAsmMPpj/+XRK9/42\n"
+ + "2xq+8bc6HojdtbCyug/fvBZvZqQXSmU8m8IVcMmWMz0ZQO8ee3QkBHMZfCy7P/kr\n"
+ + "VbWx/uETImUu+NZg22ewEw==\n"
+ + "-----END CERTIFICATE-----\n");
+ X509Certificate[] certs = {};
+ assertFalse(verifier.verify(certs, "foo.com", session));
+ assertFalse(verifier.verify(certs, "a.foo.com", session));
+ assertTrue(verifier.verify(certs, "bar.com", session));
+ assertFalse(verifier.verify(certs, "a.bar.com", session));
+ }
+
+ /**
+ * Ignored due to incompatibilities between Android and Java on how non-ASCII
+ * subject alt names are parsed. Android fails to parse these, which means we
+ * fall back to the CN. The RI does parse them, so the CN is unused.
+ */
+ @Test @Ignore public void verifyNonAsciiSubjectAlt() throws Exception {
+ // CN=foo.com, subjectAlt=bar.com, subjectAlt=花子.co.jp
+ // (hanako.co.jp in kanji)
+ SSLSession session = session(""
+ + "-----BEGIN CERTIFICATE-----\n"
+ + "MIIEajCCA1KgAwIBAgIJAIz+EYMBU6aSMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD\n"
+ + "VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE\n"
+ + "ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU\n"
+ + "FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n"
+ + "ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1MzgxM1oXDTI4MTEwNTE1MzgxM1owgaQx\n"
+ + "CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0\n"
+ + "IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl\n"
+ + "cnRpZmljYXRlczEQMA4GA1UEAxMHZm9vLmNvbTElMCMGCSqGSIb3DQEJARYWanVs\n"
+ + "aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n"
+ + "ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B\n"
+ + "lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy\n"
+ + "zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY\n"
+ + "07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8\n"
+ + "BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV\n"
+ + "JTxpTKqym93whYk93l3ocEe55c0CAwEAAaOBnjCBmzAJBgNVHRMEAjAAMCwGCWCG\n"
+ + "SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E\n"
+ + "FgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuz\n"
+ + "A1LKh6YNPg0wIAYDVR0RBBkwF4IHYmFyLmNvbYIM6Iqx5a2QLmNvLmpwMA0GCSqG\n"
+ + "SIb3DQEBBQUAA4IBAQBeZs7ZIYyKtdnVxVvdLgwySEPOE4pBSXii7XYv0Q9QUvG/\n"
+ + "++gFGQh89HhABzA1mVUjH5dJTQqSLFvRfqTHqLpxSxSWqMHnvRM4cPBkIRp/XlMK\n"
+ + "PlXadYtJLPTgpbgvulA1ickC9EwlNYWnowZ4uxnfsMghW4HskBqaV+PnQ8Zvy3L0\n"
+ + "12c7Cg4mKKS5pb1HdRuiD2opZ+Hc77gRQLvtWNS8jQvd/iTbh6fuvTKfAOFoXw22\n"
+ + "sWIKHYrmhCIRshUNohGXv50m2o+1w9oWmQ6Dkq7lCjfXfUB4wIbggJjpyEtbNqBt\n"
+ + "j4MC2x5rfsLKKqToKmNE7pFEgqwe8//Aar1b+Qj+\n"
+ + "-----END CERTIFICATE-----\n");
+ X509Certificate[] certs = {};
+ assertTrue(verifier.verify(certs, "foo.com", session));
+ assertFalse(verifier.verify(certs, "a.foo.com", session));
+ // these checks test alternative subjects. The test data contains an
+ // alternative subject starting with a japanese kanji character. This is
+ // not supported by Android because the underlying implementation from
+ // harmony follows the definition from rfc 1034 page 10 for alternative
+ // subject names. This causes the code to drop all alternative subjects.
+ // assertTrue(verifier.verify("bar.com", session));
+ // assertFalse(verifier.verify("a.bar.com", session));
+ // assertFalse(verifier.verify("a.\u82b1\u5b50.co.jp", session));
+ }
+
+ @Test public void verifySubjectAltOnly() throws Exception {
+ // subjectAlt=foo.com
+ SSLSession session = session(""
+ + "-----BEGIN CERTIFICATE-----\n"
+ + "MIIESjCCAzKgAwIBAgIJAIz+EYMBU6aYMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD\n"
+ + "VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE\n"
+ + "ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU\n"
+ + "FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n"
+ + "ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MjYxMFoXDTI4MTEwNTE2MjYxMFowgZIx\n"
+ + "CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0\n"
+ + "IEhpbGwxFzAVBgNVBAoMDmh0dHBjb21wb25lbnRzMRowGAYDVQQLDBF0ZXN0IGNl\n"
+ + "cnRpZmljYXRlczElMCMGCSqGSIb3DQEJARYWanVsaXVzZGF2aWVzQGdtYWlsLmNv\n"
+ + "bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMhjr5aCPoyp0R1iroWA\n"
+ + "fnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2BlYho4O84X244QrZTRl8kQbYt\n"
+ + "xnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRyzerA/ZtrlUqf+lKo0uWcocxe\n"
+ + "Rc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY07hNKXAb2odnVqgzcYiDkLV8\n"
+ + "ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8BqnGd87xQU3FVZI4tbtkB+Kz\n"
+ + "jD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiVJTxpTKqym93whYk93l3ocEe5\n"
+ + "5c0CAwEAAaOBkDCBjTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NM\n"
+ + "IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUnxR3vz86tso4gkJIFiza\n"
+ + "0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuzA1LKh6YNPg0wEgYDVR0RBAsw\n"
+ + "CYIHZm9vLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEAjl78oMjzFdsMy6F1sGg/IkO8\n"
+ + "tF5yUgPgFYrs41yzAca7IQu6G9qtFDJz/7ehh/9HoG+oqCCIHPuIOmS7Sd0wnkyJ\n"
+ + "Y7Y04jVXIb3a6f6AgBkEFP1nOT0z6kjT7vkA5LJ2y3MiDcXuRNMSta5PYVnrX8aZ\n"
+ + "yiqVUNi40peuZ2R8mAUSBvWgD7z2qWhF8YgDb7wWaFjg53I36vWKn90ZEti3wNCw\n"
+ + "qAVqixM+J0qJmQStgAc53i2aTMvAQu3A3snvH/PHTBo+5UL72n9S1kZyNCsVf1Qo\n"
+ + "n8jKTiRriEM+fMFlcgQP284EBFzYHyCXFb9O/hMjK2+6mY9euMB1U1aFFzM/Bg==\n"
+ + "-----END CERTIFICATE-----\n");
+ X509Certificate[] certs = {};
+ assertTrue(verifier.verify(certs, "foo.com", session));
+ assertFalse(verifier.verify(certs, "a.foo.com", session));
+ assertTrue(verifier.verify(certs, "foo.com", session));
+ assertFalse(verifier.verify(certs, "a.foo.com", session));
+ }
+
+ @Test public void verifyMultipleCn() throws Exception {
+ // CN=foo.com, CN=bar.com, CN=花子.co.jp
+ SSLSession session = session(""
+ + "-----BEGIN CERTIFICATE-----\n"
+ + "MIIEbzCCA1egAwIBAgIJAIz+EYMBU6aXMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD\n"
+ + "VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE\n"
+ + "ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU\n"
+ + "FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n"
+ + "ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTk0NVoXDTI4MTEwNTE2MTk0NVowgc0x\n"
+ + "CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0\n"
+ + "IEhpbGwxFzAVBgNVBAoMDmh0dHBjb21wb25lbnRzMRowGAYDVQQLDBF0ZXN0IGNl\n"
+ + "cnRpZmljYXRlczEQMA4GA1UEAwwHZm9vLmNvbTEQMA4GA1UEAwwHYmFyLmNvbTEV\n"
+ + "MBMGA1UEAwwM6Iqx5a2QLmNvLmpwMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n"
+ + "ZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyGOv\n"
+ + "loI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjUg4pNjYGViGjg7zhf\n"
+ + "bjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQcwHf0ZHLN6sD9m2uV\n"
+ + "Sp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t7iu1JVjTuE0pcBva\n"
+ + "h2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAnAxK6q/wGqcZ3zvFB\n"
+ + "TcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArDqUYxqJUlPGlMqrKb\n"
+ + "3fCFiT3eXehwR7nlzQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQf\n"
+ + "Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUnxR3vz86\n"
+ + "tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuzA1LKh6YNPg0w\n"
+ + "DQYJKoZIhvcNAQEFBQADggEBAGuZb8ai1NO2j4v3y9TLZvd5s0vh5/TE7n7RX+8U\n"
+ + "y37OL5k7x9nt0mM1TyAKxlCcY+9h6frue8MemZIILSIvMrtzccqNz0V1WKgA+Orf\n"
+ + "uUrabmn+CxHF5gpy6g1Qs2IjVYWA5f7FROn/J+Ad8gJYc1azOWCLQqSyfpNRLSvY\n"
+ + "EriQFEV63XvkJ8JrG62b+2OT2lqT4OO07gSPetppdlSa8NBSKP6Aro9RIX1ZjUZQ\n"
+ + "SpQFCfo02NO0uNRDPUdJx2huycdNb+AXHaO7eXevDLJ+QnqImIzxWiY6zLOdzjjI\n"
+ + "VBMkLHmnP7SjGSQ3XA4ByrQOxfOUTyLyE7NuemhHppuQPxE=\n"
+ + "-----END CERTIFICATE-----\n");
+ X509Certificate[] certs = {};
+ assertFalse(verifier.verify(certs, "foo.com", session));
+ assertFalse(verifier.verify(certs, "a.foo.com", session));
+ assertFalse(verifier.verify(certs, "bar.com", session));
+ assertFalse(verifier.verify(certs, "a.bar.com", session));
+ // Android-changed: Ignore common name in hostname verification. http://b/70278814
+ // assertTrue(verifier.verify("\u82b1\u5b50.co.jp", session));
+ assertFalse(verifier.verify(certs, "\u82b1\u5b50.co.jp", session));
+ assertFalse(verifier.verify(certs, "a.\u82b1\u5b50.co.jp", session));
+ }
+
+ @Test public void verifyWilcardCn() throws Exception {
+ // CN=*.foo.com
+ SSLSession session = session(""
+ + "-----BEGIN CERTIFICATE-----\n"
+ + "MIIESDCCAzCgAwIBAgIJAIz+EYMBU6aUMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD\n"
+ + "VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE\n"
+ + "ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU\n"
+ + "FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n"
+ + "ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTU1NVoXDTI4MTEwNTE2MTU1NVowgaYx\n"
+ + "CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0\n"
+ + "IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl\n"
+ + "cnRpZmljYXRlczESMBAGA1UEAxQJKi5mb28uY29tMSUwIwYJKoZIhvcNAQkBFhZq\n"
+ + "dWxpdXNkYXZpZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n"
+ + "CgKCAQEAyGOvloI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjUg4pN\n"
+ + "jYGViGjg7zhfbjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQcwHf0\n"
+ + "ZHLN6sD9m2uVSp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t7iu1\n"
+ + "JVjTuE0pcBvah2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAnAxK6\n"
+ + "q/wGqcZ3zvFBTcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArDqUYx\n"
+ + "qJUlPGlMqrKb3fCFiT3eXehwR7nlzQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCG\n"
+ + "SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E\n"
+ + "FgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuz\n"
+ + "A1LKh6YNPg0wDQYJKoZIhvcNAQEFBQADggEBAH0ipG6J561UKUfgkeW7GvYwW98B\n"
+ + "N1ZooWX+JEEZK7+Pf/96d3Ij0rw9ACfN4bpfnCq0VUNZVSYB+GthQ2zYuz7tf/UY\n"
+ + "A6nxVgR/IjG69BmsBl92uFO7JTNtHztuiPqBn59pt+vNx4yPvno7zmxsfI7jv0ww\n"
+ + "yfs+0FNm7FwdsC1k47GBSOaGw38kuIVWqXSAbL4EX9GkryGGOKGNh0qvAENCdRSB\n"
+ + "G9Z6tyMbmfRY+dLSh3a9JwoEcBUso6EWYBakLbq4nG/nvYdYvG9ehrnLVwZFL82e\n"
+ + "l3Q/RK95bnA6cuRClGusLad0e6bjkBzx/VQ3VarDEpAkTLUGVAa0CLXtnyc=\n"
+ + "-----END CERTIFICATE-----\n");
+ X509Certificate[] certs = {};
+ assertFalse(verifier.verify(certs, "foo.com", session));
+ // Android-changed: Ignore common name in hostname verification. http://b/70278814
+ // assertTrue(verifier.verify("www.foo.com", session));
+ assertFalse(verifier.verify(certs, "www.foo.com", session));
+ // Android-changed: Ignore common name in hostname verification. http://b/70278814
+ // assertTrue(verifier.verify("\u82b1\u5b50.foo.com", session));
+ assertFalse(verifier.verify(certs, "\u82b1\u5b50.foo.com", session));
+ assertFalse(verifier.verify(certs, "a.b.foo.com", session));
+ }
+
+ @Test public void verifyWilcardCnOnTld() throws Exception {
+ // It's the CA's responsibility to not issue broad-matching certificates!
+ // CN=*.co.jp
+ SSLSession session = session(""
+ + "-----BEGIN CERTIFICATE-----\n"
+ + "MIIERjCCAy6gAwIBAgIJAIz+EYMBU6aVMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD\n"
+ + "VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE\n"
+ + "ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU\n"
+ + "FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n"
+ + "ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTYzMFoXDTI4MTEwNTE2MTYzMFowgaQx\n"
+ + "CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0\n"
+ + "IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl\n"
+ + "cnRpZmljYXRlczEQMA4GA1UEAxQHKi5jby5qcDElMCMGCSqGSIb3DQEJARYWanVs\n"
+ + "aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n"
+ + "ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B\n"
+ + "lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy\n"
+ + "zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY\n"
+ + "07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8\n"
+ + "BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV\n"
+ + "JTxpTKqym93whYk93l3ocEe55c0CAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgB\n"
+ + "hvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYE\n"
+ + "FJ8Ud78/OrbKOIJCSBYs2tDLXofYMB8GA1UdIwQYMBaAFHua2o+QmU5S0qzbswNS\n"
+ + "yoemDT4NMA0GCSqGSIb3DQEBBQUAA4IBAQA0sWglVlMx2zNGvUqFC73XtREwii53\n"
+ + "CfMM6mtf2+f3k/d8KXhLNySrg8RRlN11zgmpPaLtbdTLrmG4UdAHHYr8O4y2BBmE\n"
+ + "1cxNfGxxechgF8HX10QV4dkyzp6Z1cfwvCeMrT5G/V1pejago0ayXx+GPLbWlNeZ\n"
+ + "S+Kl0m3p+QplXujtwG5fYcIpaGpiYraBLx3Tadih39QN65CnAh/zRDhLCUzKyt9l\n"
+ + "UGPLEUDzRHMPHLnSqT1n5UU5UDRytbjJPXzF+l/+WZIsanefWLsxnkgAuZe/oMMF\n"
+ + "EJMryEzOjg4Tfuc5qM0EXoPcQ/JlheaxZ40p2IyHqbsWV4MRYuFH4bkM\n"
+ + "-----END CERTIFICATE-----\n");
+ X509Certificate[] certs = {};
+ // Android-changed: Ignore common name in hostname verification. http://b/70278814
+ // assertTrue(verifier.verify("foo.co.jp", session));
+ assertFalse(verifier.verify(certs, "foo.co.jp", session));
+ // Android-changed: Ignore common name in hostname verification. http://b/70278814
+ // assertTrue(verifier.verify("\u82b1\u5b50.co.jp", session));
+ assertFalse(verifier.verify(certs, "\u82b1\u5b50.co.jp", session));
+ }
+
+ /**
+ * Ignored due to incompatibilities between Android and Java on how non-ASCII
+ * subject alt names are parsed. Android fails to parse these, which means we
+ * fall back to the CN. The RI does parse them, so the CN is unused.
+ */
+ @Test @Ignore public void testWilcardNonAsciiSubjectAlt() throws Exception {
+ // CN=*.foo.com, subjectAlt=*.bar.com, subjectAlt=*.花子.co.jp
+ // (*.hanako.co.jp in kanji)
+ SSLSession session = session(""
+ + "-----BEGIN CERTIFICATE-----\n"
+ + "MIIEcDCCA1igAwIBAgIJAIz+EYMBU6aWMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD\n"
+ + "VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE\n"
+ + "ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU\n"
+ + "FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n"
+ + "ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTczMVoXDTI4MTEwNTE2MTczMVowgaYx\n"
+ + "CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0\n"
+ + "IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl\n"
+ + "cnRpZmljYXRlczESMBAGA1UEAxQJKi5mb28uY29tMSUwIwYJKoZIhvcNAQkBFhZq\n"
+ + "dWxpdXNkYXZpZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n"
+ + "CgKCAQEAyGOvloI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjUg4pN\n"
+ + "jYGViGjg7zhfbjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQcwHf0\n"
+ + "ZHLN6sD9m2uVSp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t7iu1\n"
+ + "JVjTuE0pcBvah2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAnAxK6\n"
+ + "q/wGqcZ3zvFBTcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArDqUYx\n"
+ + "qJUlPGlMqrKb3fCFiT3eXehwR7nlzQIDAQABo4GiMIGfMAkGA1UdEwQCMAAwLAYJ\n"
+ + "YIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1Ud\n"
+ + "DgQWBBSfFHe/Pzq2yjiCQkgWLNrQy16H2DAfBgNVHSMEGDAWgBR7mtqPkJlOUtKs\n"
+ + "27MDUsqHpg0+DTAkBgNVHREEHTAbggkqLmJhci5jb22CDiou6Iqx5a2QLmNvLmpw\n"
+ + "MA0GCSqGSIb3DQEBBQUAA4IBAQBobWC+D5/lx6YhX64CwZ26XLjxaE0S415ajbBq\n"
+ + "DK7lz+Rg7zOE3GsTAMi+ldUYnhyz0wDiXB8UwKXl0SDToB2Z4GOgqQjAqoMmrP0u\n"
+ + "WB6Y6dpkfd1qDRUzI120zPYgSdsXjHW9q2H77iV238hqIU7qCvEz+lfqqWEY504z\n"
+ + "hYNlknbUnR525ItosEVwXFBJTkZ3Yw8gg02c19yi8TAh5Li3Ad8XQmmSJMWBV4XK\n"
+ + "qFr0AIZKBlg6NZZFf/0dP9zcKhzSriW27bY0XfzA6GSiRDXrDjgXq6baRT6YwgIg\n"
+ + "pgJsDbJtZfHnV1nd3M6zOtQPm1TIQpNmMMMd/DPrGcUQerD3\n"
+ + "-----END CERTIFICATE-----\n");
+ X509Certificate[] certs = {};
+ // try the foo.com variations
+ assertTrue(verifier.verify(certs, "foo.com", session));
+ assertTrue(verifier.verify(certs, "www.foo.com", session));
+ assertTrue(verifier.verify(certs, "\u82b1\u5b50.foo.com", session));
+ assertFalse(verifier.verify(certs, "a.b.foo.com", session));
+ // these checks test alternative subjects. The test data contains an
+ // alternative subject starting with a japanese kanji character. This is
+ // not supported by Android because the underlying implementation from
+ // harmony follows the definition from rfc 1034 page 10 for alternative
+ // subject names. This causes the code to drop all alternative subjects.
+ // assertFalse(verifier.verify("bar.com", session));
+ // assertTrue(verifier.verify("www.bar.com", session));
+ // assertTrue(verifier.verify("\u82b1\u5b50.bar.com", session));
+ // assertTrue(verifier.verify("a.b.bar.com", session));
+ }
+
+ @Test public void subjectAltUsesLocalDomainAndIp() throws Exception {
+ // cat cert.cnf
+ // [req]
+ // distinguished_name=distinguished_name
+ // req_extensions=req_extensions
+ // x509_extensions=x509_extensions
+ // [distinguished_name]
+ // [req_extensions]
+ // [x509_extensions]
+ // subjectAltName=DNS:localhost.localdomain,DNS:localhost,IP:127.0.0.1
+ //
+ // $ openssl req -x509 -nodes -days 36500 -subj '/CN=localhost' -config ./cert.cnf \
+ // -newkey rsa:512 -out cert.pem
+ X509Certificate certificate = certificate(""
+ + "-----BEGIN CERTIFICATE-----\n"
+ + "MIIBWDCCAQKgAwIBAgIJANS1EtICX2AZMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV\n"
+ + "BAMTCWxvY2FsaG9zdDAgFw0xMjAxMDIxOTA4NThaGA8yMTExMTIwOTE5MDg1OFow\n"
+ + "FDESMBAGA1UEAxMJbG9jYWxob3N0MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPpt\n"
+ + "atK8r4/hf4hSIs0os/BSlQLbRBaK9AfBReM4QdAklcQqe6CHsStKfI8pp0zs7Ptg\n"
+ + "PmMdpbttL0O7mUboBC8CAwEAAaM1MDMwMQYDVR0RBCowKIIVbG9jYWxob3N0Lmxv\n"
+ + "Y2FsZG9tYWlugglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcNAQEFBQADQQD0ntfL\n"
+ + "DCzOCv9Ma6Lv5o5jcYWVxvBSTsnt22hsJpWD1K7iY9lbkLwl0ivn73pG2evsAn9G\n"
+ + "X8YKH52fnHsCrhSD\n"
+ + "-----END CERTIFICATE-----");
+
+ assertEquals(new X500Principal("CN=localhost"), certificate.getSubjectX500Principal());
+ FakeSSLSession session = new FakeSSLSession(certificate);
+
+ X509Certificate[] certs = {};
+
+ assertTrue(verifier.verify(certs, "localhost", session));
+ assertTrue(verifier.verify(certs, "localhost.localdomain", session));
+ assertFalse(verifier.verify(certs, "local.host", session));
+
+ assertTrue(verifier.verify(certs, "127.0.0.1", session));
+ assertFalse(verifier.verify(certs, "127.0.0.2", session));
+ }
+
+ @Test public void wildcardsCannotMatchIpAddresses() throws Exception {
+ // openssl req -x509 -nodes -days 36500 -subj '/CN=*.0.0.1' -newkey rsa:512 -out cert.pem
+ SSLSession session = session(""
+ + "-----BEGIN CERTIFICATE-----\n"
+ + "MIIBkjCCATygAwIBAgIJAMdemqOwd/BEMA0GCSqGSIb3DQEBBQUAMBIxEDAOBgNV\n"
+ + "BAMUByouMC4wLjEwIBcNMTAxMjIwMTY0NDI1WhgPMjExMDExMjYxNjQ0MjVaMBIx\n"
+ + "EDAOBgNVBAMUByouMC4wLjEwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAqY8c9Qrt\n"
+ + "YPWCvb7lclI+aDHM6fgbJcHsS9Zg8nUOh5dWrS7AgeA25wyaokFl4plBbbHQe2j+\n"
+ + "cCjsRiJIcQo9HwIDAQABo3MwcTAdBgNVHQ4EFgQUJ436TZPJvwCBKklZZqIvt1Yt\n"
+ + "JjEwQgYDVR0jBDswOYAUJ436TZPJvwCBKklZZqIvt1YtJjGhFqQUMBIxEDAOBgNV\n"
+ + "BAMUByouMC4wLjGCCQDHXpqjsHfwRDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB\n"
+ + "BQUAA0EAk9i88xdjWoewqvE+iMC9tD2obMchgFDaHH0ogxxiRaIKeEly3g0uGxIt\n"
+ + "fl2WRY8hb4x+zRrwsFaLEpdEvqcjOQ==\n"
+ + "-----END CERTIFICATE-----");
+ X509Certificate[] certs = {};
+ assertFalse(verifier.verify(certs, "127.0.0.1", session));
+ }
+
+ /**
+ * Earlier implementations of Android's hostname verifier required that
+ * wildcard names wouldn't match "*.com" or similar. This was a nonstandard
+ * check that we've since dropped. It is the CA's responsibility to not hand
+ * out certificates that match so broadly.
+ */
+ @Test public void wildcardsDoesNotNeedTwoDots() throws Exception {
+ // openssl req -x509 -nodes -days 36500 -subj '/CN=*.com' -newkey rsa:512 -out cert.pem
+ SSLSession session = session(""
+ + "-----BEGIN CERTIFICATE-----\n"
+ + "MIIBjDCCATagAwIBAgIJAOVulXCSu6HuMA0GCSqGSIb3DQEBBQUAMBAxDjAMBgNV\n"
+ + "BAMUBSouY29tMCAXDTEwMTIyMDE2NDkzOFoYDzIxMTAxMTI2MTY0OTM4WjAQMQ4w\n"
+ + "DAYDVQQDFAUqLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDJd8xqni+h7Iaz\n"
+ + "ypItivs9kPuiJUqVz+SuJ1C05SFc3PmlRCvwSIfhyD67fHcbMdl+A/LrIjhhKZJe\n"
+ + "1joO0+pFAgMBAAGjcTBvMB0GA1UdDgQWBBS4Iuzf5w8JdCp+EtBfdFNudf6+YzBA\n"
+ + "BgNVHSMEOTA3gBS4Iuzf5w8JdCp+EtBfdFNudf6+Y6EUpBIwEDEOMAwGA1UEAxQF\n"
+ + "Ki5jb22CCQDlbpVwkruh7jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA0EA\n"
+ + "U6LFxmZr31lFyis2/T68PpjAppc0DpNQuA2m/Y7oTHBDi55Fw6HVHCw3lucuWZ5d\n"
+ + "qUYo4ES548JdpQtcLrW2sA==\n"
+ + "-----END CERTIFICATE-----");
+ // Android-changed: Ignore common name in hostname verification. http://b/70278814
+ // assertTrue(verifier.verify("google.com", session));
+ X509Certificate[] certs = {};
+ assertFalse(verifier.verify(certs, "google.com", session));
+ }
+
+ @Test public void subjectAltName() throws Exception {
+ // $ cat ./cert.cnf
+ // [req]
+ // distinguished_name=distinguished_name
+ // req_extensions=req_extensions
+ // x509_extensions=x509_extensions
+ // [distinguished_name]
+ // [req_extensions]
+ // [x509_extensions]
+ // subjectAltName=DNS:bar.com,DNS:baz.com
+ //
+ // $ openssl req -x509 -nodes -days 36500 -subj '/CN=foo.com' -config ./cert.cnf \
+ // -newkey rsa:512 -out cert.pem
+ SSLSession session = session(""
+ + "-----BEGIN CERTIFICATE-----\n"
+ + "MIIBPTCB6KADAgECAgkA7zoHaaqNGHQwDQYJKoZIhvcNAQEFBQAwEjEQMA4GA1UE\n"
+ + "AxMHZm9vLmNvbTAgFw0xMDEyMjAxODM5MzZaGA8yMTEwMTEyNjE4MzkzNlowEjEQ\n"
+ + "MA4GA1UEAxMHZm9vLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC+gmoSxF+8\n"
+ + "hbV+rgRQqHIJd50216OWQJbU3BvdlPbca779NYO4+UZWTFdBM8BdQqs3H4B5Agvp\n"
+ + "y7HeSff1F7XRAgMBAAGjHzAdMBsGA1UdEQQUMBKCB2Jhci5jb22CB2Jhei5jb20w\n"
+ + "DQYJKoZIhvcNAQEFBQADQQBXpZZPOY2Dy1lGG81JTr8L4or9jpKacD7n51eS8iqI\n"
+ + "oTznPNuXHU5bFN0AAGX2ij47f/EahqTpo5RdS95P4sVm\n"
+ + "-----END CERTIFICATE-----");
+ X509Certificate[] certs = {};
+ assertFalse(verifier.verify(certs, "foo.com", session));
+ assertTrue(verifier.verify(certs, "bar.com", session));
+ assertTrue(verifier.verify(certs, "baz.com", session));
+ assertFalse(verifier.verify(certs, "a.foo.com", session));
+ assertFalse(verifier.verify(certs, "quux.com", session));
+ }
+
+ @Test public void subjectAltNameWithWildcard() throws Exception {
+ // $ cat ./cert.cnf
+ // [req]
+ // distinguished_name=distinguished_name
+ // req_extensions=req_extensions
+ // x509_extensions=x509_extensions
+ // [distinguished_name]
+ // [req_extensions]
+ // [x509_extensions]
+ // subjectAltName=DNS:bar.com,DNS:*.baz.com
+ //
+ // $ openssl req -x509 -nodes -days 36500 -subj '/CN=foo.com' -config ./cert.cnf \
+ // -newkey rsa:512 -out cert.pem
+ SSLSession session = session(""
+ + "-----BEGIN CERTIFICATE-----\n"
+ + "MIIBPzCB6qADAgECAgkAnv/7Jv5r7pMwDQYJKoZIhvcNAQEFBQAwEjEQMA4GA1UE\n"
+ + "AxMHZm9vLmNvbTAgFw0xMDEyMjAxODQ2MDFaGA8yMTEwMTEyNjE4NDYwMVowEjEQ\n"
+ + "MA4GA1UEAxMHZm9vLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDAz2YXnyog\n"
+ + "YdYLSFr/OEgSumtwqtZKJTB4wqTW/eKbBCEzxnyUMxWZIqUGu353PzwfOuWp2re3\n"
+ + "nvVV+QDYQlh9AgMBAAGjITAfMB0GA1UdEQQWMBSCB2Jhci5jb22CCSouYmF6LmNv\n"
+ + "bTANBgkqhkiG9w0BAQUFAANBAB8yrSl8zqy07i0SNYx2B/FnvQY734pxioaqFWfO\n"
+ + "Bqo1ZZl/9aPHEWIwBrxYNVB0SGu/kkbt/vxqOjzzrkXukmI=\n"
+ + "-----END CERTIFICATE-----");
+ X509Certificate[] certs = {};
+ assertFalse(verifier.verify(certs, "foo.com", session));
+ assertTrue(verifier.verify(certs, "bar.com", session));
+ assertTrue(verifier.verify(certs, "a.baz.com", session));
+ assertFalse(verifier.verify(certs, "baz.com", session));
+ assertFalse(verifier.verify(certs, "a.foo.com", session));
+ assertFalse(verifier.verify(certs, "a.bar.com", session));
+ assertFalse(verifier.verify(certs, "quux.com", session));
+ }
+
+ // BEGIN Android-added: Verify behaviour with top level wildcard SAN. http://b/144694112
+ @Test
+ public void subjectAltNameWithToplevelWildcard() throws Exception {
+ // Default OkHostnameVerifier instance should allow SANs which
+ // have wildcards for top-level domains. The strict instance should not.
+ //
+ // Certificate generated using:-
+ // openssl req -x509 -nodes -days 36500 -subj "/CN=Google Inc" \
+ // -addext "subjectAltName=DNS:*.com" -newkey rsa:512
+ SSLSession session = session(""
+ + "-----BEGIN CERTIFICATE-----\n"
+ + "MIIBlTCCAT+gAwIBAgIUe1RB6C61ZW/SEQpKiywSEJOEOUMwDQYJKoZIhvcNAQEL\n"
+ + "BQAwFTETMBEGA1UEAwwKR29vZ2xlIEluYzAgFw0xOTExMjExMjE1NTBaGA8yMTE5\n"
+ + "MTAyODEyMTU1MFowFTETMBEGA1UEAwwKR29vZ2xlIEluYzBcMA0GCSqGSIb3DQEB\n"
+ + "AQUAA0sAMEgCQQCu24jT8hktpvnmcde4dqC6e7G5F4cNNLUFnTi3Ay9BzPH1r7sN\n"
+ + "v2lHTIQLKSlvjxa48mpeRBlOjDQigv7c+rfRAgMBAAGjZTBjMB0GA1UdDgQWBBQd\n"
+ + "myvYKfluxb0+kNEJoh1ZER2wUTAfBgNVHSMEGDAWgBQdmyvYKfluxb0+kNEJoh1Z\n"
+ + "ER2wUTAPBgNVHRMBAf8EBTADAQH/MBAGA1UdEQQJMAeCBSouY29tMA0GCSqGSIb3\n"
+ + "DQEBCwUAA0EAK710g2hQpXSmpbOQH4dHG61fkVDtM/kR/4/R61vDDqVkgOuyHqXl\n"
+ + "GUZFKHMeOZ8peQLT8b+5ik6pIO7Vu2pF6w==\n"
+ + "-----END CERTIFICATE-----\n");
+ X509Certificate[] certs = {};
+ assertTrue(OkHostnameVerifier.INSTANCE.verify(certs, "google.com", session));
+ assertFalse(OkHostnameVerifier.strictInstance().verify(certs, "google.com", session));
+ }
+ // END Android-added: Verify behaviour with top level wildcard SAN. http://b/144694112
+
+ // Android-changed: OkHostnameVerifier.verifyAsIpAddress not accessible on platform builds
+ @Test
+ @Ignore
+ public void verifyAsIpAddress() {
+ // IPv4
+ assertTrue(OkHostnameVerifier.verifyAsIpAddress("127.0.0.1"));
+ assertTrue(OkHostnameVerifier.verifyAsIpAddress("1.2.3.4"));
+
+ // IPv6
+ assertTrue(OkHostnameVerifier.verifyAsIpAddress("::1"));
+ assertTrue(OkHostnameVerifier.verifyAsIpAddress("2001:db8::1"));
+ assertTrue(OkHostnameVerifier.verifyAsIpAddress("::192.168.0.1"));
+ assertTrue(OkHostnameVerifier.verifyAsIpAddress("::ffff:192.168.0.1"));
+ assertTrue(OkHostnameVerifier.verifyAsIpAddress("FEDC:BA98:7654:3210:FEDC:BA98:7654:3210"));
+ assertTrue(OkHostnameVerifier.verifyAsIpAddress("1080:0:0:0:8:800:200C:417A"));
+ assertTrue(OkHostnameVerifier.verifyAsIpAddress("1080::8:800:200C:417A"));
+ assertTrue(OkHostnameVerifier.verifyAsIpAddress("FF01::101"));
+ assertTrue(OkHostnameVerifier.verifyAsIpAddress("0:0:0:0:0:0:13.1.68.3"));
+ assertTrue(OkHostnameVerifier.verifyAsIpAddress("0:0:0:0:0:FFFF:129.144.52.38"));
+ assertTrue(OkHostnameVerifier.verifyAsIpAddress("::13.1.68.3"));
+ assertTrue(OkHostnameVerifier.verifyAsIpAddress("::FFFF:129.144.52.38"));
+
+ // Hostnames
+ assertFalse(OkHostnameVerifier.verifyAsIpAddress("go"));
+ assertFalse(OkHostnameVerifier.verifyAsIpAddress("localhost"));
+ assertFalse(OkHostnameVerifier.verifyAsIpAddress("squareup.com"));
+ assertFalse(OkHostnameVerifier.verifyAsIpAddress("www.nintendo.co.jp"));
+ }
+
+ private X509Certificate certificate(String certificate) throws Exception {
+ return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(
+ new ByteArrayInputStream(certificate.getBytes(UTF_8)));
+ }
+
+ private SSLSession session(String certificate) throws Exception {
+ return new FakeSSLSession(certificate(certificate));
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/MacTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/MacTest.java
new file mode 100644
index 0000000..577162b
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/MacTest.java
@@ -0,0 +1,403 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.TestUtils.decodeHex;
+import static com.android.org.conscrypt.TestUtils.encodeHex;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.Provider;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+import javax.crypto.Mac;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class MacTest {
+ private final List<String[]> testVectors = readTestVectors();
+
+ // Column indices in test vector CSV file
+ private static final int ALGORITHM_INDEX = 0;
+ private static final int KEY_INDEX = 1;
+ private static final int MESSAGE_INDEX = 2;
+ private static final int MAC_INDEX = 3;
+
+ // Number of splits to use when testing multiple buffers
+ private static final int NUM_SPLITS = 4;
+
+ private final Random random = new Random(System.currentTimeMillis());
+
+ private final Provider conscryptProvider = TestUtils.getConscryptProvider();
+
+ @BeforeClass
+ public static void setUp() {
+ TestUtils.assumeAllowsUnsignedCrypto();
+ }
+
+ @Test
+ public void knownAnswerTest() throws Exception {
+ for (String[] entry : testVectors) {
+ String algorithm = entry[ALGORITHM_INDEX];
+ String key = entry[KEY_INDEX];
+ String msg = entry[MESSAGE_INDEX];
+ String expected = entry[MAC_INDEX];
+
+ byte[] keyBytes = decodeHex(key);
+ byte[] msgBytes = decodeHex(msg);
+ byte[] expectedBytes = decodeHex(expected);
+ SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "RawBytes");
+
+ String baseFailMsg = String.format("Mac=%s\nKey=%s\nMsg=%s\nExpected=%s",
+ algorithm, key, msg, expected);
+
+ // Calculate using Mac.update(byte[])
+ byte[] macBytes = generateMacUsingUpdate(algorithm, secretKey, msgBytes);
+ assertArrayEquals(failMessage("Using update()", baseFailMsg, macBytes),
+ expectedBytes, macBytes);
+
+ // Calculate using Mac.final(byte[])
+ macBytes = generateMacUsingFinal(algorithm, secretKey, msgBytes);
+ assertArrayEquals(failMessage("Using final()", baseFailMsg, macBytes),
+ expectedBytes, macBytes);
+
+ // Calculate using Mac.update(ByteBuffer) with a single non-direct ByteBuffer
+ ByteBuffer nondirectBuffer = ByteBuffer.wrap(msgBytes);
+ macBytes = generateMac(algorithm, secretKey, nondirectBuffer);
+ assertArrayEquals(failMessage("Non-direct ByteBuffer", baseFailMsg, macBytes),
+ expectedBytes, macBytes);
+
+ // Calculate using Mac.update(ByteBuffer) with a single direct ByteBuffer
+ ByteBuffer directBuffer = ByteBuffer.allocateDirect(msgBytes.length);
+ directBuffer.put(msgBytes);
+ directBuffer.flip();
+ macBytes = generateMac(algorithm, secretKey, directBuffer);
+ assertArrayEquals(failMessage("Direct ByteBuffer", baseFailMsg, macBytes),
+ expectedBytes, macBytes);
+
+ // Calculate using Mac.update(ByteBuffer) with a multiple non-direct ByteBuffers
+ nondirectBuffer.flip();
+ macBytes = generateMac(algorithm, secretKey, split(nondirectBuffer));
+ assertArrayEquals(failMessage("Multiple non-direct ByteBuffers", baseFailMsg, macBytes),
+ expectedBytes, macBytes);
+
+ // Calculate using Mac.update(ByteBuffer) with a multiple direct ByteBuffers
+ directBuffer.flip();
+ macBytes = generateMac(algorithm, secretKey, split(directBuffer));
+ assertArrayEquals(failMessage("Multiple direct ByteBuffers", baseFailMsg, macBytes),
+ expectedBytes, macBytes);
+
+ // Calculated using a pre-loved Mac
+ macBytes = generateReusingMac(algorithm, keyBytes, msgBytes);
+ assertArrayEquals(failMessage("Re-use Mac", baseFailMsg, macBytes),
+ expectedBytes, macBytes);
+ }
+ }
+
+ @Test
+ public void serviceCreation() {
+ newMacServiceTester()
+ // Android KeyStore can only be initialised with its own private keys - tested
+ // elsewhere.
+ .skipProvider("AndroidKeyStore")
+ .skipProvider("AndroidKeyStoreBCWorkaround")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(final Provider provider, final String algorithm)
+ throws Exception {
+ SecretKeySpec key = findAnyKey(algorithm);
+
+ Mac mac = Mac.getInstance(algorithm);
+ assertEquals(algorithm, mac.getAlgorithm());
+
+ mac = Mac.getInstance(algorithm, provider);
+ assertEquals(algorithm, mac.getAlgorithm());
+ assertEquals(provider, mac.getProvider());
+ if (key != null) {
+ // TODO(prb) Ensure we have at least one test vector for every
+ // MAC in Conscrypt and Android.
+ mac.init(key);
+ assertEquals(provider, mac.getProvider());
+ }
+
+ mac = Mac.getInstance(algorithm, provider.getName());
+ assertEquals(algorithm, mac.getAlgorithm());
+ assertEquals(provider, mac.getProvider());
+ if (key != null) {
+ mac.init(key);
+ assertEquals(provider, mac.getProvider());
+ }
+ }
+ });
+ }
+
+ @Test
+ public void invalidKeyThrows() {
+ newMacServiceTester()
+ // BC actually accepts RSA public keys for these algorithms for some reason.
+ .skipCombination("BC", "PBEWITHHMACSHA")
+ .skipCombination("BC", "PBEWITHHMACSHA1")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(final Provider provider, final String algorithm)
+ throws Exception {
+ KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
+ generator.initialize(2048);
+ KeyPair keyPair = generator.generateKeyPair();
+
+ try {
+ Mac mac = Mac.getInstance(algorithm, provider);
+ mac.init(keyPair.getPublic(), null);
+ fail();
+ } catch (InvalidKeyException e) {
+ // Expected
+ }
+ }
+ });
+ }
+
+ @Test
+ public void uninitializedMacThrows() {
+ newMacServiceTester().run(new ServiceTester.Test() {
+ @Override
+ public void test(final Provider provider, final String algorithm) throws Exception {
+ byte[] message = "Message".getBytes(StandardCharsets.UTF_8);
+
+ try {
+ Mac mac = Mac.getInstance(algorithm, provider);
+ mac.update(message);
+ fail();
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+ try {
+ Mac mac = Mac.getInstance(algorithm, provider);
+ mac.doFinal(message);
+ fail();
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+ try {
+ Mac mac = Mac.getInstance(algorithm, provider);
+ mac.doFinal();
+ fail();
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+ }
+ });
+ }
+
+ private ServiceTester newMacServiceTester() {
+ return ServiceTester
+ .test("Mac")
+ // On Android 10 and 11 BC advertises these Macs but they are deprecated so throw
+ // on initialization.
+ .skipCombination("BC", "HMACMD5")
+ .skipCombination("BC", "HMACSHA1")
+ .skipCombination("BC", "HMACSHA224")
+ .skipCombination("BC", "HMACSHA256")
+ .skipCombination("BC", "HMACSHA384")
+ .skipCombination("BC", "HMACSHA512")
+ .skipCombination("BC", "PBEWITHHMACSHA224")
+ .skipCombination("BC", "PBEWITHHMACSHA256")
+ .skipCombination("BC", "PBEWITHHMACSHA384")
+ .skipCombination("BC", "PBEWITHHMACSHA512");
+ }
+
+ private static class DummyParameterSpec implements AlgorithmParameterSpec { }
+
+ @Test
+ public void algorithmParameters() {
+ ServiceTester
+ .test("Mac")
+ // Android KeyStore can only be initialised with its own private keys - tested
+ // elsewhere.
+ .skipProvider("AndroidKeyStore")
+ .skipProvider("AndroidKeyStoreBCWorkaround")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(final Provider provider, final String algorithm)
+ throws Exception {
+ SecretKeySpec key = findAnyKey(algorithm);
+ if (key != null) {
+ Mac mac = Mac.getInstance(algorithm, provider);
+ // Equivalent to mac.init(key) - allowed
+ mac.init(key, null);
+
+ try {
+ mac = Mac.getInstance(algorithm, provider);
+ mac.init(key, new DummyParameterSpec());
+ fail();
+ } catch (InvalidAlgorithmParameterException exception) {
+ // Expected
+ }
+ }
+ }
+ });
+ }
+
+ private SecretKeySpec findAnyKey(String algorithm) {
+ for (String[] entry : testVectors) {
+ if (entry[ALGORITHM_INDEX].equals(algorithm)) {
+ return new SecretKeySpec(decodeHex(entry[KEY_INDEX]), "RawBytes");
+ }
+ }
+ return null;
+ }
+
+ @Test
+ public void anyAlgorithmParametersThrows() throws Exception {
+ Set<String> seen = new HashSet<>();
+ for (String[] entry : testVectors) {
+ String algorithm = entry[ALGORITHM_INDEX];
+ if (!seen.contains(algorithm)) {
+ seen.add(algorithm);
+ byte[] keyBytes = decodeHex(entry[KEY_INDEX]);
+ SecretKeySpec key = new SecretKeySpec(keyBytes, "RawBytes");
+ Mac mac = Mac.getInstance(algorithm);
+ try {
+ mac.init(key, new IvParameterSpec(keyBytes));
+ fail(algorithm);
+ } catch (InvalidAlgorithmParameterException exception) {
+ // Expected
+ }
+ }
+ }
+ }
+
+ private String failMessage(String test, String base, byte[] mac) {
+ return String.format("Test %s\n%s\nActual= %s", test, base, encodeHex(mac));
+ }
+
+ // Splits a ByteBuffer into an array of NUM_SPLITS ByteBuffers containing the same data.
+ // If input.remaining < NUM_SPLITS then some buffers will be empty, which is fine.
+ private ByteBuffer[] split(ByteBuffer input) {
+ ByteBuffer[] buffers = new ByteBuffer[NUM_SPLITS];
+ int targetSize = (input.remaining() / NUM_SPLITS) + 1;
+ ByteBuffer buffer;
+ for (int i = 0; i < NUM_SPLITS; i++) {
+ int size = Math.min(targetSize, input.remaining());
+ buffer = input.isDirect() ? ByteBuffer.allocateDirect(size) : ByteBuffer.allocate(size);
+ buffers[i] = buffer;
+
+ int savedLimit = input.limit();
+ input.limit(input.position() + size);
+ buffer.put(input);
+ buffer.flip();
+ input.limit(savedLimit);
+ }
+ assertEquals(0, input.remaining());
+ return buffers;
+ }
+
+ private byte[] generateMacUsingUpdate(String algorithm, SecretKeySpec key, byte[] message)
+ throws Exception {
+ Mac mac = getConscryptMac(algorithm, key);
+ mac.update(message);
+ return mac.doFinal();
+ }
+
+ private byte[] generateMacUsingFinal(String algorithm, SecretKeySpec key, byte[] message)
+ throws Exception {
+ Mac mac = getConscryptMac(algorithm, key);
+ return mac.doFinal(message);
+ }
+
+ private byte[] generateMac(String algorithm, SecretKeySpec key, ByteBuffer buffer)
+ throws Exception {
+ return generateMac(algorithm, key, new ByteBuffer[] { buffer });
+ }
+
+ private byte[] generateMac(String algorithm, SecretKeySpec key, ByteBuffer[] buffers)
+ throws Exception {
+ Mac mac = getConscryptMac(algorithm, key);
+ for (ByteBuffer buffer : buffers) {
+ mac.update(buffer);
+ }
+ return mac.doFinal();
+ }
+
+ private byte[] generateReusingMac(String algorithm, byte[] keyBytes, byte[] message)
+ throws Exception {
+ Mac mac = getConscryptMac(algorithm);
+
+ // Mutate the original message and key and calculate a MAC from them
+ byte[] otherKeyBytes = new byte[keyBytes.length];
+ random.nextBytes(otherKeyBytes);
+ SecretKeySpec otherKey = new SecretKeySpec(otherKeyBytes, "RawBytes");
+ byte[] otherMessage = new byte[message.length];
+ random.nextBytes(otherMessage);
+ mac.init(otherKey);
+ mac.doFinal(otherMessage);
+
+ // Then re-use the same Mac with the original key and message
+ SecretKeySpec key = new SecretKeySpec(keyBytes, "RawBytes");
+ mac.reset();
+ mac.init(key);
+ mac.update(message);
+ return mac.doFinal();
+ }
+
+ private Mac getConscryptMac(String algorithm) throws Exception {
+ return getConscryptMac(algorithm, null);
+ }
+
+ private Mac getConscryptMac(String algorithm, SecretKeySpec key) throws Exception {
+ Mac mac = Mac.getInstance(algorithm, conscryptProvider);
+ assertNotNull(mac);
+ if (key != null) {
+ // Provider is not actually chosen until init
+ mac.init(key);
+ assertSame(conscryptProvider, mac.getProvider());
+ }
+ return mac;
+ }
+
+ private List<String[]> readTestVectors() {
+ try {
+ return TestUtils.readCsvResource("crypto/macs.csv");
+
+ } catch (IOException e) {
+ throw new AssertionError("Unable to load MAC test vectors", e);
+ }
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/NativeCryptoArgTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/NativeCryptoArgTest.java
new file mode 100644
index 0000000..db096a0
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/NativeCryptoArgTest.java
@@ -0,0 +1,335 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.junit.AfterClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class NativeCryptoArgTest {
+ // Null value passed in for a long which represents a native address
+ private static final long NULL = 0L;
+ /*
+ * Non-null value passed in for a long which represents a native address. Shouldn't
+ * ever get de-referenced but we make it a multiple of 4 to avoid any alignment errors.
+ * Used in the case where there are multiple checks we want to test in a native method,
+ * so we can get past the first check and test the second one.
+ */
+ private static final long NOT_NULL = 4L;
+ private static final String CONSCRYPT_PACKAGE = NativeCryptoArgTest.class.getCanonicalName()
+ .substring(0, NativeCryptoArgTest.class.getCanonicalName().lastIndexOf('.') + 1);
+ private static final Set<String> testedMethods = new HashSet<>();
+ private final Map<String, Class<?>> classCache = new HashMap<>();
+ private final Map<String, Method> methodMap = buildMethodMap();
+
+ @AfterClass
+ public static void after() {
+ // TODO(prb): Temporary hacky check - remove
+ assertTrue(testedMethods.size() >= 190);
+ }
+
+ @Test
+ public void ecMethods() throws Throwable {
+ String[] illegalArgMethods = new String[] {
+ "EC_GROUP_new_arbitrary"
+ };
+ String[] ioExMethods = new String[] {
+ "EC_KEY_parse_curve_name",
+ "EC_KEY_marshal_curve_name"
+ };
+
+ // All of the EC_* methods apart from the exceptions below throw NPE if their
+ // first argument is null.
+ MethodFilter filter = MethodFilter.newBuilder("EC_ methods")
+ .hasPrefix("EC_")
+ .except(illegalArgMethods)
+ .except(ioExMethods)
+ .expectSize(16)
+ .build();
+ testMethods(filter, NullPointerException.class);
+
+ filter = MethodFilter.nameFilter("EC_ methods (IllegalArgument)", illegalArgMethods);
+ testMethods(filter, IllegalArgumentException.class);
+
+ filter = MethodFilter.nameFilter("EC_ methods (IOException)", ioExMethods);
+ testMethods(filter, IOException.class);
+ }
+
+ @Test
+ public void macMethods() throws Throwable {
+ // All of the non-void HMAC and CMAC methods throw NPE when passed a null pointer
+ MethodFilter filter = MethodFilter.newBuilder("HMAC methods")
+ .hasPrefix("HMAC_")
+ .takesArguments()
+ .expectSize(5)
+ .build();
+ testMethods(filter, NullPointerException.class);
+
+ filter = MethodFilter.newBuilder("CMAC methods")
+ .hasPrefix("CMAC_")
+ .takesArguments()
+ .expectSize(5)
+ .build();
+ testMethods(filter, NullPointerException.class);
+ }
+
+ @Test
+ public void sslMethods() throws Throwable {
+ // These methods don't throw on a null first arg as they can get called before the
+ // connection is fully initialised. However if the first arg is non-NULL, any subsequent
+ // null args should throw NPE.
+ String[] nonThrowingMethods = new String[] {
+ "SSL_interrupt",
+ "SSL_shutdown",
+ "ENGINE_SSL_shutdown",
+ };
+
+ // Most of the NativeSsl methods take a long holding a pointer to the native
+ // object followed by a {@code NativeSsl} holder object. However the second arg
+ // is unused(!) so we don't need to test it.
+ MethodFilter filter = MethodFilter.newBuilder("NativeSsl methods")
+ .hasArg(0, long.class)
+ .hasArg(1, conscryptClass("NativeSsl"))
+ .except(nonThrowingMethods)
+ .expectSize(60)
+ .build();
+
+ testMethods(filter, NullPointerException.class);
+
+ // Many of the SSL_* methods take a single long which points
+ // to a native object.
+ filter = MethodFilter.newBuilder("1-arg SSL methods")
+ .hasPrefix("SSL_")
+ .hasArgLength(1)
+ .hasArg(0, long.class)
+ .expectSize(10)
+ .build();
+
+ testMethods(filter, NullPointerException.class);
+
+ filter = MethodFilter.nameFilter("Non throwing NativeSsl methods", nonThrowingMethods);
+ testMethods(filter, null);
+
+ expectVoid("SSL_shutdown", NOT_NULL, null, null, null);
+ expectNPE("SSL_shutdown", NOT_NULL, null, new FileDescriptor(), null);
+ expectNPE("ENGINE_SSL_shutdown", NOT_NULL, null, null);
+ expectVoid("SSL_set_session", NOT_NULL, null, NULL);
+ }
+
+ @Test
+ public void evpMethods() throws Throwable {
+ String[] illegalArgMethods = new String[] {
+ "EVP_AEAD_CTX_open_buf",
+ "EVP_AEAD_CTX_seal_buf",
+ "EVP_PKEY_new_RSA"
+ };
+ String[] nonThrowingMethods = new String[] {
+ "EVP_MD_CTX_destroy",
+ "EVP_PKEY_CTX_free",
+ "EVP_PKEY_free",
+ "EVP_CIPHER_CTX_free"
+ };
+
+ // All of the non-void EVP_ methods apart from the above should throw on a null
+ // first argument.
+ MethodFilter filter = MethodFilter.newBuilder("EVP methods")
+ .hasPrefix("EVP_")
+ .takesArguments()
+ .except(illegalArgMethods)
+ .except(nonThrowingMethods)
+ .expectSize(45)
+ .build();
+
+ testMethods(filter, NullPointerException.class);
+
+ filter = MethodFilter.nameFilter("EVP methods (IllegalArgument)", illegalArgMethods);
+ testMethods(filter, IllegalArgumentException.class);
+
+ filter = MethodFilter.nameFilter("EVP methods (non-throwing)", nonThrowingMethods);
+ testMethods(filter, null);
+ }
+
+ @Test
+ public void x509Methods() throws Throwable {
+ // A number of X509 methods have a native pointer as arg 0 and an
+ // OpenSSLX509Certificate or OpenSSLX509CRL as arg 1.
+ MethodFilter filter = MethodFilter.newBuilder("X509 methods")
+ .hasArgLength(2)
+ .hasArg(0, long.class)
+ .hasArg(1, conscryptClass("OpenSSLX509Certificate"),
+ conscryptClass("OpenSSLX509CRL"))
+ .expectSize(32)
+ .build();
+ // TODO(prb): test null second argument
+ testMethods(filter, NullPointerException.class);
+
+ // The rest of the X509 methods are somewhat ad hoc.
+ expectNPE("d2i_X509", (Object) null);
+
+ invokeAndExpect( conscryptThrowable("OpenSSLX509CertificateFactory$ParsingException"),
+ "d2i_X509", new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0});
+
+ expectNPE("d2i_X509_bio", NULL);
+ expectNPE("PEM_read_bio_X509", NULL);
+ expectNPE("ASN1_seq_pack_X509", (Object) null);
+
+ // TODO(prb): Check what this should really throw
+ // expectNPE("ASN1_seq_pack_X509", (Object) new long[] { NULL });
+
+ expectNPE("ASN1_seq_unpack_X509_bio", NULL);
+
+ //
+ expectNPE("X509_cmp", NULL, null, NULL, null);
+ expectNPE("X509_cmp", NOT_NULL, null, NULL, null);
+ expectNPE("X509_cmp", NULL, null, NOT_NULL, null);
+
+ expectNPE("X509_print_ex", NULL, NULL, null, NULL, NULL);
+ expectNPE("X509_print_ex", NOT_NULL, NULL, null, NULL, NULL);
+ expectNPE("X509_print_ex", NULL, NOT_NULL, null, NULL, NULL);
+ }
+
+ private void testMethods(MethodFilter filter, Class<? extends Throwable> exceptionClass)
+ throws Throwable {
+ List<Method> methods = filter.filter(methodMap.values());
+
+ for (Method method : methods) {
+ List<Object[]> argsLists = permuteArgs(method);
+ for (Object[] args : argsLists) {
+ invokeAndExpect(exceptionClass, method, args);
+ }
+ }
+ }
+
+ private List<Object[]> permuteArgs(Method method) {
+ // For now just supply 0 for integral types and null for everything else
+ // TODO: allow user defined strategy, e.g. if two longs passed as native refs,
+ // generate {NULL,NULL}, {NULL,NOT_NULL}, {NOT_NULL,NULL} to test both null checks
+ List<Object[]> result = new ArrayList<>(1);
+
+ Class<?>[] argTypes = method.getParameterTypes();
+
+ int argCount = argTypes.length;
+ assertTrue(argCount > 0);
+ Object[] args = new Object[argCount];
+
+ for (int arg = 0; arg < argCount; arg++) {
+ if (argTypes[arg] == int.class) {
+ args[arg] = 0;
+ } else if (argTypes[arg] == long.class) {
+ args[arg] = NULL;
+ } else if (argTypes[arg] == boolean.class) {
+ args[arg] = false;
+ } else {
+ args[arg] = null;
+ }
+ }
+ result.add(args);
+ return result;
+ }
+
+ private void expectVoid(String methodName, Object... args) throws Throwable {
+ invokeAndExpect(null, methodName, args);
+ }
+
+ private void expectNPE(String methodName, Object... args) throws Throwable {
+ invokeAndExpect(NullPointerException.class, methodName, args);
+ }
+
+ private void invokeAndExpect(Class<? extends Throwable> expectedThrowable, String methodName,
+ Object... args) throws Throwable {
+ Method method = methodMap.get(methodName);
+ assertNotNull(method);
+ assertEquals(methodName, method.getName());
+ invokeAndExpect(expectedThrowable, method, args);
+ }
+
+ private void invokeAndExpect(Class<? extends Throwable> expectedThrowable, Method method,
+ Object... args) throws Throwable {
+ try {
+ method.invoke(null, args);
+ if (expectedThrowable != null) {
+ fail("No exception thrown by method " + method.getName());
+ }
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("Illegal access", e);
+ } catch (InvocationTargetException e) {
+ Throwable cause = e.getCause();
+ if (expectedThrowable != null) {
+ assertEquals("Method: " + method.getName(), expectedThrowable, cause.getClass());
+ } else {
+ throw cause;
+ }
+ }
+ testedMethods.add(method.getName());
+ }
+
+ @SuppressWarnings("unchecked")
+ private Class<? extends Throwable> conscryptThrowable(String name) {
+ Class<?> klass = conscryptClass(name);
+ assertNotNull(klass);
+ assertTrue(Throwable.class.isAssignableFrom(klass));
+ return (Class<? extends Throwable>) klass;
+ }
+
+ private Class<?> conscryptClass(String className) {
+ return classCache.computeIfAbsent(className, s -> {
+ try {
+ return Class.forName(CONSCRYPT_PACKAGE + className);
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ });
+ }
+
+ private Map<String, Method> buildMethodMap() {
+ Map<String, Method> classMap = new HashMap<>();
+ assertNotNull(classMap);
+ Class<?> nativeCryptoClass = conscryptClass("NativeCrypto");
+ assertNotNull(nativeCryptoClass);
+ for (Method method : nativeCryptoClass.getDeclaredMethods()) {
+ int modifiers = method.getModifiers();
+ if (!Modifier.isNative(modifiers)) {
+ continue;
+ }
+ method.setAccessible(true);
+ classMap.put(method.getName(), method);
+ }
+ return classMap;
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/TrustManagerImplTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/TrustManagerImplTest.java
new file mode 100644
index 0000000..ea58efb
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/TrustManagerImplTest.java
@@ -0,0 +1,484 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2011 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.org.conscrypt.java.security.TestKeyStore;
+import com.android.org.conscrypt.javax.net.ssl.TestHostnameVerifier;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.List;
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.X509TrustManager;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class TrustManagerImplTest {
+
+ /**
+ * Ensure that our non-standard behavior of learning to trust new
+ * intermediate CAs does not regress. http://b/3404902
+ */
+ @Test
+ public void testLearnIntermediate() throws Exception {
+ TestUtils.assumeExtendedTrustManagerAvailable();
+ // chain3 should be server/intermediate/root
+ KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
+ X509Certificate[] chain3 = (X509Certificate[])pke.getCertificateChain();
+ X509Certificate root = chain3[2];
+ X509Certificate intermediate = chain3[1];
+ X509Certificate server = chain3[0];
+ X509Certificate[] chain2 = new X509Certificate[] { server, intermediate };
+ X509Certificate[] chain1 = new X509Certificate[] { server };
+
+ // Normal behavior
+ assertValid(chain3, trustManager(root));
+ assertValid(chain2, trustManager(root));
+ assertInvalid(chain1, trustManager(root));
+ assertValid(chain3, trustManager(intermediate));
+ assertValid(chain2, trustManager(intermediate));
+ assertValid(chain1, trustManager(intermediate));
+ assertValid(chain3, trustManager(server));
+ assertValid(chain2, trustManager(server));
+ assertValid(chain1, trustManager(server));
+
+ // non-standard behavior
+ X509TrustManager tm = trustManager(root);
+ // fail on short chain with only root trusted
+ assertInvalid(chain1, tm);
+ // succeed on longer chain, learn intermediate
+ assertValid(chain2, tm);
+ // now we can validate the short chain
+ assertValid(chain1, tm);
+ }
+
+ // We should ignore duplicate cruft in the certificate chain
+ // See https://code.google.com/p/android/issues/detail?id=52295 http://b/8313312
+ @Test
+ public void testDuplicateInChain() throws Exception {
+ TestUtils.assumeExtendedTrustManagerAvailable();
+ // chain3 should be server/intermediate/root
+ KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
+ X509Certificate[] chain3 = (X509Certificate[])pke.getCertificateChain();
+ X509Certificate root = chain3[2];
+ X509Certificate intermediate = chain3[1];
+ X509Certificate server = chain3[0];
+
+ X509Certificate[] chain4 = new X509Certificate[] { server, intermediate,
+ server, intermediate
+ };
+ assertValid(chain4, trustManager(root));
+ }
+
+ @Test
+ public void testGetFullChain() throws Exception {
+ TestUtils.assumeExtendedTrustManagerAvailable();
+ // build the trust manager
+ KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
+ X509Certificate[] chain3 = (X509Certificate[]) pke.getCertificateChain();
+ X509Certificate root = chain3[2];
+ X509TrustManager tm = trustManager(root);
+
+ // build the chains we'll use for testing
+ X509Certificate intermediate = chain3[1];
+ X509Certificate server = chain3[0];
+ X509Certificate[] chain2 = new X509Certificate[] { server, intermediate };
+ X509Certificate[] chain1 = new X509Certificate[] { server };
+
+ assertTrue(tm instanceof TrustManagerImpl);
+ TrustManagerImpl tmi = (TrustManagerImpl) tm;
+ List<X509Certificate> certs =
+ tmi.checkServerTrusted(chain2, "RSA", new FakeSSLSession("purple.com"));
+ assertEquals(Arrays.asList(chain3), certs);
+ certs = tmi.checkServerTrusted(chain1, "RSA", new FakeSSLSession("purple.com"));
+ assertEquals(Arrays.asList(chain3), certs);
+ }
+
+ @Test
+ public void testHttpsEndpointIdentification() throws Exception {
+ TestUtils.assumeExtendedTrustManagerAvailable();
+
+ KeyStore.PrivateKeyEntry pke = TestKeyStore.getServerHostname().getPrivateKey("RSA", "RSA");
+ X509Certificate[] chain = (X509Certificate[]) pke.getCertificateChain();
+ X509Certificate root = chain[2];
+ TrustManagerImpl tmi = (TrustManagerImpl) trustManager(root);
+
+ String goodHostname = TestKeyStore.CERT_HOSTNAME;
+ String badHostname = "definitelywrong.nopenopenope";
+
+ try {
+ SSLParameters params = new SSLParameters();
+
+ // Without endpoint identification this should pass despite the mismatched hostname
+ params.setEndpointIdentificationAlgorithm(null);
+
+ List<X509Certificate> certs = tmi.getTrustedChainForServer(chain, "RSA",
+ new FakeSSLSocket(new FakeSSLSession(badHostname, chain), params));
+ assertEquals(Arrays.asList(chain), certs);
+
+ // Turn on endpoint identification
+ params.setEndpointIdentificationAlgorithm("HTTPS");
+
+ try {
+ tmi.getTrustedChainForServer(chain, "RSA",
+ new FakeSSLSocket(new FakeSSLSession(badHostname, chain), params));
+ fail();
+ } catch (CertificateException expected) {
+ }
+
+ certs = tmi.getTrustedChainForServer(chain, "RSA",
+ new FakeSSLSocket(new FakeSSLSession(goodHostname, chain), params));
+ assertEquals(Arrays.asList(chain), certs);
+
+ // Override the global default hostname verifier with a Conscrypt-specific one that
+ // always passes. Both scenarios should pass.
+ Conscrypt.setHostnameVerifier(tmi, new ConscryptHostnameVerifier() {
+ @Override
+ public boolean verify(
+ X509Certificate[] certificates, String s, SSLSession sslSession) {
+ return true;
+ }
+ });
+
+ certs = tmi.getTrustedChainForServer(chain, "RSA",
+ new FakeSSLSocket(new FakeSSLSession(badHostname, chain), params));
+ assertEquals(Arrays.asList(chain), certs);
+
+ certs = tmi.getTrustedChainForServer(chain, "RSA",
+ new FakeSSLSocket(new FakeSSLSession(goodHostname, chain), params));
+ assertEquals(Arrays.asList(chain), certs);
+
+ // Now set an instance-specific verifier on the trust manager. The bad hostname should
+ // fail again.
+ Conscrypt.setHostnameVerifier(
+ tmi, Conscrypt.wrapHostnameVerifier(new TestHostnameVerifier()));
+
+ try {
+ tmi.getTrustedChainForServer(chain, "RSA",
+ new FakeSSLSocket(new FakeSSLSession(badHostname, chain), params));
+ fail();
+ } catch (CertificateException expected) {
+ }
+
+ certs = tmi.getTrustedChainForServer(chain, "RSA",
+ new FakeSSLSocket(new FakeSSLSession(goodHostname, chain), params));
+ assertEquals(Arrays.asList(chain), certs);
+
+ // Remove the instance-specific verifier, and both should pass again.
+ Conscrypt.setHostnameVerifier(tmi, null);
+
+ try {
+ tmi.getTrustedChainForServer(chain, "RSA",
+ new FakeSSLSocket(new FakeSSLSession(badHostname, chain), params));
+ fail();
+ } catch (CertificateException expected) {
+ }
+
+ certs = tmi.getTrustedChainForServer(chain, "RSA",
+ new FakeSSLSocket(new FakeSSLSession(goodHostname, chain), params));
+ assertEquals(Arrays.asList(chain), certs);
+ } finally {
+ Conscrypt.setDefaultHostnameVerifier(null);
+ }
+ }
+
+ private X509TrustManager trustManager(X509Certificate ca) throws Exception {
+ KeyStore keyStore = TestKeyStore.createKeyStore();
+ keyStore.setCertificateEntry("alias", ca);
+
+ return new TrustManagerImpl(keyStore);
+ }
+
+ private void assertValid(X509Certificate[] chain, X509TrustManager tm) throws Exception {
+ if (tm instanceof TrustManagerImpl) {
+ TrustManagerImpl tmi = (TrustManagerImpl) tm;
+ tmi.checkServerTrusted(chain, "RSA");
+ }
+ tm.checkServerTrusted(chain, "RSA");
+ }
+
+ private void assertInvalid(X509Certificate[] chain, X509TrustManager tm) {
+ try {
+ tm.checkClientTrusted(chain, "RSA");
+ fail();
+ } catch (CertificateException expected) {
+ // Expected.
+ }
+ try {
+ tm.checkServerTrusted(chain, "RSA");
+ fail();
+ } catch (CertificateException expected) {
+ // Expected.
+ }
+ }
+
+ private static class FakeSSLSession implements SSLSession {
+ private final String hostname;
+ private final X509Certificate[] peerCerts;
+
+ FakeSSLSession(String hostname) {
+ this.hostname = hostname;
+ peerCerts = null;
+ }
+
+ FakeSSLSession(String hostname, X509Certificate[] peerCerts) {
+ this.hostname = hostname;
+ this.peerCerts = peerCerts.clone();
+ }
+
+ @Override
+ public int getApplicationBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getCipherSuite() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getCreationTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte[] getId() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getLastAccessedTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getLocalCertificates() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getLocalPrincipal() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPacketBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public javax.security.cert.X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ if (peerCerts == null) {
+ throw new SSLPeerUnverifiedException("Null peerCerts");
+ } else {
+ return peerCerts.clone();
+ }
+ }
+
+ @Override
+ public String getPeerHost() {
+ return hostname;
+ }
+
+ @Override
+ public int getPeerPort() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getProtocol() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SSLSessionContext getSessionContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void invalidate() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isValid() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putValue(String name, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private static class FakeSSLSocket extends SSLSocket {
+ private final SSLSession session;
+ private final SSLParameters parameters;
+
+ public FakeSSLSocket(SSLSession session, SSLParameters parameters) {
+ this.session = session;
+ this.parameters = parameters;
+ }
+
+ @Override
+ public SSLParameters getSSLParameters() {
+ return parameters;
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getEnabledCipherSuites() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setEnabledCipherSuites(String[] strings) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getSupportedProtocols() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getEnabledProtocols() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setEnabledProtocols(String[] strings) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SSLSession getSession() {
+ return session;
+ }
+
+ @Override
+ public SSLSession getHandshakeSession() {
+ return session;
+ }
+
+ @Override
+ public void addHandshakeCompletedListener(
+ HandshakeCompletedListener handshakeCompletedListener) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeHandshakeCompletedListener(
+ HandshakeCompletedListener handshakeCompletedListener) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void startHandshake() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setUseClientMode(boolean b) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getUseClientMode() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNeedClientAuth(boolean b) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getNeedClientAuth() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setWantClientAuth(boolean b) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getWantClientAuth() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setEnableSessionCreation(boolean b) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getEnableSessionCreation() {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/ct/CTVerifierTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/ct/CTVerifierTest.java
new file mode 100644
index 0000000..d0d4265
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/ct/CTVerifierTest.java
@@ -0,0 +1,180 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt.ct;
+
+import static com.android.org.conscrypt.TestUtils.openTestFile;
+import static com.android.org.conscrypt.TestUtils.readTestFile;
+import static org.junit.Assert.assertEquals;
+
+import java.security.PublicKey;
+import java.util.Arrays;
+import com.android.org.conscrypt.OpenSSLX509Certificate;
+import com.android.org.conscrypt.TestUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class CTVerifierTest {
+ private OpenSSLX509Certificate ca;
+ private OpenSSLX509Certificate cert;
+ private OpenSSLX509Certificate certEmbedded;
+ private CTVerifier ctVerifier;
+
+ @Before
+ public void setUp() throws Exception {
+ ca = OpenSSLX509Certificate.fromX509PemInputStream(openTestFile("ca-cert.pem"));
+ cert = OpenSSLX509Certificate.fromX509PemInputStream(openTestFile("cert.pem"));
+ certEmbedded = OpenSSLX509Certificate.fromX509PemInputStream(
+ openTestFile("cert-ct-embedded.pem"));
+
+ PublicKey key = TestUtils.readPublicKeyPemFile("ct-server-key-public.pem");
+
+ final CTLogInfo log = new CTLogInfo(key, "Test Log", "foo");
+ CTLogStore store = new CTLogStore() {
+ @Override
+ public CTLogInfo getKnownLog(byte[] logId) {
+ if (Arrays.equals(logId, log.getID())) {
+ return log;
+ } else {
+ return null;
+ }
+ }
+ };
+
+ ctVerifier = new CTVerifier(store);
+ }
+
+ @Test
+ public void test_verifySignedCertificateTimestamps_withOCSPResponse() throws Exception {
+ OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
+
+ byte[] ocspResponse = readTestFile("ocsp-response.der");
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, null, ocspResponse);
+ assertEquals(1, result.getValidSCTs().size());
+ assertEquals(0, result.getInvalidSCTs().size());
+ }
+
+ @Test
+ public void test_verifySignedCertificateTimestamps_withTLSExtension() throws Exception {
+ OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
+
+ byte[] tlsExtension = readTestFile("ct-signed-timestamp-list");
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, null);
+ assertEquals(1, result.getValidSCTs().size());
+ assertEquals(0, result.getInvalidSCTs().size());
+ }
+
+ @Test
+ public void test_verifySignedCertificateTimestamps_withEmbeddedExtension() throws Exception {
+ OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { certEmbedded, ca };
+
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, null, null);
+ assertEquals(1, result.getValidSCTs().size());
+ assertEquals(0, result.getInvalidSCTs().size());
+ }
+
+ @Test
+ public void test_verifySignedCertificateTimestamps_withoutTimestamp() throws Exception {
+ OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
+
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, null, null);
+ assertEquals(0, result.getValidSCTs().size());
+ assertEquals(0, result.getInvalidSCTs().size());
+ }
+
+ @Test
+ public void test_verifySignedCertificateTimestamps_withInvalidSignature() throws Exception {
+ OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
+
+ byte[] tlsExtension = readTestFile("ct-signed-timestamp-list-invalid");
+
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, null);
+ assertEquals(0, result.getValidSCTs().size());
+ assertEquals(1, result.getInvalidSCTs().size());
+ assertEquals(VerifiedSCT.Status.INVALID_SIGNATURE,
+ result.getInvalidSCTs().get(0).status);
+ }
+
+ @Test
+ public void test_verifySignedCertificateTimestamps_withUnknownLog() throws Exception {
+ OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
+
+ byte[] tlsExtension = readTestFile("ct-signed-timestamp-list-unknown");
+
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, null);
+ assertEquals(0, result.getValidSCTs().size());
+ assertEquals(1, result.getInvalidSCTs().size());
+ assertEquals(VerifiedSCT.Status.UNKNOWN_LOG,
+ result.getInvalidSCTs().get(0).status);
+ }
+
+ @Test
+ public void test_verifySignedCertificateTimestamps_withInvalidEncoding() throws Exception {
+ OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
+
+ // Just some garbage data which will fail to deserialize
+ byte[] tlsExtension = new byte[] { 1, 2, 3, 4 };
+
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, null);
+ assertEquals(0, result.getValidSCTs().size());
+ assertEquals(0, result.getInvalidSCTs().size());
+ }
+
+ @Test
+ public void test_verifySignedCertificateTimestamps_withInvalidOCSPResponse() throws Exception {
+ OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
+
+ // Just some garbage data which will fail to deserialize
+ byte[] ocspResponse = new byte[] { 1, 2, 3, 4 };
+
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, null, ocspResponse);
+ assertEquals(0, result.getValidSCTs().size());
+ assertEquals(0, result.getInvalidSCTs().size());
+ }
+
+ @Test
+ public void test_verifySignedCertificateTimestamps_withMultipleTimestamps() throws Exception {
+ OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
+
+ byte[] tlsExtension = readTestFile("ct-signed-timestamp-list-invalid");
+ byte[] ocspResponse = readTestFile("ocsp-response.der");
+
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, ocspResponse);
+ assertEquals(1, result.getValidSCTs().size());
+ assertEquals(1, result.getInvalidSCTs().size());
+ assertEquals(SignedCertificateTimestamp.Origin.OCSP_RESPONSE,
+ result.getValidSCTs().get(0).sct.getOrigin());
+ assertEquals(SignedCertificateTimestamp.Origin.TLS_EXTENSION,
+ result.getInvalidSCTs().get(0).sct.getOrigin());
+ }
+}
+
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/ct/SerializationTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/ct/SerializationTest.java
new file mode 100644
index 0000000..7dabf84
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/ct/SerializationTest.java
@@ -0,0 +1,229 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt.ct;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class SerializationTest {
+
+ @Test
+ public void test_decode_SignedCertificateTimestamp() throws Exception {
+ byte[] in = new byte[] {
+ 0x00, // version
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // log id
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0x01, 0x02, 0x03, 0x04, // timestamp
+ 0x05, 0x06, 0x07, 0x08,
+ 0x00, 0x00, // extensions length
+ 0x04, 0x03, // hash & signature algorithm
+ 0x00, 0x04, // signature length
+ 0x12, 0x34, 0x56, 0x78 // signature
+ };
+
+ SignedCertificateTimestamp sct
+ = SignedCertificateTimestamp.decode(in, SignedCertificateTimestamp.Origin.EMBEDDED);
+
+ assertEquals(SignedCertificateTimestamp.Version.V1, sct.getVersion());
+ assertEquals(0x0102030405060708L, sct.getTimestamp());
+ assertEquals(0, sct.getExtensions().length);
+ assertEquals(DigitallySigned.HashAlgorithm.SHA256,
+ sct.getSignature().getHashAlgorithm());
+ assertEquals(DigitallySigned.SignatureAlgorithm.ECDSA,
+ sct.getSignature().getSignatureAlgorithm());
+ assertTrue(Arrays.equals(new byte[] { 0x12, 0x34, 0x56, 0x78},
+ sct.getSignature().getSignature()));
+ assertEquals(SignedCertificateTimestamp.Origin.EMBEDDED, sct.getOrigin());
+ }
+
+ @Test
+ public void test_decode_invalid_SignedCertificateTimestamp() throws Exception {
+ byte[] sct = new byte[] {
+ 0x00, // version
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // log id
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0x01, 0x02, 0x03, 0x04, // timestamp
+ 0x05, 0x06, 0x07, 0x08,
+ 0x00, 0x00, // extensions length
+ 0x04, 0x03, // hash & signature algorithm
+ 0x00, 0x04, // signature length
+ 0x12, 0x34, 0x56, 0x78 // signature
+ };
+
+ // Make sure the original decodes fine
+ SignedCertificateTimestamp.decode(sct, SignedCertificateTimestamp.Origin.EMBEDDED);
+
+ // Perform various modification to it, and make sure it throws an exception on decoding
+ try {
+ byte[] in = sct.clone();
+ in[0] = 1; // Modify version field
+ SignedCertificateTimestamp.decode(in, SignedCertificateTimestamp.Origin.EMBEDDED);
+ fail("SerializationException not thrown on unsupported version");
+ } catch (SerializationException e) {}
+
+ try {
+ byte[] in = sct.clone();
+ in[41] = 1; // Modify extensions lemgth
+ SignedCertificateTimestamp.decode(in, SignedCertificateTimestamp.Origin.EMBEDDED);
+ fail("SerializationException not thrown on invalid extensions length");
+ } catch (SerializationException e) {}
+ }
+
+ @Test
+ public void test_decode_DigitallySigned() throws Exception {
+ byte[] in = new byte[] {
+ 0x04, 0x03, // hash & signature algorithm
+ 0x00, 0x04, // signature length
+ 0x12, 0x34, 0x56, 0x78 // signature
+ };
+
+ DigitallySigned dst = DigitallySigned.decode(in);
+ assertEquals(DigitallySigned.HashAlgorithm.SHA256, dst.getHashAlgorithm());
+ assertEquals(DigitallySigned.SignatureAlgorithm.ECDSA, dst.getSignatureAlgorithm());
+ assertEqualByteArrays(new byte[] { 0x12, 0x34, 0x56, 0x78}, dst.getSignature());
+ }
+
+ @Test
+ public void test_decode_invalid_DigitallySigned() throws Exception {
+ try {
+ DigitallySigned.decode(new byte[] {
+ 0x07, 0x03, // hash & signature algorithm
+ 0x00, 0x04, // signature length
+ 0x12, 0x34, 0x56, 0x78 // signature
+ });
+ fail("SerializationException not thrown on invalid hash type");
+ } catch (SerializationException e) {}
+
+ try {
+ DigitallySigned.decode(new byte[] {
+ 0x04, 0x04, // hash & signature algorithm
+ 0x00, 0x04, // signature length
+ 0x12, 0x34, 0x56, 0x78 // signature
+ });
+ fail("SerializationException not thrown on invalid signature type");
+ } catch (SerializationException e) {}
+
+ try {
+ DigitallySigned.decode(new byte[] {
+ 0x07, 0x03, // hash & signature algorithm
+ 0x64, 0x35, // signature length
+ 0x12, 0x34, 0x56, 0x78 // signature
+ });
+ fail("SerializationException not thrown on invalid signature length");
+ } catch (SerializationException e) {}
+
+ try {
+ DigitallySigned.decode(new byte[] {
+ 0x07, 0x03, // hash & signature algorithm
+ });
+ fail("SerializationException not thrown on missing signature");
+ } catch (SerializationException e) {}
+ }
+
+ @Test
+ public void test_encode_CertificateEntry_X509Certificate() throws Exception {
+ // Use a dummy certificate. It doesn't matter, CertificateEntry doesn't care about the contents.
+ CertificateEntry entry = CertificateEntry.createForX509Certificate(new byte[] { 0x12, 0x34, 0x56, 0x78 });
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ entry.encode(output);
+
+ assertEqualByteArrays(new byte[] {
+ 0x00, 0x00, // entry_type
+ 0x00, 0x00, 0x04, // x509_entry length
+ 0x12, 0x34, 0x56, 0x78 // x509_entry
+ }, output.toByteArray());
+ }
+
+ @Test
+ public void test_encode_CertificateEntry_PreCertificate() throws Exception {
+ // Use a dummy certificate and issuer key hash. It doesn't matter,
+ // CertificateEntry doesn't care about the contents.
+ CertificateEntry entry = CertificateEntry.createForPrecertificate(new byte[] { 0x12, 0x34, 0x56, 0x78 },
+ new byte[32]);
+
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ entry.encode(output);
+
+ assertEqualByteArrays(new byte[] {
+ 0x00, 0x01, // entry_type
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // issuer key hash
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0x00, 0x00, 0x04, // precert_entry length
+ 0x12, 0x34, 0x56, 0x78 // precert_entry
+ }, output.toByteArray());
+ }
+
+ @Test
+ public void test_readDEROctetString() throws Exception {
+ byte[] in, expected;
+
+ in = new byte[] {
+ 0x04, // TAG
+ 0x06, // length
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x05 // data
+ };
+ expected = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x05 };
+ assertEqualByteArrays(expected, Serialization.readDEROctetString(in));
+
+ in = new byte[203];
+ in[0] = 0x04; // TAG
+ in[1] = (byte)0x81; // long length flag
+ in[2] = (byte)200; // length
+ in[3] = 0x45; // data, the rest is just zeros
+
+ expected = new byte[200];
+ expected[0] = 0x45;
+ assertEqualByteArrays(expected, Serialization.readDEROctetString(in));
+
+ try {
+ in = new byte[] {
+ 0x12, // wrong tag
+ 0x06, // length
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x05 // data
+ };
+ Serialization.readDEROctetString(in);
+ fail("SerializationException not thrown on invalid tag.");
+ } catch (SerializationException e) {}
+
+ try {
+ in = new byte[] {
+ 0x04, // wrong tag
+ 0x06, // length
+ 0x01, 0x02 // data
+ };
+ Serialization.readDEROctetString(in);
+ fail("SerializationException not thrown on invalid length.");
+ } catch (SerializationException e) {}
+ }
+
+ public static void assertEqualByteArrays(byte[] expected, byte[] actual) {
+ assertEquals(Arrays.toString(expected), Arrays.toString(actual));
+ }
+}
+
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParameterGeneratorTestDH.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParameterGeneratorTestDH.java
new file mode 100644
index 0000000..8ec1867
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParameterGeneratorTestDH.java
@@ -0,0 +1,32 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class AlgorithmParameterGeneratorTestDH extends
+ AbstractAlgorithmParameterGeneratorTest {
+
+ public AlgorithmParameterGeneratorTestDH() {
+ super("DH", new AlgorithmParameterKeyAgreementHelper("DH"));
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParameterGeneratorTestDSA.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParameterGeneratorTestDSA.java
new file mode 100644
index 0000000..bd192f3
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParameterGeneratorTestDSA.java
@@ -0,0 +1,33 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import java.security.spec.DSAParameterSpec;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class AlgorithmParameterGeneratorTestDSA extends
+ AbstractAlgorithmParameterGeneratorTest {
+
+ public AlgorithmParameterGeneratorTestDSA() {
+ super("DSA", new AlgorithmParameterSignatureHelper<DSAParameterSpec>("DSA", DSAParameterSpec.class));
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersPSSTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersPSSTest.java
new file mode 100644
index 0000000..2c47180
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersPSSTest.java
@@ -0,0 +1,263 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PSSParameterSpec;
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TreeMap;
+import com.android.org.conscrypt.TestUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class AlgorithmParametersPSSTest {
+
+ // ASN.1 DER-encoded forms of DEFAULT_SPEC and WEIRD_SPEC were generated using
+ // Bouncy Castle 1.52 AlgorithmParameters of type "PSS" and checked for correctness
+ // using ASN.1 DER decoder.
+ private static final PSSParameterSpec DEFAULT_SPEC = PSSParameterSpec.DEFAULT;
+ private static final byte[] DEFAULT_SPEC_DER_ENCODED = TestUtils.decodeHex("3000");
+
+ private static final PSSParameterSpec WEIRD_SPEC =
+ new PSSParameterSpec("SHA-224", "MGF1", MGF1ParameterSpec.SHA256, 32, 1);
+ private static final byte[] WEIRD_SPEC_DER_ENCODED =
+ TestUtils.decodeHex(
+ "3034a00f300d06096086480165030402040500a11c301a06092a864886f70d010108300d060960"
+ + "86480165030402010500a203020120");
+
+ /** Truncated SEQUENCE (one more byte needed at the end) */
+ private static final byte[] BROKEN_SPEC1_DER_ENCODED =
+ TestUtils.decodeHex(
+ "303aa00f300d06096086480165030402030500a11c301a06092a864886f70d010108300d060960"
+ + "86480165030402020500a20302011ba303020103");
+
+ /** Payload of SEQUENCE extends beyond the SEQUENCE. */
+ private static final byte[] BROKEN_SPEC2_DER_ENCODED =
+ TestUtils.decodeHex(
+ "3037a00f300d06096086480165030402030500a11c301a06092a864886f70d010108300d060960"
+ + "86480165030402020500a20302011ba303020103");
+
+ @Test
+ public void testGetInstance() throws Exception {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("PSS");
+ assertNotNull(params);
+ }
+
+ @Test
+ public void testGetAlgorithm() throws Exception {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("PSS");
+ assertEquals("PSS", params.getAlgorithm());
+ }
+
+ @Test
+ public void testGetProvider() throws Exception {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("PSS");
+ params.init(DEFAULT_SPEC);
+ assertNotNull(params.getProvider());
+ }
+
+ @Test
+ public void testInitFailsWhenAlreadyInitialized() throws Exception {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("PSS");
+ params.init(DEFAULT_SPEC);
+ try {
+ params.init(DEFAULT_SPEC);
+ fail();
+ } catch (InvalidParameterSpecException expected) {}
+ try {
+ params.init(DEFAULT_SPEC_DER_ENCODED);
+ fail();
+ } catch (IOException expected) {}
+ try {
+ params.init(DEFAULT_SPEC_DER_ENCODED, "ASN.1");
+ fail();
+ } catch (IOException expected) {}
+ }
+
+ @Test
+ public void testInitWithPSSParameterSpec() throws Exception {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("PSS");
+ params.init(WEIRD_SPEC);
+ assertPSSParameterSpecEquals(WEIRD_SPEC, params.getParameterSpec(PSSParameterSpec.class));
+ }
+
+ @Test
+ public void testInitWithDerEncoded() throws Exception {
+ assertInitWithDerEncoded(WEIRD_SPEC_DER_ENCODED, WEIRD_SPEC);
+ assertInitWithDerEncoded(DEFAULT_SPEC_DER_ENCODED, DEFAULT_SPEC);
+ }
+
+ private void assertInitWithDerEncoded(
+ byte[] encoded, PSSParameterSpec expected) throws Exception {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("PSS");
+ params.init(encoded);
+ assertPSSParameterSpecEquals(expected, params.getParameterSpec(PSSParameterSpec.class));
+
+ params = AlgorithmParameters.getInstance("PSS");
+ params.init(encoded, "ASN.1");
+ assertPSSParameterSpecEquals(expected, params.getParameterSpec(PSSParameterSpec.class));
+ }
+
+ @Test
+ public void testGetEncodedThrowsWhenNotInitialized() throws Exception {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("PSS");
+ try {
+ params.getEncoded();
+ fail();
+ } catch (IOException expected) {}
+ try {
+ params.getEncoded("ASN.1");
+ fail();
+ } catch (IOException expected) {}
+ }
+
+ @Test
+ public void testGetEncoded() throws Exception {
+ assertGetEncoded(WEIRD_SPEC, WEIRD_SPEC_DER_ENCODED);
+ assertGetEncoded(DEFAULT_SPEC, DEFAULT_SPEC_DER_ENCODED);
+ }
+
+ private void assertGetEncoded(PSSParameterSpec spec, byte[] expectedEncoded) throws Exception {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("PSS");
+ params.init(spec);
+ byte[] encoded = params.getEncoded("ASN.1");
+ assertTrue(Arrays.equals(expectedEncoded, encoded));
+ // Assert that getEncoded() returns ASN.1 form.
+ assertTrue(Arrays.equals(encoded, params.getEncoded()));
+ }
+
+ @Test
+ public void testGetEncodedWithBrokenInput() throws Exception {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("PSS");
+ try {
+ params.init(BROKEN_SPEC1_DER_ENCODED);
+ fail();
+ } catch (IOException expected) {
+ } catch (IllegalArgumentException expected) {
+ // Bouncy Castle incorrectly throws an IllegalArgumentException instead of IOException.
+ if (!"BC".equals(params.getProvider().getName())) {
+ throw new RuntimeException(
+ "Unexpected exception. Provider: " + params.getProvider(),
+ expected);
+ }
+ }
+
+ params = AlgorithmParameters.getInstance("PSS");
+ try {
+ params.init(BROKEN_SPEC2_DER_ENCODED);
+ fail();
+ } catch (IOException expected) {
+ } catch (IllegalArgumentException expected) {
+ // Bouncy Castle incorrectly throws an IllegalArgumentException instead of IOException.
+ if (!"BC".equals(params.getProvider().getName())) {
+ throw new RuntimeException(
+ "Unexpected exception. Provider: " + params.getProvider(),
+ expected);
+ }
+ }
+ }
+
+ private static void assertPSSParameterSpecEquals(
+ PSSParameterSpec spec1, PSSParameterSpec spec2) {
+ assertEquals(
+ getDigestAlgorithmCanonicalName(spec1.getDigestAlgorithm()),
+ getDigestAlgorithmCanonicalName(spec2.getDigestAlgorithm()));
+ assertEquals(
+ getMGFAlgorithmCanonicalName(spec1.getMGFAlgorithm()),
+ getMGFAlgorithmCanonicalName(spec2.getMGFAlgorithm()));
+
+ AlgorithmParameterSpec spec1MgfParams = spec1.getMGFParameters();
+ assertNotNull(spec1MgfParams);
+ if (!(spec1MgfParams instanceof MGF1ParameterSpec)) {
+ fail("Unexpected type of MGF parameters: " + spec1MgfParams.getClass().getName());
+ }
+ MGF1ParameterSpec spec1Mgf1Params = (MGF1ParameterSpec) spec1MgfParams;
+ AlgorithmParameterSpec spec2MgfParams = spec2.getMGFParameters();
+ assertNotNull(spec2MgfParams);
+ if (!(spec2MgfParams instanceof MGF1ParameterSpec)) {
+ fail("Unexpected type of MGF parameters: " + spec2MgfParams.getClass().getName());
+ }
+ MGF1ParameterSpec spec2Mgf1Params = (MGF1ParameterSpec) spec2MgfParams;
+
+ assertEquals(
+ getDigestAlgorithmCanonicalName(spec1Mgf1Params.getDigestAlgorithm()),
+ getDigestAlgorithmCanonicalName(spec2Mgf1Params.getDigestAlgorithm()));
+ assertEquals(spec1.getSaltLength(), spec2.getSaltLength());
+ assertEquals(spec1.getTrailerField(), spec2.getTrailerField());
+ }
+
+ // All the craziness with supporting OIDs is needed because Bouncy Castle, when parsing from
+ // ASN.1 form, returns PSSParameterSpec instances which use OIDs instead of JCA standard names
+ // for digest algorithms and MGF algorithms.
+ private static final Map<String, String> DIGEST_OID_TO_NAME = new TreeMap<String, String>(
+ String.CASE_INSENSITIVE_ORDER);
+ private static final Map<String, String> DIGEST_NAME_TO_OID = new TreeMap<String, String>(
+ String.CASE_INSENSITIVE_ORDER);
+
+ private static void addDigestOid(String algorithm, String oid) {
+ DIGEST_OID_TO_NAME.put(oid, algorithm);
+ DIGEST_NAME_TO_OID.put(algorithm, oid);
+ }
+
+ static {
+ addDigestOid("SHA-1", "1.3.14.3.2.26");
+ addDigestOid("SHA-224", "2.16.840.1.101.3.4.2.4");
+ addDigestOid("SHA-256", "2.16.840.1.101.3.4.2.1");
+ addDigestOid("SHA-384", "2.16.840.1.101.3.4.2.2");
+ addDigestOid("SHA-512", "2.16.840.1.101.3.4.2.3");
+ }
+
+ private static String getDigestAlgorithmCanonicalName(String algorithm) {
+ if (DIGEST_NAME_TO_OID.containsKey(algorithm)) {
+ return algorithm.toUpperCase(Locale.US);
+ }
+
+ String nameByOid = DIGEST_OID_TO_NAME.get(algorithm);
+ if (nameByOid != null) {
+ return nameByOid;
+ }
+
+ return algorithm;
+ }
+
+ private static String getMGFAlgorithmCanonicalName(String name) {
+ if ("MGF1".equalsIgnoreCase(name)) {
+ return name.toUpperCase(Locale.US);
+ } else if ("1.2.840.113549.1.1.8".equals(name)) {
+ return "MGF1";
+ } else {
+ return name;
+ }
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestAES.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestAES.java
new file mode 100644
index 0000000..020b436
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestAES.java
@@ -0,0 +1,82 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import com.android.org.conscrypt.TestUtils;
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import javax.crypto.spec.IvParameterSpec;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class AlgorithmParametersTestAES extends AbstractAlgorithmParametersTest {
+ // BEGIN Android-added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work. See http://b/141919026 for more information.
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
+ private static final byte[] parameterData = new byte[] {
+ (byte) 0x04, (byte) 0x08, (byte) 0x68, (byte) 0xC8,
+ (byte) 0xFF, (byte) 0x64, (byte) 0x72, (byte) 0xF5,
+ (byte) 0x04, (byte) 0x08, (byte) 0x68, (byte) 0xC8,
+ (byte) 0xFF, (byte) 0x64, (byte) 0x72, (byte) 0xF5 };
+
+ // See README.ASN1 for how to understand and reproduce this data
+
+ // asn1=FORMAT:HEX,OCTETSTRING:040868C8FF6472F5040868C8
+ private static final String ENCODED_DATA = "BBAECGjI/2Ry9QQIaMj/ZHL1";
+
+ public AlgorithmParametersTestAES() {
+ super("AES", new AlgorithmParameterSymmetricHelper("AES", "CBC/PKCS5PADDING", 128), new IvParameterSpec(parameterData));
+ }
+
+ @Test
+ public void testEncoding() throws Exception {
+ ServiceTester.test("AlgorithmParameters")
+ .withAlgorithm("AES")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("AES", p);
+
+ params.init(new IvParameterSpec(parameterData));
+ assertEquals(ENCODED_DATA, TestUtils.encodeBase64(params.getEncoded()));
+
+ params = AlgorithmParameters.getInstance("AES", p);
+ params.init(TestUtils.decodeBase64(ENCODED_DATA));
+ assertArrayEquals(parameterData,
+ params.getParameterSpec(IvParameterSpec.class).getIV());
+ }
+ });
+ }
+
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDES.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDES.java
new file mode 100644
index 0000000..568059d
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDES.java
@@ -0,0 +1,70 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import javax.crypto.spec.IvParameterSpec;
+import com.android.org.conscrypt.TestUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class AlgorithmParametersTestDES extends AbstractAlgorithmParametersTest {
+
+ private static final byte[] parameterData = new byte[] {
+ (byte) 0x04, (byte) 0x08, (byte) 0x68, (byte) 0xC8,
+ (byte) 0xFF, (byte) 0x64, (byte) 0x72, (byte) 0xF5 };
+
+ // See README.ASN1 for how to understand and reproduce this data
+
+ // asn1=FORMAT:HEX,OCTETSTRING:040868C8FF6472F5
+ private static final String ENCODED_DATA = "BAgECGjI/2Ry9Q==";
+
+ public AlgorithmParametersTestDES() {
+ super("DES", new AlgorithmParameterSymmetricHelper("DES", "CBC/PKCS5PADDING", 56), new IvParameterSpec(parameterData));
+ }
+
+ @Test
+ public void testEncoding() throws Exception {
+ ServiceTester.test("AlgorithmParameters")
+ .withAlgorithm("DES")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("DES", p);
+
+ params.init(new IvParameterSpec(parameterData));
+ assertEquals(ENCODED_DATA, TestUtils.encodeBase64(params.getEncoded()));
+
+ params = AlgorithmParameters.getInstance("DES", p);
+ params.init(TestUtils.decodeBase64(ENCODED_DATA));
+ assertArrayEquals(parameterData,
+ params.getParameterSpec(IvParameterSpec.class).getIV());
+ }
+ });
+ }
+
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDESede.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDESede.java
new file mode 100644
index 0000000..f42c69c
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDESede.java
@@ -0,0 +1,81 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import com.android.org.conscrypt.TestUtils;
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import javax.crypto.spec.IvParameterSpec;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class AlgorithmParametersTestDESede extends AbstractAlgorithmParametersTest {
+
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
+ private static final byte[] parameterData = new byte[] {
+ (byte) 0x04, (byte) 0x08, (byte) 0x68, (byte) 0xC8,
+ (byte) 0xFF, (byte) 0x64, (byte) 0x72, (byte) 0xF5 };
+
+ // See README.ASN1 for how to understand and reproduce this data
+
+ // asn1=FORMAT:HEX,OCTETSTRING:040868C8FF6472F5
+ private static final String ENCODED_DATA = "BAgECGjI/2Ry9Q==";
+
+ public AlgorithmParametersTestDESede() {
+ super("DESede", new AlgorithmParameterSymmetricHelper("DESede", "CBC/PKCS5PADDING", 112), new IvParameterSpec(parameterData));
+ }
+
+ @Test
+ public void testEncoding() throws Exception {
+ ServiceTester.test("AlgorithmParameters")
+ .withAlgorithm("DESEDE")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("DESede", p);
+
+ params.init(new IvParameterSpec(parameterData));
+ assertEquals(ENCODED_DATA, TestUtils.encodeBase64(params.getEncoded()));
+
+ params = AlgorithmParameters.getInstance("DESede", p);
+ params.init(TestUtils.decodeBase64(ENCODED_DATA));
+ assertArrayEquals(parameterData,
+ params.getParameterSpec(IvParameterSpec.class).getIV());
+ }
+ });
+ }
+
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDH.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDH.java
new file mode 100644
index 0000000..b6429d0
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDH.java
@@ -0,0 +1,67 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import java.math.BigInteger;
+import javax.crypto.spec.DHParameterSpec;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class AlgorithmParametersTestDH extends AbstractAlgorithmParametersTest {
+
+ private static final byte[] P = new byte[] {
+ (byte) 0x00, (byte) 0xB8, (byte) 0xA4, (byte) 0x06, (byte) 0x10,
+ (byte) 0xA2, (byte) 0x8B, (byte) 0xD2, (byte) 0xC0, (byte) 0xB6,
+ (byte) 0x87, (byte) 0xFF, (byte) 0x15, (byte) 0xBA, (byte) 0x18,
+ (byte) 0xE9, (byte) 0x7D, (byte) 0x77, (byte) 0x9F, (byte) 0xAF,
+ (byte) 0x6F, (byte) 0x0B, (byte) 0xA4, (byte) 0xB6, (byte) 0x2B,
+ (byte) 0x35, (byte) 0xE2, (byte) 0x01, (byte) 0x66, (byte) 0x41,
+ (byte) 0x05, (byte) 0xE7, (byte) 0x6A, (byte) 0x62, (byte) 0x19,
+ (byte) 0x94, (byte) 0x18, (byte) 0x46, (byte) 0xBA, (byte) 0x60,
+ (byte) 0x2E, (byte) 0x5A, (byte) 0x48, (byte) 0x6C, (byte) 0x4B,
+ (byte) 0xBF, (byte) 0x8C, (byte) 0xBF, (byte) 0xB9, (byte) 0xEE,
+ (byte) 0xCC, (byte) 0x35, (byte) 0x89, (byte) 0x18, (byte) 0x02,
+ (byte) 0x18, (byte) 0xFE, (byte) 0xF4, (byte) 0x02, (byte) 0x3B,
+ (byte) 0x5E, (byte) 0x8A, (byte) 0x42, (byte) 0xB3, (byte) 0x39};
+
+ private static final byte[] Q = new byte[] {
+ (byte) 0x00, (byte) 0x87, (byte) 0xE2, (byte) 0xD1, (byte) 0x8A,
+ (byte) 0x23, (byte) 0x90, (byte) 0x3A, (byte) 0x0F, (byte) 0xC8,
+ (byte) 0x38, (byte) 0xA8, (byte) 0x65, (byte) 0x35, (byte) 0x89,
+ (byte) 0x4F, (byte) 0x4B, (byte) 0xB3, (byte) 0xBF, (byte) 0x18,
+ (byte) 0x3C, (byte) 0x3B, (byte) 0xD8, (byte) 0x72, (byte) 0xC3,
+ (byte) 0xCF, (byte) 0xC9, (byte) 0xA7, (byte) 0x39, (byte) 0x7E,
+ (byte) 0x9C, (byte) 0x69, (byte) 0xDA, (byte) 0xDE, (byte) 0x8E,
+ (byte) 0x96, (byte) 0x9D, (byte) 0x44, (byte) 0xC1, (byte) 0x1E,
+ (byte) 0x58, (byte) 0xC7, (byte) 0xFC, (byte) 0x40, (byte) 0x1B,
+ (byte) 0xE8, (byte) 0x23, (byte) 0xF3, (byte) 0x6B, (byte) 0x95,
+ (byte) 0x68, (byte) 0x29, (byte) 0x93, (byte) 0x35, (byte) 0x05,
+ (byte) 0xC5, (byte) 0xCB, (byte) 0xB8, (byte) 0x57, (byte) 0x8F,
+ (byte) 0xB9, (byte) 0xC3, (byte) 0x36, (byte) 0x09, (byte) 0x51};
+
+ private static final int l = 511;
+
+ public AlgorithmParametersTestDH() {
+ super("DH", new AlgorithmParameterKeyAgreementHelper("DH"),
+ new DHParameterSpec(new BigInteger(P), new BigInteger(Q), l));
+ }
+
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDSA.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDSA.java
new file mode 100644
index 0000000..c226ce1
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDSA.java
@@ -0,0 +1,151 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertEquals;
+
+import java.math.BigInteger;
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import java.security.spec.DSAParameterSpec;
+import com.android.org.conscrypt.TestUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class AlgorithmParametersTestDSA extends AbstractAlgorithmParametersTest {
+
+ /*
+ * Parameters generated with OpenSSL:
+ * openssl dsaparam -genkey 1024 -C
+ */
+ private static final byte[] P = new byte[] {
+ (byte) 0xE6, (byte) 0x41, (byte) 0x58, (byte) 0x77, (byte) 0x76,
+ (byte) 0x5A, (byte) 0x4A, (byte) 0x53, (byte) 0xF1, (byte) 0xD6,
+ (byte) 0xC8, (byte) 0x7D, (byte) 0x67, (byte) 0x1F, (byte) 0x2F,
+ (byte) 0xFA, (byte) 0xDE, (byte) 0xB7, (byte) 0xAA, (byte) 0xCD,
+ (byte) 0xD7, (byte) 0x5D, (byte) 0xD0, (byte) 0xE9, (byte) 0xB1,
+ (byte) 0xDA, (byte) 0xFE, (byte) 0x42, (byte) 0xBE, (byte) 0xCC,
+ (byte) 0x42, (byte) 0x52, (byte) 0x2E, (byte) 0x01, (byte) 0xD2,
+ (byte) 0x16, (byte) 0xB1, (byte) 0x5B, (byte) 0xC4, (byte) 0x42,
+ (byte) 0xF9, (byte) 0x55, (byte) 0x0F, (byte) 0xE2, (byte) 0xD5,
+ (byte) 0x01, (byte) 0xD2, (byte) 0x7E, (byte) 0x22, (byte) 0xF6,
+ (byte) 0xC1, (byte) 0xFE, (byte) 0x5C, (byte) 0x6A, (byte) 0xCF,
+ (byte) 0x82, (byte) 0x1B, (byte) 0x5C, (byte) 0x46, (byte) 0x66,
+ (byte) 0x8B, (byte) 0xAF, (byte) 0xDF, (byte) 0x44, (byte) 0xE2,
+ (byte) 0x0E, (byte) 0xA3, (byte) 0x58, (byte) 0xF7, (byte) 0xA3,
+ (byte) 0x24, (byte) 0xE3, (byte) 0x84, (byte) 0xA6, (byte) 0x16,
+ (byte) 0xE0, (byte) 0xCA, (byte) 0x72, (byte) 0x55, (byte) 0x07,
+ (byte) 0xA0, (byte) 0x99, (byte) 0x7B, (byte) 0xF8, (byte) 0xB1,
+ (byte) 0x5A, (byte) 0x84, (byte) 0x36, (byte) 0x5A, (byte) 0xC8,
+ (byte) 0x6A, (byte) 0xFE, (byte) 0xA6, (byte) 0xB4, (byte) 0x1B,
+ (byte) 0x3A, (byte) 0x0A, (byte) 0x00, (byte) 0x6B, (byte) 0x72,
+ (byte) 0xDC, (byte) 0x0C, (byte) 0xD1, (byte) 0x09, (byte) 0x25,
+ (byte) 0x11, (byte) 0x68, (byte) 0x6B, (byte) 0x75, (byte) 0xDE,
+ (byte) 0x2C, (byte) 0x1A, (byte) 0xC2, (byte) 0x3A, (byte) 0xCB,
+ (byte) 0xA0, (byte) 0x17, (byte) 0xCA, (byte) 0x2D, (byte) 0xEE,
+ (byte) 0xA2, (byte) 0x5A, (byte) 0x9D, (byte) 0x1F, (byte) 0x33,
+ (byte) 0x1B, (byte) 0x07, (byte) 0x6D,
+ };
+ private static final byte[] Q = new byte[] {
+ (byte) 0x9B, (byte) 0x39, (byte) 0xD0, (byte) 0x02, (byte) 0x0F,
+ (byte) 0xE9, (byte) 0x96, (byte) 0x16, (byte) 0xC5, (byte) 0x25,
+ (byte) 0xF7, (byte) 0x94, (byte) 0xA9, (byte) 0x2C, (byte) 0xD0,
+ (byte) 0x25, (byte) 0x5B, (byte) 0x6E, (byte) 0xE0, (byte) 0x8F,
+ };
+ private static final byte[] G = new byte[] {
+ (byte) 0x5E, (byte) 0x9C, (byte) 0x95, (byte) 0x5F, (byte) 0x7E,
+ (byte) 0x91, (byte) 0x47, (byte) 0x4D, (byte) 0x68, (byte) 0xA4,
+ (byte) 0x1C, (byte) 0x44, (byte) 0x3B, (byte) 0xEC, (byte) 0x0A,
+ (byte) 0x7E, (byte) 0x59, (byte) 0x54, (byte) 0xF7, (byte) 0xEF,
+ (byte) 0x42, (byte) 0xFB, (byte) 0x63, (byte) 0x95, (byte) 0x08,
+ (byte) 0x2F, (byte) 0x4A, (byte) 0xD3, (byte) 0xBC, (byte) 0x79,
+ (byte) 0x9D, (byte) 0xBA, (byte) 0xD8, (byte) 0x8A, (byte) 0x83,
+ (byte) 0x84, (byte) 0xAE, (byte) 0x5B, (byte) 0x26, (byte) 0x80,
+ (byte) 0xB3, (byte) 0xFB, (byte) 0x9C, (byte) 0xA3, (byte) 0xCF,
+ (byte) 0xF4, (byte) 0x0A, (byte) 0xD5, (byte) 0xB6, (byte) 0x65,
+ (byte) 0x65, (byte) 0x1A, (byte) 0x4F, (byte) 0xC0, (byte) 0x86,
+ (byte) 0x3B, (byte) 0xE6, (byte) 0xFB, (byte) 0x4E, (byte) 0x9E,
+ (byte) 0x49, (byte) 0x0A, (byte) 0x8C, (byte) 0x77, (byte) 0x2D,
+ (byte) 0x93, (byte) 0x0B, (byte) 0xCA, (byte) 0x81, (byte) 0x07,
+ (byte) 0x09, (byte) 0xC4, (byte) 0x71, (byte) 0xFD, (byte) 0xC8,
+ (byte) 0xC7, (byte) 0xD1, (byte) 0xA3, (byte) 0xD0, (byte) 0xBB,
+ (byte) 0x7D, (byte) 0x92, (byte) 0x74, (byte) 0x8B, (byte) 0x3B,
+ (byte) 0x2A, (byte) 0x45, (byte) 0x1F, (byte) 0x5D, (byte) 0x85,
+ (byte) 0x90, (byte) 0xE3, (byte) 0xFB, (byte) 0x0E, (byte) 0x16,
+ (byte) 0xBA, (byte) 0x8A, (byte) 0xDE, (byte) 0x10, (byte) 0x0F,
+ (byte) 0xE0, (byte) 0x0F, (byte) 0x37, (byte) 0xA7, (byte) 0xC1,
+ (byte) 0xDC, (byte) 0xBC, (byte) 0x00, (byte) 0xB8, (byte) 0x24,
+ (byte) 0x0F, (byte) 0xF6, (byte) 0x5F, (byte) 0xB1, (byte) 0xA8,
+ (byte) 0x9A, (byte) 0xDB, (byte) 0x9F, (byte) 0x36, (byte) 0x54,
+ (byte) 0x45, (byte) 0xBD, (byte) 0xC0, (byte) 0xE8, (byte) 0x27,
+ (byte) 0x82, (byte) 0xC9, (byte) 0x75,
+ };
+
+ // The ASN.1 module for DSA is defined in RFC 3279 section 3. See README.ASN1 for how
+ // to understand and reproduce this data.
+
+ // asn1=SEQUENCE:dsa
+ // [dsa]
+ // p=INT:0xE6415877765A4A53F1D6C87D671F2FFADEB7AACDD75DD0E9B1DAFE42BECC42522E01D216B15BC442F9550FE2D501D27E22F6C1FE5C6ACF821B5C46668BAFDF44E20EA358F7A324E384A616E0CA725507A0997BF8B15A84365AC86AFEA6B41B3A0A006B72DC0CD1092511686B75DE2C1AC23ACBA017CA2DEEA25A9D1F331B076D
+ // q=INT:0x9B39D0020FE99616C525F794A92CD0255B6EE08F
+ // g=INT:0x5E9C955F7E91474D68A41C443BEC0A7E5954F7EF42FB6395082F4AD3BC799DBAD88A8384AE5B2680B3FB9CA3CFF40AD5B665651A4FC0863BE6FB4E9E490A8C772D930BCA810709C471FDC8C7D1A3D0BB7D92748B3B2A451F5D8590E3FB0E16BA8ADE100FE00F37A7C1DCBC00B8240FF65FB1A89ADB9F365445BDC0E82782C975
+ private static final String ENCODED_DATA = "MIIBHgKBgQDmQVh3dlpKU/HWyH1nHy/63reqzddd0Omx2v5"
+ + "CvsxCUi4B0haxW8RC+VUP4tUB0n4i9sH+XGrPghtcRmaLr99E4g6jWPejJOOEphbgynJVB6CZe/ixWoQ"
+ + "2Wshq/qa0GzoKAGty3AzRCSURaGt13iwawjrLoBfKLe6iWp0fMxsHbQIVAJs50AIP6ZYWxSX3lKks0CV"
+ + "bbuCPAoGAXpyVX36RR01opBxEO+wKfllU9+9C+2OVCC9K07x5nbrYioOErlsmgLP7nKPP9ArVtmVlGk/"
+ + "Ahjvm+06eSQqMdy2TC8qBBwnEcf3Ix9Gj0Lt9knSLOypFH12FkOP7Dha6it4QD+APN6fB3LwAuCQP9l+"
+ + "xqJrbnzZURb3A6CeCyXU=";
+
+ public AlgorithmParametersTestDSA() {
+ super("DSA", new AlgorithmParameterSignatureHelper<DSAParameterSpec>(
+ "DSA", DSAParameterSpec.class), new DSAParameterSpec(
+ new BigInteger(1, P), new BigInteger(1, Q), new BigInteger(1, G)));
+ }
+
+ @Test
+ public void testEncoding() throws Exception {
+ ServiceTester.test("AlgorithmParameters")
+ .withAlgorithm("DSA")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("DSA", p);
+
+ DSAParameterSpec spec = new DSAParameterSpec(
+ new BigInteger(1, P), new BigInteger(1, Q), new BigInteger(1, G));
+
+ params.init(spec);
+ assertEquals(ENCODED_DATA, TestUtils.encodeBase64(params.getEncoded()));
+
+ params = AlgorithmParameters.getInstance("DSA", p);
+ params.init(TestUtils.decodeBase64(ENCODED_DATA));
+ DSAParameterSpec derivedSpec = params.getParameterSpec(DSAParameterSpec.class);
+
+ assertEquals(new BigInteger(1, P), derivedSpec.getP());
+ assertEquals(new BigInteger(1, Q), derivedSpec.getQ());
+ assertEquals(new BigInteger(1, G), derivedSpec.getG());
+ }
+ });
+ }
+
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestEC.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestEC.java
new file mode 100644
index 0000000..9747e9c
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestEC.java
@@ -0,0 +1,116 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2019 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.org.conscrypt.TestUtils;
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.util.Arrays;
+import java.util.List;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class AlgorithmParametersTestEC extends AbstractAlgorithmParametersTest {
+ // BEGIN Android-added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work. See http://b/141919026 for more information.
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
+ private static final String CURVE_NAME = "secp384r1";
+ private static final String CURVE_OID = "1.3.132.0.34";
+
+ // See README.ASN1 for how to understand and reproduce this data
+
+ // asn1=OID:1.3.132.0.34
+ private static final String ENCODED_DATA = "BgUrgQQAIg==";
+
+ public AlgorithmParametersTestEC() {
+ super("EC", new AlgorithmParameterSignatureHelper<>(
+ "SHA256withECDSA", "EC", ECGenParameterSpec.class),
+ new ECGenParameterSpec(CURVE_NAME));
+ }
+
+ @Test
+ public void testEncoding() throws Exception {
+ ServiceTester.test("AlgorithmParameters")
+ .withAlgorithm("EC")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("EC", p);
+ params.init(new ECGenParameterSpec(CURVE_NAME));
+ assertEquals(ENCODED_DATA, TestUtils.encodeBase64(params.getEncoded()));
+
+ params = AlgorithmParameters.getInstance("EC", p);
+ params.init(new ECGenParameterSpec(CURVE_OID));
+ assertEquals(ENCODED_DATA, TestUtils.encodeBase64(params.getEncoded()));
+
+ params = AlgorithmParameters.getInstance("EC", p);
+ params.init(TestUtils.decodeBase64(ENCODED_DATA));
+ String name = params.getParameterSpec(ECGenParameterSpec.class).getName();
+ assertTrue(CURVE_NAME.equals(name) || CURVE_OID.equals(name));
+ }
+ });
+ }
+
+ // This should be an exhaustive list of all curves that are supported in Conscrypt
+ private static final List<String> SUPPORTED_CURVES =
+ Arrays.asList("secp224r1", "secp256r1", "secp384r1", "secp521r1", "prime256v1",
+ "1.3.132.0.33", "1.3.132.0.34", "1.3.132.0.35", "1.2.840.10045.3.1.7");
+
+ // A selection of curves that aren't supported
+ private static final List<String> UNSUPPORTED_CURVES =
+ Arrays.asList("secp192r1", "secp256k1", "prime192v1", "curve25519", "x25519",
+ "1.2.840.10045.3.1.1", "1.3.132.0.10");
+
+ @Test
+ public void testCurveSupport() throws Exception {
+ AlgorithmParameterSignatureHelper<ECGenParameterSpec> helper =
+ new AlgorithmParameterSignatureHelper<>(
+ "SHA256withECDSA", "EC", ECGenParameterSpec.class);
+ for (String curve : SUPPORTED_CURVES) {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("EC");
+ params.init(new ECGenParameterSpec(curve));
+ helper.test(params);
+ }
+ for (String curve : UNSUPPORTED_CURVES) {
+ try {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("EC");
+ params.init(new ECGenParameterSpec(curve));
+ } catch (InvalidParameterSpecException expected) {
+ }
+ }
+ }
+
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestGCM.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestGCM.java
new file mode 100644
index 0000000..1705541
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestGCM.java
@@ -0,0 +1,110 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.org.conscrypt.TestUtils;
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import javax.crypto.spec.GCMParameterSpec;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class AlgorithmParametersTestGCM extends AbstractAlgorithmParametersTest {
+
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
+ private static final byte[] IV = new byte[] {
+ (byte) 0x04, (byte) 0x08, (byte) 0x68, (byte) 0xC8,
+ (byte) 0xFF, (byte) 0x64, (byte) 0x72, (byte) 0xF5,
+ (byte) 0x04, (byte) 0x08, (byte) 0x68, (byte) 0xC8 };
+
+ private static final int TLEN = 96;
+ private static final int SUN_ALT_TLEN = 128;
+
+ // The ASN.1 encoding for GCM params (specified in RFC 5084 section 3.2) specifies
+ // a default value of 12 for TLEN, so both values with and without TLEN should work.
+ // See README.ASN1 for how to understand and reproduce this data.
+
+ // asn1=SEQUENCE:gcm
+ // [gcm]
+ // iv=FORMAT:HEX,OCTETSTRING:040868C8FF6472F5040868C8
+ private static final String ENCODED_DATA_NO_TLEN = "MA4EDAQIaMj/ZHL1BAhoyA==";
+
+ // asn1=SEQUENCE:gcm
+ // [gcm]
+ // iv=FORMAT:HEX,OCTETSTRING:040868C8FF6472F5040868C8
+ // tlen=INT:12
+ private static final String ENCODED_DATA_TLEN = "MBEEDAQIaMj/ZHL1BAhoyAIBDA==";
+
+ public AlgorithmParametersTestGCM() {
+ super("GCM", new AlgorithmParameterSymmetricHelper("AES", "GCM/NOPADDING", 128), new GCMParameterSpec(TLEN, IV));
+ }
+
+ @Test
+ public void testEncoding() throws Exception {
+ ServiceTester.test("AlgorithmParameters")
+ .withAlgorithm("GCM")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("GCM", p);
+
+ params.init(new GCMParameterSpec(TLEN, IV));
+ String encoded = TestUtils.encodeBase64(params.getEncoded());
+ assertTrue("Encoded: " + encoded,
+ encoded.equals(ENCODED_DATA_TLEN) || encoded.equals(ENCODED_DATA_NO_TLEN));
+
+ params = AlgorithmParameters.getInstance("GCM", p);
+ params.init(TestUtils.decodeBase64(ENCODED_DATA_NO_TLEN));
+ GCMParameterSpec spec = params.getParameterSpec(GCMParameterSpec.class);
+ if (!p.getName().equals("SunJCE")) {
+ assertEquals(TLEN, spec.getTLen());
+ } else {
+ // In some cases the SunJCE provider uses 128 as the default instead of 96
+ assertTrue(spec.getTLen() == TLEN || spec.getTLen() == SUN_ALT_TLEN);
+ }
+ assertArrayEquals(IV, spec.getIV());
+
+ params = AlgorithmParameters.getInstance("GCM", p);
+ params.init(TestUtils.decodeBase64(ENCODED_DATA_TLEN));
+ spec = params.getParameterSpec(GCMParameterSpec.class);
+ assertEquals(TLEN, spec.getTLen());
+ assertArrayEquals(IV, spec.getIV());
+ }
+ });
+ }
+
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestOAEP.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestOAEP.java
new file mode 100644
index 0000000..594a456
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestOAEP.java
@@ -0,0 +1,264 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import com.android.org.conscrypt.TestUtils;
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import java.security.spec.MGF1ParameterSpec;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+import javax.crypto.spec.PSource.PSpecified;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class AlgorithmParametersTestOAEP extends AbstractAlgorithmParametersTest {
+
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
+ // The ASN.1 encoding for OAEP params (specified in RFC 4055 section 4.1) specifies
+ // default values for all parameters, so we need to consider encodings with those
+ // values both explicitly specified and unspecified. When encoding values, it is required
+ // that default values are left empty, but implementations must be able to parse explicitly-
+ // specified defaults as well.
+ //
+ // See README.ASN1 for how to understand and reproduce this data.
+
+ // asn1=SEQUENCE
+ private static final String ENCODED_DATA_ALL_DEFAULTS = "MAA=";
+
+ // asn1=SEQUENCE:oaep
+ // [oaep]
+ // hashFunc=EXP:0,SEQUENCE:sha1
+ // maskGenFunc=EXP:1,SEQUENCE:mgf1
+ // pSourceFunc=EXP:2,SEQUENCE:pSpecified
+ // [mgf1]
+ // oid=OID:1.2.840.113549.1.1.8
+ // params=SEQUENCE:sha1
+ // [pSpecified]
+ // oid=OID:1.2.840.113549.1.1.9
+ // val=OCTETSTRING:
+ // [sha1]
+ // oid=OID:sha1
+ // params=NULL
+ private static final String ENCODED_DATA_EXPLICIT_DEFAULTS =
+ "MDigCzAJBgUrDgMCGgUAoRgwFgYJKoZIhvcNAQEIMAkGBSsOAwIaBQCiDzANBgkqhkiG9w0BAQkEAA==";
+
+ // Base64 version of ASN.1-encoded data with none of the default values. Specifically:
+ // SHA-256 hashFunc, MGF1-SHA-384 maskGenFunc, and [1, 2, 3, 4] pSourceFunc
+
+ // asn1=SEQUENCE:oaep
+ // [oaep]
+ // hashFunc=EXP:0,SEQUENCE:sha256
+ // maskGenFunc=EXP:1,SEQUENCE:mgf1
+ // pSourceFunc=EXP:2,SEQUENCE:pSpecified
+ // [sha256]
+ // oid=OID:sha256
+ // params=NULL
+ // [mgf1]
+ // oid=OID:1.2.840.113549.1.1.8
+ // params=SEQUENCE:sha384
+ // [sha384]
+ // oid=OID:sha384
+ // params=NULL
+ // [pSpecified]
+ // oid=OID:1.2.840.113549.1.1.9
+ // val=FORMAT:HEX,OCTETSTRING:01020304
+ private static final String ENCODED_DATA_NON_DEFAULTS = "MESgDzANBglghkgBZQMEAgEFAKEc"
+ + "MBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgIFAKITMBEGCSqGSIb3DQEBCQQEAQIDBA==";
+
+ // Base64 version of ASN.1-encoded data with some default and some non-default values.
+ // Specifically, SHA-1 hashFunc (default), MGF1-SHA-512 maskGenFunc (non-default),
+ // empty pSourceFunc (default)
+
+ // asn1=SEQUENCE:oaep
+ // [oaep]
+ // maskGenFunc=EXP:1,SEQUENCE:mgf1
+ // [mgf1]
+ // oid=OID:1.2.840.113549.1.1.8
+ // params=SEQUENCE:sha512
+ // [sha512]
+ // oid=OID:sha512
+ // params=NULL
+ private static final String ENCODED_DATA_MIXED = "MB6hHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAIDBQA=";
+
+ // Base64 version of the same ASN.1-encoded data as ENCODED_DATA_MIXED, but with the
+ // default values explicitly specified.
+
+ // asn1=SEQUENCE:oaep
+ // [oaep]
+ // hashFunc=EXP:0,SEQUENCE:sha1
+ // maskGenFunc=EXP:1,SEQUENCE:mgf1
+ // pSourceFunc=EXP:2,SEQUENCE:pSpecified
+ // [sha1]
+ // oid=OID:sha1
+ // params=NULL
+ // [mgf1]
+ // oid=OID:1.2.840.113549.1.1.8
+ // params=SEQUENCE:sha512
+ // [pSpecified]
+ // oid=OID:1.2.840.113549.1.1.9
+ // val=OCTETSTRING:
+ // [sha512]
+ // oid=OID:sha512
+ // params=NULL
+ private static final String ENCODED_DATA_MIXED_EXPLICIT_DEFAULTS = "MDygCzAJBgUrDgMCGgUAoRww"
+ + "GgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAwUAog8wDQYJKoZIhvcNAQEJBAA=";
+
+ public AlgorithmParametersTestOAEP() {
+ super("OAEP", new AlgorithmParameterAsymmetricHelper("RSA/ECB/OAEPPadding"), new OAEPParameterSpec("SHA-1", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT));
+ }
+
+ @Test
+ public void testEncoding() throws Exception {
+ ServiceTester.test("AlgorithmParameters")
+ .withAlgorithm("OAEP")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("OAEP", p);
+
+ OAEPParameterSpec spec = new OAEPParameterSpec(
+ "SHA-1", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT);
+ params.init(spec);
+ if (!p.getName().equals("SunJCE")) {
+ assertEquals(
+ ENCODED_DATA_ALL_DEFAULTS,
+ TestUtils.encodeBase64(params.getEncoded()));
+ } else {
+ // SunJCE encodes the defaults explicitly, which is not allowed by RFC 4055.
+ assertEquals(
+ ENCODED_DATA_EXPLICIT_DEFAULTS,
+ TestUtils.encodeBase64(params.getEncoded()));
+ }
+
+ params = AlgorithmParameters.getInstance("OAEP", p);
+ spec = new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA384,
+ new PSource.PSpecified(new byte[]{1, 2, 3, 4}));
+ params.init(spec);
+ assertEquals(
+ ENCODED_DATA_NON_DEFAULTS,
+ TestUtils.encodeBase64(params.getEncoded()));
+
+ params = AlgorithmParameters.getInstance("OAEP", p);
+ spec = new OAEPParameterSpec(
+ "SHA-1", "MGF1", MGF1ParameterSpec.SHA512, PSource.PSpecified.DEFAULT);
+ params.init(spec);
+ if (!p.getName().equals("SunJCE")) {
+ assertEquals(
+ ENCODED_DATA_MIXED,
+ TestUtils.encodeBase64(params.getEncoded()));
+ } else {
+ // SunJCE encodes the defaults explicitly, which is not allowed by RFC 4055.
+ assertEquals(
+ ENCODED_DATA_MIXED_EXPLICIT_DEFAULTS,
+ TestUtils.encodeBase64(params.getEncoded()));
+ }
+
+ params = AlgorithmParameters.getInstance("OAEP", p);
+ params.init(TestUtils.decodeBase64(ENCODED_DATA_ALL_DEFAULTS));
+ OAEPParameterSpec producedSpec = params
+ .getParameterSpec(OAEPParameterSpec.class);
+
+ assertEquals( "SHA-1",
+ producedSpec.getDigestAlgorithm());
+ assertEquals( "MGF1",
+ producedSpec.getMGFAlgorithm());
+ assertEquals(
+ MGF1ParameterSpec.SHA1.getDigestAlgorithm(),
+ ((MGF1ParameterSpec) producedSpec.getMGFParameters()).getDigestAlgorithm());
+ assertArrayEquals(PSpecified.DEFAULT.getValue(),
+ ((PSpecified) producedSpec.getPSource()).getValue());
+
+ params = AlgorithmParameters.getInstance("OAEP", p);
+ params.init(TestUtils.decodeBase64(ENCODED_DATA_EXPLICIT_DEFAULTS));
+ producedSpec = params.getParameterSpec(OAEPParameterSpec.class);
+
+ assertEquals( "SHA-1",
+ producedSpec.getDigestAlgorithm());
+ assertEquals( "MGF1",
+ producedSpec.getMGFAlgorithm());
+ assertEquals(
+ MGF1ParameterSpec.SHA1.getDigestAlgorithm(),
+ ((MGF1ParameterSpec) producedSpec.getMGFParameters()).getDigestAlgorithm());
+ assertArrayEquals(PSpecified.DEFAULT.getValue(),
+ ((PSpecified) producedSpec.getPSource()).getValue());
+
+ params = AlgorithmParameters.getInstance("OAEP", p);
+ params.init(TestUtils.decodeBase64(ENCODED_DATA_NON_DEFAULTS));
+ producedSpec = params.getParameterSpec(OAEPParameterSpec.class);
+
+ assertEquals( "SHA-256",
+ producedSpec.getDigestAlgorithm());
+ assertEquals( "MGF1",
+ producedSpec.getMGFAlgorithm());
+ assertEquals(
+ MGF1ParameterSpec.SHA384.getDigestAlgorithm(),
+ ((MGF1ParameterSpec) producedSpec.getMGFParameters()).getDigestAlgorithm());
+ assertArrayEquals(new byte[]{1, 2, 3, 4},
+ ((PSpecified) producedSpec.getPSource()).getValue());
+
+ params = AlgorithmParameters.getInstance("OAEP", p);
+ params.init(TestUtils.decodeBase64(ENCODED_DATA_MIXED));
+ producedSpec = params.getParameterSpec(OAEPParameterSpec.class);
+
+ assertEquals( "SHA-1",
+ producedSpec.getDigestAlgorithm());
+ assertEquals( "MGF1",
+ producedSpec.getMGFAlgorithm());
+ assertEquals(
+ MGF1ParameterSpec.SHA512.getDigestAlgorithm(),
+ ((MGF1ParameterSpec) producedSpec.getMGFParameters()).getDigestAlgorithm());
+ assertArrayEquals(PSpecified.DEFAULT.getValue(),
+ ((PSpecified) producedSpec.getPSource()).getValue());
+
+ params = AlgorithmParameters.getInstance("OAEP", p);
+ params.init(TestUtils.decodeBase64(ENCODED_DATA_MIXED_EXPLICIT_DEFAULTS));
+ producedSpec = params.getParameterSpec(OAEPParameterSpec.class);
+
+ assertEquals( "SHA-1",
+ producedSpec.getDigestAlgorithm());
+ assertEquals( "MGF1",
+ producedSpec.getMGFAlgorithm());
+ assertEquals(
+ MGF1ParameterSpec.SHA512.getDigestAlgorithm(),
+ ((MGF1ParameterSpec) producedSpec.getMGFParameters()).getDigestAlgorithm());
+ assertArrayEquals(PSpecified.DEFAULT.getValue(),
+ ((PSpecified) producedSpec.getPSource()).getValue());
+ }
+ });
+ }
+
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestDH.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestDH.java
new file mode 100644
index 0000000..c316d94
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestDH.java
@@ -0,0 +1,39 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import java.security.KeyPair;
+import javax.crypto.spec.DHPrivateKeySpec;
+import javax.crypto.spec.DHPublicKeySpec;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class KeyFactoryTestDH extends AbstractKeyFactoryTest<DHPublicKeySpec, DHPrivateKeySpec> {
+
+ public KeyFactoryTestDH() {
+ super("DH", DHPublicKeySpec.class, DHPrivateKeySpec.class);
+ }
+
+ @Override
+ protected void check(KeyPair keyPair) throws Exception {
+ new KeyAgreementHelper("DH").test(keyPair);
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestDSA.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestDSA.java
new file mode 100644
index 0000000..d4e6984
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestDSA.java
@@ -0,0 +1,40 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import java.security.KeyPair;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.DSAPublicKeySpec;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class KeyFactoryTestDSA extends
+ AbstractKeyFactoryTest<DSAPublicKeySpec, DSAPrivateKeySpec> {
+
+ public KeyFactoryTestDSA() {
+ super("DSA", DSAPublicKeySpec.class, DSAPrivateKeySpec.class);
+ }
+
+ @Override
+ protected void check(KeyPair keyPair) throws Exception {
+ new SignatureHelper("DSA").test(keyPair);
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestEC.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestEC.java
new file mode 100644
index 0000000..de48861
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestEC.java
@@ -0,0 +1,74 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2019 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Arrays;
+import java.util.List;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class KeyFactoryTestEC extends AbstractKeyFactoryTest<ECPublicKeySpec, ECPrivateKeySpec> {
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
+ public KeyFactoryTestEC() {
+ super("EC", ECPublicKeySpec.class, ECPrivateKeySpec.class);
+ }
+
+ @Override
+ public ServiceTester customizeTester(ServiceTester tester) {
+ // BC's EC keys always use explicit params, even though it's a bad idea, and we don't
+ // support those, so don't test BC keys
+ return tester.skipProvider("BC");
+ }
+
+ @Override
+ protected void check(KeyPair keyPair) throws Exception {
+ new SignatureHelper("SHA256withECDSA").test(keyPair);
+ }
+
+ @Override
+ protected List<KeyPair> getKeys() throws NoSuchAlgorithmException, InvalidKeySpecException {
+ return Arrays.asList(
+ new KeyPair(DefaultKeys.getPublicKey("EC"), DefaultKeys.getPrivateKey("EC")),
+ new KeyPair(new TestPublicKey(DefaultKeys.getPublicKey("EC")),
+ new TestPrivateKey(DefaultKeys.getPrivateKey("EC"))),
+ new KeyPair(new TestECPublicKey((ECPublicKey) DefaultKeys.getPublicKey("EC")),
+ new TestECPrivateKey((ECPrivateKey) DefaultKeys.getPrivateKey("EC"))));
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestRSA.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestRSA.java
new file mode 100644
index 0000000..b4287f9
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestRSA.java
@@ -0,0 +1,157 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
+import java.util.List;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class KeyFactoryTestRSA extends AbstractKeyFactoryTest<RSAPublicKeySpec, RSAPrivateKeySpec> {
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
+ public KeyFactoryTestRSA() {
+ super("RSA", RSAPublicKeySpec.class, RSAPrivateKeySpec.class);
+ }
+
+ @Override
+ protected void check(KeyPair keyPair) throws Exception {
+ new CipherAsymmetricCryptHelper("RSA").test(keyPair);
+ }
+
+ @Test
+ public void getEncodedFailsWhenCrtValuesMissing() throws Exception {
+ PrivateKey privateKey = getPrivateKey();
+ try {
+ // Key has only modulus and private exponent so can't be encoded as PKCS#8
+ privateKey.getEncoded();
+ fail();
+ } catch (RuntimeException e) {
+ // Expected
+ }
+ }
+
+ @Test
+ public void testExtraBufferSpace_Public() throws Exception {
+ PublicKey publicKey = DefaultKeys.getPublicKey("RSA");
+ byte[] encoded = publicKey.getEncoded();
+ byte[] longBuffer = new byte[encoded.length + 147];
+ System.arraycopy(encoded, 0, longBuffer, 0, encoded.length);
+ KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(longBuffer));
+ }
+
+ @Test
+ public void testInvalidKeySpec() throws Exception {
+ Provider p = Security.getProvider(StandardNames.JSSE_PROVIDER_NAME);
+ final KeyFactory factory = KeyFactory.getInstance("RSA", p);
+
+ try {
+ factory.getKeySpec(new TestPrivateKey(DefaultKeys.getPrivateKey("RSA"), "Invalid"),
+ RSAPrivateKeySpec.class);
+ fail();
+ } catch (InvalidKeySpecException e) {
+ // expected
+ }
+
+ try {
+ factory.getKeySpec(new TestPrivateKey(DefaultKeys.getPrivateKey("RSA"), "Invalid"),
+ RSAPrivateCrtKeySpec.class);
+ fail();
+ } catch (InvalidKeySpecException e) {
+ // expected
+ }
+
+ try {
+ factory.getKeySpec(new TestPublicKey(DefaultKeys.getPublicKey("RSA"), "Invalid"),
+ RSAPublicKeySpec.class);
+ fail();
+ } catch (InvalidKeySpecException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void javaSerialization() throws Exception {
+ PrivateKey privatekey = getPrivateKey();
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutputStream out = new ObjectOutputStream(bos);
+ out.writeObject(privatekey);
+
+ ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+ ObjectInputStream in = new ObjectInputStream(bis);
+ PrivateKey copy = (PrivateKey) in.readObject();
+
+ assertEquals(privatekey, copy);
+ }
+
+ @Override
+ protected List<KeyPair> getKeys() throws NoSuchAlgorithmException, InvalidKeySpecException {
+ return Arrays.asList(new KeyPair(DefaultKeys.getPublicKey(algorithmName), getPrivateKey()));
+ }
+
+ // The private RSA key returned by DefaultKeys.getPrivateKey() is built from a PKCS#8
+ // KeySpec and so will be an instance of RSAPrivateCrtKey, but we want to test RSAPrivateKey
+ // in this unit test and so we extract the modulus and private exponent to build the
+ // correct private key subtype.
+ private PrivateKey getPrivateKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
+ RSAPrivateCrtKey crtKey = (RSAPrivateCrtKey) DefaultKeys.getPrivateKey(algorithmName);
+ RSAPrivateKeySpec spec =
+ new RSAPrivateKeySpec(crtKey.getModulus(), crtKey.getPrivateExponent());
+ PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(spec);
+ assertTrue(privateKey instanceof RSAPrivateKey);
+ assertFalse(privateKey instanceof RSAPrivateCrtKey);
+ return privateKey;
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestRSACrt.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestRSACrt.java
new file mode 100644
index 0000000..762f2af
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestRSACrt.java
@@ -0,0 +1,93 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2020 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+// Similar to KeyFactoryTestRSA, but uses RSAPrivateCrtKeySpec instead of RSAPrivateKeySpec.
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class KeyFactoryTestRSACrt extends
+ AbstractKeyFactoryTest<RSAPublicKeySpec, RSAPrivateCrtKeySpec> {
+
+ public KeyFactoryTestRSACrt() {
+ super("RSA", RSAPublicKeySpec.class, RSAPrivateCrtKeySpec.class);
+ }
+
+ @Override
+ protected void check(KeyPair keyPair) throws Exception {
+ new CipherAsymmetricCryptHelper("RSA").test(keyPair);
+ }
+
+ @Override
+ public ServiceTester customizeTester(ServiceTester tester) {
+ // BouncyCastle's KeyFactory.engineGetKeySpec() doesn't handle custom PublicKey
+ // implmenetations.
+ return tester.skipProvider("BC");
+ }
+
+ @Test
+ public void testExtraBufferSpace_Private() throws Exception {
+ PrivateKey privateKey = DefaultKeys.getPrivateKey("RSA");
+ assertTrue(privateKey instanceof RSAPrivateCrtKey);
+
+ byte[] encoded = privateKey.getEncoded();
+ byte[] longBuffer = new byte[encoded.length + 147];
+ System.arraycopy(encoded, 0, longBuffer, 0, encoded.length);
+ PrivateKey copy =
+ KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(longBuffer));
+ assertEquals(privateKey, copy);
+ }
+
+ @Test
+ public void javaSerialization() throws Exception {
+ PrivateKey privateKey = DefaultKeys.getPrivateKey("RSA");
+ assertTrue(privateKey instanceof RSAPrivateCrtKey);
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutputStream out = new ObjectOutputStream(bos);
+ out.writeObject(privateKey);
+
+ ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+ ObjectInputStream in = new ObjectInputStream(bis);
+ PrivateKey copy = (PrivateKey) in.readObject();
+ assertTrue(copy instanceof RSAPrivateCrtKey);
+
+ assertEquals(privateKey.getFormat(), copy.getFormat());
+ assertArrayEquals(privateKey.getEncoded(), copy.getEncoded());
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestRSACustom.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestRSACustom.java
new file mode 100644
index 0000000..05dd7ad
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestRSACustom.java
@@ -0,0 +1,64 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2020 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+// Similar to KeyFactoryTestRSA, but uses custom RSA PublicKey
+// implementation to exercise less common parts of OpenSSLRSAKeyFactory.
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class KeyFactoryTestRSACustom extends
+ AbstractKeyFactoryTest<RSAPublicKeySpec, RSAPrivateKeySpec> {
+
+ public KeyFactoryTestRSACustom() {
+ super("RSA", RSAPublicKeySpec.class, RSAPrivateKeySpec.class);
+ }
+
+ @Override
+ protected void check(KeyPair keyPair) throws Exception {
+ new CipherAsymmetricCryptHelper("RSA").test(keyPair);
+ }
+
+ @Override
+ public ServiceTester customizeTester(ServiceTester tester) {
+ // BouncyCastle's KeyFactory.engineGetKeySpec() doesn't handle custom PublicKey
+ // implmenetations.
+ return tester.skipProvider("BC");
+ }
+
+ @Override
+ protected List<KeyPair> getKeys() throws NoSuchAlgorithmException, InvalidKeySpecException {
+ return Arrays.asList(
+ new KeyPair(
+ new TestPublicKey(DefaultKeys.getPublicKey("RSA")),
+ new TestPrivateKey(DefaultKeys.getPrivateKey("RSA"))
+ )
+ );
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestXDH.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestXDH.java
new file mode 100644
index 0000000..31aeda9
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestXDH.java
@@ -0,0 +1,65 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2019 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class KeyFactoryTestXDH extends
+ AbstractKeyFactoryTest<X509EncodedKeySpec, PKCS8EncodedKeySpec> {
+
+ public KeyFactoryTestXDH() {
+ super("XDH", X509EncodedKeySpec.class, PKCS8EncodedKeySpec.class);
+ }
+
+ @Override
+ protected void check(KeyPair keyPair) throws Exception {
+ new KeyAgreementHelper("XDH").test(keyPair);
+ }
+
+ @Override
+ protected ServiceTester customizeTester(ServiceTester tester) {
+ // TODO: fix this test when Conscrypt's XDH keys can inherit from XECPublicKey and XECPrivateKey
+ return tester.skipProvider("SunEC");
+ }
+
+ @Override
+ protected List<KeyPair> getKeys() throws NoSuchAlgorithmException, InvalidKeySpecException {
+ return Arrays.asList(
+ new KeyPair(
+ DefaultKeys.getPublicKey("XDH"),
+ DefaultKeys.getPrivateKey("XDH")
+ ),
+ new KeyPair(
+ new TestPublicKey(DefaultKeys.getPublicKey("XDH")),
+ new TestPrivateKey(DefaultKeys.getPrivateKey("XDH"))
+ )
+ );
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTest.java
new file mode 100644
index 0000000..3c83bad
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTest.java
@@ -0,0 +1,473 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import com.android.org.conscrypt.TestUtils;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class KeyPairGeneratorTest {
+
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
+ @Test
+ public void test_getInstance() throws Exception {
+ ServiceTester.test("KeyPairGenerator")
+ // Do not test AndroidKeyStore Provider. It does not accept vanilla public keys for
+ // signature verification. It's OKish not to test here because it's tested by
+ // cts/tests/tests/keystore.
+ .skipProvider("AndroidKeyStore")
+ // The SunEC provider tries to pass a sun-only AlgorithmParameterSpec to the default
+ // AlgorithmParameters:EC when its KeyPairGenerator is initialized. Since Conscrypt
+ // is the highest-ranked provider when running our tests, its implementation of
+ // AlgorithmParameters:EC is returned, and it doesn't understand the special
+ // AlgorithmParameterSpec, so the KeyPairGenerator can't be initialized.
+ .skipProvider("SunEC")
+ // The SunPKCS11-NSS provider on OpenJDK 7 attempts to delegate to the SunEC provider,
+ // which doesn't exist on OpenJDK 7, and thus totally fails. This appears to be a bug
+ // introduced into later revisions of OpenJDK 7.
+ .skipProvider("SunPKCS11-NSS")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider provider, String algorithm) throws Exception {
+ AlgorithmParameterSpec params = null;
+
+ if ("DH".equals(algorithm) || "DiffieHellman".equalsIgnoreCase(algorithm)) {
+ params = getDHParams();
+ }
+ // KeyPairGenerator.getInstance(String)
+ KeyPairGenerator kpg1 = KeyPairGenerator.getInstance(algorithm);
+ assertEquals(algorithm, kpg1.getAlgorithm());
+ if (params != null) {
+ kpg1.initialize(params);
+ }
+ test_KeyPairGenerator(kpg1);
+
+ // KeyPairGenerator.getInstance(String, Provider)
+ KeyPairGenerator kpg2 = KeyPairGenerator.getInstance(algorithm, provider);
+ assertEquals(algorithm, kpg2.getAlgorithm());
+ assertEquals(provider, kpg2.getProvider());
+ if (params != null) {
+ kpg2.initialize(params);
+ }
+ test_KeyPairGenerator(kpg2);
+
+ // KeyPairGenerator.getInstance(String, String)
+ KeyPairGenerator kpg3 = KeyPairGenerator.getInstance(algorithm,
+ provider.getName());
+ assertEquals(algorithm, kpg3.getAlgorithm());
+ assertEquals(provider, kpg3.getProvider());
+ if (params != null) {
+ kpg3.initialize(params);
+ }
+ test_KeyPairGenerator(kpg3);
+ }
+ });
+ }
+
+ private static final Map<String, List<Integer>> KEY_SIZES
+ = new HashMap<String, List<Integer>>();
+ private static void putKeySize(String algorithm, int keySize) {
+ algorithm = algorithm.toUpperCase();
+ List<Integer> keySizes = KEY_SIZES.get(algorithm);
+ if (keySizes == null) {
+ keySizes = new ArrayList<Integer>();
+ KEY_SIZES.put(algorithm, keySizes);
+ }
+ keySizes.add(keySize);
+ }
+ private static List<Integer> getKeySizes(String algorithm) throws Exception {
+ algorithm = algorithm.toUpperCase();
+ List<Integer> keySizes = KEY_SIZES.get(algorithm);
+ if (keySizes == null) {
+ throw new Exception("Unknown key sizes for KeyPairGenerator." + algorithm);
+ }
+ return keySizes;
+ }
+ static {
+ putKeySize("DSA", 512);
+ putKeySize("DSA", 512+64);
+ putKeySize("DSA", 1024);
+ putKeySize("RSA", 2048);
+ putKeySize("RSASSA-PSS", 2048);
+ putKeySize("DH", 512);
+ putKeySize("DH", 512+64);
+ putKeySize("DH", 1024);
+ putKeySize("DiffieHellman", 512);
+ putKeySize("DiffieHellman", 512+64);
+ putKeySize("DiffieHellman", 1024);
+ putKeySize("EC", 224);
+ putKeySize("EC", 256);
+ putKeySize("EC", 384);
+ putKeySize("EC", 521);
+ putKeySize("XDH", 256);
+ }
+
+ /** Elliptic Curve Crypto named curves that should be supported. */
+ private static final String[] EC_NAMED_CURVES = {
+ // NIST P-256 aka SECG secp256r1 aka ANSI X9.62 prime256v1
+ "secp256r1", "prime256v1",
+ // NIST P-521 aka SECG secp521r1
+ "secp521r1",
+ };
+
+ private void test_KeyPairGenerator(KeyPairGenerator kpg) throws Exception {
+ // without a call to initialize
+ test_KeyPair(kpg, kpg.genKeyPair());
+ test_KeyPair(kpg, kpg.generateKeyPair());
+
+ String algorithm = kpg.getAlgorithm();
+
+ // TODO: detect if we're running in vogar and run the full test
+ if ("DH".equals(algorithm) || "DiffieHellman".equalsIgnoreCase(algorithm)) {
+ // Disabled because this takes too long on devices.
+ // TODO: Re-enable DH test. http://b/5513723.
+ return;
+ }
+
+ List<Integer> keySizes = getKeySizes(algorithm);
+ for (int keySize : keySizes) {
+ // TODO(flooey): Remove when we don't support Java 6 anymore
+ if ("DSA".equals(algorithm)
+ && ("SUN".equalsIgnoreCase(kpg.getProvider().getName())
+ || "SunPKCS11-NSS".equalsIgnoreCase(kpg.getProvider().getName()))
+ && keySize != 512 && keySize != 1024) {
+ // The Sun provider doesn't support DSA in all the key sizes, so ignore
+ // the uncommon ones.
+ continue;
+ }
+ kpg.initialize(keySize);
+ test_KeyPair(kpg, kpg.genKeyPair());
+ test_KeyPair(kpg, kpg.generateKeyPair());
+
+ kpg.initialize(keySize, (SecureRandom) null);
+ test_KeyPair(kpg, kpg.genKeyPair());
+ test_KeyPair(kpg, kpg.generateKeyPair());
+
+ kpg.initialize(keySize, new SecureRandom());
+ test_KeyPair(kpg, kpg.genKeyPair());
+ test_KeyPair(kpg, kpg.generateKeyPair());
+ }
+
+ if ("EC".equals(algorithm) || "ECDH".equals(algorithm)
+ || "ECDSA".equals(algorithm)) {
+ if ("SunPKCS11-NSS".equalsIgnoreCase(kpg.getProvider().getName())) {
+ // SunPKCS11 doesn't support some of the named curves that we expect, so it
+ // fails. Skip it.
+ return;
+ }
+ for (String curveName : EC_NAMED_CURVES) {
+ kpg.initialize(new ECGenParameterSpec(curveName));
+ test_KeyPair(kpg, kpg.genKeyPair());
+ test_KeyPair(kpg, kpg.generateKeyPair());
+
+ kpg.initialize(new ECGenParameterSpec(curveName), (SecureRandom) null);
+ test_KeyPair(kpg, kpg.genKeyPair());
+ test_KeyPair(kpg, kpg.generateKeyPair());
+
+ kpg.initialize(new ECGenParameterSpec(curveName), new SecureRandom());
+ test_KeyPair(kpg, kpg.genKeyPair());
+ test_KeyPair(kpg, kpg.generateKeyPair());
+ }
+ }
+ }
+
+ private void test_KeyPair(KeyPairGenerator kpg, KeyPair kp) throws Exception {
+ assertNotNull(kp);
+ test_Key(kpg, kp.getPrivate());
+ test_Key(kpg, kp.getPublic());
+ }
+
+ private void test_Key(KeyPairGenerator kpg, Key k) throws Exception {
+ String expectedAlgorithm = kpg.getAlgorithm().toUpperCase(Locale.ROOT);
+ if (StandardNames.IS_RI && expectedAlgorithm.equals("DIFFIEHELLMAN")) {
+ expectedAlgorithm = "DH";
+ }
+ assertEquals(expectedAlgorithm, k.getAlgorithm().toUpperCase());
+ if (expectedAlgorithm.equals("DH")) {
+ if (k instanceof DHPublicKey) {
+ DHPublicKey dhPub = (DHPublicKey) k;
+ assertEquals(dhPub.getParams().getP(), getDHParams().getP());
+ } else if (k instanceof DHPrivateKey) {
+ DHPrivateKey dhPriv = (DHPrivateKey) k;
+ assertEquals(dhPriv.getParams().getP(), getDHParams().getP());
+ } else {
+ fail("not a public or private key!?");
+ }
+ }
+ if (kpg.getProvider().getName().equalsIgnoreCase("SunMSCAPI")
+ && expectedAlgorithm.equals("RSA")) {
+ // The SunMSCAPI RSA keys don't provide encoded versions at all, nor are they
+ // serializable, so just skip them.
+ return;
+ }
+ assertNotNull(k.getEncoded());
+ assertNotNull(k.getFormat());
+
+ // Test serialization
+ // SunPKCS11-NSS on Java 6 replaces serialized keys with one from the default provider,
+ // so the deserialized key doesn't match the original.
+ if (!kpg.getProvider().getName().equalsIgnoreCase("SunPKCS11-NSS")) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(16384);
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(k);
+
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ ObjectInputStream ois = new ObjectInputStream(bais);
+ Key inflatedKey = (Key) ois.readObject();
+
+ assertEquals("Provider: " + kpg.getProvider(), k, inflatedKey);
+ }
+
+ test_KeyWithAllKeyFactories(k);
+ }
+
+ private void test_KeyWithAllKeyFactories(Key k) throws Exception {
+ byte[] encoded = k.getEncoded();
+
+ String keyAlgo = k.getAlgorithm();
+ for (Provider p : Security.getProviders()) {
+ Set<Provider.Service> services = p.getServices();
+ for (Provider.Service service : services) {
+ if (!"KeyFactory".equals(service.getType())) {
+ continue;
+ }
+ if (!service.getAlgorithm().equals(keyAlgo)) {
+ continue;
+ }
+ if (p.getName().equalsIgnoreCase("AndroidKeyStore")) {
+ // AndroidKeyStore only works with its own keys
+ continue;
+ }
+ if ("EC".equals(k.getAlgorithm())
+ && "SunPKCS11-NSS".equalsIgnoreCase(p.getName())) {
+ // SunPKCS11 doesn't support some of the named curves that we expect, so it
+ // fails. Skip testing that combination.
+ continue;
+ }
+ if ("DH".equals(k.getAlgorithm())
+ && "SunPKCS11-NSS".equalsIgnoreCase(p.getName())) {
+ // SunPKCS11 omits the privateValueLength field from the DHParameter
+ // structure in its encoded keys, unlike every other provider seen,
+ // so ignore it.
+ continue;
+ }
+ if ("XDH".equals(k.getAlgorithm()) && "SunEC".equalsIgnoreCase(p.getName())
+ && "11".equals(System.getProperty("java.specification.version"))) {
+ // SunEC in OpenJDK 11 has a bug where the format specified in RFC 8410
+ // Section 7. It uses a single OCTET STRING to represent the key instead
+ // of an OCTET STRING inside of an OCTET STRING as defined in the RFC:
+ // ("For the keys defined in this document, the private key is always an
+ // opaque byte sequence. The ASN.1 type CurvePrivateKey is defined in
+ // this document to hold the byte sequence. Thus, when encoding a
+ // OneAsymmetricKey object, the private key is wrapped in a
+ // CurvePrivateKey object and wrapped by the OCTET STRING of the
+ // "privateKey" field.")
+ continue;
+ }
+
+ if ("PKCS#8".equals(k.getFormat())) {
+ PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(encoded);
+ KeyFactory kf = KeyFactory.getInstance(k.getAlgorithm(), p);
+ PrivateKey privKey = kf.generatePrivate(spec);
+ assertNotNull(k.getAlgorithm() + ", provider=" + p.getName(), privKey);
+
+ /*
+ * EC keys are unique because they can have explicit parameters or a curve
+ * name. Check them specially so this test can continue to function.
+ */
+ if (k instanceof ECPrivateKey) {
+ assertECPrivateKeyEquals((ECPrivateKey) k, (ECPrivateKey) privKey);
+ } else {
+ assertEquals(k.getAlgorithm() + ", provider=" + p.getName(),
+ TestUtils.encodeBase64(encoded),
+ TestUtils.encodeBase64(privKey.getEncoded()));
+ }
+ } else if ("X.509".equals(k.getFormat())) {
+ X509EncodedKeySpec spec = new X509EncodedKeySpec(encoded);
+ KeyFactory kf = KeyFactory.getInstance(k.getAlgorithm(), p);
+ PublicKey pubKey = kf.generatePublic(spec);
+ assertNotNull(pubKey);
+ assertEquals(k.getAlgorithm() + ", provider=" + p.getName(),
+ TestUtils.encodeBase64(encoded),
+ TestUtils.encodeBase64(pubKey.getEncoded()));
+ }
+ }
+ }
+ }
+
+ private static void assertECPrivateKeyEquals(ECPrivateKey expected, ECPrivateKey actual) {
+ assertEquals(expected.getS(), actual.getS());
+ assertECParametersEquals(expected.getParams(), actual.getParams());
+ }
+
+ private static void assertECParametersEquals(ECParameterSpec expected, ECParameterSpec actual) {
+ assertEquals(expected.getCurve(), actual.getCurve());
+ assertEquals(expected.getGenerator(), actual.getGenerator());
+ assertEquals(expected.getOrder(), actual.getOrder());
+ assertEquals(expected.getCofactor(), actual.getCofactor());
+ }
+
+ /**
+ * DH parameters pre-generated so that the test doesn't take too long.
+ * These parameters were generated with:
+ *
+ * openssl gendh 512 | openssl dhparams -C
+ */
+ private static DHParameterSpec getDHParams() {
+ BigInteger p = new BigInteger("E7AB1768BD75CD24700960FFA32D3F1557344E587101237532CC641646ED7A7C104743377F6D46251698B665CE2A6CBAB6714C2569A7D2CA22C0CF03FA40AC93", 16);
+ BigInteger g = new BigInteger("02", 16);
+ return new DHParameterSpec(p, g, 512);
+ }
+
+ private static final BigInteger DSA_P = new BigInteger(new byte[] {
+ (byte) 0x00, (byte) 0x9e, (byte) 0x61, (byte) 0xc2, (byte) 0x89, (byte) 0xef, (byte) 0x77, (byte) 0xa9,
+ (byte) 0x4e, (byte) 0x13, (byte) 0x67, (byte) 0x64, (byte) 0x1f, (byte) 0x09, (byte) 0x01, (byte) 0xfe,
+ (byte) 0x24, (byte) 0x13, (byte) 0x53, (byte) 0xe0, (byte) 0xb7, (byte) 0x90, (byte) 0xa8, (byte) 0x4e,
+ (byte) 0x76, (byte) 0xfe, (byte) 0x89, (byte) 0x82, (byte) 0x7f, (byte) 0x7a, (byte) 0xc5, (byte) 0x3c,
+ (byte) 0x4e, (byte) 0x0c, (byte) 0x20, (byte) 0x55, (byte) 0x30, (byte) 0x95, (byte) 0x42, (byte) 0x85,
+ (byte) 0xe1, (byte) 0x40, (byte) 0x7d, (byte) 0x27, (byte) 0x8f, (byte) 0x07, (byte) 0x0d, (byte) 0xe8,
+ (byte) 0xdc, (byte) 0x99, (byte) 0xef, (byte) 0xb3, (byte) 0x07, (byte) 0x94, (byte) 0x34, (byte) 0xd6,
+ (byte) 0x7c, (byte) 0xff, (byte) 0x9c, (byte) 0xbe, (byte) 0x69, (byte) 0xd3, (byte) 0xeb, (byte) 0x44,
+ (byte) 0x37, (byte) 0x50, (byte) 0xef, (byte) 0x49, (byte) 0xf8, (byte) 0xe2, (byte) 0x5b, (byte) 0xd8,
+ (byte) 0xd1, (byte) 0x10, (byte) 0x84, (byte) 0x97, (byte) 0xea, (byte) 0xe3, (byte) 0xa5, (byte) 0x1c,
+ (byte) 0xc0, (byte) 0x4e, (byte) 0x69, (byte) 0xca, (byte) 0x70, (byte) 0x3d, (byte) 0x78, (byte) 0xb9,
+ (byte) 0x16, (byte) 0xe5, (byte) 0xfe, (byte) 0x61, (byte) 0x5d, (byte) 0x8a, (byte) 0x5a, (byte) 0xb3,
+ (byte) 0x2c, (byte) 0x61, (byte) 0xb6, (byte) 0x01, (byte) 0x3b, (byte) 0xd0, (byte) 0x01, (byte) 0x7c,
+ (byte) 0x32, (byte) 0x8d, (byte) 0xe1, (byte) 0xf3, (byte) 0x69, (byte) 0x0e, (byte) 0x8b, (byte) 0x58,
+ (byte) 0xc6, (byte) 0xcf, (byte) 0x00, (byte) 0x94, (byte) 0xf8, (byte) 0x49, (byte) 0x2a, (byte) 0x4b,
+ (byte) 0xea, (byte) 0xda, (byte) 0x00, (byte) 0xff, (byte) 0x4b, (byte) 0xd0, (byte) 0xbe, (byte) 0x40,
+ (byte) 0x23,
+ });
+
+ private static final BigInteger DSA_Q = new BigInteger(new byte[] {
+ (byte) 0x00, (byte) 0xbf, (byte) 0xee, (byte) 0xaa, (byte) 0x0f, (byte) 0x12, (byte) 0x34, (byte) 0x50,
+ (byte) 0x72, (byte) 0xf8, (byte) 0x60, (byte) 0x13, (byte) 0xd8, (byte) 0xf1, (byte) 0x41, (byte) 0x01,
+ (byte) 0x10, (byte) 0xa5, (byte) 0x2f, (byte) 0x57, (byte) 0x5f,
+ });
+
+ private static final BigInteger DSA_G = new BigInteger(new byte[] {
+ (byte) 0x77, (byte) 0xd4, (byte) 0x7a, (byte) 0x12, (byte) 0xcc, (byte) 0x81, (byte) 0x7e, (byte) 0x7e,
+ (byte) 0xeb, (byte) 0x3a, (byte) 0xfb, (byte) 0xe6, (byte) 0x86, (byte) 0x6d, (byte) 0x5a, (byte) 0x10,
+ (byte) 0x1d, (byte) 0xad, (byte) 0xa9, (byte) 0x4f, (byte) 0xb9, (byte) 0x03, (byte) 0x5d, (byte) 0x21,
+ (byte) 0x1a, (byte) 0xe4, (byte) 0x30, (byte) 0x95, (byte) 0x75, (byte) 0x8e, (byte) 0xcd, (byte) 0x5e,
+ (byte) 0xd1, (byte) 0xbd, (byte) 0x0a, (byte) 0x45, (byte) 0xee, (byte) 0xe7, (byte) 0xf7, (byte) 0x6b,
+ (byte) 0x65, (byte) 0x02, (byte) 0x60, (byte) 0xd0, (byte) 0x2e, (byte) 0xaf, (byte) 0x3d, (byte) 0xbc,
+ (byte) 0x07, (byte) 0xdd, (byte) 0x2b, (byte) 0x8e, (byte) 0x33, (byte) 0xc0, (byte) 0x93, (byte) 0x80,
+ (byte) 0xd9, (byte) 0x2b, (byte) 0xa7, (byte) 0x71, (byte) 0x57, (byte) 0x76, (byte) 0xbc, (byte) 0x8e,
+ (byte) 0xb9, (byte) 0xe0, (byte) 0xd7, (byte) 0xf4, (byte) 0x23, (byte) 0x8d, (byte) 0x41, (byte) 0x1a,
+ (byte) 0x97, (byte) 0x4f, (byte) 0x2c, (byte) 0x1b, (byte) 0xd5, (byte) 0x4b, (byte) 0x66, (byte) 0xe8,
+ (byte) 0xfa, (byte) 0xd2, (byte) 0x50, (byte) 0x0d, (byte) 0x17, (byte) 0xab, (byte) 0x34, (byte) 0x31,
+ (byte) 0x3d, (byte) 0xa4, (byte) 0x88, (byte) 0xd8, (byte) 0x8e, (byte) 0xa8, (byte) 0xa7, (byte) 0x6e,
+ (byte) 0x17, (byte) 0x03, (byte) 0xb7, (byte) 0x0f, (byte) 0x68, (byte) 0x7c, (byte) 0x64, (byte) 0x7b,
+ (byte) 0x92, (byte) 0xb8, (byte) 0x63, (byte) 0xe4, (byte) 0x9a, (byte) 0x67, (byte) 0x18, (byte) 0x81,
+ (byte) 0x27, (byte) 0xd4, (byte) 0x0b, (byte) 0x13, (byte) 0x48, (byte) 0xd3, (byte) 0x7d, (byte) 0x4e,
+ (byte) 0xf6, (byte) 0xa8, (byte) 0x8f, (byte) 0x56, (byte) 0x17, (byte) 0x2d, (byte) 0x08, (byte) 0x51,
+ });
+
+ @Test
+ public void testDSAGeneratorWithParams() throws Exception {
+ final DSAParameterSpec dsaSpec = new DSAParameterSpec(DSA_P, DSA_Q, DSA_G);
+
+ ServiceTester.test("KeyPairGenerator")
+ .withAlgorithm("DSA")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ final KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA", p);
+ kpg.initialize(dsaSpec);
+ KeyPair pair = kpg.generateKeyPair();
+ DSAPrivateKey privKey = (DSAPrivateKey) pair.getPrivate();
+ DSAPublicKey pubKey = (DSAPublicKey) pair.getPublic();
+
+ DSAParams actualParams = privKey.getParams();
+ assertNotNull("DSA params should not be null", actualParams);
+
+ assertEquals("DSA P should be the same as supplied",
+ DSA_P, actualParams.getP());
+ assertEquals("DSA Q should be the same as supplied",
+ DSA_Q, actualParams.getQ());
+ assertEquals("DSA G should be the same as supplied",
+ DSA_G, actualParams.getG());
+
+ actualParams = pubKey.getParams();
+ assertNotNull("DSA params should not be null", actualParams);
+
+ assertEquals("DSA P should be the same as supplied",
+ DSA_P, actualParams.getP());
+ assertEquals("DSA Q should be the same as supplied",
+ DSA_Q, actualParams.getQ());
+ assertEquals("DSA G should be the same as supplied",
+ DSA_G, actualParams.getG());
+
+ }
+ });
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestDH.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestDH.java
new file mode 100644
index 0000000..16b23f7
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestDH.java
@@ -0,0 +1,37 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class KeyPairGeneratorTestDH extends AbstractKeyPairGeneratorTest {
+
+ public KeyPairGeneratorTestDH() {
+ super("DH", new KeyAgreementHelper("DH"));
+ }
+
+ // Broken Test: Takes ages due to DH computations. Disabling for now.
+ @Override
+ public void testKeyPairGenerator() throws Exception {
+ super.testKeyPairGenerator();
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestDSA.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestDSA.java
new file mode 100644
index 0000000..b97adce
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestDSA.java
@@ -0,0 +1,32 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class KeyPairGeneratorTestDSA extends AbstractKeyPairGeneratorTest {
+
+ public KeyPairGeneratorTestDSA() {
+ super("DSA", new SignatureHelper("DSA"));
+ }
+
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestRSA.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestRSA.java
new file mode 100644
index 0000000..f2f2539
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestRSA.java
@@ -0,0 +1,31 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class KeyPairGeneratorTestRSA extends AbstractKeyPairGeneratorTest {
+
+ public KeyPairGeneratorTestRSA() {
+ super("RSA", new CipherAsymmetricCryptHelper("RSA"));
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestXDH.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestXDH.java
new file mode 100644
index 0000000..f2e3d0e
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestXDH.java
@@ -0,0 +1,36 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class KeyPairGeneratorTestXDH extends AbstractKeyPairGeneratorTest {
+
+ public KeyPairGeneratorTestXDH() {
+ super("XDH", new KeyAgreementHelper("XDH"));
+ }
+
+ @Override
+ protected int getKeySize() {
+ return 256;
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/MessageDigestTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/MessageDigestTest.java
new file mode 100644
index 0000000..d5d3fd0
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/MessageDigestTest.java
@@ -0,0 +1,280 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.org.conscrypt.TestUtils;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public final class MessageDigestTest {
+
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
+ private final byte[] sha_456 = {
+ -24, 9, -59, -47, -50, -92, 123, 69, -29, 71,
+ 1, -46, 63, 96, -118, -102, 88, 3, 77, -55
+ };
+
+ @Test
+ public void testShaReset() throws NoSuchAlgorithmException {
+ MessageDigest sha = MessageDigest.getInstance("SHA");
+ sha.update(new byte[] { 1, 2, 3 });
+ sha.reset();
+ sha.update(new byte[] { 4, 5, 6 });
+ assertEquals(Arrays.toString(sha_456), Arrays.toString(sha.digest()));
+ }
+
+ @Test
+ public void test_getInstance() throws Exception {
+ ServiceTester.test("MessageDigest").run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider provider, String algorithm) throws Exception {
+ // MessageDigest.getInstance(String)
+ MessageDigest md1 = MessageDigest.getInstance(algorithm);
+ assertEquals(algorithm, md1.getAlgorithm());
+ test_MessageDigest(md1);
+
+ // MessageDigest.getInstance(String, Provider)
+ MessageDigest md2 = MessageDigest.getInstance(algorithm, provider);
+ assertEquals(algorithm, md2.getAlgorithm());
+ assertEquals(provider, md2.getProvider());
+ test_MessageDigest(md2);
+
+ // MessageDigest.getInstance(String, String)
+ MessageDigest md3 = MessageDigest.getInstance(algorithm, provider.getName());
+ assertEquals(algorithm, md3.getAlgorithm());
+ assertEquals(provider, md3.getProvider());
+ test_MessageDigest(md3);
+ }
+ });
+ }
+
+ private static final Map<String, Map<String, byte[]>> EXPECTATIONS
+ = new HashMap<String, Map<String, byte[]>>();
+ private static void putExpectation(String algorithm, String inputName, byte[] expected) {
+ algorithm = algorithm.toUpperCase();
+ Map<String, byte[]> expectations = EXPECTATIONS.get(algorithm);
+ if (expectations == null) {
+ expectations = new HashMap<String, byte[]>();
+ EXPECTATIONS.put(algorithm, expectations);
+ }
+ expectations.put(inputName, expected);
+ }
+ private static Map<String, byte[]> getExpectations(String algorithm) throws Exception {
+ algorithm = algorithm.toUpperCase();
+ Map<String, byte[]> expectations = EXPECTATIONS.get(algorithm);
+ if (expectations == null) {
+ throw new Exception("No expectations for MessageDigest." + algorithm);
+ }
+ return expectations;
+ }
+ private static final String INPUT_EMPTY = "empty";
+ private static final String INPUT_256MB = "256mb";
+ static {
+ // INPUT_EMPTY
+ putExpectation("MD2",
+ INPUT_EMPTY,
+ new byte[] { -125, 80, -27, -93, -30, 76, 21, 61,
+ -14, 39, 92, -97, -128, 105, 39, 115 });
+ putExpectation("MD5",
+ INPUT_EMPTY,
+ new byte[] { -44, 29, -116, -39, -113, 0, -78, 4,
+ -23, -128, 9, -104, -20, -8, 66, 126 });
+ putExpectation("SHA",
+ INPUT_EMPTY,
+ new byte[] { -38, 57, -93, -18, 94, 107, 75, 13,
+ 50, 85, -65, -17, -107, 96, 24, -112,
+ -81, -40, 7, 9});
+ putExpectation("SHA1",
+ INPUT_EMPTY,
+ new byte[] { -38, 57, -93, -18, 94, 107, 75, 13,
+ 50, 85, -65, -17, -107, 96, 24, -112,
+ -81, -40, 7, 9});
+ putExpectation("SHA-1",
+ INPUT_EMPTY,
+ new byte[] { -38, 57, -93, -18, 94, 107, 75, 13,
+ 50, 85, -65, -17, -107, 96, 24, -112,
+ -81, -40, 7, 9});
+ putExpectation("SHA-224",
+ INPUT_EMPTY,
+ new byte[] { -47, 74, 2, -116, 42, 58, 43, -55, 71,
+ 97, 2, -69, 40, -126, 52, -60, 21,
+ -94, -80, 31, -126, -114, -90, 42,
+ -59, -77, -28, 47});
+ putExpectation("SHA-256",
+ INPUT_EMPTY,
+ new byte[] { -29, -80, -60, 66, -104, -4, 28, 20,
+ -102, -5, -12, -56, -103, 111, -71, 36,
+ 39, -82, 65, -28, 100, -101, -109, 76,
+ -92, -107, -103, 27, 120, 82, -72, 85 });
+ putExpectation("SHA-384",
+ INPUT_EMPTY,
+ new byte[] { 56, -80, 96, -89, 81, -84, -106, 56,
+ 76, -39, 50, 126, -79, -79, -29, 106,
+ 33, -3, -73, 17, 20, -66, 7, 67,
+ 76, 12, -57, -65, 99, -10, -31, -38,
+ 39, 78, -34, -65, -25, 111, 101, -5,
+ -43, 26, -46, -15, 72, -104, -71, 91 });
+ putExpectation("SHA-512",
+ INPUT_EMPTY,
+ new byte[] { -49, -125, -31, 53, 126, -17, -72, -67,
+ -15, 84, 40, 80, -42, 109, -128, 7,
+ -42, 32, -28, 5, 11, 87, 21, -36,
+ -125, -12, -87, 33, -45, 108, -23, -50,
+ 71, -48, -47, 60, 93, -123, -14, -80,
+ -1, -125, 24, -46, -121, 126, -20, 47,
+ 99, -71, 49, -67, 71, 65, 122, -127,
+ -91, 56, 50, 122, -7, 39, -38, 62 });
+ putExpectation("SHA-512/224",
+ INPUT_EMPTY,
+ TestUtils.decodeHex(
+ "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4"));
+ putExpectation("SHA-512/256",
+ INPUT_EMPTY,
+ TestUtils.decodeHex(
+ "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a"));
+ putExpectation("SHA3-224",
+ INPUT_EMPTY,
+ TestUtils.decodeHex(
+ "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7"));
+ putExpectation("SHA3-256",
+ INPUT_EMPTY,
+ TestUtils.decodeHex(
+ "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"));
+ putExpectation("SHA3-384",
+ INPUT_EMPTY,
+ TestUtils.decodeHex(
+ "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2a"
+ + "c3713831264adb47fb6bd1e058d5f004"));
+ putExpectation("SHA3-512",
+ INPUT_EMPTY,
+ TestUtils.decodeHex(
+ "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a6"
+ + "15b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"));
+
+ // Regression test for a SHA-1 problem with inputs larger than 256 MiB. http://b/4501620
+ // In mid-2013 this takes 3 minutes even on the host, so let's not run it on devices.
+ if (System.getenv("ANDROID_BUILD_TOP") != null) {
+ // INPUT_256MB
+ putExpectation("MD2",
+ INPUT_256MB,
+ new byte[] { -63, -120, 6, 67, 12, -87, -39, -11,
+ -67, -3, -31, -41, -91, 16, -35, 91 });
+ putExpectation("MD5",
+ INPUT_256MB,
+ new byte[] { 31, 80, 57, -27, 11, -42, 107, 41,
+ 12, 86, 104, 77, -123, 80, -58, -62 });
+ putExpectation("SHA",
+ INPUT_256MB,
+ new byte[] { 123, -111, -37, -36, 86, -59, 120, 30,
+ -33, 108, -120, 71, -76, -86, 105, 101,
+ 86, 108, 92, 117 });
+ putExpectation("SHA-1",
+ INPUT_256MB,
+ new byte[] { 123, -111, -37, -36, 86, -59, 120, 30,
+ -33, 108, -120, 71, -76, -86, 105, 101,
+ 86, 108, 92, 117 });
+ putExpectation("SHA-224",
+ INPUT_256MB,
+ new byte[] { -78, 82, 5, -71, 57, 119, 77, -32,
+ -62, -74, -40, 64, -57, 79, 40, 116,
+ -18, 48, -69, 45, 18, -94, 111, 114,
+ -45, -93, 43, -11 });
+ putExpectation("SHA-256",
+ INPUT_256MB,
+ new byte[] { -90, -41, 42, -57, 105, 15, 83, -66,
+ 106, -28, 107, -88, -123, 6, -67, -105,
+ 48, 42, 9, 63, 113, 8, 71, 43,
+ -39, -17, -61, -50, -3, -96, 100, -124 });
+ putExpectation("SHA-384",
+ INPUT_256MB,
+ new byte[] { 71, 72, 77, -83, -110, 22, -118, -18,
+ -58, 119, 115, 74, -67, -36, 84, 122,
+ -105, -67, -75, 15, -33, 37, 78, -95,
+ 4, 118, -53, 106, 65, -115, -19, 121,
+ -59, -94, -45, -111, -124, 35, 35, 60,
+ 67, -34, 62, 106, -16, 122, -110, -14 });
+ putExpectation("SHA-512",
+ INPUT_256MB,
+ new byte[] { 36, 7, -120, 39, -87, -87, 84, -40,
+ -66, 114, 62, -73, 107, 101, -117, -12,
+ -124, 20, 109, 103, -92, 125, 111, 102,
+ 12, 114, -68, 100, 30, 25, -88, 62,
+ 108, 56, 9, -107, 89, -25, -50, 118,
+ -87, 100, 13, 37, -14, 66, -40, -97,
+ 105, -27, 79, -62, 53, -31, 83, 40,
+ 4, 57, 90, -81, 63, -77, -42, 113 });
+ }
+ }
+
+ private void test_MessageDigest(MessageDigest md) throws Exception {
+ String algorithm = md.getAlgorithm();
+ for (Map.Entry<String, byte[]> expectation : getExpectations(algorithm).entrySet()) {
+ String inputName = expectation.getKey();
+ byte[] expected = expectation.getValue();
+ byte[] actual;
+ if (inputName.equals(INPUT_EMPTY)) {
+ actual = md.digest();
+ } else if (inputName.equals(INPUT_256MB)) {
+ byte[] mb = new byte[1 * 1024 * 1024];
+ for (int i = 0; i < 256; i++) {
+ md.update(mb);
+ }
+ actual = md.digest();
+ } else {
+ throw new AssertionError(inputName);
+ }
+ assertEquals(algorithm, javaBytes(expected), javaBytes(actual));
+ assertEquals(algorithm, expected.length, md.getDigestLength());
+ }
+ }
+
+ private String javaBytes(byte[] bytes) {
+ StringBuilder buf = new StringBuilder();
+ buf.append("new byte[] { ");
+ for (byte b : bytes) {
+ buf.append(b);
+ buf.append(", ");
+ }
+ buf.append(" }");
+ return buf.toString();
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/SignatureTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/SignatureTest.java
new file mode 100644
index 0000000..1599bfc
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/SignatureTest.java
@@ -0,0 +1,3251 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.org.conscrypt.Conscrypt;
+import com.android.org.conscrypt.TestUtils;
+import com.android.org.conscrypt.testing.BrokenProvider;
+import com.android.org.conscrypt.testing.OpaqueProvider;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.ProviderException;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.EllipticCurve;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PSSParameterSpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class SignatureTest {
+
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
+ // 20 bytes for DSA
+ private final byte[] EMPTY_DATA = new byte[20];
+
+ @Test
+ public void test_getInstance() throws Exception {
+ ServiceTester
+ .test("Signature")
+ // Do not test AndroidKeyStore's Signature. It needs an AndroidKeyStore-specific
+ // key. It's OKish not to test AndroidKeyStore's Signature here because it's tested
+ // by cts/tests/test/keystore.
+ .skipProvider("AndroidKeyStore")
+ .skipProvider("AndroidKeyStoreBCWorkaround")
+ // The SunMSCAPI is very strange, including only supporting its own keys,
+ // so don't test it.
+ .skipProvider("SunMSCAPI")
+ // SunPKCS11-NSS has a problem where failed verifications can leave the
+ // operation open, which results in future init() calls to throw an exception.
+ // This appears to be a problem in the underlying library (see
+ // https://bugs.openjdk.java.net/browse/JDK-8044554), but skip verifying it all
+ // the same.
+ .skipProvider("SunPKCS11-NSS")
+ // We don't have code to generate key pairs for these yet.
+ .skipAlgorithm("Ed448")
+ .skipAlgorithm("Ed25519")
+ .skipAlgorithm("EdDSA")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider provider, String algorithm) throws Exception {
+ KeyPair kp = keyPair(algorithm);
+ // Signature.getInstance(String)
+ Signature sig1 = Signature.getInstance(algorithm);
+ assertEquals(algorithm, sig1.getAlgorithm());
+ test_Signature(sig1, kp);
+
+ // Signature.getInstance(String, Provider)
+ Signature sig2 = Signature.getInstance(algorithm, provider);
+ assertEquals(algorithm, sig2.getAlgorithm());
+ assertEquals(provider, sig2.getProvider());
+ test_Signature(sig2, kp);
+
+ // Signature.getInstance(String, String)
+ Signature sig3 = Signature.getInstance(algorithm, provider.getName());
+ assertEquals(algorithm, sig3.getAlgorithm());
+ assertEquals(provider, sig3.getProvider());
+ test_Signature(sig3, kp);
+ }
+ });
+ }
+
+ private final Map<String, KeyPair> keypairAlgorithmToInstance
+ = new HashMap<String, KeyPair>();
+
+ private KeyPair keyPair(String sigAlgorithm) throws Exception {
+ String sigAlgorithmUpperCase = sigAlgorithm.toUpperCase(Locale.US);
+ if (sigAlgorithmUpperCase.endsWith("ENCRYPTION")) {
+ sigAlgorithm = sigAlgorithm.substring(0, sigAlgorithm.length()-"ENCRYPTION".length());
+ sigAlgorithmUpperCase = sigAlgorithm.toUpperCase(Locale.US);
+ }
+
+ String kpAlgorithm;
+ // note ECDSA must be before DSA
+ if (sigAlgorithmUpperCase.endsWith("ECDSA")
+ || sigAlgorithmUpperCase.endsWith("ECDSAINP1363FORMAT")) {
+ kpAlgorithm = "EC";
+ } else if (sigAlgorithmUpperCase.endsWith("DSA")
+ || sigAlgorithmUpperCase.endsWith("DSAINP1363FORMAT")) {
+ kpAlgorithm = "DSA";
+ } else if (sigAlgorithmUpperCase.endsWith("RSA")
+ || sigAlgorithmUpperCase.endsWith("RSA/PSS")
+ || sigAlgorithmUpperCase.endsWith("RSASSA-PSS")) {
+ kpAlgorithm = "RSA";
+ } else {
+ throw new Exception("Unknown KeyPair algorithm for Signature algorithm "
+ + sigAlgorithm);
+ }
+
+ KeyPair kp = keypairAlgorithmToInstance.get(kpAlgorithm);
+ if (kp == null) {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpAlgorithm);
+ if (kpAlgorithm.equals("DSA")) {
+ kpg.initialize(1024);
+ }
+ kp = kpg.generateKeyPair();
+ keypairAlgorithmToInstance.put(kpAlgorithm, kp);
+ }
+ return kp;
+ }
+
+ private AlgorithmParameterSpec getAlgParamSpec(String algorithm) {
+ if (algorithm.equalsIgnoreCase("RSASSA-PSS")) {
+ return PSSParameterSpec.DEFAULT;
+ }
+ return null;
+ }
+
+ private void test_Signature(Signature sig, KeyPair keyPair) throws Exception {
+ AlgorithmParameterSpec params = getAlgParamSpec(sig.getAlgorithm());
+ sig.initSign(keyPair.getPrivate());
+ if (params != null) {
+ sig.setParameter(params);
+ }
+ sig.update(EMPTY_DATA);
+ byte[] signature = sig.sign();
+ assertNotNull(sig.getAlgorithm(), signature);
+ assertTrue(sig.getAlgorithm(), signature.length > 0);
+
+ sig.initVerify(keyPair.getPublic());
+ if (params != null) {
+ sig.setParameter(params);
+ }
+ sig.update(EMPTY_DATA);
+ assertTrue(sig.getAlgorithm(), sig.verify(signature));
+
+ // After verify, should be reusable as if we are after initVerify
+ sig.update(EMPTY_DATA);
+ assertTrue(sig.getAlgorithm(), sig.verify(signature));
+
+ /*
+ * The RI appears to clear out the input data in RawDSA while calling
+ * verify a second time.
+ */
+ if (StandardNames.IS_RI && (
+ "NONEwithDSA".equalsIgnoreCase(sig.getAlgorithm())
+ || "NONEwithDSAinP1363Format".equalsIgnoreCase(sig.getAlgorithm())
+ || "RawDSA".equalsIgnoreCase(sig.getAlgorithm()))) {
+ try {
+ sig.verify(signature);
+ fail("Expected RI to have a NONEwithDSA bug");
+ } catch (SignatureException bug) {
+ }
+ } else if (StandardNames.IS_RI
+ && "NONEwithECDSA".equalsIgnoreCase(sig.getAlgorithm())
+ && "SunPKCS11-NSS".equalsIgnoreCase(sig.getProvider().getName())) {
+ // This provider doesn't work properly
+ try {
+ sig.verify(signature);
+ fail("Expected RI to have a NONEwithECDSA bug");
+ } catch (ProviderException bug) {
+ }
+ } else {
+ // Calling Signature.verify a second time should not throw
+ // http://code.google.com/p/android/issues/detail?id=34933
+ sig.verify(signature);
+ }
+
+ if (Conscrypt.isConscrypt(sig.getProvider())) {
+ testSignature_MultipleThreads_Misuse(sig, keyPair.getPrivate());
+ }
+ }
+
+ private static final byte[] PK_BYTES = TestUtils.decodeHex(
+ "30819f300d06092a864886f70d010101050003818d0030818902818100cd769d178f61475fce3001"
+ + "2604218320c77a427121d3b41dd76756c8fc0c428cd15cb754adc85466f47547b1c85623d9c17fc6"
+ + "4f202fca21099caf99460c824ad657caa8c2db34996838d32623c4f23c8b6a4e6698603901262619"
+ + "4840e0896b1a6ec4f6652484aad04569bb6a885b822a10d700224359c632dc7324520cbb3d020301"
+ + "0001");
+ private static final byte[] CONTENT = TestUtils.decodeHex(
+ "f2fa9d73656e00fa01edc12e73656e2e7670632e6432004867268c46dd95030b93ce7260423e5c00"
+ + "fabd4d656d6265727300fa018dc12e73656e2e7670632e643100d7c258dc00fabd44657669636573"
+ + "00faa54b65797300fa02b5c12e4d2e4b009471968cc68835f8a68dde10f53d19693d480de767e5fb"
+ + "976f3562324006372300fabdfd04e1f51ef3aa00fa8d00000001a203e202859471968cc68835f8a6"
+ + "8dde10f53d19693d480de767e5fb976f356232400637230002bab504e1f51ef5810002c29d28463f"
+ + "0003da8d000001e201eaf2fa9d73656e00fa01edc12e73656e2e7670632e6432004867268c46dd95"
+ + "030b93ce7260423e5c00fabd4d656d6265727300fa018dc12e73656e2e7670632e643100d7c258dc"
+ + "00fabd4465766963657300faa54b65797300fa02b5c12e4d2e4b009471968cc68835f8a68dde10f5"
+ + "3d19693d480de767e5fb976f3562324006372300fabdfd04e1f51ef3aa000003e202859471968cc6"
+ + "8835f8a68dde10f53d19693d480de767e5fb976f3562324006372300000000019a0a9530819f300d"
+ + "06092a864886f70d010101050003818d0030818902818100cd769d178f61475fce30012604218320"
+ + "c77a427121d3b41dd76756c8fc0c428cd15cb754adc85466f47547b1c85623d9c17fc64f202fca21"
+ + "099caf99460c824ad657caa8c2db34996838d32623c4f23c8b6a4e66986039012626194840e0896b"
+ + "1a6ec4f6652484aad04569bb6a885b822a10d700224359c632dc7324520cbb3d020301000100");
+ private static final byte[] SIGNATURE = TestUtils.decodeHex(
+ "b4016456148cd2e9f580470aad63d19c1fee52b38c9dcb5b4d61a7ca369a7277497775d106d86394"
+ + "a69229184333b5a3e6261d5bcebdb02530ca9909f4d790199eae7c140f7db39dee2232191bdf0bfb"
+ + "34fdadc44326b9b3f3fa828652bab07f0362ac141c8c3784ebdec44e0b156a5e7bccdc81a56fe954"
+ + "56ac8c0e4ae12d97");
+
+
+ /**
+ * This should actually fail because the ASN.1 encoding is incorrect. It is
+ * missing the NULL in the AlgorithmIdentifier field.
+ * <p>
+ * http://code.google.com/p/android/issues/detail?id=18566 <br/>
+ * http://b/5038554
+ */
+ @Test
+ public void test18566_AlgorithmOid_MissingNull_Failure() throws Exception {
+ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(PK_BYTES);
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ PublicKey pk = keyFactory.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA256withRSA");
+ sig.initVerify(pk);
+ sig.update(CONTENT);
+ assertFalse(sig.verify(SIGNATURE));
+ }
+
+ /*
+ * Test vectors generated with this private key:
+ *
+ * -----BEGIN RSA PRIVATE KEY-----
+ * MIIEpAIBAAKCAQEA4Ec+irjyKE/rnnQv+XSPoRjtmGM8kvUq63ouvg075gMpvnZq
+ * 0Q62pRXQ0s/ZvqeTDwwwZTeJn3lYzT6FsB+IGFJNMSWEqUslHjYltUFB7b/uGYgI
+ * 4buX/Hy0m56qr2jpyY19DtxTu8D6ADQ1bWMF+7zDxwAUBThqu8hzyw8+90JfPTPf
+ * ezFa4DbSoLZq/UdQOxab8247UWJRW3Ff2oPeryxYrrmr+zCXw8yd2dvl7ylsF2E5
+ * Ao6KZx5jBW1F9AGI0sQTNJCEXeUsJTTpxrJHjAe9rpKII7YtBmx3cPn2Pz26JH9T
+ * CER0e+eqqF2FO4vSRKzsPePImrRkU6tNJMOsaQIDAQABAoIBADd4R3al8XaY9ayW
+ * DfuDobZ1ZOZIvQWXz4q4CHGG8macJ6nsvdSA8Bl6gNBzCebGqW+SUzHlf4tKxvTU
+ * XtpFojJpwJ/EKMB6Tm7fc4oV3sl/q9Lyu0ehTyDqcvz+TDbgGtp3vRN82NTaELsW
+ * LpSkZilx8XX5hfoYjwVsuX7igW9Dq503R2Ekhs2owWGWwwgYqZXshdOEZ3kSZ7O/
+ * IfJzcQppJYYldoQcW2cSwS1L0govMpmtt8E12l6VFavadufK8qO+gFUdBzt4vxFi
+ * xIrSt/R0OgI47k0lL31efmUzzK5kzLOTYAdaL9HgNOw65c6cQIzL8OJeQRQCFoez
+ * 3UdUroECgYEA9UGIS8Nzeyki1BGe9F4t7izUy7dfRVBaFXqlAJ+Zxzot8HJKxGAk
+ * MGMy6omBd2NFRl3G3x4KbxQK/ztzluaomUrF2qloc0cv43dJ0U6z4HXmKdvrNYMz
+ * im82SdCiZUp6Qv2atr+krE1IHTkLsimwZL3DEcwb4bYxidp8QM3s8rECgYEA6hp0
+ * LduIHO23KIyH442GjdekCdFaQ/RF1Td6C1cx3b/KLa8oqOE81cCvzsM0fXSjniNa
+ * PNljPydN4rlPkt9DgzkR2enxz1jyfeLgj/RZZMcg0+whOdx8r8kSlTzeyy81Wi4s
+ * NaUPrXVMs7IxZkJLo7bjESoriYw4xcFe2yOGkzkCgYBRgo8exv2ZYCmQG68dfjN7
+ * pfCvJ+mE6tiVrOYr199O5FoiQInyzBUa880XP84EdLywTzhqLNzA4ANrokGfVFeS
+ * YtRxAL6TGYSj76Bb7PFBV03AebOpXEqD5sQ/MhTW3zLVEt4ZgIXlMeYWuD/X3Z0f
+ * TiYHwzM9B8VdEH0dOJNYcQKBgQDbT7UPUN6O21P/NMgJMYigUShn2izKBIl3WeWH
+ * wkQBDa+GZNWegIPRbBZHiTAfZ6nweAYNg0oq29NnV1toqKhCwrAqibPzH8zsiiL+
+ * OVeVxcbHQitOXXSh6ajzDndZufwtY5wfFWc+hOk6XvFQb0MVODw41Fy9GxQEj0ch
+ * 3IIyYQKBgQDYEUWTr0FfthLb8ZI3ENVNB0hiBadqO0MZSWjA3/HxHvD2GkozfV/T
+ * dBu8lkDkR7i2tsR8OsEgQ1fTsMVbqShr2nP2KSlvX6kUbYl2NX08dR51FIaWpAt0
+ * aFyCzjCQLWOdck/yTV4ulAfuNO3tLjtN9lqpvP623yjQe6aQPxZXaA==
+ * -----END RSA PRIVATE KEY-----
+ *
+ */
+
+ private static final BigInteger RSA_2048_modulus = new BigInteger(new byte[] {
+ (byte) 0x00, (byte) 0xe0, (byte) 0x47, (byte) 0x3e, (byte) 0x8a, (byte) 0xb8, (byte) 0xf2, (byte) 0x28,
+ (byte) 0x4f, (byte) 0xeb, (byte) 0x9e, (byte) 0x74, (byte) 0x2f, (byte) 0xf9, (byte) 0x74, (byte) 0x8f,
+ (byte) 0xa1, (byte) 0x18, (byte) 0xed, (byte) 0x98, (byte) 0x63, (byte) 0x3c, (byte) 0x92, (byte) 0xf5,
+ (byte) 0x2a, (byte) 0xeb, (byte) 0x7a, (byte) 0x2e, (byte) 0xbe, (byte) 0x0d, (byte) 0x3b, (byte) 0xe6,
+ (byte) 0x03, (byte) 0x29, (byte) 0xbe, (byte) 0x76, (byte) 0x6a, (byte) 0xd1, (byte) 0x0e, (byte) 0xb6,
+ (byte) 0xa5, (byte) 0x15, (byte) 0xd0, (byte) 0xd2, (byte) 0xcf, (byte) 0xd9, (byte) 0xbe, (byte) 0xa7,
+ (byte) 0x93, (byte) 0x0f, (byte) 0x0c, (byte) 0x30, (byte) 0x65, (byte) 0x37, (byte) 0x89, (byte) 0x9f,
+ (byte) 0x79, (byte) 0x58, (byte) 0xcd, (byte) 0x3e, (byte) 0x85, (byte) 0xb0, (byte) 0x1f, (byte) 0x88,
+ (byte) 0x18, (byte) 0x52, (byte) 0x4d, (byte) 0x31, (byte) 0x25, (byte) 0x84, (byte) 0xa9, (byte) 0x4b,
+ (byte) 0x25, (byte) 0x1e, (byte) 0x36, (byte) 0x25, (byte) 0xb5, (byte) 0x41, (byte) 0x41, (byte) 0xed,
+ (byte) 0xbf, (byte) 0xee, (byte) 0x19, (byte) 0x88, (byte) 0x08, (byte) 0xe1, (byte) 0xbb, (byte) 0x97,
+ (byte) 0xfc, (byte) 0x7c, (byte) 0xb4, (byte) 0x9b, (byte) 0x9e, (byte) 0xaa, (byte) 0xaf, (byte) 0x68,
+ (byte) 0xe9, (byte) 0xc9, (byte) 0x8d, (byte) 0x7d, (byte) 0x0e, (byte) 0xdc, (byte) 0x53, (byte) 0xbb,
+ (byte) 0xc0, (byte) 0xfa, (byte) 0x00, (byte) 0x34, (byte) 0x35, (byte) 0x6d, (byte) 0x63, (byte) 0x05,
+ (byte) 0xfb, (byte) 0xbc, (byte) 0xc3, (byte) 0xc7, (byte) 0x00, (byte) 0x14, (byte) 0x05, (byte) 0x38,
+ (byte) 0x6a, (byte) 0xbb, (byte) 0xc8, (byte) 0x73, (byte) 0xcb, (byte) 0x0f, (byte) 0x3e, (byte) 0xf7,
+ (byte) 0x42, (byte) 0x5f, (byte) 0x3d, (byte) 0x33, (byte) 0xdf, (byte) 0x7b, (byte) 0x31, (byte) 0x5a,
+ (byte) 0xe0, (byte) 0x36, (byte) 0xd2, (byte) 0xa0, (byte) 0xb6, (byte) 0x6a, (byte) 0xfd, (byte) 0x47,
+ (byte) 0x50, (byte) 0x3b, (byte) 0x16, (byte) 0x9b, (byte) 0xf3, (byte) 0x6e, (byte) 0x3b, (byte) 0x51,
+ (byte) 0x62, (byte) 0x51, (byte) 0x5b, (byte) 0x71, (byte) 0x5f, (byte) 0xda, (byte) 0x83, (byte) 0xde,
+ (byte) 0xaf, (byte) 0x2c, (byte) 0x58, (byte) 0xae, (byte) 0xb9, (byte) 0xab, (byte) 0xfb, (byte) 0x30,
+ (byte) 0x97, (byte) 0xc3, (byte) 0xcc, (byte) 0x9d, (byte) 0xd9, (byte) 0xdb, (byte) 0xe5, (byte) 0xef,
+ (byte) 0x29, (byte) 0x6c, (byte) 0x17, (byte) 0x61, (byte) 0x39, (byte) 0x02, (byte) 0x8e, (byte) 0x8a,
+ (byte) 0x67, (byte) 0x1e, (byte) 0x63, (byte) 0x05, (byte) 0x6d, (byte) 0x45, (byte) 0xf4, (byte) 0x01,
+ (byte) 0x88, (byte) 0xd2, (byte) 0xc4, (byte) 0x13, (byte) 0x34, (byte) 0x90, (byte) 0x84, (byte) 0x5d,
+ (byte) 0xe5, (byte) 0x2c, (byte) 0x25, (byte) 0x34, (byte) 0xe9, (byte) 0xc6, (byte) 0xb2, (byte) 0x47,
+ (byte) 0x8c, (byte) 0x07, (byte) 0xbd, (byte) 0xae, (byte) 0x92, (byte) 0x88, (byte) 0x23, (byte) 0xb6,
+ (byte) 0x2d, (byte) 0x06, (byte) 0x6c, (byte) 0x77, (byte) 0x70, (byte) 0xf9, (byte) 0xf6, (byte) 0x3f,
+ (byte) 0x3d, (byte) 0xba, (byte) 0x24, (byte) 0x7f, (byte) 0x53, (byte) 0x08, (byte) 0x44, (byte) 0x74,
+ (byte) 0x7b, (byte) 0xe7, (byte) 0xaa, (byte) 0xa8, (byte) 0x5d, (byte) 0x85, (byte) 0x3b, (byte) 0x8b,
+ (byte) 0xd2, (byte) 0x44, (byte) 0xac, (byte) 0xec, (byte) 0x3d, (byte) 0xe3, (byte) 0xc8, (byte) 0x9a,
+ (byte) 0xb4, (byte) 0x64, (byte) 0x53, (byte) 0xab, (byte) 0x4d, (byte) 0x24, (byte) 0xc3, (byte) 0xac,
+ (byte) 0x69,
+ });
+
+ private static final BigInteger RSA_2048_privateExponent = new BigInteger(new byte[] {
+ (byte) 0x37, (byte) 0x78, (byte) 0x47, (byte) 0x76, (byte) 0xa5, (byte) 0xf1, (byte) 0x76, (byte) 0x98,
+ (byte) 0xf5, (byte) 0xac, (byte) 0x96, (byte) 0x0d, (byte) 0xfb, (byte) 0x83, (byte) 0xa1, (byte) 0xb6,
+ (byte) 0x75, (byte) 0x64, (byte) 0xe6, (byte) 0x48, (byte) 0xbd, (byte) 0x05, (byte) 0x97, (byte) 0xcf,
+ (byte) 0x8a, (byte) 0xb8, (byte) 0x08, (byte) 0x71, (byte) 0x86, (byte) 0xf2, (byte) 0x66, (byte) 0x9c,
+ (byte) 0x27, (byte) 0xa9, (byte) 0xec, (byte) 0xbd, (byte) 0xd4, (byte) 0x80, (byte) 0xf0, (byte) 0x19,
+ (byte) 0x7a, (byte) 0x80, (byte) 0xd0, (byte) 0x73, (byte) 0x09, (byte) 0xe6, (byte) 0xc6, (byte) 0xa9,
+ (byte) 0x6f, (byte) 0x92, (byte) 0x53, (byte) 0x31, (byte) 0xe5, (byte) 0x7f, (byte) 0x8b, (byte) 0x4a,
+ (byte) 0xc6, (byte) 0xf4, (byte) 0xd4, (byte) 0x5e, (byte) 0xda, (byte) 0x45, (byte) 0xa2, (byte) 0x32,
+ (byte) 0x69, (byte) 0xc0, (byte) 0x9f, (byte) 0xc4, (byte) 0x28, (byte) 0xc0, (byte) 0x7a, (byte) 0x4e,
+ (byte) 0x6e, (byte) 0xdf, (byte) 0x73, (byte) 0x8a, (byte) 0x15, (byte) 0xde, (byte) 0xc9, (byte) 0x7f,
+ (byte) 0xab, (byte) 0xd2, (byte) 0xf2, (byte) 0xbb, (byte) 0x47, (byte) 0xa1, (byte) 0x4f, (byte) 0x20,
+ (byte) 0xea, (byte) 0x72, (byte) 0xfc, (byte) 0xfe, (byte) 0x4c, (byte) 0x36, (byte) 0xe0, (byte) 0x1a,
+ (byte) 0xda, (byte) 0x77, (byte) 0xbd, (byte) 0x13, (byte) 0x7c, (byte) 0xd8, (byte) 0xd4, (byte) 0xda,
+ (byte) 0x10, (byte) 0xbb, (byte) 0x16, (byte) 0x2e, (byte) 0x94, (byte) 0xa4, (byte) 0x66, (byte) 0x29,
+ (byte) 0x71, (byte) 0xf1, (byte) 0x75, (byte) 0xf9, (byte) 0x85, (byte) 0xfa, (byte) 0x18, (byte) 0x8f,
+ (byte) 0x05, (byte) 0x6c, (byte) 0xb9, (byte) 0x7e, (byte) 0xe2, (byte) 0x81, (byte) 0x6f, (byte) 0x43,
+ (byte) 0xab, (byte) 0x9d, (byte) 0x37, (byte) 0x47, (byte) 0x61, (byte) 0x24, (byte) 0x86, (byte) 0xcd,
+ (byte) 0xa8, (byte) 0xc1, (byte) 0x61, (byte) 0x96, (byte) 0xc3, (byte) 0x08, (byte) 0x18, (byte) 0xa9,
+ (byte) 0x95, (byte) 0xec, (byte) 0x85, (byte) 0xd3, (byte) 0x84, (byte) 0x67, (byte) 0x79, (byte) 0x12,
+ (byte) 0x67, (byte) 0xb3, (byte) 0xbf, (byte) 0x21, (byte) 0xf2, (byte) 0x73, (byte) 0x71, (byte) 0x0a,
+ (byte) 0x69, (byte) 0x25, (byte) 0x86, (byte) 0x25, (byte) 0x76, (byte) 0x84, (byte) 0x1c, (byte) 0x5b,
+ (byte) 0x67, (byte) 0x12, (byte) 0xc1, (byte) 0x2d, (byte) 0x4b, (byte) 0xd2, (byte) 0x0a, (byte) 0x2f,
+ (byte) 0x32, (byte) 0x99, (byte) 0xad, (byte) 0xb7, (byte) 0xc1, (byte) 0x35, (byte) 0xda, (byte) 0x5e,
+ (byte) 0x95, (byte) 0x15, (byte) 0xab, (byte) 0xda, (byte) 0x76, (byte) 0xe7, (byte) 0xca, (byte) 0xf2,
+ (byte) 0xa3, (byte) 0xbe, (byte) 0x80, (byte) 0x55, (byte) 0x1d, (byte) 0x07, (byte) 0x3b, (byte) 0x78,
+ (byte) 0xbf, (byte) 0x11, (byte) 0x62, (byte) 0xc4, (byte) 0x8a, (byte) 0xd2, (byte) 0xb7, (byte) 0xf4,
+ (byte) 0x74, (byte) 0x3a, (byte) 0x02, (byte) 0x38, (byte) 0xee, (byte) 0x4d, (byte) 0x25, (byte) 0x2f,
+ (byte) 0x7d, (byte) 0x5e, (byte) 0x7e, (byte) 0x65, (byte) 0x33, (byte) 0xcc, (byte) 0xae, (byte) 0x64,
+ (byte) 0xcc, (byte) 0xb3, (byte) 0x93, (byte) 0x60, (byte) 0x07, (byte) 0x5a, (byte) 0x2f, (byte) 0xd1,
+ (byte) 0xe0, (byte) 0x34, (byte) 0xec, (byte) 0x3a, (byte) 0xe5, (byte) 0xce, (byte) 0x9c, (byte) 0x40,
+ (byte) 0x8c, (byte) 0xcb, (byte) 0xf0, (byte) 0xe2, (byte) 0x5e, (byte) 0x41, (byte) 0x14, (byte) 0x02,
+ (byte) 0x16, (byte) 0x87, (byte) 0xb3, (byte) 0xdd, (byte) 0x47, (byte) 0x54, (byte) 0xae, (byte) 0x81,
+ });
+
+ private static final BigInteger RSA_2048_publicExponent = new BigInteger(new byte[] {
+ (byte) 0x01, (byte) 0x00, (byte) 0x01,
+ });
+
+ private static final BigInteger RSA_2048_primeP = new BigInteger(new byte[] {
+ (byte) 0x00, (byte) 0xf5, (byte) 0x41, (byte) 0x88, (byte) 0x4b, (byte) 0xc3, (byte) 0x73, (byte) 0x7b,
+ (byte) 0x29, (byte) 0x22, (byte) 0xd4, (byte) 0x11, (byte) 0x9e, (byte) 0xf4, (byte) 0x5e, (byte) 0x2d,
+ (byte) 0xee, (byte) 0x2c, (byte) 0xd4, (byte) 0xcb, (byte) 0xb7, (byte) 0x5f, (byte) 0x45, (byte) 0x50,
+ (byte) 0x5a, (byte) 0x15, (byte) 0x7a, (byte) 0xa5, (byte) 0x00, (byte) 0x9f, (byte) 0x99, (byte) 0xc7,
+ (byte) 0x3a, (byte) 0x2d, (byte) 0xf0, (byte) 0x72, (byte) 0x4a, (byte) 0xc4, (byte) 0x60, (byte) 0x24,
+ (byte) 0x30, (byte) 0x63, (byte) 0x32, (byte) 0xea, (byte) 0x89, (byte) 0x81, (byte) 0x77, (byte) 0x63,
+ (byte) 0x45, (byte) 0x46, (byte) 0x5d, (byte) 0xc6, (byte) 0xdf, (byte) 0x1e, (byte) 0x0a, (byte) 0x6f,
+ (byte) 0x14, (byte) 0x0a, (byte) 0xff, (byte) 0x3b, (byte) 0x73, (byte) 0x96, (byte) 0xe6, (byte) 0xa8,
+ (byte) 0x99, (byte) 0x4a, (byte) 0xc5, (byte) 0xda, (byte) 0xa9, (byte) 0x68, (byte) 0x73, (byte) 0x47,
+ (byte) 0x2f, (byte) 0xe3, (byte) 0x77, (byte) 0x49, (byte) 0xd1, (byte) 0x4e, (byte) 0xb3, (byte) 0xe0,
+ (byte) 0x75, (byte) 0xe6, (byte) 0x29, (byte) 0xdb, (byte) 0xeb, (byte) 0x35, (byte) 0x83, (byte) 0x33,
+ (byte) 0x8a, (byte) 0x6f, (byte) 0x36, (byte) 0x49, (byte) 0xd0, (byte) 0xa2, (byte) 0x65, (byte) 0x4a,
+ (byte) 0x7a, (byte) 0x42, (byte) 0xfd, (byte) 0x9a, (byte) 0xb6, (byte) 0xbf, (byte) 0xa4, (byte) 0xac,
+ (byte) 0x4d, (byte) 0x48, (byte) 0x1d, (byte) 0x39, (byte) 0x0b, (byte) 0xb2, (byte) 0x29, (byte) 0xb0,
+ (byte) 0x64, (byte) 0xbd, (byte) 0xc3, (byte) 0x11, (byte) 0xcc, (byte) 0x1b, (byte) 0xe1, (byte) 0xb6,
+ (byte) 0x31, (byte) 0x89, (byte) 0xda, (byte) 0x7c, (byte) 0x40, (byte) 0xcd, (byte) 0xec, (byte) 0xf2,
+ (byte) 0xb1,
+ });
+
+ private static final BigInteger RSA_2048_primeQ = new BigInteger(new byte[] {
+ (byte) 0x00, (byte) 0xea, (byte) 0x1a, (byte) 0x74, (byte) 0x2d, (byte) 0xdb, (byte) 0x88, (byte) 0x1c,
+ (byte) 0xed, (byte) 0xb7, (byte) 0x28, (byte) 0x8c, (byte) 0x87, (byte) 0xe3, (byte) 0x8d, (byte) 0x86,
+ (byte) 0x8d, (byte) 0xd7, (byte) 0xa4, (byte) 0x09, (byte) 0xd1, (byte) 0x5a, (byte) 0x43, (byte) 0xf4,
+ (byte) 0x45, (byte) 0xd5, (byte) 0x37, (byte) 0x7a, (byte) 0x0b, (byte) 0x57, (byte) 0x31, (byte) 0xdd,
+ (byte) 0xbf, (byte) 0xca, (byte) 0x2d, (byte) 0xaf, (byte) 0x28, (byte) 0xa8, (byte) 0xe1, (byte) 0x3c,
+ (byte) 0xd5, (byte) 0xc0, (byte) 0xaf, (byte) 0xce, (byte) 0xc3, (byte) 0x34, (byte) 0x7d, (byte) 0x74,
+ (byte) 0xa3, (byte) 0x9e, (byte) 0x23, (byte) 0x5a, (byte) 0x3c, (byte) 0xd9, (byte) 0x63, (byte) 0x3f,
+ (byte) 0x27, (byte) 0x4d, (byte) 0xe2, (byte) 0xb9, (byte) 0x4f, (byte) 0x92, (byte) 0xdf, (byte) 0x43,
+ (byte) 0x83, (byte) 0x39, (byte) 0x11, (byte) 0xd9, (byte) 0xe9, (byte) 0xf1, (byte) 0xcf, (byte) 0x58,
+ (byte) 0xf2, (byte) 0x7d, (byte) 0xe2, (byte) 0xe0, (byte) 0x8f, (byte) 0xf4, (byte) 0x59, (byte) 0x64,
+ (byte) 0xc7, (byte) 0x20, (byte) 0xd3, (byte) 0xec, (byte) 0x21, (byte) 0x39, (byte) 0xdc, (byte) 0x7c,
+ (byte) 0xaf, (byte) 0xc9, (byte) 0x12, (byte) 0x95, (byte) 0x3c, (byte) 0xde, (byte) 0xcb, (byte) 0x2f,
+ (byte) 0x35, (byte) 0x5a, (byte) 0x2e, (byte) 0x2c, (byte) 0x35, (byte) 0xa5, (byte) 0x0f, (byte) 0xad,
+ (byte) 0x75, (byte) 0x4c, (byte) 0xb3, (byte) 0xb2, (byte) 0x31, (byte) 0x66, (byte) 0x42, (byte) 0x4b,
+ (byte) 0xa3, (byte) 0xb6, (byte) 0xe3, (byte) 0x11, (byte) 0x2a, (byte) 0x2b, (byte) 0x89, (byte) 0x8c,
+ (byte) 0x38, (byte) 0xc5, (byte) 0xc1, (byte) 0x5e, (byte) 0xdb, (byte) 0x23, (byte) 0x86, (byte) 0x93,
+ (byte) 0x39,
+ });
+
+ /* Test data is: "Android.\n" */
+ private static final byte[] Vector1Data = new byte[] {
+ (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x2e,
+ (byte) 0x0a,
+ };
+
+ private static final byte[] SHA1withRSA_Vector1Signature = {
+ (byte) 0x6d, (byte) 0x5b, (byte) 0xff, (byte) 0x68, (byte) 0xda, (byte) 0x18, (byte) 0x98, (byte) 0x72,
+ (byte) 0x5c, (byte) 0x1f, (byte) 0x46, (byte) 0x51, (byte) 0x77, (byte) 0x15, (byte) 0x11, (byte) 0xcb,
+ (byte) 0xe0, (byte) 0xb9, (byte) 0x3b, (byte) 0x7d, (byte) 0xf5, (byte) 0x96, (byte) 0x98, (byte) 0x24,
+ (byte) 0x85, (byte) 0x9d, (byte) 0x3e, (byte) 0xed, (byte) 0x9b, (byte) 0xb2, (byte) 0x8a, (byte) 0x91,
+ (byte) 0xfb, (byte) 0xf6, (byte) 0x85, (byte) 0x64, (byte) 0x74, (byte) 0x18, (byte) 0xb5, (byte) 0x1c,
+ (byte) 0xb3, (byte) 0x8d, (byte) 0x99, (byte) 0x0d, (byte) 0xdf, (byte) 0xaa, (byte) 0xa6, (byte) 0xa1,
+ (byte) 0xc3, (byte) 0xb6, (byte) 0x25, (byte) 0xb3, (byte) 0x06, (byte) 0xe0, (byte) 0xef, (byte) 0x28,
+ (byte) 0xb0, (byte) 0x4d, (byte) 0x50, (byte) 0xc7, (byte) 0x75, (byte) 0x39, (byte) 0xb9, (byte) 0x2c,
+ (byte) 0x47, (byte) 0xb5, (byte) 0xe2, (byte) 0x96, (byte) 0xf8, (byte) 0xf6, (byte) 0xcb, (byte) 0xa0,
+ (byte) 0x58, (byte) 0xc9, (byte) 0x3e, (byte) 0xd5, (byte) 0xfc, (byte) 0x26, (byte) 0xd9, (byte) 0x55,
+ (byte) 0x73, (byte) 0x39, (byte) 0x75, (byte) 0xb3, (byte) 0xb0, (byte) 0x0a, (byte) 0x5f, (byte) 0x5e,
+ (byte) 0x3b, (byte) 0x4a, (byte) 0x2e, (byte) 0xb1, (byte) 0x0e, (byte) 0x7d, (byte) 0xe5, (byte) 0xcc,
+ (byte) 0x04, (byte) 0x2c, (byte) 0xd1, (byte) 0x0a, (byte) 0x32, (byte) 0xaa, (byte) 0xd9, (byte) 0x8d,
+ (byte) 0x1f, (byte) 0xcb, (byte) 0xe3, (byte) 0x7f, (byte) 0x63, (byte) 0x12, (byte) 0xb1, (byte) 0x98,
+ (byte) 0x46, (byte) 0x46, (byte) 0x07, (byte) 0xd9, (byte) 0x49, (byte) 0xd2, (byte) 0xbf, (byte) 0xb5,
+ (byte) 0xbc, (byte) 0xbb, (byte) 0xfd, (byte) 0x1c, (byte) 0xd7, (byte) 0x11, (byte) 0x94, (byte) 0xaa,
+ (byte) 0x5f, (byte) 0x7b, (byte) 0xb2, (byte) 0x0c, (byte) 0x5d, (byte) 0x94, (byte) 0x53, (byte) 0x5e,
+ (byte) 0x81, (byte) 0x5c, (byte) 0xbb, (byte) 0x1d, (byte) 0x4f, (byte) 0x30, (byte) 0xcd, (byte) 0xf8,
+ (byte) 0xd7, (byte) 0xa5, (byte) 0xfa, (byte) 0x5e, (byte) 0xe0, (byte) 0x19, (byte) 0x3f, (byte) 0xa4,
+ (byte) 0xaa, (byte) 0x56, (byte) 0x4e, (byte) 0xec, (byte) 0xeb, (byte) 0xee, (byte) 0xa2, (byte) 0x6c,
+ (byte) 0xc9, (byte) 0x4f, (byte) 0xc2, (byte) 0xcc, (byte) 0x2a, (byte) 0xbc, (byte) 0x5b, (byte) 0x09,
+ (byte) 0x10, (byte) 0x73, (byte) 0x61, (byte) 0x0c, (byte) 0x04, (byte) 0xb6, (byte) 0xb7, (byte) 0x2c,
+ (byte) 0x37, (byte) 0xd2, (byte) 0xca, (byte) 0x2d, (byte) 0x54, (byte) 0xf2, (byte) 0xf7, (byte) 0x77,
+ (byte) 0xe1, (byte) 0xba, (byte) 0x9f, (byte) 0x29, (byte) 0x07, (byte) 0xa2, (byte) 0x74, (byte) 0xc6,
+ (byte) 0xe9, (byte) 0x1e, (byte) 0xde, (byte) 0xd7, (byte) 0x9c, (byte) 0x4b, (byte) 0xb7, (byte) 0x66,
+ (byte) 0x52, (byte) 0xe8, (byte) 0xac, (byte) 0xf6, (byte) 0x76, (byte) 0xab, (byte) 0x16, (byte) 0x82,
+ (byte) 0x96, (byte) 0x87, (byte) 0x40, (byte) 0x0f, (byte) 0xad, (byte) 0x2d, (byte) 0x46, (byte) 0xa6,
+ (byte) 0x28, (byte) 0x04, (byte) 0x13, (byte) 0xc2, (byte) 0xce, (byte) 0x50, (byte) 0x56, (byte) 0x6d,
+ (byte) 0xbe, (byte) 0x0c, (byte) 0x91, (byte) 0xd0, (byte) 0x8e, (byte) 0x80, (byte) 0x9e, (byte) 0x91,
+ (byte) 0x8f, (byte) 0x62, (byte) 0xb3, (byte) 0x57, (byte) 0xd6, (byte) 0xae, (byte) 0x53, (byte) 0x91,
+ (byte) 0x83, (byte) 0xe9, (byte) 0x38, (byte) 0x77, (byte) 0x8f, (byte) 0x20, (byte) 0xdd, (byte) 0x13,
+ (byte) 0x7d, (byte) 0x15, (byte) 0x44, (byte) 0x7e, (byte) 0xb5, (byte) 0x00, (byte) 0xd6, (byte) 0x45,
+ };
+
+ private static final byte[] Vector2Data = new byte[] {
+ (byte) 0x54, (byte) 0x68, (byte) 0x69, (byte) 0x73, (byte) 0x20, (byte) 0x69, (byte) 0x73, (byte) 0x20,
+ (byte) 0x61, (byte) 0x20, (byte) 0x73, (byte) 0x69, (byte) 0x67, (byte) 0x6e, (byte) 0x65, (byte) 0x64,
+ (byte) 0x20, (byte) 0x6d, (byte) 0x65, (byte) 0x73, (byte) 0x73, (byte) 0x61, (byte) 0x67, (byte) 0x65,
+ (byte) 0x20, (byte) 0x66, (byte) 0x72, (byte) 0x6f, (byte) 0x6d, (byte) 0x20, (byte) 0x4b, (byte) 0x65,
+ (byte) 0x6e, (byte) 0x6e, (byte) 0x79, (byte) 0x20, (byte) 0x52, (byte) 0x6f, (byte) 0x6f, (byte) 0x74,
+ (byte) 0x2e, (byte) 0x0a,
+ };
+
+ private static final byte[] SHA1withRSA_Vector2Signature = new byte[] {
+ (byte) 0x2e, (byte) 0xa6, (byte) 0x33, (byte) 0xd1, (byte) 0x9d, (byte) 0xfc, (byte) 0x4e, (byte) 0x27,
+ (byte) 0xb3, (byte) 0xa8, (byte) 0x9a, (byte) 0xf2, (byte) 0x48, (byte) 0x62, (byte) 0x15, (byte) 0xa2,
+ (byte) 0xce, (byte) 0x5f, (byte) 0x2b, (byte) 0x0e, (byte) 0xc5, (byte) 0x26, (byte) 0xba, (byte) 0xd9,
+ (byte) 0x0f, (byte) 0x60, (byte) 0xeb, (byte) 0xf0, (byte) 0xd5, (byte) 0x5c, (byte) 0x6b, (byte) 0x23,
+ (byte) 0x11, (byte) 0x95, (byte) 0xa4, (byte) 0xbd, (byte) 0x11, (byte) 0x68, (byte) 0xe7, (byte) 0x3a,
+ (byte) 0x37, (byte) 0x3d, (byte) 0x79, (byte) 0xb8, (byte) 0x4f, (byte) 0xe9, (byte) 0xa1, (byte) 0x88,
+ (byte) 0xfb, (byte) 0xa9, (byte) 0x8b, (byte) 0x34, (byte) 0xa1, (byte) 0xe0, (byte) 0xca, (byte) 0x11,
+ (byte) 0xdd, (byte) 0xd0, (byte) 0x83, (byte) 0x7f, (byte) 0xc1, (byte) 0x0b, (byte) 0x16, (byte) 0x61,
+ (byte) 0xac, (byte) 0x09, (byte) 0xa2, (byte) 0xdd, (byte) 0x40, (byte) 0x5b, (byte) 0x8c, (byte) 0x7a,
+ (byte) 0xb2, (byte) 0xb4, (byte) 0x02, (byte) 0x7c, (byte) 0xd4, (byte) 0x9a, (byte) 0xe6, (byte) 0xa5,
+ (byte) 0x1a, (byte) 0x27, (byte) 0x77, (byte) 0x70, (byte) 0xe3, (byte) 0xe3, (byte) 0x71, (byte) 0xc7,
+ (byte) 0x59, (byte) 0xc7, (byte) 0x9f, (byte) 0xb8, (byte) 0xef, (byte) 0xe7, (byte) 0x15, (byte) 0x02,
+ (byte) 0x0d, (byte) 0x70, (byte) 0xdc, (byte) 0x2c, (byte) 0xe9, (byte) 0xf7, (byte) 0x63, (byte) 0x2a,
+ (byte) 0xb5, (byte) 0xee, (byte) 0x9f, (byte) 0x29, (byte) 0x56, (byte) 0x86, (byte) 0x99, (byte) 0xb3,
+ (byte) 0x0f, (byte) 0xe5, (byte) 0x1f, (byte) 0x76, (byte) 0x22, (byte) 0x3b, (byte) 0x7f, (byte) 0xa9,
+ (byte) 0x9e, (byte) 0xd4, (byte) 0xc4, (byte) 0x83, (byte) 0x5d, (byte) 0x57, (byte) 0xcc, (byte) 0x37,
+ (byte) 0xcb, (byte) 0x9a, (byte) 0x9e, (byte) 0x73, (byte) 0x44, (byte) 0x93, (byte) 0xb4, (byte) 0xf1,
+ (byte) 0x6b, (byte) 0x98, (byte) 0xa0, (byte) 0x57, (byte) 0xbb, (byte) 0x5e, (byte) 0x8f, (byte) 0x89,
+ (byte) 0x5b, (byte) 0x97, (byte) 0x26, (byte) 0xe4, (byte) 0xd0, (byte) 0x51, (byte) 0x0a, (byte) 0x5a,
+ (byte) 0xb7, (byte) 0x12, (byte) 0x1a, (byte) 0x6d, (byte) 0xb0, (byte) 0x79, (byte) 0x30, (byte) 0x51,
+ (byte) 0x83, (byte) 0x2e, (byte) 0xe2, (byte) 0x7a, (byte) 0x67, (byte) 0x66, (byte) 0xd3, (byte) 0x95,
+ (byte) 0xca, (byte) 0xfc, (byte) 0xcb, (byte) 0x92, (byte) 0x79, (byte) 0x32, (byte) 0x26, (byte) 0x86,
+ (byte) 0xe1, (byte) 0x0d, (byte) 0xd8, (byte) 0x19, (byte) 0xfa, (byte) 0x65, (byte) 0x37, (byte) 0xc9,
+ (byte) 0x4c, (byte) 0x2a, (byte) 0xe1, (byte) 0x42, (byte) 0xc7, (byte) 0xd4, (byte) 0xb7, (byte) 0xeb,
+ (byte) 0x1f, (byte) 0xc3, (byte) 0x53, (byte) 0x64, (byte) 0x6f, (byte) 0x2b, (byte) 0x78, (byte) 0x18,
+ (byte) 0x03, (byte) 0xda, (byte) 0x8d, (byte) 0x62, (byte) 0x24, (byte) 0x70, (byte) 0xab, (byte) 0xe6,
+ (byte) 0x16, (byte) 0x13, (byte) 0x24, (byte) 0x6b, (byte) 0x5f, (byte) 0xd3, (byte) 0xec, (byte) 0xc1,
+ (byte) 0x58, (byte) 0x64, (byte) 0xbd, (byte) 0x30, (byte) 0x98, (byte) 0x5e, (byte) 0x33, (byte) 0xce,
+ (byte) 0x87, (byte) 0x64, (byte) 0x14, (byte) 0x07, (byte) 0x85, (byte) 0x43, (byte) 0x3e, (byte) 0x9f,
+ (byte) 0x27, (byte) 0x9f, (byte) 0x63, (byte) 0x66, (byte) 0x9d, (byte) 0x26, (byte) 0x19, (byte) 0xc0,
+ (byte) 0x02, (byte) 0x08, (byte) 0x15, (byte) 0xcb, (byte) 0xb4, (byte) 0xaa, (byte) 0x4a, (byte) 0xc8,
+ (byte) 0xc0, (byte) 0x09, (byte) 0x15, (byte) 0x7d, (byte) 0x8a, (byte) 0x21, (byte) 0xbc, (byte) 0xa3,
+ };
+
+ /*
+ * echo 'Android.' | openssl dgst -sha224 -binary -sign privkey.pem | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] SHA224withRSA_Vector2Signature = new byte[] {
+ (byte) 0xBD, (byte) 0x3F, (byte) 0xD4, (byte) 0x20, (byte) 0x5B, (byte) 0xC0, (byte) 0x89, (byte) 0x4F,
+ (byte) 0x99, (byte) 0x6C, (byte) 0xF4, (byte) 0xA4, (byte) 0x70, (byte) 0xE3, (byte) 0x5B, (byte) 0x33,
+ (byte) 0xB3, (byte) 0xCA, (byte) 0xFE, (byte) 0x1F, (byte) 0xB9, (byte) 0x3A, (byte) 0xD6, (byte) 0x9B,
+ (byte) 0x1E, (byte) 0xDA, (byte) 0x65, (byte) 0x06, (byte) 0xBD, (byte) 0xC3, (byte) 0x2B, (byte) 0xF8,
+ (byte) 0x0E, (byte) 0xA0, (byte) 0xB5, (byte) 0x33, (byte) 0x7F, (byte) 0x15, (byte) 0xDC, (byte) 0xBB,
+ (byte) 0xDC, (byte) 0x98, (byte) 0x96, (byte) 0xF5, (byte) 0xF8, (byte) 0xE5, (byte) 0x55, (byte) 0x7D,
+ (byte) 0x48, (byte) 0x51, (byte) 0xC5, (byte) 0xAE, (byte) 0x12, (byte) 0xA2, (byte) 0x61, (byte) 0xC7,
+ (byte) 0xA2, (byte) 0x00, (byte) 0x0F, (byte) 0x35, (byte) 0x54, (byte) 0x3C, (byte) 0x7E, (byte) 0x97,
+ (byte) 0x19, (byte) 0x2D, (byte) 0x8F, (byte) 0xFD, (byte) 0x51, (byte) 0x04, (byte) 0x72, (byte) 0x23,
+ (byte) 0x65, (byte) 0x16, (byte) 0x41, (byte) 0x12, (byte) 0x46, (byte) 0xD6, (byte) 0x20, (byte) 0xB6,
+ (byte) 0x4E, (byte) 0xD6, (byte) 0xE8, (byte) 0x60, (byte) 0x91, (byte) 0x05, (byte) 0xCA, (byte) 0x57,
+ (byte) 0x6F, (byte) 0x53, (byte) 0xA4, (byte) 0x05, (byte) 0x2A, (byte) 0x37, (byte) 0xDD, (byte) 0x2E,
+ (byte) 0xA4, (byte) 0xC7, (byte) 0xBF, (byte) 0x9E, (byte) 0xF6, (byte) 0xD5, (byte) 0xD4, (byte) 0x34,
+ (byte) 0xB8, (byte) 0xB3, (byte) 0x8B, (byte) 0x66, (byte) 0x2C, (byte) 0xB6, (byte) 0x5F, (byte) 0xA4,
+ (byte) 0xB7, (byte) 0x77, (byte) 0xF8, (byte) 0x9A, (byte) 0x9C, (byte) 0x44, (byte) 0x9F, (byte) 0xF0,
+ (byte) 0xCA, (byte) 0x53, (byte) 0x56, (byte) 0x2F, (byte) 0x99, (byte) 0x2E, (byte) 0x4B, (byte) 0xA2,
+ (byte) 0x26, (byte) 0x50, (byte) 0x30, (byte) 0x97, (byte) 0x2B, (byte) 0x4B, (byte) 0x0C, (byte) 0x3E,
+ (byte) 0x28, (byte) 0x0B, (byte) 0x88, (byte) 0x87, (byte) 0x9E, (byte) 0xCE, (byte) 0xCB, (byte) 0x57,
+ (byte) 0x72, (byte) 0x6B, (byte) 0xF6, (byte) 0xD6, (byte) 0xAA, (byte) 0x4D, (byte) 0x5F, (byte) 0x19,
+ (byte) 0x7A, (byte) 0xAD, (byte) 0x44, (byte) 0x09, (byte) 0x33, (byte) 0x62, (byte) 0xC8, (byte) 0x56,
+ (byte) 0x82, (byte) 0x84, (byte) 0xBF, (byte) 0x52, (byte) 0xC6, (byte) 0xA2, (byte) 0x2B, (byte) 0xE3,
+ (byte) 0xC2, (byte) 0x7F, (byte) 0xE3, (byte) 0x06, (byte) 0xC3, (byte) 0x30, (byte) 0xB8, (byte) 0xD4,
+ (byte) 0x01, (byte) 0xE6, (byte) 0x3D, (byte) 0xDB, (byte) 0xCA, (byte) 0xE4, (byte) 0xFB, (byte) 0xA8,
+ (byte) 0x7B, (byte) 0x2D, (byte) 0x8F, (byte) 0x39, (byte) 0x7A, (byte) 0x63, (byte) 0x9F, (byte) 0x02,
+ (byte) 0xE8, (byte) 0x91, (byte) 0xD1, (byte) 0xEE, (byte) 0x60, (byte) 0xEE, (byte) 0xCA, (byte) 0xF2,
+ (byte) 0x33, (byte) 0x7D, (byte) 0xF2, (byte) 0x41, (byte) 0x52, (byte) 0x0B, (byte) 0x9B, (byte) 0x1B,
+ (byte) 0x2D, (byte) 0x89, (byte) 0x38, (byte) 0xEC, (byte) 0x24, (byte) 0x60, (byte) 0x40, (byte) 0x40,
+ (byte) 0x6F, (byte) 0xB6, (byte) 0x6F, (byte) 0x86, (byte) 0xB5, (byte) 0x0A, (byte) 0x3D, (byte) 0x98,
+ (byte) 0x77, (byte) 0x3F, (byte) 0x59, (byte) 0x41, (byte) 0x3E, (byte) 0x4D, (byte) 0xE4, (byte) 0x4E,
+ (byte) 0x91, (byte) 0xCD, (byte) 0x8E, (byte) 0x33, (byte) 0x60, (byte) 0x16, (byte) 0x8D, (byte) 0xAB,
+ (byte) 0x04, (byte) 0x14, (byte) 0xE8, (byte) 0x76, (byte) 0xF1, (byte) 0x06, (byte) 0xCD, (byte) 0x4A,
+ (byte) 0x88, (byte) 0xC7, (byte) 0x69, (byte) 0x6B, (byte) 0xC6, (byte) 0xDA, (byte) 0x9E, (byte) 0x09
+ };
+
+ private static final byte[] SHA256withRSA_Vector2Signature = new byte[] {
+ (byte) 0x18, (byte) 0x6e, (byte) 0x31, (byte) 0x1f, (byte) 0x1d, (byte) 0x44, (byte) 0x09, (byte) 0x3e,
+ (byte) 0xa0, (byte) 0xc4, (byte) 0x3d, (byte) 0xb4, (byte) 0x1b, (byte) 0xf2, (byte) 0xd8, (byte) 0xa4,
+ (byte) 0x59, (byte) 0xab, (byte) 0xb5, (byte) 0x37, (byte) 0x28, (byte) 0xb8, (byte) 0x94, (byte) 0x6b,
+ (byte) 0x6f, (byte) 0x13, (byte) 0x54, (byte) 0xff, (byte) 0xac, (byte) 0x15, (byte) 0x84, (byte) 0xd0,
+ (byte) 0xc9, (byte) 0x15, (byte) 0x5b, (byte) 0x69, (byte) 0x05, (byte) 0xf1, (byte) 0x44, (byte) 0xfd,
+ (byte) 0xde, (byte) 0xe8, (byte) 0xb4, (byte) 0x12, (byte) 0x59, (byte) 0x9e, (byte) 0x4c, (byte) 0x0b,
+ (byte) 0xd5, (byte) 0x49, (byte) 0x33, (byte) 0x28, (byte) 0xe0, (byte) 0xcb, (byte) 0x87, (byte) 0x85,
+ (byte) 0xd8, (byte) 0x18, (byte) 0x6f, (byte) 0xfe, (byte) 0xa2, (byte) 0x23, (byte) 0x82, (byte) 0xf0,
+ (byte) 0xe5, (byte) 0x39, (byte) 0x1b, (byte) 0x8c, (byte) 0x93, (byte) 0x11, (byte) 0x49, (byte) 0x72,
+ (byte) 0x2a, (byte) 0x5b, (byte) 0x25, (byte) 0xff, (byte) 0x4e, (byte) 0x88, (byte) 0x70, (byte) 0x9d,
+ (byte) 0x9d, (byte) 0xff, (byte) 0xe2, (byte) 0xc0, (byte) 0x7e, (byte) 0xc8, (byte) 0x03, (byte) 0x40,
+ (byte) 0xbe, (byte) 0x44, (byte) 0x09, (byte) 0xeb, (byte) 0x9e, (byte) 0x8e, (byte) 0x88, (byte) 0xe4,
+ (byte) 0x98, (byte) 0x82, (byte) 0x06, (byte) 0xa4, (byte) 0x9d, (byte) 0x63, (byte) 0x88, (byte) 0x65,
+ (byte) 0xa3, (byte) 0x8e, (byte) 0x0d, (byte) 0x22, (byte) 0xf3, (byte) 0x33, (byte) 0xf2, (byte) 0x40,
+ (byte) 0xe8, (byte) 0x91, (byte) 0x67, (byte) 0x72, (byte) 0x29, (byte) 0x1c, (byte) 0x08, (byte) 0xff,
+ (byte) 0x54, (byte) 0xa0, (byte) 0xcc, (byte) 0xad, (byte) 0x84, (byte) 0x88, (byte) 0x4b, (byte) 0x3b,
+ (byte) 0xef, (byte) 0xf9, (byte) 0x5e, (byte) 0xb3, (byte) 0x41, (byte) 0x6a, (byte) 0xbd, (byte) 0x94,
+ (byte) 0x16, (byte) 0x7d, (byte) 0x9d, (byte) 0x53, (byte) 0x77, (byte) 0xf1, (byte) 0x6a, (byte) 0x95,
+ (byte) 0x57, (byte) 0xad, (byte) 0x65, (byte) 0x9d, (byte) 0x75, (byte) 0x95, (byte) 0xf6, (byte) 0x6a,
+ (byte) 0xd2, (byte) 0x88, (byte) 0xea, (byte) 0x5b, (byte) 0xa2, (byte) 0x94, (byte) 0x8f, (byte) 0x5e,
+ (byte) 0x84, (byte) 0x18, (byte) 0x19, (byte) 0x46, (byte) 0x83, (byte) 0x0b, (byte) 0x6d, (byte) 0x5b,
+ (byte) 0xb9, (byte) 0xdb, (byte) 0xa4, (byte) 0xe5, (byte) 0x17, (byte) 0x02, (byte) 0x9e, (byte) 0x11,
+ (byte) 0xed, (byte) 0xd9, (byte) 0x7b, (byte) 0x83, (byte) 0x87, (byte) 0x89, (byte) 0xf3, (byte) 0xe4,
+ (byte) 0xbf, (byte) 0x0e, (byte) 0xe8, (byte) 0xdc, (byte) 0x55, (byte) 0x9c, (byte) 0xf7, (byte) 0xc9,
+ (byte) 0xc3, (byte) 0xe2, (byte) 0x2c, (byte) 0xf7, (byte) 0x8c, (byte) 0xaa, (byte) 0x17, (byte) 0x1f,
+ (byte) 0xd1, (byte) 0xc7, (byte) 0x74, (byte) 0xc7, (byte) 0x8e, (byte) 0x1c, (byte) 0x5b, (byte) 0xd2,
+ (byte) 0x31, (byte) 0x74, (byte) 0x43, (byte) 0x9a, (byte) 0x52, (byte) 0xbf, (byte) 0x89, (byte) 0xc5,
+ (byte) 0xb4, (byte) 0x80, (byte) 0x6a, (byte) 0x9e, (byte) 0x05, (byte) 0xdb, (byte) 0xbb, (byte) 0x07,
+ (byte) 0x8c, (byte) 0x08, (byte) 0x61, (byte) 0xba, (byte) 0xa4, (byte) 0xbc, (byte) 0x80, (byte) 0x3a,
+ (byte) 0xdd, (byte) 0x3b, (byte) 0x1a, (byte) 0x8c, (byte) 0x21, (byte) 0xd8, (byte) 0xa3, (byte) 0xc0,
+ (byte) 0xc7, (byte) 0xd1, (byte) 0x08, (byte) 0xe1, (byte) 0x34, (byte) 0x99, (byte) 0xc0, (byte) 0xcf,
+ (byte) 0x80, (byte) 0xff, (byte) 0xfa, (byte) 0x07, (byte) 0xef, (byte) 0x5c, (byte) 0x45, (byte) 0xe5,
+ };
+
+ private static final byte[] SHA384withRSA_Vector2Signature = new byte[] {
+ (byte) 0xaf, (byte) 0xf7, (byte) 0x7a, (byte) 0xc2, (byte) 0xbb, (byte) 0xb8, (byte) 0xbd, (byte) 0xe3,
+ (byte) 0x42, (byte) 0xaa, (byte) 0x16, (byte) 0x8a, (byte) 0x52, (byte) 0x6c, (byte) 0x99, (byte) 0x66,
+ (byte) 0x08, (byte) 0xbe, (byte) 0x15, (byte) 0xd9, (byte) 0x7c, (byte) 0x60, (byte) 0x2c, (byte) 0xac,
+ (byte) 0x4d, (byte) 0x4c, (byte) 0xf4, (byte) 0xdf, (byte) 0xbc, (byte) 0x16, (byte) 0x58, (byte) 0x0a,
+ (byte) 0x4e, (byte) 0xde, (byte) 0x8d, (byte) 0xb3, (byte) 0xbd, (byte) 0x03, (byte) 0x4e, (byte) 0x23,
+ (byte) 0x40, (byte) 0xa5, (byte) 0x80, (byte) 0xae, (byte) 0x83, (byte) 0xb4, (byte) 0x0f, (byte) 0x99,
+ (byte) 0x44, (byte) 0xc3, (byte) 0x5e, (byte) 0xdb, (byte) 0x59, (byte) 0x1d, (byte) 0xea, (byte) 0x7b,
+ (byte) 0x4d, (byte) 0xf3, (byte) 0xd2, (byte) 0xad, (byte) 0xbd, (byte) 0x21, (byte) 0x9f, (byte) 0x8e,
+ (byte) 0x87, (byte) 0x8f, (byte) 0x12, (byte) 0x13, (byte) 0x33, (byte) 0xf1, (byte) 0xc0, (byte) 0x9d,
+ (byte) 0xe7, (byte) 0xec, (byte) 0x6e, (byte) 0xad, (byte) 0xea, (byte) 0x5d, (byte) 0x69, (byte) 0xbb,
+ (byte) 0xab, (byte) 0x5b, (byte) 0xd8, (byte) 0x55, (byte) 0x56, (byte) 0xc8, (byte) 0xda, (byte) 0x81,
+ (byte) 0x41, (byte) 0xfb, (byte) 0xd3, (byte) 0x11, (byte) 0x6c, (byte) 0x97, (byte) 0xa7, (byte) 0xc3,
+ (byte) 0xf1, (byte) 0x31, (byte) 0xbf, (byte) 0xbe, (byte) 0x3f, (byte) 0xdb, (byte) 0x35, (byte) 0x85,
+ (byte) 0xb7, (byte) 0xb0, (byte) 0x75, (byte) 0x7f, (byte) 0xaf, (byte) 0xfb, (byte) 0x65, (byte) 0x61,
+ (byte) 0xc7, (byte) 0x0e, (byte) 0x63, (byte) 0xb5, (byte) 0x7d, (byte) 0x95, (byte) 0xe9, (byte) 0x16,
+ (byte) 0x9d, (byte) 0x6a, (byte) 0x00, (byte) 0x9f, (byte) 0x5e, (byte) 0xcd, (byte) 0xff, (byte) 0xa6,
+ (byte) 0xbc, (byte) 0x71, (byte) 0xf2, (byte) 0x2c, (byte) 0xd3, (byte) 0x68, (byte) 0xb9, (byte) 0x3f,
+ (byte) 0xaa, (byte) 0x06, (byte) 0xf1, (byte) 0x9c, (byte) 0x7e, (byte) 0xca, (byte) 0x4a, (byte) 0xfe,
+ (byte) 0xb1, (byte) 0x73, (byte) 0x19, (byte) 0x80, (byte) 0x05, (byte) 0xa6, (byte) 0x85, (byte) 0x14,
+ (byte) 0xda, (byte) 0x7a, (byte) 0x16, (byte) 0x7a, (byte) 0xc2, (byte) 0x46, (byte) 0x57, (byte) 0xa7,
+ (byte) 0xc0, (byte) 0xbf, (byte) 0xcd, (byte) 0xdc, (byte) 0x2f, (byte) 0x64, (byte) 0xf6, (byte) 0x6d,
+ (byte) 0xdc, (byte) 0xcb, (byte) 0x5a, (byte) 0x29, (byte) 0x95, (byte) 0x1c, (byte) 0xfe, (byte) 0xf2,
+ (byte) 0xda, (byte) 0x7e, (byte) 0xcb, (byte) 0x26, (byte) 0x12, (byte) 0xc6, (byte) 0xb0, (byte) 0xba,
+ (byte) 0x84, (byte) 0x9b, (byte) 0x4f, (byte) 0xba, (byte) 0x1b, (byte) 0x78, (byte) 0x25, (byte) 0xb8,
+ (byte) 0x8f, (byte) 0x2e, (byte) 0x51, (byte) 0x5f, (byte) 0x9e, (byte) 0xfc, (byte) 0x40, (byte) 0xbc,
+ (byte) 0x85, (byte) 0xcd, (byte) 0x86, (byte) 0x7f, (byte) 0x88, (byte) 0xc5, (byte) 0xaa, (byte) 0x2b,
+ (byte) 0x78, (byte) 0xb1, (byte) 0x9c, (byte) 0x51, (byte) 0x9a, (byte) 0xe1, (byte) 0xe1, (byte) 0xc0,
+ (byte) 0x40, (byte) 0x47, (byte) 0xcb, (byte) 0xa4, (byte) 0xb7, (byte) 0x6c, (byte) 0x31, (byte) 0xf2,
+ (byte) 0xc8, (byte) 0x9a, (byte) 0xad, (byte) 0x0b, (byte) 0xd3, (byte) 0xf6, (byte) 0x85, (byte) 0x9a,
+ (byte) 0x8f, (byte) 0x4f, (byte) 0xc9, (byte) 0xd8, (byte) 0x33, (byte) 0x7c, (byte) 0x45, (byte) 0x30,
+ (byte) 0xea, (byte) 0x17, (byte) 0xd3, (byte) 0xe3, (byte) 0x90, (byte) 0x2c, (byte) 0xda, (byte) 0xde,
+ (byte) 0x41, (byte) 0x17, (byte) 0x3f, (byte) 0x08, (byte) 0xb9, (byte) 0x34, (byte) 0xc0, (byte) 0xd1,
+ };
+
+ private static final byte[] SHA512withRSA_Vector2Signature = new byte[] {
+ (byte) 0x19, (byte) 0xe2, (byte) 0xe5, (byte) 0xf3, (byte) 0x18, (byte) 0x83, (byte) 0xec, (byte) 0xf0,
+ (byte) 0xab, (byte) 0x50, (byte) 0x05, (byte) 0x4b, (byte) 0x5f, (byte) 0x22, (byte) 0xfc, (byte) 0x82,
+ (byte) 0x6d, (byte) 0xca, (byte) 0xe7, (byte) 0xbe, (byte) 0x23, (byte) 0x94, (byte) 0xfa, (byte) 0xf9,
+ (byte) 0xa4, (byte) 0x8a, (byte) 0x95, (byte) 0x4d, (byte) 0x14, (byte) 0x08, (byte) 0x8b, (byte) 0x5e,
+ (byte) 0x03, (byte) 0x1b, (byte) 0x74, (byte) 0xde, (byte) 0xc1, (byte) 0x45, (byte) 0x9c, (byte) 0xce,
+ (byte) 0x1d, (byte) 0xac, (byte) 0xab, (byte) 0xd3, (byte) 0xa8, (byte) 0xc3, (byte) 0xca, (byte) 0x67,
+ (byte) 0x80, (byte) 0xf6, (byte) 0x03, (byte) 0x46, (byte) 0x65, (byte) 0x77, (byte) 0x59, (byte) 0xbb,
+ (byte) 0xb8, (byte) 0x83, (byte) 0xee, (byte) 0xc2, (byte) 0x3e, (byte) 0x78, (byte) 0xdd, (byte) 0x89,
+ (byte) 0xcd, (byte) 0x9b, (byte) 0x78, (byte) 0x35, (byte) 0xa9, (byte) 0x09, (byte) 0xc8, (byte) 0x77,
+ (byte) 0xdd, (byte) 0xd3, (byte) 0xa0, (byte) 0x64, (byte) 0xb0, (byte) 0x74, (byte) 0x48, (byte) 0x51,
+ (byte) 0x4f, (byte) 0xa0, (byte) 0xae, (byte) 0x33, (byte) 0xb3, (byte) 0x28, (byte) 0xb0, (byte) 0xa8,
+ (byte) 0x78, (byte) 0x8f, (byte) 0xa2, (byte) 0x32, (byte) 0xa6, (byte) 0x0a, (byte) 0xaa, (byte) 0x09,
+ (byte) 0xb5, (byte) 0x8d, (byte) 0x4c, (byte) 0x44, (byte) 0x46, (byte) 0xb4, (byte) 0xd2, (byte) 0x06,
+ (byte) 0x6b, (byte) 0x8c, (byte) 0x51, (byte) 0x6e, (byte) 0x9c, (byte) 0xfa, (byte) 0x1f, (byte) 0x94,
+ (byte) 0x3e, (byte) 0x19, (byte) 0x9c, (byte) 0x63, (byte) 0xfe, (byte) 0xa9, (byte) 0x9a, (byte) 0xe3,
+ (byte) 0x6c, (byte) 0x82, (byte) 0x64, (byte) 0x5f, (byte) 0xca, (byte) 0xc2, (byte) 0x8d, (byte) 0x66,
+ (byte) 0xbe, (byte) 0x12, (byte) 0x6e, (byte) 0xb6, (byte) 0x35, (byte) 0x6d, (byte) 0xaa, (byte) 0xed,
+ (byte) 0x4b, (byte) 0x50, (byte) 0x08, (byte) 0x1c, (byte) 0xbf, (byte) 0x07, (byte) 0x70, (byte) 0x78,
+ (byte) 0xc0, (byte) 0xbb, (byte) 0xc5, (byte) 0x8d, (byte) 0x6c, (byte) 0x8d, (byte) 0x35, (byte) 0xff,
+ (byte) 0x04, (byte) 0x81, (byte) 0xd8, (byte) 0xf4, (byte) 0xd2, (byte) 0x4a, (byte) 0xc3, (byte) 0x05,
+ (byte) 0x23, (byte) 0xcb, (byte) 0xeb, (byte) 0x20, (byte) 0xb1, (byte) 0xd4, (byte) 0x2d, (byte) 0xd8,
+ (byte) 0x7a, (byte) 0xd4, (byte) 0x7e, (byte) 0xf6, (byte) 0xa9, (byte) 0xe8, (byte) 0x72, (byte) 0x69,
+ (byte) 0xfe, (byte) 0xab, (byte) 0x54, (byte) 0x4d, (byte) 0xd1, (byte) 0xf4, (byte) 0x6b, (byte) 0x83,
+ (byte) 0x31, (byte) 0x17, (byte) 0xed, (byte) 0x26, (byte) 0xe9, (byte) 0xd2, (byte) 0x5b, (byte) 0xad,
+ (byte) 0x42, (byte) 0x42, (byte) 0xa5, (byte) 0x8f, (byte) 0x98, (byte) 0x7c, (byte) 0x1b, (byte) 0x5c,
+ (byte) 0x8e, (byte) 0x88, (byte) 0x56, (byte) 0x20, (byte) 0x8e, (byte) 0x48, (byte) 0xf9, (byte) 0x4d,
+ (byte) 0x82, (byte) 0x91, (byte) 0xcb, (byte) 0xc8, (byte) 0x1c, (byte) 0x7c, (byte) 0xa5, (byte) 0x69,
+ (byte) 0x1b, (byte) 0x40, (byte) 0xc2, (byte) 0x4c, (byte) 0x25, (byte) 0x16, (byte) 0x4f, (byte) 0xfa,
+ (byte) 0x09, (byte) 0xeb, (byte) 0xf5, (byte) 0x6c, (byte) 0x55, (byte) 0x3c, (byte) 0x6e, (byte) 0xf7,
+ (byte) 0xc0, (byte) 0xc1, (byte) 0x34, (byte) 0xd1, (byte) 0x53, (byte) 0xa3, (byte) 0x69, (byte) 0x64,
+ (byte) 0xee, (byte) 0xf4, (byte) 0xf9, (byte) 0xc7, (byte) 0x96, (byte) 0x60, (byte) 0x84, (byte) 0x87,
+ (byte) 0xb4, (byte) 0xc7, (byte) 0x3c, (byte) 0x26, (byte) 0xa7, (byte) 0x3a, (byte) 0xbf, (byte) 0x95,
+ };
+
+ private static final byte[] MD5withRSA_Vector2Signature = new byte[] {
+ (byte) 0x04, (byte) 0x17, (byte) 0x83, (byte) 0x10, (byte) 0xe2, (byte) 0x6e, (byte) 0xdf, (byte) 0xa9,
+ (byte) 0xae, (byte) 0xd2, (byte) 0xdc, (byte) 0x5f, (byte) 0x70, (byte) 0x1d, (byte) 0xaf, (byte) 0x54,
+ (byte) 0xc0, (byte) 0x5f, (byte) 0x0b, (byte) 0x2c, (byte) 0xe6, (byte) 0xd0, (byte) 0x00, (byte) 0x18,
+ (byte) 0x4c, (byte) 0xf6, (byte) 0x8f, (byte) 0x18, (byte) 0x10, (byte) 0x74, (byte) 0x90, (byte) 0x99,
+ (byte) 0xa9, (byte) 0x90, (byte) 0x3c, (byte) 0x5a, (byte) 0x38, (byte) 0xd3, (byte) 0x3d, (byte) 0x48,
+ (byte) 0xcf, (byte) 0x31, (byte) 0xaf, (byte) 0x12, (byte) 0x98, (byte) 0xfb, (byte) 0x66, (byte) 0xe8,
+ (byte) 0x58, (byte) 0xec, (byte) 0xca, (byte) 0xe1, (byte) 0x42, (byte) 0xf9, (byte) 0x84, (byte) 0x17,
+ (byte) 0x6f, (byte) 0x4c, (byte) 0x3e, (byte) 0xc4, (byte) 0x40, (byte) 0xc6, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x38, (byte) 0xf3, (byte) 0x47, (byte) 0xeb, (byte) 0x6f, (byte) 0xcb, (byte) 0xea, (byte) 0x21,
+ (byte) 0x41, (byte) 0xf3, (byte) 0xa0, (byte) 0x3e, (byte) 0x42, (byte) 0xad, (byte) 0xa5, (byte) 0xad,
+ (byte) 0x5d, (byte) 0x2c, (byte) 0x1a, (byte) 0x8e, (byte) 0x3e, (byte) 0xb3, (byte) 0xa5, (byte) 0x78,
+ (byte) 0x3d, (byte) 0x56, (byte) 0x09, (byte) 0x93, (byte) 0xc9, (byte) 0x93, (byte) 0xd3, (byte) 0xd2,
+ (byte) 0x9a, (byte) 0xc5, (byte) 0xa5, (byte) 0x2e, (byte) 0xb2, (byte) 0xd8, (byte) 0x37, (byte) 0xc7,
+ (byte) 0x13, (byte) 0x1a, (byte) 0x0b, (byte) 0xda, (byte) 0x50, (byte) 0x28, (byte) 0x6d, (byte) 0x47,
+ (byte) 0x65, (byte) 0x52, (byte) 0xcd, (byte) 0xe7, (byte) 0xec, (byte) 0x57, (byte) 0x00, (byte) 0x41,
+ (byte) 0x34, (byte) 0x28, (byte) 0xb9, (byte) 0x8b, (byte) 0x03, (byte) 0x41, (byte) 0xb6, (byte) 0xd5,
+ (byte) 0xa8, (byte) 0xef, (byte) 0xd3, (byte) 0xdd, (byte) 0x80, (byte) 0xd5, (byte) 0x69, (byte) 0xe4,
+ (byte) 0xf0, (byte) 0x4d, (byte) 0xa4, (byte) 0x7d, (byte) 0x60, (byte) 0x2f, (byte) 0xef, (byte) 0x79,
+ (byte) 0x07, (byte) 0x75, (byte) 0xeb, (byte) 0xf7, (byte) 0x4b, (byte) 0x43, (byte) 0x41, (byte) 0xdb,
+ (byte) 0x33, (byte) 0xad, (byte) 0x9c, (byte) 0x7b, (byte) 0x78, (byte) 0x83, (byte) 0x34, (byte) 0x77,
+ (byte) 0xe4, (byte) 0x80, (byte) 0xbe, (byte) 0xe6, (byte) 0x6f, (byte) 0xdd, (byte) 0xac, (byte) 0xa5,
+ (byte) 0x37, (byte) 0xcf, (byte) 0xb5, (byte) 0x44, (byte) 0x11, (byte) 0x77, (byte) 0x96, (byte) 0x45,
+ (byte) 0xf9, (byte) 0xae, (byte) 0x48, (byte) 0xa6, (byte) 0xbe, (byte) 0x30, (byte) 0x32, (byte) 0xeb,
+ (byte) 0x43, (byte) 0x6f, (byte) 0x66, (byte) 0x39, (byte) 0x57, (byte) 0xf8, (byte) 0xe6, (byte) 0x60,
+ (byte) 0x31, (byte) 0xd0, (byte) 0xfc, (byte) 0xcf, (byte) 0x9f, (byte) 0xe5, (byte) 0x3d, (byte) 0xcf,
+ (byte) 0xbd, (byte) 0x7b, (byte) 0x13, (byte) 0x20, (byte) 0xce, (byte) 0x11, (byte) 0xfd, (byte) 0xe5,
+ (byte) 0xff, (byte) 0x90, (byte) 0x85, (byte) 0xdf, (byte) 0xca, (byte) 0x3d, (byte) 0xd9, (byte) 0x44,
+ (byte) 0x16, (byte) 0xc2, (byte) 0x32, (byte) 0x28, (byte) 0xc7, (byte) 0x01, (byte) 0x6d, (byte) 0xea,
+ (byte) 0xcb, (byte) 0x0d, (byte) 0x85, (byte) 0x08, (byte) 0x6f, (byte) 0xcb, (byte) 0x41, (byte) 0x6a,
+ (byte) 0x3c, (byte) 0x0f, (byte) 0x3d, (byte) 0x38, (byte) 0xb5, (byte) 0x61, (byte) 0xc5, (byte) 0x64,
+ (byte) 0x64, (byte) 0x81, (byte) 0x4c, (byte) 0xcd, (byte) 0xd1, (byte) 0x6a, (byte) 0x87, (byte) 0x28,
+ (byte) 0x02, (byte) 0xaf, (byte) 0x8f, (byte) 0x59, (byte) 0xe5, (byte) 0x67, (byte) 0x25, (byte) 0x00,
+ };
+
+ /*
+ * openssl rsautl -raw -sign -inkey rsa.key | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] NONEwithRSA_Vector1Signature = new byte[] {
+ (byte) 0x35, (byte) 0x43, (byte) 0x38, (byte) 0x44, (byte) 0xAD, (byte) 0x3F,
+ (byte) 0x97, (byte) 0x02, (byte) 0xFB, (byte) 0x59, (byte) 0x1F, (byte) 0x4A,
+ (byte) 0x2B, (byte) 0xB9, (byte) 0x06, (byte) 0xEC, (byte) 0x66, (byte) 0xE6,
+ (byte) 0xD2, (byte) 0xC5, (byte) 0x8B, (byte) 0x7B, (byte) 0xE3, (byte) 0x18,
+ (byte) 0xBF, (byte) 0x07, (byte) 0xD6, (byte) 0x01, (byte) 0xF9, (byte) 0xD9,
+ (byte) 0x89, (byte) 0xC4, (byte) 0xDB, (byte) 0x00, (byte) 0x68, (byte) 0xFF,
+ (byte) 0x9B, (byte) 0x43, (byte) 0x90, (byte) 0xF2, (byte) 0xDB, (byte) 0x83,
+ (byte) 0xF4, (byte) 0x7E, (byte) 0xC6, (byte) 0x81, (byte) 0x01, (byte) 0x3A,
+ (byte) 0x0B, (byte) 0xE5, (byte) 0xED, (byte) 0x08, (byte) 0x73, (byte) 0x3E,
+ (byte) 0xE1, (byte) 0x3F, (byte) 0xDF, (byte) 0x1F, (byte) 0x07, (byte) 0x6D,
+ (byte) 0x22, (byte) 0x8D, (byte) 0xCC, (byte) 0x4E, (byte) 0xE3, (byte) 0x9A,
+ (byte) 0xBC, (byte) 0xCC, (byte) 0x8F, (byte) 0x9E, (byte) 0x9B, (byte) 0x02,
+ (byte) 0x48, (byte) 0x00, (byte) 0xAC, (byte) 0x9F, (byte) 0xA4, (byte) 0x8F,
+ (byte) 0x87, (byte) 0xA1, (byte) 0xA8, (byte) 0xE6, (byte) 0x9D, (byte) 0xCD,
+ (byte) 0x8B, (byte) 0x05, (byte) 0xE9, (byte) 0xD2, (byte) 0x05, (byte) 0x8D,
+ (byte) 0xC9, (byte) 0x95, (byte) 0x16, (byte) 0xD0, (byte) 0xCD, (byte) 0x43,
+ (byte) 0x25, (byte) 0x8A, (byte) 0x11, (byte) 0x46, (byte) 0xD7, (byte) 0x74,
+ (byte) 0x4C, (byte) 0xCF, (byte) 0x58, (byte) 0xF9, (byte) 0xA1, (byte) 0x30,
+ (byte) 0x84, (byte) 0x52, (byte) 0xC9, (byte) 0x01, (byte) 0x5F, (byte) 0x24,
+ (byte) 0x4C, (byte) 0xB1, (byte) 0x9F, (byte) 0x7D, (byte) 0x12, (byte) 0x38,
+ (byte) 0x27, (byte) 0x0F, (byte) 0x5E, (byte) 0xFF, (byte) 0xE0, (byte) 0x55,
+ (byte) 0x8B, (byte) 0xA3, (byte) 0xAD, (byte) 0x60, (byte) 0x35, (byte) 0x83,
+ (byte) 0x58, (byte) 0xAF, (byte) 0x99, (byte) 0xDE, (byte) 0x3F, (byte) 0x5D,
+ (byte) 0x80, (byte) 0x80, (byte) 0xFF, (byte) 0x9B, (byte) 0xDE, (byte) 0x5C,
+ (byte) 0xAB, (byte) 0x97, (byte) 0x43, (byte) 0x64, (byte) 0xD9, (byte) 0x9F,
+ (byte) 0xFB, (byte) 0x67, (byte) 0x65, (byte) 0xA5, (byte) 0x99, (byte) 0xE7,
+ (byte) 0xE6, (byte) 0xEB, (byte) 0x05, (byte) 0x95, (byte) 0xFC, (byte) 0x46,
+ (byte) 0x28, (byte) 0x4B, (byte) 0xD8, (byte) 0x8C, (byte) 0xF5, (byte) 0x0A,
+ (byte) 0xEB, (byte) 0x1F, (byte) 0x30, (byte) 0xEA, (byte) 0xE7, (byte) 0x67,
+ (byte) 0x11, (byte) 0x25, (byte) 0xF0, (byte) 0x44, (byte) 0x75, (byte) 0x74,
+ (byte) 0x94, (byte) 0x06, (byte) 0x78, (byte) 0xD0, (byte) 0x21, (byte) 0xF4,
+ (byte) 0x3F, (byte) 0xC8, (byte) 0xC4, (byte) 0x4A, (byte) 0x57, (byte) 0xBE,
+ (byte) 0x02, (byte) 0x3C, (byte) 0x93, (byte) 0xF6, (byte) 0x95, (byte) 0xFB,
+ (byte) 0xD1, (byte) 0x77, (byte) 0x8B, (byte) 0x43, (byte) 0xF0, (byte) 0xB9,
+ (byte) 0x7D, (byte) 0xE0, (byte) 0x32, (byte) 0xE1, (byte) 0x72, (byte) 0xB5,
+ (byte) 0x62, (byte) 0x3F, (byte) 0x86, (byte) 0xC3, (byte) 0xD4, (byte) 0x5F,
+ (byte) 0x5E, (byte) 0x54, (byte) 0x1B, (byte) 0x5B, (byte) 0xE6, (byte) 0x74,
+ (byte) 0xA1, (byte) 0x0B, (byte) 0xE5, (byte) 0x18, (byte) 0xD2, (byte) 0x4F,
+ (byte) 0x93, (byte) 0xF3, (byte) 0x09, (byte) 0x58, (byte) 0xCE, (byte) 0xF0,
+ (byte) 0xA3, (byte) 0x61, (byte) 0xE4, (byte) 0x6E, (byte) 0x46, (byte) 0x45,
+ (byte) 0x89, (byte) 0x50, (byte) 0xBD, (byte) 0x03, (byte) 0x3F, (byte) 0x38,
+ (byte) 0xDA, (byte) 0x5D, (byte) 0xD0, (byte) 0x1B, (byte) 0x1F, (byte) 0xB1,
+ (byte) 0xEE, (byte) 0x89, (byte) 0x59, (byte) 0xC5,
+ };
+
+ /*
+ * echo "This is a signed message from Kenny Root." | openssl sha1 -binary -out digest.bin \
+ * && openssl pkeyutl -sign -in digest.bin -inkey privkey.pem \
+ * -pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha1 -pkeyopt rsa_pss_saltlen:20 \
+ * | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] SHA1withRSAPSS_Vector2Signature = new byte[] {
+ (byte) 0x66, (byte) 0xE3, (byte) 0xA5, (byte) 0x20, (byte) 0xE9, (byte) 0x5D,
+ (byte) 0xDF, (byte) 0x99, (byte) 0xA6, (byte) 0x04, (byte) 0x77, (byte) 0xF8,
+ (byte) 0x39, (byte) 0x78, (byte) 0x74, (byte) 0xF5, (byte) 0xC2, (byte) 0x4E,
+ (byte) 0x9E, (byte) 0xEB, (byte) 0x24, (byte) 0xDE, (byte) 0xB4, (byte) 0x36,
+ (byte) 0x69, (byte) 0x1F, (byte) 0xAC, (byte) 0x01, (byte) 0xFF, (byte) 0x5A,
+ (byte) 0xE3, (byte) 0x89, (byte) 0x8A, (byte) 0xE9, (byte) 0x92, (byte) 0x32,
+ (byte) 0xA7, (byte) 0xA4, (byte) 0xC0, (byte) 0x25, (byte) 0x00, (byte) 0x14,
+ (byte) 0xFF, (byte) 0x38, (byte) 0x19, (byte) 0x37, (byte) 0x84, (byte) 0x1A,
+ (byte) 0x3D, (byte) 0xCA, (byte) 0xEE, (byte) 0xF3, (byte) 0xC6, (byte) 0x91,
+ (byte) 0xED, (byte) 0x02, (byte) 0xE6, (byte) 0x1D, (byte) 0x73, (byte) 0xDA,
+ (byte) 0xD4, (byte) 0x55, (byte) 0x93, (byte) 0x54, (byte) 0x9A, (byte) 0xE6,
+ (byte) 0x2E, (byte) 0x7D, (byte) 0x5C, (byte) 0x41, (byte) 0xAF, (byte) 0xED,
+ (byte) 0xAD, (byte) 0x8E, (byte) 0x7F, (byte) 0x47, (byte) 0x3B, (byte) 0x23,
+ (byte) 0xC3, (byte) 0xB8, (byte) 0xBB, (byte) 0xCD, (byte) 0x87, (byte) 0xC4,
+ (byte) 0xA3, (byte) 0x32, (byte) 0x16, (byte) 0x57, (byte) 0xCC, (byte) 0xB8,
+ (byte) 0xB6, (byte) 0x96, (byte) 0x84, (byte) 0x1A, (byte) 0xBC, (byte) 0xF8,
+ (byte) 0x09, (byte) 0x53, (byte) 0xB0, (byte) 0x9D, (byte) 0xE1, (byte) 0x6F,
+ (byte) 0xB2, (byte) 0xEB, (byte) 0x83, (byte) 0xDC, (byte) 0x61, (byte) 0x31,
+ (byte) 0xD7, (byte) 0x02, (byte) 0xB4, (byte) 0xD1, (byte) 0xBA, (byte) 0xBD,
+ (byte) 0xF0, (byte) 0x78, (byte) 0xC6, (byte) 0xBE, (byte) 0x1F, (byte) 0xB0,
+ (byte) 0xE1, (byte) 0xCA, (byte) 0x32, (byte) 0x57, (byte) 0x9F, (byte) 0x8C,
+ (byte) 0xD3, (byte) 0xBB, (byte) 0x04, (byte) 0x1B, (byte) 0x30, (byte) 0x74,
+ (byte) 0x5D, (byte) 0xEA, (byte) 0xD3, (byte) 0x6B, (byte) 0x74, (byte) 0x31,
+ (byte) 0x6F, (byte) 0x33, (byte) 0x5A, (byte) 0x70, (byte) 0x96, (byte) 0x8B,
+ (byte) 0xCB, (byte) 0x22, (byte) 0xF3, (byte) 0xAA, (byte) 0x74, (byte) 0x82,
+ (byte) 0xB2, (byte) 0x82, (byte) 0x71, (byte) 0x4D, (byte) 0x42, (byte) 0x13,
+ (byte) 0x3F, (byte) 0xEA, (byte) 0xE3, (byte) 0x39, (byte) 0xC5, (byte) 0x03,
+ (byte) 0x27, (byte) 0xFF, (byte) 0x78, (byte) 0xB2, (byte) 0xA6, (byte) 0x71,
+ (byte) 0x07, (byte) 0x1C, (byte) 0xB3, (byte) 0x97, (byte) 0xFB, (byte) 0xE8,
+ (byte) 0x85, (byte) 0x6D, (byte) 0x14, (byte) 0xDF, (byte) 0xF9, (byte) 0x7D,
+ (byte) 0x0D, (byte) 0x0C, (byte) 0x9F, (byte) 0xC3, (byte) 0xE2, (byte) 0xDB,
+ (byte) 0xE0, (byte) 0xA5, (byte) 0x05, (byte) 0xBC, (byte) 0x47, (byte) 0x36,
+ (byte) 0xEB, (byte) 0x1E, (byte) 0xBA, (byte) 0x60, (byte) 0x12, (byte) 0x19,
+ (byte) 0xA5, (byte) 0x7E, (byte) 0x55, (byte) 0x0C, (byte) 0x9B, (byte) 0xD4,
+ (byte) 0x9A, (byte) 0xE9, (byte) 0x72, (byte) 0x5C, (byte) 0x5B, (byte) 0xF4,
+ (byte) 0xAA, (byte) 0x4A, (byte) 0x12, (byte) 0x8B, (byte) 0xC2, (byte) 0x8E,
+ (byte) 0xC2, (byte) 0x9A, (byte) 0x3E, (byte) 0x0C, (byte) 0x40, (byte) 0xA4,
+ (byte) 0x0A, (byte) 0xFF, (byte) 0xF8, (byte) 0xC1, (byte) 0x85, (byte) 0x59,
+ (byte) 0xDA, (byte) 0xC6, (byte) 0x8C, (byte) 0x83, (byte) 0x2A, (byte) 0x68,
+ (byte) 0x84, (byte) 0x53, (byte) 0x17, (byte) 0x28, (byte) 0x78, (byte) 0x3F,
+ (byte) 0x5A, (byte) 0xA4, (byte) 0x04, (byte) 0xE6, (byte) 0x23, (byte) 0x8D,
+ (byte) 0x2A, (byte) 0x71, (byte) 0xC1, (byte) 0xBC, (byte) 0x1C, (byte) 0xFD,
+ (byte) 0x75, (byte) 0x16, (byte) 0x6E, (byte) 0x85,
+ };
+ private static final PSSParameterSpec SHA1withRSAPSS_Vector2Signature_ParameterSpec =
+ new PSSParameterSpec("SHA-1", "MGF1", MGF1ParameterSpec.SHA1, 20, 1);
+
+ /*
+ * echo "This is a signed message from Kenny Root." | openssl sha1 -binary -out digest.bin \
+ * && openssl pkeyutl -sign -in digest.bin -inkey privkey.pem \
+ * -pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha1 -pkeyopt rsa_pss_saltlen:0 \
+ * | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] SHA1withRSAPSS_NoSalt_Vector2Signature = new byte[] {
+ (byte) 0x31, (byte) 0x61, (byte) 0xA5, (byte) 0x47, (byte) 0x28, (byte) 0x44,
+ (byte) 0x48, (byte) 0x5A, (byte) 0xDA, (byte) 0x78, (byte) 0xA7, (byte) 0x85,
+ (byte) 0xE9, (byte) 0x64, (byte) 0x69, (byte) 0xCF, (byte) 0x14, (byte) 0x07,
+ (byte) 0x3F, (byte) 0xA8, (byte) 0xDB, (byte) 0xFC, (byte) 0xB7, (byte) 0x89,
+ (byte) 0x87, (byte) 0x74, (byte) 0xB9, (byte) 0x81, (byte) 0x37, (byte) 0x62,
+ (byte) 0xD1, (byte) 0x07, (byte) 0x0F, (byte) 0x3D, (byte) 0xDF, (byte) 0xA8,
+ (byte) 0x84, (byte) 0x38, (byte) 0x31, (byte) 0xEB, (byte) 0x17, (byte) 0x3F,
+ (byte) 0xE0, (byte) 0x28, (byte) 0x75, (byte) 0x1F, (byte) 0xE9, (byte) 0x4D,
+ (byte) 0xD3, (byte) 0x62, (byte) 0xFA, (byte) 0xCF, (byte) 0xCC, (byte) 0x2E,
+ (byte) 0xC7, (byte) 0x81, (byte) 0xE1, (byte) 0xEA, (byte) 0xEC, (byte) 0x78,
+ (byte) 0xFE, (byte) 0x19, (byte) 0x59, (byte) 0x54, (byte) 0x1D, (byte) 0x27,
+ (byte) 0xED, (byte) 0x0C, (byte) 0x54, (byte) 0xDF, (byte) 0xE3, (byte) 0x44,
+ (byte) 0x31, (byte) 0x21, (byte) 0x31, (byte) 0xA7, (byte) 0x23, (byte) 0xC4,
+ (byte) 0xE2, (byte) 0x69, (byte) 0x8A, (byte) 0xB3, (byte) 0x1A, (byte) 0x72,
+ (byte) 0x4F, (byte) 0x4E, (byte) 0x82, (byte) 0x86, (byte) 0x2D, (byte) 0x2B,
+ (byte) 0x85, (byte) 0xFE, (byte) 0x4A, (byte) 0x28, (byte) 0x90, (byte) 0xF7,
+ (byte) 0xDF, (byte) 0xD6, (byte) 0xB1, (byte) 0x3E, (byte) 0xC6, (byte) 0xFB,
+ (byte) 0x76, (byte) 0x7B, (byte) 0x3D, (byte) 0x12, (byte) 0x81, (byte) 0x6E,
+ (byte) 0xFD, (byte) 0x00, (byte) 0x7D, (byte) 0xD0, (byte) 0xDC, (byte) 0x25,
+ (byte) 0xD0, (byte) 0x86, (byte) 0x6C, (byte) 0xE8, (byte) 0x0F, (byte) 0x09,
+ (byte) 0x82, (byte) 0x74, (byte) 0x89, (byte) 0x79, (byte) 0x69, (byte) 0x73,
+ (byte) 0x37, (byte) 0x64, (byte) 0xEE, (byte) 0x53, (byte) 0x57, (byte) 0x20,
+ (byte) 0xFA, (byte) 0x0B, (byte) 0x4A, (byte) 0x5A, (byte) 0x4D, (byte) 0x33,
+ (byte) 0xAC, (byte) 0x8B, (byte) 0x04, (byte) 0xA5, (byte) 0x4A, (byte) 0x1A,
+ (byte) 0x9B, (byte) 0x66, (byte) 0xAA, (byte) 0x0B, (byte) 0x3D, (byte) 0x15,
+ (byte) 0xD9, (byte) 0x3E, (byte) 0x2F, (byte) 0xD2, (byte) 0xA1, (byte) 0x28,
+ (byte) 0x13, (byte) 0x59, (byte) 0x98, (byte) 0xC3, (byte) 0x45, (byte) 0x7C,
+ (byte) 0xEE, (byte) 0x60, (byte) 0xD0, (byte) 0xBD, (byte) 0x42, (byte) 0x16,
+ (byte) 0x84, (byte) 0x19, (byte) 0xF6, (byte) 0xD9, (byte) 0xF7, (byte) 0x7D,
+ (byte) 0x77, (byte) 0xAD, (byte) 0x60, (byte) 0xE2, (byte) 0xE3, (byte) 0x22,
+ (byte) 0xB9, (byte) 0xFA, (byte) 0xD5, (byte) 0xFA, (byte) 0x6E, (byte) 0x1F,
+ (byte) 0x69, (byte) 0x3F, (byte) 0xB1, (byte) 0xA7, (byte) 0x1A, (byte) 0x22,
+ (byte) 0xF7, (byte) 0x31, (byte) 0x97, (byte) 0x68, (byte) 0x62, (byte) 0x0F,
+ (byte) 0x39, (byte) 0xB0, (byte) 0xE7, (byte) 0x63, (byte) 0xAE, (byte) 0x65,
+ (byte) 0x69, (byte) 0xD0, (byte) 0xD3, (byte) 0x56, (byte) 0xC9, (byte) 0xA6,
+ (byte) 0xA4, (byte) 0xA5, (byte) 0xA4, (byte) 0x61, (byte) 0xA9, (byte) 0xC4,
+ (byte) 0x45, (byte) 0xCD, (byte) 0x49, (byte) 0x76, (byte) 0xC8, (byte) 0x53,
+ (byte) 0x46, (byte) 0xD0, (byte) 0x63, (byte) 0x35, (byte) 0x89, (byte) 0x04,
+ (byte) 0x22, (byte) 0xD7, (byte) 0xB6, (byte) 0x63, (byte) 0xAF, (byte) 0xC2,
+ (byte) 0x97, (byte) 0x10, (byte) 0xDF, (byte) 0xDE, (byte) 0xE6, (byte) 0x39,
+ (byte) 0x25, (byte) 0x2F, (byte) 0xEA, (byte) 0xD8, (byte) 0x56, (byte) 0x5A,
+ (byte) 0xC1, (byte) 0xB8, (byte) 0xCA, (byte) 0xC1, (byte) 0x8A, (byte) 0xB8,
+ (byte) 0x87, (byte) 0x2F, (byte) 0xCD, (byte) 0x21,
+ };
+ private static final PSSParameterSpec SHA1withRSAPSS_NoSalt_Vector2Signature_ParameterSpec =
+ new PSSParameterSpec("SHA-1", "MGF1", MGF1ParameterSpec.SHA1, 0, 1);
+
+ /*
+ * echo "This is a signed message from Kenny Root." | openssl sha1 -binary -out digest.bin \
+ * && openssl pkeyutl -sign -in digest.bin -inkey privkey.pem \
+ * -pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha1 -pkeyopt rsa_pss_saltlen:234 \
+ * | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] SHA1withRSAPSS_MaxSalt_Vector2Signature = new byte[] {
+ (byte) 0x49, (byte) 0xDB, (byte) 0xAD, (byte) 0x48, (byte) 0x7C, (byte) 0x06,
+ (byte) 0x03, (byte) 0x7C, (byte) 0x58, (byte) 0xE1, (byte) 0x38, (byte) 0x20,
+ (byte) 0x46, (byte) 0x28, (byte) 0x60, (byte) 0x64, (byte) 0x94, (byte) 0x51,
+ (byte) 0xA3, (byte) 0xD1, (byte) 0xC9, (byte) 0x52, (byte) 0xC6, (byte) 0x2A,
+ (byte) 0xB3, (byte) 0xCC, (byte) 0xD6, (byte) 0x19, (byte) 0x50, (byte) 0x99,
+ (byte) 0x60, (byte) 0x58, (byte) 0xA2, (byte) 0x86, (byte) 0xA8, (byte) 0x74,
+ (byte) 0x50, (byte) 0x8C, (byte) 0x0E, (byte) 0x32, (byte) 0x58, (byte) 0x56,
+ (byte) 0x6D, (byte) 0x30, (byte) 0x38, (byte) 0xFB, (byte) 0x26, (byte) 0xC3,
+ (byte) 0xFD, (byte) 0x8E, (byte) 0x36, (byte) 0x73, (byte) 0x82, (byte) 0x9A,
+ (byte) 0xB4, (byte) 0xE5, (byte) 0x22, (byte) 0x96, (byte) 0x55, (byte) 0x3C,
+ (byte) 0x18, (byte) 0xD7, (byte) 0x46, (byte) 0xF1, (byte) 0x7C, (byte) 0xE6,
+ (byte) 0x8E, (byte) 0x0A, (byte) 0x18, (byte) 0xA7, (byte) 0x29, (byte) 0x96,
+ (byte) 0x8D, (byte) 0xFC, (byte) 0x0E, (byte) 0xBE, (byte) 0x91, (byte) 0xA0,
+ (byte) 0xF8, (byte) 0xE2, (byte) 0x70, (byte) 0x5A, (byte) 0xE3, (byte) 0x76,
+ (byte) 0xAC, (byte) 0x18, (byte) 0x10, (byte) 0xB4, (byte) 0xB1, (byte) 0xFF,
+ (byte) 0x58, (byte) 0xBC, (byte) 0x10, (byte) 0xF5, (byte) 0x88, (byte) 0x2F,
+ (byte) 0x0B, (byte) 0x10, (byte) 0x9D, (byte) 0x52, (byte) 0x2D, (byte) 0x42,
+ (byte) 0xDB, (byte) 0xFD, (byte) 0xA7, (byte) 0x23, (byte) 0x3C, (byte) 0x4B,
+ (byte) 0xB3, (byte) 0xD2, (byte) 0x96, (byte) 0x1B, (byte) 0xCE, (byte) 0xB3,
+ (byte) 0xA3, (byte) 0xC3, (byte) 0x42, (byte) 0xA4, (byte) 0x0E, (byte) 0x35,
+ (byte) 0x5C, (byte) 0xC2, (byte) 0x32, (byte) 0xC7, (byte) 0x8C, (byte) 0xFC,
+ (byte) 0x7F, (byte) 0xE0, (byte) 0xF7, (byte) 0x1D, (byte) 0x38, (byte) 0x21,
+ (byte) 0x3C, (byte) 0xDF, (byte) 0x82, (byte) 0x1A, (byte) 0xBD, (byte) 0x83,
+ (byte) 0xE9, (byte) 0x56, (byte) 0xF0, (byte) 0xF1, (byte) 0x54, (byte) 0x76,
+ (byte) 0xE3, (byte) 0xCE, (byte) 0x86, (byte) 0x69, (byte) 0xC2, (byte) 0x61,
+ (byte) 0x6D, (byte) 0x8E, (byte) 0xF5, (byte) 0xA3, (byte) 0x61, (byte) 0xCA,
+ (byte) 0x16, (byte) 0xCB, (byte) 0x7A, (byte) 0xF5, (byte) 0xBF, (byte) 0x36,
+ (byte) 0xCB, (byte) 0x7D, (byte) 0xB1, (byte) 0xE9, (byte) 0x70, (byte) 0x41,
+ (byte) 0xCF, (byte) 0x89, (byte) 0x51, (byte) 0x13, (byte) 0xCC, (byte) 0x95,
+ (byte) 0x50, (byte) 0xC8, (byte) 0xB6, (byte) 0x30, (byte) 0x35, (byte) 0xE3,
+ (byte) 0x13, (byte) 0x08, (byte) 0xF6, (byte) 0xBE, (byte) 0x20, (byte) 0xF1,
+ (byte) 0x48, (byte) 0x4D, (byte) 0x46, (byte) 0x95, (byte) 0xFE, (byte) 0x9E,
+ (byte) 0xD2, (byte) 0xD5, (byte) 0x29, (byte) 0x81, (byte) 0x2E, (byte) 0x0F,
+ (byte) 0x6F, (byte) 0xA7, (byte) 0x02, (byte) 0x15, (byte) 0xCA, (byte) 0x75,
+ (byte) 0x77, (byte) 0x29, (byte) 0x7C, (byte) 0x3A, (byte) 0xE3, (byte) 0x2B,
+ (byte) 0xD7, (byte) 0x3D, (byte) 0x5C, (byte) 0x94, (byte) 0x3B, (byte) 0x2A,
+ (byte) 0x91, (byte) 0xDB, (byte) 0xFA, (byte) 0x69, (byte) 0x47, (byte) 0x1C,
+ (byte) 0x2C, (byte) 0x46, (byte) 0x49, (byte) 0xE6, (byte) 0x37, (byte) 0x5D,
+ (byte) 0x78, (byte) 0x71, (byte) 0x76, (byte) 0xC1, (byte) 0xB6, (byte) 0x2E,
+ (byte) 0x4E, (byte) 0x3C, (byte) 0x83, (byte) 0x6F, (byte) 0x82, (byte) 0xC3,
+ (byte) 0xD8, (byte) 0x50, (byte) 0xD7, (byte) 0x1B, (byte) 0xAF, (byte) 0xF9,
+ (byte) 0xE3, (byte) 0xF1, (byte) 0x47, (byte) 0xC8, (byte) 0x12, (byte) 0x86,
+ (byte) 0x82, (byte) 0x9D, (byte) 0x3F, (byte) 0xCE,
+ };
+ private static final PSSParameterSpec SHA1withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec =
+ new PSSParameterSpec("SHA-1", "MGF1", MGF1ParameterSpec.SHA1, 234, 1);
+
+ /*
+ * echo "This is a signed message from Kenny Root." | openssl sha224 -binary -out digest.bin \
+ * && openssl pkeyutl -sign -in digest.bin -inkey privkey.pem \
+ * -pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha224 -pkeyopt rsa_pss_saltlen:28 \
+ * | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] SHA224withRSAPSS_Vector2Signature = new byte[] {
+ (byte) 0x86, (byte) 0x41, (byte) 0xCC, (byte) 0x4B, (byte) 0x82, (byte) 0x74,
+ (byte) 0x04, (byte) 0x43, (byte) 0x8C, (byte) 0xAB, (byte) 0xF6, (byte) 0x3B,
+ (byte) 0xFB, (byte) 0x94, (byte) 0xBC, (byte) 0x4C, (byte) 0x0A, (byte) 0xFE,
+ (byte) 0x0F, (byte) 0x4F, (byte) 0x0F, (byte) 0x9F, (byte) 0x84, (byte) 0x35,
+ (byte) 0x57, (byte) 0x8B, (byte) 0x8D, (byte) 0xC3, (byte) 0x58, (byte) 0xA6,
+ (byte) 0x70, (byte) 0xAC, (byte) 0x40, (byte) 0x6D, (byte) 0xBC, (byte) 0xC1,
+ (byte) 0x6A, (byte) 0xFA, (byte) 0x31, (byte) 0x3B, (byte) 0x7A, (byte) 0x23,
+ (byte) 0xCA, (byte) 0x1F, (byte) 0xCD, (byte) 0xA7, (byte) 0xE3, (byte) 0xD6,
+ (byte) 0x7C, (byte) 0x2C, (byte) 0xF3, (byte) 0x6F, (byte) 0xF5, (byte) 0x82,
+ (byte) 0x9E, (byte) 0x18, (byte) 0x70, (byte) 0x90, (byte) 0xE6, (byte) 0xA3,
+ (byte) 0x44, (byte) 0x61, (byte) 0xB6, (byte) 0x46, (byte) 0x9B, (byte) 0x0D,
+ (byte) 0xE5, (byte) 0x3C, (byte) 0xAE, (byte) 0x22, (byte) 0xF4, (byte) 0x87,
+ (byte) 0xB7, (byte) 0x03, (byte) 0xD8, (byte) 0x42, (byte) 0x33, (byte) 0x4E,
+ (byte) 0xCC, (byte) 0x7A, (byte) 0xDF, (byte) 0xD7, (byte) 0x57, (byte) 0xEB,
+ (byte) 0x51, (byte) 0x6C, (byte) 0xB1, (byte) 0x99, (byte) 0x4D, (byte) 0x94,
+ (byte) 0x82, (byte) 0xA7, (byte) 0x69, (byte) 0x85, (byte) 0x8D, (byte) 0x82,
+ (byte) 0x18, (byte) 0xE4, (byte) 0x53, (byte) 0xF5, (byte) 0x9F, (byte) 0x82,
+ (byte) 0x1C, (byte) 0xE1, (byte) 0x25, (byte) 0x1C, (byte) 0x8E, (byte) 0xE7,
+ (byte) 0xC1, (byte) 0xEC, (byte) 0xBE, (byte) 0x3F, (byte) 0xC3, (byte) 0xED,
+ (byte) 0x41, (byte) 0x89, (byte) 0x94, (byte) 0x13, (byte) 0x11, (byte) 0x75,
+ (byte) 0x3F, (byte) 0x38, (byte) 0x52, (byte) 0x58, (byte) 0xAB, (byte) 0x88,
+ (byte) 0x01, (byte) 0x30, (byte) 0xB4, (byte) 0xCD, (byte) 0x45, (byte) 0x3E,
+ (byte) 0x1A, (byte) 0x5F, (byte) 0x36, (byte) 0xF8, (byte) 0x51, (byte) 0x90,
+ (byte) 0x6E, (byte) 0x6F, (byte) 0x31, (byte) 0x9D, (byte) 0x40, (byte) 0x90,
+ (byte) 0x1A, (byte) 0xA8, (byte) 0x10, (byte) 0xEF, (byte) 0x9D, (byte) 0xF8,
+ (byte) 0xB0, (byte) 0x03, (byte) 0x01, (byte) 0xFB, (byte) 0xD8, (byte) 0x3D,
+ (byte) 0x83, (byte) 0x79, (byte) 0x01, (byte) 0xA7, (byte) 0x82, (byte) 0xC2,
+ (byte) 0x46, (byte) 0x35, (byte) 0x68, (byte) 0xD2, (byte) 0x08, (byte) 0x81,
+ (byte) 0x31, (byte) 0x14, (byte) 0xE8, (byte) 0x13, (byte) 0x8C, (byte) 0xD4,
+ (byte) 0xC4, (byte) 0xCB, (byte) 0xB9, (byte) 0x85, (byte) 0x25, (byte) 0x93,
+ (byte) 0x40, (byte) 0x88, (byte) 0x34, (byte) 0x11, (byte) 0xDA, (byte) 0xFF,
+ (byte) 0xEF, (byte) 0x4D, (byte) 0xDC, (byte) 0x31, (byte) 0x74, (byte) 0x7B,
+ (byte) 0x5E, (byte) 0xA7, (byte) 0x51, (byte) 0x15, (byte) 0x13, (byte) 0xB1,
+ (byte) 0x9E, (byte) 0x06, (byte) 0x51, (byte) 0xBA, (byte) 0x11, (byte) 0xDA,
+ (byte) 0x64, (byte) 0x1B, (byte) 0x78, (byte) 0x76, (byte) 0x57, (byte) 0x96,
+ (byte) 0xF3, (byte) 0x1B, (byte) 0x86, (byte) 0xB2, (byte) 0xF3, (byte) 0x66,
+ (byte) 0x64, (byte) 0x2B, (byte) 0x04, (byte) 0x81, (byte) 0x8C, (byte) 0xDC,
+ (byte) 0xE0, (byte) 0xEA, (byte) 0x66, (byte) 0x62, (byte) 0x44, (byte) 0x31,
+ (byte) 0xA2, (byte) 0x19, (byte) 0xF1, (byte) 0x77, (byte) 0x67, (byte) 0x58,
+ (byte) 0x18, (byte) 0x5B, (byte) 0xCB, (byte) 0xBA, (byte) 0x28, (byte) 0x91,
+ (byte) 0x47, (byte) 0x5B, (byte) 0x4F, (byte) 0x17, (byte) 0x23, (byte) 0x2A,
+ (byte) 0xE4, (byte) 0xB0, (byte) 0xAE, (byte) 0x82, (byte) 0x4E, (byte) 0xCA,
+ (byte) 0xA6, (byte) 0x12, (byte) 0xCA, (byte) 0x70,
+ };
+ private static final PSSParameterSpec SHA224withRSAPSS_Vector2Signature_ParameterSpec =
+ new PSSParameterSpec("SHA-224", "MGF1", new MGF1ParameterSpec("SHA-224"), 28, 1);
+
+ /*
+ * echo "This is a signed message from Kenny Root." | openssl sha224 -binary -out digest.bin \
+ * && openssl pkeyutl -sign -in digest.bin -inkey privkey.pem \
+ * -pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha224 -pkeyopt rsa_pss_saltlen:0 \
+ * | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] SHA224withRSAPSS_NoSalt_Vector2Signature = new byte[] {
+ (byte) 0xD8, (byte) 0x38, (byte) 0x48, (byte) 0xCD, (byte) 0xA4, (byte) 0x09,
+ (byte) 0x36, (byte) 0x35, (byte) 0x47, (byte) 0x55, (byte) 0xDB, (byte) 0x6C,
+ (byte) 0x2D, (byte) 0x83, (byte) 0x17, (byte) 0x10, (byte) 0x3E, (byte) 0xCE,
+ (byte) 0x95, (byte) 0x02, (byte) 0x58, (byte) 0xCE, (byte) 0xA8, (byte) 0x02,
+ (byte) 0x44, (byte) 0xB7, (byte) 0xE4, (byte) 0x32, (byte) 0x3D, (byte) 0x50,
+ (byte) 0xE1, (byte) 0x8C, (byte) 0xF3, (byte) 0x24, (byte) 0x6F, (byte) 0xA4,
+ (byte) 0x2D, (byte) 0xD7, (byte) 0xFB, (byte) 0x70, (byte) 0x97, (byte) 0xBE,
+ (byte) 0xED, (byte) 0x27, (byte) 0x2D, (byte) 0x22, (byte) 0xDC, (byte) 0x62,
+ (byte) 0x97, (byte) 0x66, (byte) 0x39, (byte) 0xE0, (byte) 0x36, (byte) 0x5F,
+ (byte) 0x07, (byte) 0x78, (byte) 0xAF, (byte) 0x5E, (byte) 0xDC, (byte) 0xFD,
+ (byte) 0x21, (byte) 0xA8, (byte) 0xD5, (byte) 0xA7, (byte) 0xD1, (byte) 0xBA,
+ (byte) 0x1C, (byte) 0xDA, (byte) 0xCA, (byte) 0x80, (byte) 0x72, (byte) 0x8A,
+ (byte) 0xDD, (byte) 0x5C, (byte) 0x16, (byte) 0x6A, (byte) 0x47, (byte) 0xFC,
+ (byte) 0x11, (byte) 0x42, (byte) 0x7E, (byte) 0x4E, (byte) 0x3F, (byte) 0x49,
+ (byte) 0xCF, (byte) 0x2F, (byte) 0x54, (byte) 0xD7, (byte) 0x13, (byte) 0x76,
+ (byte) 0x5D, (byte) 0xE9, (byte) 0x2A, (byte) 0x29, (byte) 0xCC, (byte) 0x73,
+ (byte) 0xDB, (byte) 0xE5, (byte) 0xDE, (byte) 0x48, (byte) 0xA2, (byte) 0xE9,
+ (byte) 0xD1, (byte) 0xD0, (byte) 0x35, (byte) 0xFE, (byte) 0xA1, (byte) 0x1C,
+ (byte) 0x13, (byte) 0x04, (byte) 0x75, (byte) 0x77, (byte) 0xF4, (byte) 0x55,
+ (byte) 0x03, (byte) 0xC4, (byte) 0x6D, (byte) 0xAC, (byte) 0x25, (byte) 0x1D,
+ (byte) 0x57, (byte) 0xFF, (byte) 0x0D, (byte) 0xE0, (byte) 0x91, (byte) 0xEA,
+ (byte) 0xF6, (byte) 0x1F, (byte) 0x3F, (byte) 0x69, (byte) 0xD6, (byte) 0x00,
+ (byte) 0xBD, (byte) 0x89, (byte) 0xEA, (byte) 0xD3, (byte) 0x31, (byte) 0x80,
+ (byte) 0x5E, (byte) 0x04, (byte) 0x4C, (byte) 0x59, (byte) 0xDE, (byte) 0xD0,
+ (byte) 0x62, (byte) 0x93, (byte) 0x3B, (byte) 0xC9, (byte) 0x9F, (byte) 0xE7,
+ (byte) 0x69, (byte) 0xC0, (byte) 0xB8, (byte) 0xED, (byte) 0xBF, (byte) 0x0D,
+ (byte) 0x60, (byte) 0x28, (byte) 0x55, (byte) 0x20, (byte) 0x0C, (byte) 0x9F,
+ (byte) 0xA2, (byte) 0x42, (byte) 0x34, (byte) 0x95, (byte) 0xAE, (byte) 0xF8,
+ (byte) 0x67, (byte) 0x7C, (byte) 0xF1, (byte) 0xA0, (byte) 0xC0, (byte) 0x74,
+ (byte) 0xF2, (byte) 0xDF, (byte) 0x75, (byte) 0x5B, (byte) 0x6E, (byte) 0x2F,
+ (byte) 0xFB, (byte) 0x1F, (byte) 0xDD, (byte) 0xC3, (byte) 0xD3, (byte) 0x90,
+ (byte) 0x0A, (byte) 0x33, (byte) 0xF6, (byte) 0x03, (byte) 0x16, (byte) 0xC4,
+ (byte) 0xF8, (byte) 0xED, (byte) 0xB7, (byte) 0x45, (byte) 0x39, (byte) 0x5D,
+ (byte) 0x7C, (byte) 0xF8, (byte) 0x82, (byte) 0xCE, (byte) 0x7D, (byte) 0xFB,
+ (byte) 0x02, (byte) 0x2D, (byte) 0xE0, (byte) 0x96, (byte) 0x35, (byte) 0x60,
+ (byte) 0x5D, (byte) 0xBC, (byte) 0x35, (byte) 0x80, (byte) 0x4C, (byte) 0x39,
+ (byte) 0x7C, (byte) 0xE7, (byte) 0xD4, (byte) 0xB4, (byte) 0x19, (byte) 0xD1,
+ (byte) 0xE5, (byte) 0x8E, (byte) 0x6D, (byte) 0x25, (byte) 0x0C, (byte) 0xB9,
+ (byte) 0x0C, (byte) 0x8D, (byte) 0x45, (byte) 0xE4, (byte) 0x67, (byte) 0x73,
+ (byte) 0xCF, (byte) 0x87, (byte) 0x7C, (byte) 0x78, (byte) 0xAA, (byte) 0xB9,
+ (byte) 0x42, (byte) 0xAE, (byte) 0x7F, (byte) 0xB8, (byte) 0xEC, (byte) 0x4F,
+ (byte) 0xD2, (byte) 0x85, (byte) 0x01, (byte) 0x80, (byte) 0x00, (byte) 0xBD,
+ (byte) 0xF5, (byte) 0xEA, (byte) 0x44, (byte) 0x6D,
+ };
+ private static final PSSParameterSpec SHA224withRSAPSS_NoSalt_Vector2Signature_ParameterSpec =
+ new PSSParameterSpec("SHA-224", "MGF1", new MGF1ParameterSpec("SHA-224"), 0, 1);
+
+ /*
+ * echo "This is a signed message from Kenny Root." | openssl sha224 -binary -out digest.bin \
+ * && openssl pkeyutl -sign -in digest.bin -inkey privkey.pem \
+ * -pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha224 -pkeyopt rsa_pss_saltlen:226 \
+ * | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] SHA224withRSAPSS_MaxSalt_Vector2Signature = new byte[] {
+ (byte) 0x2C, (byte) 0x19, (byte) 0x5E, (byte) 0x63, (byte) 0xC5, (byte) 0x32,
+ (byte) 0xC3, (byte) 0xC7, (byte) 0x52, (byte) 0xE9, (byte) 0x69, (byte) 0x4C,
+ (byte) 0x04, (byte) 0xE5, (byte) 0x4A, (byte) 0xF2, (byte) 0x72, (byte) 0x78,
+ (byte) 0xBF, (byte) 0xC5, (byte) 0x8D, (byte) 0x5A, (byte) 0x71, (byte) 0xEF,
+ (byte) 0xA9, (byte) 0x58, (byte) 0x77, (byte) 0x94, (byte) 0x49, (byte) 0x71,
+ (byte) 0xBF, (byte) 0x45, (byte) 0x3E, (byte) 0xA4, (byte) 0x2E, (byte) 0x33,
+ (byte) 0x9B, (byte) 0x4E, (byte) 0xA4, (byte) 0x95, (byte) 0x07, (byte) 0x9C,
+ (byte) 0xAA, (byte) 0xC4, (byte) 0xA8, (byte) 0x60, (byte) 0xBC, (byte) 0xCD,
+ (byte) 0xC3, (byte) 0x45, (byte) 0xE6, (byte) 0xBC, (byte) 0xAD, (byte) 0xB6,
+ (byte) 0xF3, (byte) 0x0E, (byte) 0xF6, (byte) 0xD5, (byte) 0xCF, (byte) 0x33,
+ (byte) 0xA3, (byte) 0x82, (byte) 0x62, (byte) 0x52, (byte) 0x95, (byte) 0xA8,
+ (byte) 0x0E, (byte) 0xD4, (byte) 0xAC, (byte) 0x1F, (byte) 0x9A, (byte) 0xDC,
+ (byte) 0x00, (byte) 0xD6, (byte) 0x78, (byte) 0xEA, (byte) 0x53, (byte) 0x00,
+ (byte) 0x19, (byte) 0xE3, (byte) 0x81, (byte) 0x7C, (byte) 0x7A, (byte) 0x8E,
+ (byte) 0x30, (byte) 0x57, (byte) 0xB7, (byte) 0x81, (byte) 0xD7, (byte) 0x4D,
+ (byte) 0x1D, (byte) 0xCB, (byte) 0x99, (byte) 0x8D, (byte) 0xE4, (byte) 0xFA,
+ (byte) 0x6E, (byte) 0x4E, (byte) 0xA6, (byte) 0xDA, (byte) 0x13, (byte) 0x92,
+ (byte) 0x31, (byte) 0x7C, (byte) 0x2B, (byte) 0x3A, (byte) 0xA0, (byte) 0xF1,
+ (byte) 0x03, (byte) 0x83, (byte) 0x12, (byte) 0xD1, (byte) 0x23, (byte) 0xED,
+ (byte) 0xC4, (byte) 0x01, (byte) 0x57, (byte) 0x63, (byte) 0xAF, (byte) 0x40,
+ (byte) 0x15, (byte) 0xEC, (byte) 0xB8, (byte) 0x5A, (byte) 0xCE, (byte) 0x3D,
+ (byte) 0x3E, (byte) 0xCD, (byte) 0xD8, (byte) 0xF3, (byte) 0x76, (byte) 0xCA,
+ (byte) 0x23, (byte) 0x20, (byte) 0x68, (byte) 0x17, (byte) 0x5B, (byte) 0x7F,
+ (byte) 0xBC, (byte) 0x22, (byte) 0x67, (byte) 0x2A, (byte) 0x91, (byte) 0x05,
+ (byte) 0xB3, (byte) 0x85, (byte) 0x60, (byte) 0xD8, (byte) 0x76, (byte) 0xD5,
+ (byte) 0x2B, (byte) 0x9C, (byte) 0x80, (byte) 0xB6, (byte) 0xEA, (byte) 0x1E,
+ (byte) 0x05, (byte) 0xC7, (byte) 0x95, (byte) 0x2C, (byte) 0x4F, (byte) 0x14,
+ (byte) 0x5F, (byte) 0xEE, (byte) 0x08, (byte) 0x32, (byte) 0xF7, (byte) 0x12,
+ (byte) 0x2B, (byte) 0xCD, (byte) 0xF3, (byte) 0x83, (byte) 0x7C, (byte) 0xCE,
+ (byte) 0x04, (byte) 0x8A, (byte) 0x36, (byte) 0x3D, (byte) 0xB2, (byte) 0x97,
+ (byte) 0x15, (byte) 0xDB, (byte) 0xD6, (byte) 0xFA, (byte) 0x53, (byte) 0x29,
+ (byte) 0xD1, (byte) 0x43, (byte) 0x55, (byte) 0xDD, (byte) 0xAE, (byte) 0xA7,
+ (byte) 0xB4, (byte) 0x2C, (byte) 0xD9, (byte) 0xA7, (byte) 0x74, (byte) 0xA8,
+ (byte) 0x08, (byte) 0xD6, (byte) 0xC2, (byte) 0x05, (byte) 0xBF, (byte) 0x67,
+ (byte) 0x3B, (byte) 0xBA, (byte) 0x8D, (byte) 0x99, (byte) 0xC1, (byte) 0x14,
+ (byte) 0x1A, (byte) 0x32, (byte) 0xCA, (byte) 0xD5, (byte) 0xCC, (byte) 0xF9,
+ (byte) 0x64, (byte) 0x07, (byte) 0x5B, (byte) 0xB8, (byte) 0xA9, (byte) 0x69,
+ (byte) 0xED, (byte) 0x01, (byte) 0xCD, (byte) 0xD2, (byte) 0x88, (byte) 0x67,
+ (byte) 0xFF, (byte) 0x92, (byte) 0xA3, (byte) 0xC6, (byte) 0x97, (byte) 0x97,
+ (byte) 0xA1, (byte) 0xC5, (byte) 0x15, (byte) 0xC8, (byte) 0xB6, (byte) 0xFE,
+ (byte) 0x4A, (byte) 0x07, (byte) 0x2E, (byte) 0x46, (byte) 0x3F, (byte) 0x27,
+ (byte) 0xB8, (byte) 0xEE, (byte) 0x69, (byte) 0xCB, (byte) 0xDC, (byte) 0x30,
+ (byte) 0x19, (byte) 0x77, (byte) 0xC5, (byte) 0xEF,
+ };
+ private static final PSSParameterSpec SHA224withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec =
+ new PSSParameterSpec("SHA-224", "MGF1", new MGF1ParameterSpec("SHA-224"), 226, 1);
+
+ /*
+ * echo "This is a signed message from Kenny Root." | openssl sha256 -binary -out digest.bin \
+ * && openssl pkeyutl -sign -in digest.bin -inkey privkey.pem \
+ * -pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha256 -pkeyopt rsa_pss_saltlen:32 \
+ * | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] SHA256withRSAPSS_Vector2Signature = new byte[] {
+ (byte) 0x94, (byte) 0x33, (byte) 0xCB, (byte) 0x9E, (byte) 0x2C, (byte) 0x17,
+ (byte) 0x46, (byte) 0xB3, (byte) 0x8F, (byte) 0xB7, (byte) 0x93, (byte) 0x98,
+ (byte) 0xA3, (byte) 0x45, (byte) 0xEA, (byte) 0xD4, (byte) 0x51, (byte) 0x60,
+ (byte) 0x3E, (byte) 0x00, (byte) 0xA3, (byte) 0x93, (byte) 0x05, (byte) 0x0F,
+ (byte) 0xCB, (byte) 0x6E, (byte) 0xFF, (byte) 0xA5, (byte) 0x97, (byte) 0x18,
+ (byte) 0xF6, (byte) 0xED, (byte) 0x6B, (byte) 0x6C, (byte) 0xAD, (byte) 0x9C,
+ (byte) 0x73, (byte) 0x63, (byte) 0x9C, (byte) 0x5B, (byte) 0xA5, (byte) 0xA1,
+ (byte) 0x42, (byte) 0xA3, (byte) 0x0E, (byte) 0x32, (byte) 0xF5, (byte) 0xF0,
+ (byte) 0x55, (byte) 0xEE, (byte) 0x58, (byte) 0xC1, (byte) 0xBD, (byte) 0x99,
+ (byte) 0x0A, (byte) 0x2B, (byte) 0xFD, (byte) 0xBD, (byte) 0x1E, (byte) 0x23,
+ (byte) 0xEF, (byte) 0x99, (byte) 0x7D, (byte) 0xC1, (byte) 0xE2, (byte) 0xD5,
+ (byte) 0x71, (byte) 0x6C, (byte) 0x96, (byte) 0x70, (byte) 0xC3, (byte) 0x75,
+ (byte) 0x48, (byte) 0x83, (byte) 0x85, (byte) 0x5E, (byte) 0xC6, (byte) 0x3A,
+ (byte) 0xFF, (byte) 0xE5, (byte) 0xF1, (byte) 0x6B, (byte) 0x85, (byte) 0x7B,
+ (byte) 0x61, (byte) 0xA6, (byte) 0xB1, (byte) 0xCF, (byte) 0x60, (byte) 0x09,
+ (byte) 0x32, (byte) 0xAF, (byte) 0xEF, (byte) 0x95, (byte) 0xA4, (byte) 0x1B,
+ (byte) 0xD6, (byte) 0xFA, (byte) 0xD0, (byte) 0xD7, (byte) 0x17, (byte) 0xCA,
+ (byte) 0xB0, (byte) 0x19, (byte) 0x21, (byte) 0x7F, (byte) 0x5E, (byte) 0x9B,
+ (byte) 0xBB, (byte) 0xB8, (byte) 0xE0, (byte) 0xB1, (byte) 0x95, (byte) 0xB3,
+ (byte) 0xDA, (byte) 0x0B, (byte) 0xB8, (byte) 0xFA, (byte) 0x15, (byte) 0x75,
+ (byte) 0x73, (byte) 0x88, (byte) 0xC8, (byte) 0x45, (byte) 0x33, (byte) 0xD1,
+ (byte) 0x5C, (byte) 0xB7, (byte) 0xFB, (byte) 0x38, (byte) 0x05, (byte) 0xA0,
+ (byte) 0x85, (byte) 0x99, (byte) 0x2C, (byte) 0xB1, (byte) 0xC2, (byte) 0xFE,
+ (byte) 0xAC, (byte) 0x5D, (byte) 0x2C, (byte) 0x1B, (byte) 0xD3, (byte) 0x42,
+ (byte) 0x81, (byte) 0xC8, (byte) 0x1C, (byte) 0xB7, (byte) 0x53, (byte) 0x7E,
+ (byte) 0xC5, (byte) 0x9F, (byte) 0x84, (byte) 0x97, (byte) 0x6F, (byte) 0x00,
+ (byte) 0xC3, (byte) 0x5E, (byte) 0x8B, (byte) 0x67, (byte) 0x3D, (byte) 0x9A,
+ (byte) 0xD0, (byte) 0xE2, (byte) 0x9B, (byte) 0x2D, (byte) 0xC6, (byte) 0xD8,
+ (byte) 0xEF, (byte) 0x19, (byte) 0x14, (byte) 0x49, (byte) 0x88, (byte) 0x52,
+ (byte) 0xF7, (byte) 0x93, (byte) 0xEB, (byte) 0xDB, (byte) 0xB6, (byte) 0x55,
+ (byte) 0x05, (byte) 0xB6, (byte) 0xE7, (byte) 0x70, (byte) 0xE4, (byte) 0x5A,
+ (byte) 0x9E, (byte) 0x80, (byte) 0x78, (byte) 0x48, (byte) 0xA8, (byte) 0xE5,
+ (byte) 0x59, (byte) 0x8D, (byte) 0x1C, (byte) 0x5D, (byte) 0x95, (byte) 0x38,
+ (byte) 0x25, (byte) 0xFC, (byte) 0x38, (byte) 0xC3, (byte) 0xFF, (byte) 0xE2,
+ (byte) 0x6F, (byte) 0xE4, (byte) 0xFC, (byte) 0x64, (byte) 0x8B, (byte) 0xCA,
+ (byte) 0x91, (byte) 0x5F, (byte) 0x0B, (byte) 0x4E, (byte) 0x9A, (byte) 0xB5,
+ (byte) 0x22, (byte) 0x5D, (byte) 0xC5, (byte) 0x5A, (byte) 0x77, (byte) 0xED,
+ (byte) 0x23, (byte) 0xE0, (byte) 0x13, (byte) 0x8F, (byte) 0xAC, (byte) 0x13,
+ (byte) 0xE5, (byte) 0x81, (byte) 0xEE, (byte) 0xD1, (byte) 0xAD, (byte) 0x8A,
+ (byte) 0x0F, (byte) 0x2B, (byte) 0x4C, (byte) 0xB2, (byte) 0x13, (byte) 0x54,
+ (byte) 0x44, (byte) 0x8E, (byte) 0x53, (byte) 0xE2, (byte) 0x33, (byte) 0x14,
+ (byte) 0x7F, (byte) 0x9B, (byte) 0xA9, (byte) 0xD3, (byte) 0xBB, (byte) 0xFC,
+ (byte) 0xAC, (byte) 0xC9, (byte) 0x31, (byte) 0xB6,
+ };
+ private static final PSSParameterSpec SHA256withRSAPSS_Vector2Signature_ParameterSpec =
+ new PSSParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, 32, 1);
+
+ /*
+ * echo "This is a signed message from Kenny Root." | openssl sha256 -binary -out digest.bin \
+ * && openssl pkeyutl -sign -in digest.bin -inkey privkey.pem \
+ * -pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha256 -pkeyopt rsa_pss_saltlen:0 \
+ * | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] SHA256withRSAPSS_NoSalt_Vector2Signature = new byte[] {
+ (byte) 0x4C, (byte) 0xB7, (byte) 0x33, (byte) 0x78, (byte) 0x0A, (byte) 0xA7,
+ (byte) 0xEB, (byte) 0x35, (byte) 0x5E, (byte) 0x99, (byte) 0x8F, (byte) 0xE9,
+ (byte) 0x2A, (byte) 0x3D, (byte) 0x8C, (byte) 0x9B, (byte) 0x19, (byte) 0xC7,
+ (byte) 0xC8, (byte) 0xB8, (byte) 0x10, (byte) 0xC5, (byte) 0x6D, (byte) 0xA4,
+ (byte) 0x44, (byte) 0x3E, (byte) 0xAB, (byte) 0x90, (byte) 0x82, (byte) 0x70,
+ (byte) 0xFA, (byte) 0x7B, (byte) 0xE6, (byte) 0x06, (byte) 0x36, (byte) 0x06,
+ (byte) 0x93, (byte) 0x54, (byte) 0x50, (byte) 0xCD, (byte) 0x5F, (byte) 0xAA,
+ (byte) 0x01, (byte) 0x42, (byte) 0xAD, (byte) 0xB9, (byte) 0x02, (byte) 0x6E,
+ (byte) 0xAE, (byte) 0x60, (byte) 0x00, (byte) 0x60, (byte) 0x55, (byte) 0x1B,
+ (byte) 0xBB, (byte) 0x9E, (byte) 0x03, (byte) 0xB7, (byte) 0x86, (byte) 0x3D,
+ (byte) 0xCC, (byte) 0xFA, (byte) 0x6E, (byte) 0x20, (byte) 0x07, (byte) 0x61,
+ (byte) 0x8F, (byte) 0x53, (byte) 0xC6, (byte) 0x2B, (byte) 0xEF, (byte) 0x8F,
+ (byte) 0x0F, (byte) 0x8B, (byte) 0x80, (byte) 0x22, (byte) 0xDC, (byte) 0x9E,
+ (byte) 0x20, (byte) 0x4A, (byte) 0x57, (byte) 0xA1, (byte) 0x15, (byte) 0xE0,
+ (byte) 0x01, (byte) 0x95, (byte) 0xDB, (byte) 0x46, (byte) 0x85, (byte) 0x6D,
+ (byte) 0x27, (byte) 0x9F, (byte) 0x44, (byte) 0x3B, (byte) 0xB1, (byte) 0x35,
+ (byte) 0x04, (byte) 0x9D, (byte) 0xF8, (byte) 0xC6, (byte) 0xD7, (byte) 0xD7,
+ (byte) 0xEF, (byte) 0x9A, (byte) 0x53, (byte) 0x5A, (byte) 0x73, (byte) 0xB3,
+ (byte) 0xD0, (byte) 0x32, (byte) 0x39, (byte) 0xE1, (byte) 0x28, (byte) 0x3A,
+ (byte) 0x9D, (byte) 0x69, (byte) 0x4E, (byte) 0x57, (byte) 0xC1, (byte) 0xDF,
+ (byte) 0xFE, (byte) 0x5F, (byte) 0xA8, (byte) 0xFF, (byte) 0xE8, (byte) 0x75,
+ (byte) 0x85, (byte) 0x33, (byte) 0x90, (byte) 0x83, (byte) 0x3D, (byte) 0x8F,
+ (byte) 0x15, (byte) 0x47, (byte) 0x16, (byte) 0xF2, (byte) 0x32, (byte) 0xF9,
+ (byte) 0x46, (byte) 0x96, (byte) 0xCC, (byte) 0x2E, (byte) 0x8F, (byte) 0x27,
+ (byte) 0x3F, (byte) 0xCF, (byte) 0x91, (byte) 0xA6, (byte) 0x9E, (byte) 0xBF,
+ (byte) 0x42, (byte) 0x2F, (byte) 0xD6, (byte) 0x52, (byte) 0xD7, (byte) 0x3B,
+ (byte) 0xCD, (byte) 0xFE, (byte) 0x0B, (byte) 0x4A, (byte) 0x3B, (byte) 0x19,
+ (byte) 0x57, (byte) 0x47, (byte) 0x65, (byte) 0x33, (byte) 0xD9, (byte) 0xF7,
+ (byte) 0xE4, (byte) 0xC3, (byte) 0x05, (byte) 0x49, (byte) 0x3C, (byte) 0xC0,
+ (byte) 0xDF, (byte) 0xC1, (byte) 0x54, (byte) 0x18, (byte) 0x8D, (byte) 0xDA,
+ (byte) 0xE4, (byte) 0x59, (byte) 0xE9, (byte) 0x3B, (byte) 0xD6, (byte) 0x89,
+ (byte) 0x07, (byte) 0x99, (byte) 0xB0, (byte) 0xF4, (byte) 0x09, (byte) 0x0A,
+ (byte) 0x2C, (byte) 0xBA, (byte) 0x0B, (byte) 0xE4, (byte) 0x79, (byte) 0xB1,
+ (byte) 0xDB, (byte) 0xAD, (byte) 0xAB, (byte) 0x5D, (byte) 0xA2, (byte) 0x1E,
+ (byte) 0x76, (byte) 0x7F, (byte) 0x74, (byte) 0x62, (byte) 0x49, (byte) 0x07,
+ (byte) 0x7A, (byte) 0x5B, (byte) 0xD7, (byte) 0x0F, (byte) 0xA4, (byte) 0x2C,
+ (byte) 0x36, (byte) 0x13, (byte) 0x42, (byte) 0xBA, (byte) 0xCF, (byte) 0x0A,
+ (byte) 0xFC, (byte) 0xC3, (byte) 0x31, (byte) 0x5E, (byte) 0x06, (byte) 0x84,
+ (byte) 0x8A, (byte) 0x8A, (byte) 0x84, (byte) 0x0D, (byte) 0x48, (byte) 0xBD,
+ (byte) 0x67, (byte) 0xCF, (byte) 0x04, (byte) 0xB4, (byte) 0xFB, (byte) 0xBB,
+ (byte) 0x04, (byte) 0x91, (byte) 0xB1, (byte) 0x0A, (byte) 0xA4, (byte) 0x70,
+ (byte) 0x58, (byte) 0x1A, (byte) 0x9B, (byte) 0x02, (byte) 0x86, (byte) 0xBD,
+ (byte) 0xAE, (byte) 0x77, (byte) 0x97, (byte) 0x1C,
+ };
+ private static final PSSParameterSpec SHA256withRSAPSS_NoSalt_Vector2Signature_ParameterSpec =
+ new PSSParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, 0, 1);
+
+ /*
+ * echo "This is a signed message from Kenny Root." | openssl sha256 -binary -out digest.bin \
+ * && openssl pkeyutl -sign -in digest.bin -inkey privkey.pem \
+ * -pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha256 -pkeyopt rsa_pss_saltlen:222 \
+ * | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] SHA256withRSAPSS_MaxSalt_Vector2Signature = new byte[] {
+ (byte) 0x3B, (byte) 0x43, (byte) 0xA8, (byte) 0xB5, (byte) 0x34, (byte) 0xD8,
+ (byte) 0xF9, (byte) 0xAD, (byte) 0xDD, (byte) 0x1F, (byte) 0x7A, (byte) 0x73,
+ (byte) 0xBF, (byte) 0xFA, (byte) 0xED, (byte) 0x10, (byte) 0xF3, (byte) 0x16,
+ (byte) 0xCC, (byte) 0xE5, (byte) 0x09, (byte) 0x0F, (byte) 0x68, (byte) 0x02,
+ (byte) 0xE7, (byte) 0x55, (byte) 0x0D, (byte) 0xCF, (byte) 0x1B, (byte) 0x83,
+ (byte) 0xCD, (byte) 0xA2, (byte) 0xD6, (byte) 0x02, (byte) 0xDD, (byte) 0x72,
+ (byte) 0xA6, (byte) 0x5F, (byte) 0x05, (byte) 0x8A, (byte) 0x1E, (byte) 0xA1,
+ (byte) 0x4F, (byte) 0x92, (byte) 0xD9, (byte) 0x09, (byte) 0x19, (byte) 0x6E,
+ (byte) 0x80, (byte) 0xA0, (byte) 0x47, (byte) 0x98, (byte) 0x5C, (byte) 0xF7,
+ (byte) 0x34, (byte) 0x52, (byte) 0x7D, (byte) 0x85, (byte) 0xCF, (byte) 0x9F,
+ (byte) 0xEB, (byte) 0xAF, (byte) 0xB4, (byte) 0x53, (byte) 0xF0, (byte) 0x5D,
+ (byte) 0x28, (byte) 0x87, (byte) 0xAC, (byte) 0xA7, (byte) 0xB4, (byte) 0xCF,
+ (byte) 0xDD, (byte) 0x8B, (byte) 0xA4, (byte) 0xC9, (byte) 0xCA, (byte) 0xAA,
+ (byte) 0xF4, (byte) 0xA8, (byte) 0x25, (byte) 0x26, (byte) 0x34, (byte) 0x11,
+ (byte) 0x14, (byte) 0x24, (byte) 0x1C, (byte) 0x1C, (byte) 0x50, (byte) 0xC8,
+ (byte) 0xFF, (byte) 0x7E, (byte) 0xFF, (byte) 0x6F, (byte) 0x4F, (byte) 0x14,
+ (byte) 0xB3, (byte) 0x57, (byte) 0x48, (byte) 0x0A, (byte) 0x5A, (byte) 0x95,
+ (byte) 0x5D, (byte) 0xEB, (byte) 0x71, (byte) 0x4E, (byte) 0x86, (byte) 0xFC,
+ (byte) 0x38, (byte) 0x1B, (byte) 0x93, (byte) 0x45, (byte) 0x09, (byte) 0x15,
+ (byte) 0xD3, (byte) 0x06, (byte) 0x6B, (byte) 0x9D, (byte) 0x05, (byte) 0x5C,
+ (byte) 0x4A, (byte) 0xB3, (byte) 0x93, (byte) 0xD1, (byte) 0x01, (byte) 0x54,
+ (byte) 0xCC, (byte) 0xED, (byte) 0xBF, (byte) 0x0E, (byte) 0x7E, (byte) 0x33,
+ (byte) 0x32, (byte) 0xA6, (byte) 0xA5, (byte) 0xF7, (byte) 0x3D, (byte) 0x2E,
+ (byte) 0xCB, (byte) 0x76, (byte) 0xA7, (byte) 0x22, (byte) 0x64, (byte) 0xB8,
+ (byte) 0x19, (byte) 0x53, (byte) 0xFE, (byte) 0x8C, (byte) 0xC8, (byte) 0x1E,
+ (byte) 0x6C, (byte) 0xEE, (byte) 0x08, (byte) 0x07, (byte) 0x7E, (byte) 0x93,
+ (byte) 0x43, (byte) 0x1B, (byte) 0xCF, (byte) 0x37, (byte) 0xE4, (byte) 0xAB,
+ (byte) 0xE7, (byte) 0xD7, (byte) 0x83, (byte) 0x8E, (byte) 0x19, (byte) 0xAE,
+ (byte) 0x05, (byte) 0x51, (byte) 0x91, (byte) 0x10, (byte) 0x7B, (byte) 0x70,
+ (byte) 0xFC, (byte) 0x73, (byte) 0x12, (byte) 0x96, (byte) 0xFA, (byte) 0xD0,
+ (byte) 0xCA, (byte) 0xA3, (byte) 0x59, (byte) 0xA7, (byte) 0xDD, (byte) 0xC3,
+ (byte) 0x1D, (byte) 0x9C, (byte) 0x7B, (byte) 0x50, (byte) 0xBB, (byte) 0x57,
+ (byte) 0xB8, (byte) 0x86, (byte) 0xF2, (byte) 0xCA, (byte) 0xC4, (byte) 0x86,
+ (byte) 0x7A, (byte) 0x96, (byte) 0x90, (byte) 0x02, (byte) 0xDF, (byte) 0xA0,
+ (byte) 0x88, (byte) 0x0E, (byte) 0x89, (byte) 0x45, (byte) 0x27, (byte) 0x52,
+ (byte) 0xDA, (byte) 0x86, (byte) 0x42, (byte) 0x4B, (byte) 0x90, (byte) 0xC3,
+ (byte) 0xC1, (byte) 0x41, (byte) 0x60, (byte) 0x5C, (byte) 0x29, (byte) 0x15,
+ (byte) 0xE5, (byte) 0x5C, (byte) 0x43, (byte) 0x9B, (byte) 0x40, (byte) 0xE5,
+ (byte) 0x04, (byte) 0x1B, (byte) 0x4A, (byte) 0x93, (byte) 0xDD, (byte) 0x55,
+ (byte) 0xC4, (byte) 0xFC, (byte) 0xFE, (byte) 0x0C, (byte) 0x65, (byte) 0x96,
+ (byte) 0x98, (byte) 0xDE, (byte) 0xC5, (byte) 0x05, (byte) 0xC5, (byte) 0x3E,
+ (byte) 0xB0, (byte) 0x25, (byte) 0x4E, (byte) 0x65, (byte) 0x24, (byte) 0x8D,
+ (byte) 0x4E, (byte) 0x9D, (byte) 0x94, (byte) 0x01,
+ };
+ private static final PSSParameterSpec SHA256withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec =
+ new PSSParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, 222, 1);
+
+ /*
+ * echo "This is a signed message from Kenny Root." | openssl sha384 -binary -out digest.bin \
+ * && openssl pkeyutl -sign -in digest.bin -inkey privkey.pem \
+ * -pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha384 -pkeyopt rsa_pss_saltlen:48 \
+ * | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] SHA384withRSAPSS_Vector2Signature = new byte[] {
+ (byte) 0x20, (byte) 0xCB, (byte) 0x97, (byte) 0x9C, (byte) 0x2E, (byte) 0x51,
+ (byte) 0x59, (byte) 0x56, (byte) 0x9F, (byte) 0x04, (byte) 0x47, (byte) 0x7C,
+ (byte) 0x5C, (byte) 0x57, (byte) 0x59, (byte) 0xBC, (byte) 0x43, (byte) 0xD9,
+ (byte) 0x4B, (byte) 0xEC, (byte) 0xAC, (byte) 0xB9, (byte) 0x88, (byte) 0xA2,
+ (byte) 0x30, (byte) 0x8B, (byte) 0xEE, (byte) 0x2F, (byte) 0xC1, (byte) 0x73,
+ (byte) 0xF1, (byte) 0x13, (byte) 0xB2, (byte) 0x5E, (byte) 0x1A, (byte) 0xC8,
+ (byte) 0xD2, (byte) 0xAA, (byte) 0x27, (byte) 0x16, (byte) 0xA1, (byte) 0x14,
+ (byte) 0xAB, (byte) 0x45, (byte) 0x8A, (byte) 0x7E, (byte) 0x22, (byte) 0x22,
+ (byte) 0x2A, (byte) 0x2E, (byte) 0xDA, (byte) 0x6A, (byte) 0x7E, (byte) 0x3F,
+ (byte) 0x66, (byte) 0x99, (byte) 0x55, (byte) 0xAF, (byte) 0x2B, (byte) 0x94,
+ (byte) 0xD8, (byte) 0x6B, (byte) 0xC2, (byte) 0x60, (byte) 0xB5, (byte) 0x55,
+ (byte) 0xA9, (byte) 0x26, (byte) 0x29, (byte) 0xFC, (byte) 0x17, (byte) 0x56,
+ (byte) 0x05, (byte) 0xB7, (byte) 0x48, (byte) 0x2F, (byte) 0xAB, (byte) 0x68,
+ (byte) 0xCF, (byte) 0x37, (byte) 0x62, (byte) 0x79, (byte) 0x4F, (byte) 0x32,
+ (byte) 0x04, (byte) 0xF6, (byte) 0xEA, (byte) 0xBE, (byte) 0x79, (byte) 0x84,
+ (byte) 0x73, (byte) 0xEE, (byte) 0x1C, (byte) 0xEE, (byte) 0x9F, (byte) 0x72,
+ (byte) 0x7A, (byte) 0xC6, (byte) 0x64, (byte) 0xB4, (byte) 0x4F, (byte) 0xDE,
+ (byte) 0x0B, (byte) 0x38, (byte) 0x47, (byte) 0x62, (byte) 0xA9, (byte) 0xFD,
+ (byte) 0x1B, (byte) 0x75, (byte) 0xEC, (byte) 0xFE, (byte) 0x2D, (byte) 0x04,
+ (byte) 0x2D, (byte) 0x0A, (byte) 0xCE, (byte) 0x13, (byte) 0xFA, (byte) 0xDA,
+ (byte) 0x3F, (byte) 0x4C, (byte) 0x11, (byte) 0xEA, (byte) 0x02, (byte) 0x00,
+ (byte) 0x0A, (byte) 0x93, (byte) 0x12, (byte) 0xDC, (byte) 0x60, (byte) 0xE7,
+ (byte) 0x52, (byte) 0x90, (byte) 0x8A, (byte) 0xA3, (byte) 0xAE, (byte) 0xC5,
+ (byte) 0x9A, (byte) 0xD7, (byte) 0xD5, (byte) 0x0D, (byte) 0xBC, (byte) 0x7A,
+ (byte) 0xDB, (byte) 0xF4, (byte) 0x10, (byte) 0xE0, (byte) 0xDB, (byte) 0xC0,
+ (byte) 0x97, (byte) 0xF1, (byte) 0x84, (byte) 0xCF, (byte) 0x66, (byte) 0xB2,
+ (byte) 0x04, (byte) 0x58, (byte) 0x81, (byte) 0xB5, (byte) 0x9B, (byte) 0x4A,
+ (byte) 0xF9, (byte) 0xD7, (byte) 0xCA, (byte) 0x51, (byte) 0x09, (byte) 0x67,
+ (byte) 0x48, (byte) 0x7B, (byte) 0xE5, (byte) 0xE9, (byte) 0x07, (byte) 0x4E,
+ (byte) 0x6A, (byte) 0xC1, (byte) 0xA6, (byte) 0x68, (byte) 0x90, (byte) 0x17,
+ (byte) 0xAB, (byte) 0x0E, (byte) 0xFB, (byte) 0x3E, (byte) 0x39, (byte) 0x74,
+ (byte) 0x85, (byte) 0x04, (byte) 0x42, (byte) 0x0A, (byte) 0x9E, (byte) 0x02,
+ (byte) 0xA9, (byte) 0x50, (byte) 0xFF, (byte) 0x23, (byte) 0x2D, (byte) 0x30,
+ (byte) 0xDD, (byte) 0x17, (byte) 0xC0, (byte) 0x82, (byte) 0xF7, (byte) 0xBB,
+ (byte) 0x3B, (byte) 0x03, (byte) 0xBD, (byte) 0xB1, (byte) 0x96, (byte) 0xCD,
+ (byte) 0x71, (byte) 0x3F, (byte) 0x67, (byte) 0x59, (byte) 0x5E, (byte) 0x45,
+ (byte) 0xE0, (byte) 0x1C, (byte) 0x80, (byte) 0x52, (byte) 0xD7, (byte) 0xF0,
+ (byte) 0xC1, (byte) 0xE6, (byte) 0xCF, (byte) 0x59, (byte) 0x13, (byte) 0x25,
+ (byte) 0x6F, (byte) 0x9F, (byte) 0xBB, (byte) 0xB9, (byte) 0x7F, (byte) 0x7E,
+ (byte) 0x7D, (byte) 0x93, (byte) 0xD9, (byte) 0x3F, (byte) 0x95, (byte) 0xB7,
+ (byte) 0x9A, (byte) 0xDB, (byte) 0xE2, (byte) 0x2C, (byte) 0x53, (byte) 0x83,
+ (byte) 0x9A, (byte) 0x06, (byte) 0x6D, (byte) 0x22, (byte) 0x81, (byte) 0xB5,
+ (byte) 0x63, (byte) 0xAE, (byte) 0x4A, (byte) 0xEE,
+ };
+ private static final PSSParameterSpec SHA384withRSAPSS_Vector2Signature_ParameterSpec =
+ new PSSParameterSpec("SHA-384", "MGF1", MGF1ParameterSpec.SHA384, 48, 1);
+
+ /*
+ * echo "This is a signed message from Kenny Root." | openssl sha384 -binary -out digest.bin \
+ * && openssl pkeyutl -sign -in digest.bin -inkey privkey.pem \
+ * -pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha384 -pkeyopt rsa_pss_saltlen:0 \
+ * | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] SHA384withRSAPSS_NoSalt_Vector2Signature = new byte[] {
+ (byte) 0x41, (byte) 0x0C, (byte) 0x3A, (byte) 0xEC, (byte) 0xF6, (byte) 0xD9,
+ (byte) 0x8F, (byte) 0xA3, (byte) 0x61, (byte) 0xBB, (byte) 0x03, (byte) 0xED,
+ (byte) 0xD9, (byte) 0x69, (byte) 0x7D, (byte) 0xE1, (byte) 0xE1, (byte) 0x4E,
+ (byte) 0x5E, (byte) 0x71, (byte) 0x4E, (byte) 0x88, (byte) 0x9C, (byte) 0x79,
+ (byte) 0xD3, (byte) 0x71, (byte) 0x28, (byte) 0x07, (byte) 0x28, (byte) 0x19,
+ (byte) 0x96, (byte) 0x55, (byte) 0x30, (byte) 0x81, (byte) 0x29, (byte) 0x5C,
+ (byte) 0x4A, (byte) 0x18, (byte) 0x69, (byte) 0x36, (byte) 0x74, (byte) 0xAC,
+ (byte) 0x99, (byte) 0xB1, (byte) 0xBC, (byte) 0xA0, (byte) 0xFC, (byte) 0x17,
+ (byte) 0xA4, (byte) 0xD1, (byte) 0xAE, (byte) 0x84, (byte) 0xA6, (byte) 0x09,
+ (byte) 0x6B, (byte) 0xB3, (byte) 0x02, (byte) 0xB2, (byte) 0x81, (byte) 0x04,
+ (byte) 0x59, (byte) 0x8C, (byte) 0xCF, (byte) 0xAD, (byte) 0xFB, (byte) 0x76,
+ (byte) 0x6F, (byte) 0xE2, (byte) 0x5E, (byte) 0x09, (byte) 0xE5, (byte) 0xBC,
+ (byte) 0x54, (byte) 0xBD, (byte) 0x08, (byte) 0xA8, (byte) 0x18, (byte) 0x60,
+ (byte) 0xAF, (byte) 0x09, (byte) 0x67, (byte) 0x15, (byte) 0x03, (byte) 0xA8,
+ (byte) 0x8B, (byte) 0x3F, (byte) 0x31, (byte) 0xB7, (byte) 0x76, (byte) 0xFD,
+ (byte) 0xF6, (byte) 0x82, (byte) 0xC7, (byte) 0x89, (byte) 0xC2, (byte) 0x47,
+ (byte) 0x80, (byte) 0x06, (byte) 0x4F, (byte) 0x8C, (byte) 0x9C, (byte) 0xD7,
+ (byte) 0x4F, (byte) 0x63, (byte) 0x1E, (byte) 0xF0, (byte) 0x34, (byte) 0xD7,
+ (byte) 0x91, (byte) 0xD2, (byte) 0x96, (byte) 0x62, (byte) 0xFD, (byte) 0x68,
+ (byte) 0xE3, (byte) 0xE0, (byte) 0xFB, (byte) 0x7D, (byte) 0x0A, (byte) 0xD7,
+ (byte) 0x52, (byte) 0xFE, (byte) 0xD1, (byte) 0x95, (byte) 0x9E, (byte) 0xD2,
+ (byte) 0x84, (byte) 0xBE, (byte) 0x3D, (byte) 0x1F, (byte) 0x8C, (byte) 0xC4,
+ (byte) 0xD6, (byte) 0xE3, (byte) 0xCF, (byte) 0xE8, (byte) 0xB3, (byte) 0x82,
+ (byte) 0x2E, (byte) 0xFA, (byte) 0x39, (byte) 0xA3, (byte) 0x20, (byte) 0x3C,
+ (byte) 0xBE, (byte) 0x6A, (byte) 0xFA, (byte) 0x04, (byte) 0xD2, (byte) 0x74,
+ (byte) 0x41, (byte) 0xDC, (byte) 0xE8, (byte) 0x0E, (byte) 0xE7, (byte) 0xF2,
+ (byte) 0x36, (byte) 0xD4, (byte) 0x2E, (byte) 0x6A, (byte) 0xCF, (byte) 0xDF,
+ (byte) 0x8B, (byte) 0x4B, (byte) 0x77, (byte) 0xE8, (byte) 0x0A, (byte) 0x64,
+ (byte) 0x86, (byte) 0x2C, (byte) 0xCA, (byte) 0x92, (byte) 0x01, (byte) 0xB2,
+ (byte) 0x8A, (byte) 0xB8, (byte) 0xB2, (byte) 0x6C, (byte) 0x0B, (byte) 0x18,
+ (byte) 0x90, (byte) 0x31, (byte) 0x93, (byte) 0x29, (byte) 0xBA, (byte) 0xB1,
+ (byte) 0x88, (byte) 0x94, (byte) 0x44, (byte) 0x0B, (byte) 0x38, (byte) 0x64,
+ (byte) 0xC1, (byte) 0xDE, (byte) 0x0B, (byte) 0xD8, (byte) 0xE4, (byte) 0xBA,
+ (byte) 0x0A, (byte) 0x41, (byte) 0x24, (byte) 0x35, (byte) 0xAA, (byte) 0xE3,
+ (byte) 0x59, (byte) 0x8E, (byte) 0x57, (byte) 0x51, (byte) 0x43, (byte) 0xE1,
+ (byte) 0x9C, (byte) 0xF6, (byte) 0xF8, (byte) 0x16, (byte) 0x68, (byte) 0x83,
+ (byte) 0x08, (byte) 0x8C, (byte) 0x2D, (byte) 0x40, (byte) 0xD2, (byte) 0xEF,
+ (byte) 0xD6, (byte) 0xAE, (byte) 0x98, (byte) 0x77, (byte) 0xE8, (byte) 0xF2,
+ (byte) 0xC7, (byte) 0x19, (byte) 0x61, (byte) 0xD6, (byte) 0x43, (byte) 0xCD,
+ (byte) 0x76, (byte) 0x2E, (byte) 0x7A, (byte) 0xCB, (byte) 0x1A, (byte) 0x5D,
+ (byte) 0x73, (byte) 0x45, (byte) 0xF2, (byte) 0x7C, (byte) 0xD0, (byte) 0x88,
+ (byte) 0x83, (byte) 0x51, (byte) 0xF3, (byte) 0x19, (byte) 0x0F, (byte) 0xD5,
+ (byte) 0x40, (byte) 0x3F, (byte) 0xD9, (byte) 0xBF,
+ };
+ private static final PSSParameterSpec SHA384withRSAPSS_NoSalt_Vector2Signature_ParameterSpec =
+ new PSSParameterSpec("SHA-384", "MGF1", MGF1ParameterSpec.SHA384, 0, 1);
+
+ /*
+ * echo "This is a signed message from Kenny Root." | openssl sha384 -binary -out digest.bin \
+ * && openssl pkeyutl -sign -in digest.bin -inkey privkey.pem \
+ * -pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha384 -pkeyopt rsa_pss_saltlen:206 \
+ * | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] SHA384withRSAPSS_MaxSalt_Vector2Signature = new byte[] {
+ (byte) 0xDE, (byte) 0xF7, (byte) 0xC3, (byte) 0x21, (byte) 0x79, (byte) 0x0F,
+ (byte) 0x55, (byte) 0xD1, (byte) 0x56, (byte) 0x9A, (byte) 0xB0, (byte) 0x08,
+ (byte) 0xA1, (byte) 0x27, (byte) 0xC9, (byte) 0x5E, (byte) 0x64, (byte) 0xF4,
+ (byte) 0xC7, (byte) 0x83, (byte) 0x94, (byte) 0xCA, (byte) 0xBD, (byte) 0x50,
+ (byte) 0xD6, (byte) 0xC5, (byte) 0x56, (byte) 0x94, (byte) 0xBD, (byte) 0x0B,
+ (byte) 0x55, (byte) 0xE6, (byte) 0x04, (byte) 0xAD, (byte) 0xAF, (byte) 0xAF,
+ (byte) 0x4F, (byte) 0x2D, (byte) 0x91, (byte) 0x7F, (byte) 0xF1, (byte) 0x60,
+ (byte) 0x0C, (byte) 0xEE, (byte) 0xE8, (byte) 0x44, (byte) 0xFC, (byte) 0x69,
+ (byte) 0x80, (byte) 0x43, (byte) 0xBC, (byte) 0xAB, (byte) 0x83, (byte) 0x35,
+ (byte) 0xB0, (byte) 0xC6, (byte) 0xCB, (byte) 0xE6, (byte) 0x92, (byte) 0x29,
+ (byte) 0x09, (byte) 0xCF, (byte) 0xDB, (byte) 0xAD, (byte) 0x16, (byte) 0x93,
+ (byte) 0xC7, (byte) 0xBE, (byte) 0x81, (byte) 0x68, (byte) 0x0F, (byte) 0x7B,
+ (byte) 0xC1, (byte) 0xC2, (byte) 0x8C, (byte) 0xBA, (byte) 0x59, (byte) 0x80,
+ (byte) 0xAE, (byte) 0xFB, (byte) 0x60, (byte) 0x22, (byte) 0x28, (byte) 0x36,
+ (byte) 0xBE, (byte) 0x37, (byte) 0x72, (byte) 0x86, (byte) 0x02, (byte) 0x4B,
+ (byte) 0xF9, (byte) 0x14, (byte) 0x5A, (byte) 0x6B, (byte) 0x32, (byte) 0x44,
+ (byte) 0x72, (byte) 0x33, (byte) 0x2E, (byte) 0x7F, (byte) 0xA1, (byte) 0xFD,
+ (byte) 0x07, (byte) 0xF2, (byte) 0xD9, (byte) 0x9D, (byte) 0x03, (byte) 0x77,
+ (byte) 0x17, (byte) 0xFB, (byte) 0x0E, (byte) 0xFF, (byte) 0xF7, (byte) 0x37,
+ (byte) 0x68, (byte) 0xF6, (byte) 0x8F, (byte) 0x9B, (byte) 0x2C, (byte) 0xEB,
+ (byte) 0xAF, (byte) 0x6C, (byte) 0x50, (byte) 0x9F, (byte) 0x34, (byte) 0xB2,
+ (byte) 0x52, (byte) 0x3B, (byte) 0x94, (byte) 0x6F, (byte) 0x60, (byte) 0x16,
+ (byte) 0x52, (byte) 0x0A, (byte) 0xBF, (byte) 0x95, (byte) 0x41, (byte) 0x44,
+ (byte) 0x83, (byte) 0x91, (byte) 0x85, (byte) 0xA1, (byte) 0xF7, (byte) 0xF9,
+ (byte) 0x17, (byte) 0x4A, (byte) 0xF7, (byte) 0xF1, (byte) 0xE8, (byte) 0x9C,
+ (byte) 0x75, (byte) 0x86, (byte) 0x12, (byte) 0x44, (byte) 0x19, (byte) 0x5C,
+ (byte) 0x65, (byte) 0x31, (byte) 0x89, (byte) 0x2A, (byte) 0xFC, (byte) 0xBE,
+ (byte) 0xE8, (byte) 0xEC, (byte) 0xC9, (byte) 0xD7, (byte) 0x41, (byte) 0xDA,
+ (byte) 0xD9, (byte) 0xC9, (byte) 0x8B, (byte) 0x90, (byte) 0x60, (byte) 0xCC,
+ (byte) 0xB2, (byte) 0x7A, (byte) 0xBA, (byte) 0xA0, (byte) 0xEE, (byte) 0xBE,
+ (byte) 0x9C, (byte) 0xE7, (byte) 0xF2, (byte) 0x27, (byte) 0x92, (byte) 0x9C,
+ (byte) 0x3C, (byte) 0x0F, (byte) 0x5C, (byte) 0xEE, (byte) 0x38, (byte) 0x48,
+ (byte) 0xCF, (byte) 0xFF, (byte) 0x33, (byte) 0x35, (byte) 0x80, (byte) 0x99,
+ (byte) 0x5D, (byte) 0xA7, (byte) 0x5A, (byte) 0x7A, (byte) 0xEA, (byte) 0x96,
+ (byte) 0x74, (byte) 0x28, (byte) 0x36, (byte) 0x7B, (byte) 0xE1, (byte) 0x33,
+ (byte) 0x7C, (byte) 0x78, (byte) 0xEC, (byte) 0x05, (byte) 0x72, (byte) 0x0E,
+ (byte) 0x5D, (byte) 0x16, (byte) 0x5C, (byte) 0x77, (byte) 0x58, (byte) 0xA7,
+ (byte) 0x31, (byte) 0x3F, (byte) 0xBA, (byte) 0x91, (byte) 0xA7, (byte) 0x16,
+ (byte) 0xFC, (byte) 0x31, (byte) 0xCA, (byte) 0x30, (byte) 0xE0, (byte) 0xF4,
+ (byte) 0x5D, (byte) 0x07, (byte) 0x4A, (byte) 0x9C, (byte) 0x1D, (byte) 0x2B,
+ (byte) 0x4E, (byte) 0xB8, (byte) 0x7C, (byte) 0x67, (byte) 0xCB, (byte) 0x34,
+ (byte) 0x69, (byte) 0x85, (byte) 0x4E, (byte) 0x99, (byte) 0x41, (byte) 0x8A,
+ (byte) 0x35, (byte) 0x85, (byte) 0xF2, (byte) 0x1A,
+ };
+ private static final PSSParameterSpec SHA384withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec =
+ new PSSParameterSpec("SHA-384", "MGF1", MGF1ParameterSpec.SHA384, 206, 1);
+
+ /*
+ * echo "This is a signed message from Kenny Root." | openssl sha512 -binary -out digest.bin \
+ * && openssl pkeyutl -sign -in digest.bin -inkey privkey.pem \
+ * -pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha512 -pkeyopt rsa_pss_saltlen:64 \
+ * | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] SHA512withRSAPSS_Vector2Signature = new byte[] {
+ (byte) 0x9F, (byte) 0xED, (byte) 0xF8, (byte) 0xEE, (byte) 0x30, (byte) 0x5F,
+ (byte) 0x30, (byte) 0x63, (byte) 0x1D, (byte) 0x86, (byte) 0xD3, (byte) 0xAD,
+ (byte) 0x1D, (byte) 0xD8, (byte) 0xD2, (byte) 0x67, (byte) 0xE2, (byte) 0x43,
+ (byte) 0x64, (byte) 0x71, (byte) 0x98, (byte) 0x82, (byte) 0x00, (byte) 0x84,
+ (byte) 0x2C, (byte) 0x88, (byte) 0x1A, (byte) 0x28, (byte) 0xCD, (byte) 0xA2,
+ (byte) 0x34, (byte) 0x17, (byte) 0x0F, (byte) 0x34, (byte) 0x8A, (byte) 0x10,
+ (byte) 0x79, (byte) 0x6C, (byte) 0xCB, (byte) 0xDA, (byte) 0x2F, (byte) 0xDF,
+ (byte) 0x4D, (byte) 0x98, (byte) 0x01, (byte) 0xE8, (byte) 0xB3, (byte) 0xF5,
+ (byte) 0xCD, (byte) 0x60, (byte) 0xEA, (byte) 0xDE, (byte) 0xA5, (byte) 0x0C,
+ (byte) 0x09, (byte) 0xA1, (byte) 0x4A, (byte) 0xC4, (byte) 0x6B, (byte) 0x09,
+ (byte) 0xB3, (byte) 0x37, (byte) 0x1F, (byte) 0x8A, (byte) 0x64, (byte) 0x81,
+ (byte) 0x2E, (byte) 0x22, (byte) 0x75, (byte) 0x24, (byte) 0x3B, (byte) 0xC0,
+ (byte) 0x0E, (byte) 0x1F, (byte) 0x37, (byte) 0xC9, (byte) 0x1E, (byte) 0x6F,
+ (byte) 0xAF, (byte) 0x3E, (byte) 0x9B, (byte) 0x3F, (byte) 0xA3, (byte) 0xC3,
+ (byte) 0x0B, (byte) 0xB9, (byte) 0x83, (byte) 0x60, (byte) 0x02, (byte) 0xC6,
+ (byte) 0x29, (byte) 0x83, (byte) 0x09, (byte) 0x16, (byte) 0xD9, (byte) 0x3D,
+ (byte) 0x84, (byte) 0x02, (byte) 0x81, (byte) 0x20, (byte) 0xE9, (byte) 0x01,
+ (byte) 0x5B, (byte) 0x85, (byte) 0xC8, (byte) 0x81, (byte) 0x25, (byte) 0x6B,
+ (byte) 0xCB, (byte) 0x78, (byte) 0x48, (byte) 0x65, (byte) 0x3A, (byte) 0xD6,
+ (byte) 0x95, (byte) 0x9B, (byte) 0x62, (byte) 0x2D, (byte) 0x84, (byte) 0x54,
+ (byte) 0x12, (byte) 0x94, (byte) 0xB7, (byte) 0xF0, (byte) 0x1C, (byte) 0xB6,
+ (byte) 0x59, (byte) 0xCD, (byte) 0xC3, (byte) 0x86, (byte) 0xE6, (byte) 0x63,
+ (byte) 0xD7, (byte) 0x99, (byte) 0x9A, (byte) 0xC4, (byte) 0xBF, (byte) 0x8E,
+ (byte) 0xDD, (byte) 0x46, (byte) 0x10, (byte) 0xBE, (byte) 0xAB, (byte) 0x78,
+ (byte) 0xC6, (byte) 0x30, (byte) 0x47, (byte) 0x23, (byte) 0xB6, (byte) 0x2C,
+ (byte) 0x02, (byte) 0x5E, (byte) 0x1F, (byte) 0x07, (byte) 0x96, (byte) 0x54,
+ (byte) 0xEE, (byte) 0x28, (byte) 0xC7, (byte) 0xEC, (byte) 0x57, (byte) 0xDB,
+ (byte) 0x9E, (byte) 0xEF, (byte) 0xE4, (byte) 0x11, (byte) 0xF8, (byte) 0x04,
+ (byte) 0xA9, (byte) 0x26, (byte) 0xC2, (byte) 0x61, (byte) 0xF1, (byte) 0x84,
+ (byte) 0xEB, (byte) 0x94, (byte) 0xBD, (byte) 0x48, (byte) 0xCA, (byte) 0xD1,
+ (byte) 0x84, (byte) 0xCE, (byte) 0x82, (byte) 0x2E, (byte) 0xF6, (byte) 0x4E,
+ (byte) 0x17, (byte) 0x6F, (byte) 0x78, (byte) 0xB9, (byte) 0x0B, (byte) 0xA9,
+ (byte) 0x7D, (byte) 0xBC, (byte) 0xE5, (byte) 0xF8, (byte) 0x7D, (byte) 0xA8,
+ (byte) 0x76, (byte) 0x7A, (byte) 0x8B, (byte) 0xB5, (byte) 0x05, (byte) 0x42,
+ (byte) 0x37, (byte) 0xDA, (byte) 0x15, (byte) 0xE2, (byte) 0xC4, (byte) 0x70,
+ (byte) 0x6E, (byte) 0x95, (byte) 0x60, (byte) 0x47, (byte) 0xF9, (byte) 0x0F,
+ (byte) 0xF4, (byte) 0xA2, (byte) 0x73, (byte) 0xF1, (byte) 0x73, (byte) 0xBD,
+ (byte) 0x0B, (byte) 0x9B, (byte) 0x44, (byte) 0xB6, (byte) 0xA9, (byte) 0xAF,
+ (byte) 0x50, (byte) 0x2D, (byte) 0x5C, (byte) 0xA3, (byte) 0x72, (byte) 0x6F,
+ (byte) 0x85, (byte) 0xE8, (byte) 0x0C, (byte) 0xF9, (byte) 0xE1, (byte) 0xE8,
+ (byte) 0xF7, (byte) 0xC0, (byte) 0x85, (byte) 0x14, (byte) 0x53, (byte) 0x95,
+ (byte) 0xF9, (byte) 0x9E, (byte) 0x65, (byte) 0x05, (byte) 0xF0, (byte) 0x22,
+ (byte) 0x7F, (byte) 0x4F, (byte) 0x40, (byte) 0x45,
+ };
+ private static final PSSParameterSpec SHA512withRSAPSS_Vector2Signature_ParameterSpec =
+ new PSSParameterSpec("SHA-512", "MGF1", MGF1ParameterSpec.SHA512, 64, 1);
+
+ /*
+ * echo "This is a signed message from Kenny Root." | openssl sha512 -binary -out digest.bin \
+ * && openssl pkeyutl -sign -in digest.bin -inkey privkey.pem \
+ * -pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha512 -pkeyopt rsa_pss_saltlen:64 \
+ * | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] SHA512withRSAPSS_NoSalt_Vector2Signature = new byte[] {
+ (byte) 0x49, (byte) 0xA3, (byte) 0xBC, (byte) 0x2E, (byte) 0x67, (byte) 0x96,
+ (byte) 0xA5, (byte) 0x3E, (byte) 0x39, (byte) 0x46, (byte) 0xD6, (byte) 0xA1,
+ (byte) 0xA0, (byte) 0x4F, (byte) 0x3A, (byte) 0x03, (byte) 0x8F, (byte) 0x62,
+ (byte) 0xF2, (byte) 0xD8, (byte) 0x90, (byte) 0xAD, (byte) 0xE2, (byte) 0x3B,
+ (byte) 0x4F, (byte) 0x98, (byte) 0x88, (byte) 0x51, (byte) 0x41, (byte) 0x09,
+ (byte) 0x23, (byte) 0xEB, (byte) 0xF4, (byte) 0x5D, (byte) 0x6A, (byte) 0x22,
+ (byte) 0x12, (byte) 0x12, (byte) 0xDC, (byte) 0x27, (byte) 0xE9, (byte) 0xF7,
+ (byte) 0x64, (byte) 0xA3, (byte) 0xDE, (byte) 0x3A, (byte) 0xB0, (byte) 0xD6,
+ (byte) 0xF2, (byte) 0xC6, (byte) 0xBC, (byte) 0x0B, (byte) 0xA2, (byte) 0xA1,
+ (byte) 0xAA, (byte) 0xB0, (byte) 0x51, (byte) 0xDA, (byte) 0x4F, (byte) 0x28,
+ (byte) 0xA8, (byte) 0xEB, (byte) 0x34, (byte) 0x60, (byte) 0x37, (byte) 0xF7,
+ (byte) 0x50, (byte) 0x7D, (byte) 0xB8, (byte) 0xE7, (byte) 0x24, (byte) 0x8E,
+ (byte) 0xAC, (byte) 0x03, (byte) 0x31, (byte) 0xB8, (byte) 0xE0, (byte) 0xDB,
+ (byte) 0x97, (byte) 0xE9, (byte) 0x1B, (byte) 0x7E, (byte) 0x27, (byte) 0x99,
+ (byte) 0x93, (byte) 0x4D, (byte) 0x46, (byte) 0xB3, (byte) 0xFE, (byte) 0xD6,
+ (byte) 0x23, (byte) 0xB3, (byte) 0xAB, (byte) 0x3E, (byte) 0x33, (byte) 0xA1,
+ (byte) 0x10, (byte) 0x4E, (byte) 0x34, (byte) 0x27, (byte) 0x58, (byte) 0x25,
+ (byte) 0xB7, (byte) 0xBA, (byte) 0xEE, (byte) 0xBE, (byte) 0xE0, (byte) 0x6E,
+ (byte) 0x54, (byte) 0xF7, (byte) 0x73, (byte) 0x7B, (byte) 0x5A, (byte) 0x9C,
+ (byte) 0x74, (byte) 0xEA, (byte) 0xC7, (byte) 0x7E, (byte) 0xC6, (byte) 0xF7,
+ (byte) 0xD5, (byte) 0x32, (byte) 0x0E, (byte) 0x28, (byte) 0x99, (byte) 0xD8,
+ (byte) 0xEF, (byte) 0x97, (byte) 0x62, (byte) 0x8A, (byte) 0xE3, (byte) 0x16,
+ (byte) 0xAD, (byte) 0xE2, (byte) 0xF4, (byte) 0x11, (byte) 0x91, (byte) 0x17,
+ (byte) 0xF3, (byte) 0x32, (byte) 0x90, (byte) 0xCB, (byte) 0x3C, (byte) 0x89,
+ (byte) 0xF4, (byte) 0x20, (byte) 0xF1, (byte) 0x2D, (byte) 0x74, (byte) 0x22,
+ (byte) 0x50, (byte) 0x64, (byte) 0xC2, (byte) 0xF4, (byte) 0xC4, (byte) 0x0D,
+ (byte) 0x18, (byte) 0x6A, (byte) 0x02, (byte) 0x52, (byte) 0x14, (byte) 0x85,
+ (byte) 0x67, (byte) 0xA4, (byte) 0x08, (byte) 0xE5, (byte) 0xBF, (byte) 0x65,
+ (byte) 0x15, (byte) 0xB3, (byte) 0x5A, (byte) 0x88, (byte) 0xEB, (byte) 0xD4,
+ (byte) 0x75, (byte) 0xF9, (byte) 0x52, (byte) 0x73, (byte) 0xA0, (byte) 0x5E,
+ (byte) 0xBA, (byte) 0x37, (byte) 0x6A, (byte) 0x61, (byte) 0x2B, (byte) 0x16,
+ (byte) 0x8A, (byte) 0xA8, (byte) 0x00, (byte) 0xBB, (byte) 0x4D, (byte) 0xFA,
+ (byte) 0x04, (byte) 0xB8, (byte) 0xAB, (byte) 0x4D, (byte) 0xA4, (byte) 0xFC,
+ (byte) 0x9D, (byte) 0xCF, (byte) 0x63, (byte) 0x83, (byte) 0x34, (byte) 0xAE,
+ (byte) 0xAE, (byte) 0xA6, (byte) 0x77, (byte) 0x73, (byte) 0xA2, (byte) 0xB5,
+ (byte) 0x77, (byte) 0xAC, (byte) 0x00, (byte) 0x03, (byte) 0x06, (byte) 0xD4,
+ (byte) 0xDF, (byte) 0x81, (byte) 0x61, (byte) 0xCE, (byte) 0x8E, (byte) 0xC1,
+ (byte) 0xD5, (byte) 0x99, (byte) 0xD5, (byte) 0x2F, (byte) 0xE8, (byte) 0x27,
+ (byte) 0xFA, (byte) 0x84, (byte) 0x7E, (byte) 0x57, (byte) 0xF1, (byte) 0xC9,
+ (byte) 0xEB, (byte) 0x4F, (byte) 0xF9, (byte) 0x92, (byte) 0xC6, (byte) 0xD0,
+ (byte) 0x25, (byte) 0x8A, (byte) 0x16, (byte) 0xD0, (byte) 0xEC, (byte) 0xE5,
+ (byte) 0x33, (byte) 0xA6, (byte) 0xF9, (byte) 0xD5, (byte) 0x0C, (byte) 0x7B,
+ (byte) 0xEC, (byte) 0xC6, (byte) 0x58, (byte) 0x45,
+ };
+ private static final PSSParameterSpec SHA512withRSAPSS_NoSalt_Vector2Signature_ParameterSpec =
+ new PSSParameterSpec("SHA-512", "MGF1", MGF1ParameterSpec.SHA512, 0, 1);
+
+ /*
+ * echo "This is a signed message from Kenny Root." | openssl sha512 -binary -out digest.bin \
+ * && openssl pkeyutl -sign -in digest.bin -inkey privkey.pem \
+ * -pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha512 -pkeyopt rsa_pss_saltlen:190 \
+ * | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] SHA512withRSAPSS_MaxSalt_Vector2Signature = new byte[] {
+ (byte) 0x90, (byte) 0x92, (byte) 0x45, (byte) 0xA1, (byte) 0x1E, (byte) 0x0F,
+ (byte) 0x5F, (byte) 0xF6, (byte) 0x8F, (byte) 0xA0, (byte) 0xBE, (byte) 0x34,
+ (byte) 0x29, (byte) 0x62, (byte) 0xBE, (byte) 0x41, (byte) 0x80, (byte) 0xF0,
+ (byte) 0xB8, (byte) 0x9F, (byte) 0x29, (byte) 0x63, (byte) 0x89, (byte) 0x26,
+ (byte) 0xC2, (byte) 0x22, (byte) 0x1F, (byte) 0x60, (byte) 0xB6, (byte) 0xFC,
+ (byte) 0x5A, (byte) 0x3E, (byte) 0x99, (byte) 0xB8, (byte) 0xC6, (byte) 0x3B,
+ (byte) 0x67, (byte) 0x33, (byte) 0x97, (byte) 0x19, (byte) 0xC6, (byte) 0xFF,
+ (byte) 0x0C, (byte) 0xA9, (byte) 0x04, (byte) 0x5A, (byte) 0xF0, (byte) 0x02,
+ (byte) 0x9A, (byte) 0x19, (byte) 0x0F, (byte) 0xEA, (byte) 0x77, (byte) 0x0D,
+ (byte) 0x56, (byte) 0x38, (byte) 0x0A, (byte) 0xED, (byte) 0x4E, (byte) 0xB7,
+ (byte) 0x57, (byte) 0xBD, (byte) 0xC9, (byte) 0xA3, (byte) 0xE8, (byte) 0xC0,
+ (byte) 0x7D, (byte) 0xF6, (byte) 0xA3, (byte) 0x4B, (byte) 0x61, (byte) 0x45,
+ (byte) 0x06, (byte) 0x5E, (byte) 0x56, (byte) 0xF5, (byte) 0xEF, (byte) 0x76,
+ (byte) 0x6B, (byte) 0xB7, (byte) 0xD4, (byte) 0xBB, (byte) 0xA4, (byte) 0x3C,
+ (byte) 0x52, (byte) 0xF8, (byte) 0x06, (byte) 0x67, (byte) 0xF7, (byte) 0xC3,
+ (byte) 0x8C, (byte) 0x5E, (byte) 0xDF, (byte) 0xFE, (byte) 0x30, (byte) 0x2E,
+ (byte) 0xF8, (byte) 0x59, (byte) 0x3C, (byte) 0x3B, (byte) 0xEA, (byte) 0xA0,
+ (byte) 0x5D, (byte) 0x8F, (byte) 0x18, (byte) 0x73, (byte) 0x1A, (byte) 0x2D,
+ (byte) 0xB1, (byte) 0x55, (byte) 0x07, (byte) 0xC8, (byte) 0x33, (byte) 0xED,
+ (byte) 0x8A, (byte) 0x5E, (byte) 0xC3, (byte) 0xAE, (byte) 0x51, (byte) 0x31,
+ (byte) 0xC4, (byte) 0xFA, (byte) 0xE8, (byte) 0xE9, (byte) 0xBE, (byte) 0x2E,
+ (byte) 0x28, (byte) 0xAA, (byte) 0xED, (byte) 0xA8, (byte) 0x4B, (byte) 0xA3,
+ (byte) 0x13, (byte) 0xB9, (byte) 0x82, (byte) 0x57, (byte) 0xD1, (byte) 0x72,
+ (byte) 0x0D, (byte) 0xA7, (byte) 0xF8, (byte) 0x67, (byte) 0xB8, (byte) 0x55,
+ (byte) 0xF3, (byte) 0x06, (byte) 0xAE, (byte) 0xA7, (byte) 0x69, (byte) 0x66,
+ (byte) 0x0B, (byte) 0x80, (byte) 0x56, (byte) 0x65, (byte) 0xC7, (byte) 0xE9,
+ (byte) 0x60, (byte) 0xDC, (byte) 0x2D, (byte) 0x4B, (byte) 0x26, (byte) 0xA9,
+ (byte) 0xED, (byte) 0x54, (byte) 0x79, (byte) 0x9E, (byte) 0x55, (byte) 0x1D,
+ (byte) 0xEE, (byte) 0x78, (byte) 0x49, (byte) 0xA1, (byte) 0x1F, (byte) 0x9B,
+ (byte) 0x37, (byte) 0xC0, (byte) 0xBA, (byte) 0xE6, (byte) 0x4B, (byte) 0x3B,
+ (byte) 0xAF, (byte) 0x12, (byte) 0x99, (byte) 0x32, (byte) 0x14, (byte) 0x8C,
+ (byte) 0x4D, (byte) 0xEB, (byte) 0x08, (byte) 0xA4, (byte) 0xE3, (byte) 0xC6,
+ (byte) 0x37, (byte) 0x8B, (byte) 0x6E, (byte) 0x7C, (byte) 0xEC, (byte) 0xA3,
+ (byte) 0x78, (byte) 0xED, (byte) 0x4E, (byte) 0x36, (byte) 0xBC, (byte) 0xA2,
+ (byte) 0x7D, (byte) 0x11, (byte) 0x0E, (byte) 0xD0, (byte) 0x53, (byte) 0x14,
+ (byte) 0x93, (byte) 0x16, (byte) 0x54, (byte) 0x45, (byte) 0x79, (byte) 0x7A,
+ (byte) 0x1A, (byte) 0xA1, (byte) 0xEC, (byte) 0xF3, (byte) 0x12, (byte) 0x3F,
+ (byte) 0xFE, (byte) 0x68, (byte) 0xFF, (byte) 0x5A, (byte) 0x3F, (byte) 0xE7,
+ (byte) 0x13, (byte) 0x37, (byte) 0xEB, (byte) 0x60, (byte) 0x0A, (byte) 0x8E,
+ (byte) 0x4F, (byte) 0x54, (byte) 0x46, (byte) 0x19, (byte) 0x82, (byte) 0xBF,
+ (byte) 0xB7, (byte) 0xD2, (byte) 0x19, (byte) 0x71, (byte) 0x78, (byte) 0x38,
+ (byte) 0x4C, (byte) 0xE3, (byte) 0xC4, (byte) 0xEA, (byte) 0x8F, (byte) 0x9B,
+ (byte) 0xE5, (byte) 0xBA, (byte) 0x06, (byte) 0xFC,
+ };
+ private static final PSSParameterSpec SHA512withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec =
+ new PSSParameterSpec("SHA-512", "MGF1", MGF1ParameterSpec.SHA512, 190, 1);
+
+ @Test
+ public void testGetCommonInstances_Success() throws Exception {
+ assertNotNull(Signature.getInstance("SHA1withRSA"));
+ assertNotNull(Signature.getInstance("SHA256withRSA"));
+ assertNotNull(Signature.getInstance("SHA384withRSA"));
+ assertNotNull(Signature.getInstance("SHA512withRSA"));
+ assertNotNull(Signature.getInstance("NONEwithRSA"));
+ assertNotNull(Signature.getInstance("MD5withRSA"));
+ assertNotNull(Signature.getInstance("SHA1withDSA"));
+ }
+
+ private void verify(Signature sig, PublicKey key, byte[] data, byte[] signature)
+ throws Exception {
+ sig.initVerify(key);
+ sig.update(data);
+
+ assertTrue("Signature must match expected signature",
+ sig.verify(signature));
+
+ ByteBuffer heap = ByteBuffer.wrap(data);
+ sig.initVerify(key);
+ sig.update(heap);
+
+ assertTrue("Signature must match expected signature",
+ sig.verify(signature));
+
+ ByteBuffer direct = ByteBuffer.allocateDirect(data.length);
+ direct.put(data);
+ direct.flip();
+ sig.initVerify(key);
+ sig.update(direct);
+
+ assertTrue("Signature must match expected signature",
+ sig.verify(signature));
+ }
+
+ @Test
+ public void testVerify_SHA1withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA1withRSA");
+ verify(sig, pubKey, Vector1Data, SHA1withRSA_Vector1Signature);
+ }
+
+ @Test
+ public void testVerify_SHA256withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA256withRSA");
+ verify(sig, pubKey, Vector2Data, SHA256withRSA_Vector2Signature);
+ }
+
+ @Test
+ public void testVerify_SHA384withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA384withRSA");
+ verify(sig, pubKey, Vector2Data, SHA384withRSA_Vector2Signature);
+ }
+
+ @Test
+ public void testVerify_SHA512withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA512withRSA");
+ verify(sig, pubKey, Vector2Data, SHA512withRSA_Vector2Signature);
+ }
+
+ @Test
+ public void testVerify_MD5withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("MD5withRSA");
+ verify(sig, pubKey, Vector2Data, MD5withRSA_Vector2Signature);
+ }
+
+ @Test
+ public void testVerify_SHA1withRSAPSS_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA1withRSA/PSS");
+ sig.initVerify(pubKey);
+ assertPSSAlgorithmParametersEquals(
+ SHA1withRSAPSS_Vector2Signature_ParameterSpec, sig.getParameters());
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must verify",
+ sig.verify(SHA1withRSAPSS_Vector2Signature));
+ }
+
+ @Test
+ public void testVerify_SHA1withRSAPSS_NoSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA1withRSA/PSS");
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA1withRSAPSS_NoSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must verify",
+ sig.verify(SHA1withRSAPSS_NoSalt_Vector2Signature));
+ }
+
+ @Test
+ public void testVerify_SHA1withRSAPSS_MaxSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA1withRSA/PSS");
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA1withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must verify",
+ sig.verify(SHA1withRSAPSS_MaxSalt_Vector2Signature));
+ }
+
+ @Test
+ public void testVerify_SHA224withRSAPSS_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA224withRSA/PSS");
+ sig.initVerify(pubKey);
+ assertPSSAlgorithmParametersEquals(
+ SHA224withRSAPSS_Vector2Signature_ParameterSpec, sig.getParameters());
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must verify",
+ sig.verify(SHA224withRSAPSS_Vector2Signature));
+ }
+
+ @Test
+ public void testVerify_SHA224withRSAPSS_NoSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA224withRSA/PSS");
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA224withRSAPSS_NoSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must verify",
+ sig.verify(SHA224withRSAPSS_NoSalt_Vector2Signature));
+ }
+
+ @Test
+ public void testVerify_SHA224withRSAPSS_MaxSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA224withRSA/PSS");
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA224withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must verify",
+ sig.verify(SHA224withRSAPSS_MaxSalt_Vector2Signature));
+ }
+
+ @Test
+ public void testVerify_SHA256withRSAPSS_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA256withRSA/PSS");
+ sig.initVerify(pubKey);
+ assertPSSAlgorithmParametersEquals(
+ SHA256withRSAPSS_Vector2Signature_ParameterSpec, sig.getParameters());
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must verify",
+ sig.verify(SHA256withRSAPSS_Vector2Signature));
+ }
+
+ @Test
+ public void testVerify_SHA256withRSAPSS_NoSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA256withRSA/PSS");
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA256withRSAPSS_NoSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must verify",
+ sig.verify(SHA256withRSAPSS_NoSalt_Vector2Signature));
+ }
+
+ @Test
+ public void testVerify_SHA256withRSAPSS_MaxSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA256withRSA/PSS");
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA256withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must verify",
+ sig.verify(SHA256withRSAPSS_MaxSalt_Vector2Signature));
+ }
+
+ @Test
+ public void testVerify_SHA384withRSAPSS_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA384withRSA/PSS");
+ sig.initVerify(pubKey);
+ assertPSSAlgorithmParametersEquals(
+ SHA384withRSAPSS_Vector2Signature_ParameterSpec, sig.getParameters());
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must verify",
+ sig.verify(SHA384withRSAPSS_Vector2Signature));
+ }
+
+ @Test
+ public void testVerify_SHA384withRSAPSS_NoSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA384withRSA/PSS");
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA384withRSAPSS_NoSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must verify",
+ sig.verify(SHA384withRSAPSS_NoSalt_Vector2Signature));
+ }
+
+ @Test
+ public void testVerify_SHA384withRSAPSS_MaxSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA384withRSA/PSS");
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA384withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must verify",
+ sig.verify(SHA384withRSAPSS_MaxSalt_Vector2Signature));
+ }
+
+ @Test
+ public void testVerify_SHA512withRSAPSS_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA512withRSA/PSS");
+ sig.initVerify(pubKey);
+ assertPSSAlgorithmParametersEquals(
+ SHA512withRSAPSS_Vector2Signature_ParameterSpec, sig.getParameters());
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must verify",
+ sig.verify(SHA512withRSAPSS_Vector2Signature));
+ }
+
+ @Test
+ public void testVerify_SHA512withRSAPSS_NoSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA512withRSA/PSS");
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA512withRSAPSS_NoSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must verify",
+ sig.verify(SHA512withRSAPSS_NoSalt_Vector2Signature));
+ }
+
+ @Test
+ public void testVerify_SHA512withRSAPSS_MaxSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA512withRSA/PSS");
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA512withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must verify",
+ sig.verify(SHA512withRSAPSS_MaxSalt_Vector2Signature));
+ }
+
+ @Test
+ public void testVerify_SHA1withRSA_Key_InitSignThenInitVerify_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+ RSAPrivateKeySpec privKeySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(privKeySpec);
+
+ Signature sig = Signature.getInstance("SHA1withRSA");
+
+ // Start a signing operation
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ // Switch to verify
+ sig.initVerify(pubKey);
+ sig.update(Vector1Data);
+
+ assertTrue("Signature must match expected signature",
+ sig.verify(SHA1withRSA_Vector1Signature));
+ }
+
+ @Test
+ public void testVerify_SHA1withRSA_Key_TwoMessages_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA1withRSA");
+ sig.initVerify(pubKey);
+
+ sig.update(Vector1Data);
+ assertTrue("First signature must match expected signature",
+ sig.verify(SHA1withRSA_Vector1Signature));
+
+ sig.update(Vector2Data);
+ assertTrue("Second signature must match expected signature",
+ sig.verify(SHA1withRSA_Vector2Signature));
+ }
+
+ @Test
+ public void testVerify_SHA1withRSA_Key_WrongExpectedSignature_Failure() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA1withRSA");
+ sig.initVerify(pubKey);
+ sig.update(Vector1Data);
+
+ assertFalse("Signature should fail to verify", sig.verify(SHA1withRSA_Vector2Signature));
+ }
+
+ @Test
+ public void testSign_SHA1withRSA_CrtKeyWithPublicExponent_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent, RSA_2048_privateExponent, null, null, null, null, null);
+
+ // The RI fails on this key which is totally unreasonable.
+ final PrivateKey privKey;
+ try {
+ privKey = kf.generatePrivate(keySpec);
+ } catch (NullPointerException e) {
+ if (StandardNames.IS_RI) {
+ return;
+ } else {
+ fail("Private key should be created");
+ return;
+ }
+ }
+
+ Signature sig = Signature.getInstance("SHA1withRSA");
+ sig.initSign(privKey);
+ sig.update(Vector1Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertTrue("Signature should match expected",
+ Arrays.equals(signature, SHA1withRSA_Vector1Signature));
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.update(Vector1Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testSign_SHA1withRSA_CrtKey_NoPrivateExponent_Failure() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent, null, RSA_2048_primeP, RSA_2048_primeQ, null, null, null);
+
+ // Failing on this key early is okay.
+ final PrivateKey privKey;
+ try {
+ privKey = kf.generatePrivate(keySpec);
+ } catch (NullPointerException e) {
+ return;
+ } catch (InvalidKeySpecException e) {
+ return;
+ }
+
+ Signature sig = Signature.getInstance("SHA1withRSA");
+
+ try {
+ sig.initSign(privKey);
+ fail("Should throw error when private exponent is not available");
+ } catch (InvalidKeyException expected) {
+ }
+ }
+
+ @Test
+ public void testSign_SHA1withRSA_CrtKey_NoModulus_Failure() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(null, RSA_2048_publicExponent,
+ RSA_2048_privateExponent, RSA_2048_primeP, RSA_2048_primeQ, null, null, null);
+
+ // Failing on this key early is okay.
+ final PrivateKey privKey;
+ try {
+ privKey = kf.generatePrivate(keySpec);
+ } catch (NullPointerException e) {
+ return;
+ } catch (InvalidKeySpecException e) {
+ return;
+ }
+
+ Signature sig = Signature.getInstance("SHA1withRSA");
+
+ try {
+ sig.initSign(privKey);
+ fail("Should throw error when modulus is not available");
+ } catch (InvalidKeyException expected) {
+ }
+ }
+
+ @Test
+ public void testSign_SHA1withRSA_Key_EmptyKey_Failure() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(null, null);
+
+ // Failing on this key early is okay.
+ final PrivateKey privKey;
+ try {
+ privKey = kf.generatePrivate(keySpec);
+ } catch (NullPointerException e) {
+ return;
+ } catch (InvalidKeySpecException e) {
+ return;
+ }
+
+ Signature sig = Signature.getInstance("SHA1withRSA");
+
+ try {
+ sig.initSign(privKey);
+ fail("Should throw error when key is empty");
+ } catch (InvalidKeyException expected) {
+ }
+ }
+
+ private void sign(Signature sig, PrivateKey privKey, PublicKey pubKey, byte[] data,
+ byte[] signature) throws Exception {
+ sig.initSign(privKey);
+ sig.update(data);
+
+ byte[] generatedSignature = sig.sign();
+ assertNotNull("Signature must not be null", generatedSignature);
+ assertArrayEquals("Signature should match expected", signature, generatedSignature);
+
+ sig.initVerify(pubKey);
+ sig.update(data);
+ assertTrue("Signature must verify correctly", sig.verify(generatedSignature));
+
+ ByteBuffer heap = ByteBuffer.wrap(data);
+ sig.initSign(privKey);
+ sig.update(heap);
+
+ generatedSignature = sig.sign();
+ assertNotNull("Signature must not be null", generatedSignature);
+ assertArrayEquals("Signature should match expected", signature, generatedSignature);
+
+ heap.rewind();
+ sig.initVerify(pubKey);
+ sig.update(heap);
+ assertTrue("Signature must verify correctly", sig.verify(generatedSignature));
+
+ ByteBuffer direct = ByteBuffer.allocateDirect(data.length);
+ direct.put(data);
+ direct.flip();
+ sig.initSign(privKey);
+ sig.update(direct);
+
+ generatedSignature = sig.sign();
+ assertNotNull("Signature must not be null", generatedSignature);
+ assertArrayEquals("Signature should match expected", signature, generatedSignature);
+
+ direct.rewind();
+ sig.initVerify(pubKey);
+ sig.update(direct);
+ assertTrue("Signature must verify correctly", sig.verify(generatedSignature));
+
+ }
+
+ @Test
+ public void testSign_SHA1withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+ Signature sig = Signature.getInstance("SHA1withRSA");
+ sign(sig, privKey, pubKey, Vector1Data, SHA1withRSA_Vector1Signature);
+ }
+
+ @Test
+ public void testSign_SHA224withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+ Signature sig = Signature.getInstance("SHA224withRSA");
+ sign(sig, privKey, pubKey, Vector2Data, SHA224withRSA_Vector2Signature);
+ }
+
+ @Test
+ public void testSign_SHA256withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+ Signature sig = Signature.getInstance("SHA256withRSA");
+ sign(sig, privKey, pubKey, Vector2Data, SHA256withRSA_Vector2Signature);
+ }
+
+ @Test
+ public void testSign_SHA384withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+ Signature sig = Signature.getInstance("SHA384withRSA");
+ sign(sig, privKey, pubKey, Vector2Data, SHA384withRSA_Vector2Signature);
+ }
+
+ @Test
+ public void testSign_SHA512withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+ Signature sig = Signature.getInstance("SHA512withRSA");
+ sign(sig, privKey, pubKey, Vector2Data, SHA512withRSA_Vector2Signature);
+ }
+
+ @Test
+ public void testSign_MD5withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+ Signature sig = Signature.getInstance("MD5withRSA");
+ sign(sig, privKey, pubKey, Vector2Data, MD5withRSA_Vector2Signature);
+ }
+
+ @Test
+ public void testSign_SHA1withRSAPSS_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA1withRSA/PSS");
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertPSSAlgorithmParametersEquals(
+ SHA1withRSAPSS_Vector2Signature_ParameterSpec, sig.getParameters());
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testSign_SHA1withRSAPSS_NoSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA1withRSA/PSS");
+ sig.initSign(privKey);
+ sig.setParameter(SHA1withRSAPSS_NoSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertPSSAlgorithmParametersEquals(
+ SHA1withRSAPSS_NoSalt_Vector2Signature_ParameterSpec, sig.getParameters());
+ assertTrue("Signature should match expected",
+ Arrays.equals(signature, SHA1withRSAPSS_NoSalt_Vector2Signature));
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA1withRSAPSS_NoSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testSign_SHA1withRSAPSS_MaxSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA1withRSA/PSS");
+ sig.initSign(privKey);
+ sig.setParameter(SHA1withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertPSSAlgorithmParametersEquals(
+ SHA1withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec, sig.getParameters());
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig = Signature.getInstance("SHA1withRSA/PSS");
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA1withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testSign_SHA224withRSAPSS_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA224withRSA/PSS");
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertPSSAlgorithmParametersEquals(
+ SHA224withRSAPSS_Vector2Signature_ParameterSpec, sig.getParameters());
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testSign_SHA224withRSAPSS_NoSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA224withRSA/PSS");
+ sig.initSign(privKey);
+ sig.setParameter(SHA224withRSAPSS_NoSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertPSSAlgorithmParametersEquals(
+ SHA224withRSAPSS_NoSalt_Vector2Signature_ParameterSpec, sig.getParameters());
+ assertTrue("Signature should match expected",
+ Arrays.equals(signature, SHA224withRSAPSS_NoSalt_Vector2Signature));
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA224withRSAPSS_NoSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testSign_SHA224withRSAPSS_MaxSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA224withRSA/PSS");
+ sig.initSign(privKey);
+ sig.setParameter(SHA224withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertPSSAlgorithmParametersEquals(
+ SHA224withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec, sig.getParameters());
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig = Signature.getInstance("SHA224withRSA/PSS");
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA224withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testSign_SHA256withRSAPSS_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA256withRSA/PSS");
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertPSSAlgorithmParametersEquals(
+ SHA256withRSAPSS_Vector2Signature_ParameterSpec, sig.getParameters());
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testSign_SHA256withRSAPSS_NoSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA256withRSA/PSS");
+ sig.initSign(privKey);
+ sig.setParameter(SHA256withRSAPSS_NoSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertPSSAlgorithmParametersEquals(
+ SHA256withRSAPSS_NoSalt_Vector2Signature_ParameterSpec, sig.getParameters());
+ assertTrue("Signature should match expected",
+ Arrays.equals(signature, SHA256withRSAPSS_NoSalt_Vector2Signature));
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA256withRSAPSS_NoSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testSign_SHA256withRSAPSS_MaxSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA256withRSA/PSS");
+ sig.initSign(privKey);
+ sig.setParameter(SHA256withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertPSSAlgorithmParametersEquals(
+ SHA256withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec, sig.getParameters());
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig = Signature.getInstance("SHA256withRSA/PSS");
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA256withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testSign_SHA384withRSAPSS_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA384withRSA/PSS");
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertPSSAlgorithmParametersEquals(
+ SHA384withRSAPSS_Vector2Signature_ParameterSpec, sig.getParameters());
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testSign_SHA384withRSAPSS_NoSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA384withRSA/PSS");
+ sig.initSign(privKey);
+ sig.setParameter(SHA384withRSAPSS_NoSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertPSSAlgorithmParametersEquals(
+ SHA384withRSAPSS_NoSalt_Vector2Signature_ParameterSpec, sig.getParameters());
+ assertTrue("Signature should match expected",
+ Arrays.equals(signature, SHA384withRSAPSS_NoSalt_Vector2Signature));
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA384withRSAPSS_NoSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testSign_SHA384withRSAPSS_MaxSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA384withRSA/PSS");
+ sig.initSign(privKey);
+ sig.setParameter(SHA384withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertPSSAlgorithmParametersEquals(
+ SHA384withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec, sig.getParameters());
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig = Signature.getInstance("SHA384withRSA/PSS");
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA384withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testSign_SHA512withRSAPSS_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA512withRSA/PSS");
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertPSSAlgorithmParametersEquals(
+ SHA512withRSAPSS_Vector2Signature_ParameterSpec, sig.getParameters());
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testSign_SHA512withRSAPSS_NoSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA512withRSA/PSS");
+ sig.initSign(privKey);
+ sig.setParameter(SHA512withRSAPSS_NoSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertPSSAlgorithmParametersEquals(
+ SHA512withRSAPSS_NoSalt_Vector2Signature_ParameterSpec, sig.getParameters());
+ assertTrue("Signature should match expected",
+ Arrays.equals(signature, SHA512withRSAPSS_NoSalt_Vector2Signature));
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA512withRSAPSS_NoSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testSign_SHA512withRSAPSS_MaxSalt_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA512withRSA/PSS");
+ sig.initSign(privKey);
+ sig.setParameter(SHA512withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertPSSAlgorithmParametersEquals(
+ SHA512withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec, sig.getParameters());
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig = Signature.getInstance("SHA512withRSA/PSS");
+ sig.initVerify(pubKey);
+ sig.setParameter(SHA512withRSAPSS_MaxSalt_Vector2Signature_ParameterSpec);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testSign_NONEwithRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("NONEwithRSA");
+ sig.initSign(privKey);
+ sig.update(Vector1Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertTrue("Signature should match expected",
+ Arrays.equals(signature, NONEwithRSA_Vector1Signature));
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.update(Vector1Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testVerify_NONEwithRSA_Key_WrongSignature_Failure() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+ Signature sig = Signature.getInstance("NONEwithRSA");
+ sig.initVerify(pubKey);
+ sig.update(Vector1Data);
+ assertFalse("Invalid signature must not verify",
+ sig.verify("Invalid".getBytes("UTF-8")));
+ }
+
+ @Test
+ public void testSign_NONEwithRSA_Key_DataTooLarge_Failure() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("NONEwithRSA");
+ sig.initSign(privKey);
+
+ final int oneTooBig = RSA_2048_modulus.bitLength() - 10;
+ for (int i = 0; i < oneTooBig; i++) {
+ sig.update((byte) i);
+ }
+
+ try {
+ sig.sign();
+ fail("Should throw exception when data is too large");
+ } catch (SignatureException expected) {
+ }
+ }
+
+ @Test
+ public void testSign_NONEwithRSA_Key_DataTooLarge_SingleByte_Failure() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("NONEwithRSA");
+ sig.initSign(privKey);
+
+ // This should make it two bytes too big.
+ final int oneTooBig = RSA_2048_modulus.bitLength() - 10;
+ for (int i = 0; i < oneTooBig; i++) {
+ sig.update((byte) i);
+ }
+
+ try {
+ sig.sign();
+ fail("Should throw exception when data is too large");
+ } catch (SignatureException expected) {
+ }
+ }
+
+ @Test
+ public void testVerify_NONEwithRSA_Key_DataTooLarge_Failure() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+ Signature sig = Signature.getInstance("NONEwithRSA");
+ sig.initVerify(pubKey);
+
+ // This should make it one bytes too big.
+ final int oneTooBig = RSA_2048_modulus.bitLength() + 1;
+ final byte[] vector = new byte[oneTooBig];
+ for (int i = 0; i < oneTooBig; i++) {
+ vector[i] = Vector1Data[i % Vector1Data.length];
+ }
+ sig.update(vector);
+
+ assertFalse("Should not verify when signature is too large",
+ sig.verify(NONEwithRSA_Vector1Signature));
+ }
+
+ @Test
+ public void testVerify_NONEwithRSA_Key_DataTooLarge_SingleByte_Failure() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+ Signature sig = Signature.getInstance("NONEwithRSA");
+ sig.initVerify(pubKey);
+
+ // This should make it twice as big as it should be.
+ final int tooBig = RSA_2048_modulus.bitLength() * 2;
+ for (int i = 0; i < tooBig; i++) {
+ sig.update(Vector1Data[i % Vector1Data.length]);
+ }
+
+ assertFalse("Should not verify when signature is too large",
+ sig.verify(NONEwithRSA_Vector1Signature));
+ }
+
+ @Test
+ public void testVerify_NONEwithRSA_Key_SignatureTooSmall_Failure() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+ Signature sig = Signature.getInstance("NONEwithRSA");
+ sig.initVerify(pubKey);
+ sig.update(Vector1Data);
+
+ assertFalse("Invalid signature should not verify",
+ sig.verify("Invalid sig".getBytes("UTF-8")));
+ }
+
+ @Test
+ public void testVerify_NONEwithRSA_Key_SignatureTooLarge_Failure() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+ Signature sig = Signature.getInstance("NONEwithRSA");
+ sig.initVerify(pubKey);
+ sig.update(Vector1Data);
+
+ byte[] invalidSignature = new byte[NONEwithRSA_Vector1Signature.length * 2];
+ System.arraycopy(NONEwithRSA_Vector1Signature, 0, invalidSignature, 0,
+ NONEwithRSA_Vector1Signature.length);
+ System.arraycopy(NONEwithRSA_Vector1Signature, 0, invalidSignature,
+ NONEwithRSA_Vector1Signature.length, NONEwithRSA_Vector1Signature.length);
+
+ try {
+ sig.verify(invalidSignature);
+ fail("Should throw exception when signature is too large");
+ } catch (SignatureException expected) {
+ }
+ }
+
+ @Test
+ public void testSign_NONEwithECDSA_Key_Success() throws Exception {
+ KeyPair keys = keyPair("NONEwithECDSA");
+ Signature sig = Signature.getInstance("NONEwithECDSA");
+
+ sig.initSign(keys.getPrivate());
+ sig.update(Vector1Data);
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertTrue("Signature must not be empty", signature.length > 0);
+
+ sig.initVerify(keys.getPublic());
+ sig.update(Vector1Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testVerify_NONEwithECDSA_Key_Success() throws Exception {
+ PublicKey pub = getNamedCurveEcPublicKey();
+ MessageDigest sha1 = MessageDigest.getInstance("SHA1");
+ Signature sig = Signature.getInstance("NONEwithECDSA");
+
+ // NAMED_CURVE_SIGNATURE was signed using SHA1withECDSA, so NONEwithECDSA should
+ // verify the digest
+ sig.initVerify(pub);
+ sig.update(sha1.digest(NAMED_CURVE_VECTOR));
+ assertTrue(sig.verify(NAMED_CURVE_SIGNATURE));
+ }
+
+ @Test
+ public void testVerify_NONEwithECDSA_Key_WrongData_Failure() throws Exception {
+ PublicKey pub = getNamedCurveEcPublicKey();
+ Signature sig = Signature.getInstance("NONEwithECDSA");
+
+ sig.initVerify(pub);
+ sig.update(NAMED_CURVE_VECTOR);
+ assertFalse(sig.verify(NAMED_CURVE_SIGNATURE));
+ }
+
+ // Suppress ErrorProne's warning about the try block that doesn't call fail() but
+ // expects an exception, it's intentional
+ @SuppressWarnings("MissingFail")
+ @Test
+ public void testVerify_NONEwithECDSA_Key_SingleByte_Failure() throws Exception {
+ PublicKey pub = getNamedCurveEcPublicKey();
+ MessageDigest sha1 = MessageDigest.getInstance("SHA1");
+ Signature sig = Signature.getInstance("NONEwithECDSA");
+
+ byte[] corrupted = new byte[NAMED_CURVE_SIGNATURE.length];
+ corrupted[0] = (byte) (corrupted[0] ^ 1);
+
+ sig.initVerify(pub);
+ sig.update(sha1.digest(NAMED_CURVE_VECTOR));
+ try {
+ assertFalse(sig.verify(corrupted));
+ } catch (SignatureException expected) {
+ // It's valid to either return false or throw an exception, accept either
+ }
+ }
+
+ // Tests that an opaque key will be accepted by the ECDSA signature and will delegate to a
+ // functioning alternative provider
+ @Test
+ public void test_NONEwithECDSA_OpaqueKey() throws Exception {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
+ keyGen.initialize(256);
+ KeyPair kp = keyGen.generateKeyPair();
+
+ // Insert this at #2 so that Conscrypt is still the first provider and CryptoUpcalls
+ // has to drop to manual provider selection rather than relying on Signature's internals
+ Security.insertProviderAt(new OpaqueProvider(), 2);
+ try {
+ Signature sig = Signature.getInstance(
+ "NONEwithECDSA", TestUtils.getConscryptProvider());
+ sig.initSign(OpaqueProvider.wrapKeyMarked(kp.getPrivate()));
+ sig.update(new byte[]{1, 2, 3, 4, 5, 6, 7, 8});
+ byte[] data = sig.sign();
+
+ sig.initVerify(kp.getPublic());
+ sig.update(new byte[]{1, 2, 3, 4, 5, 6, 7, 8});
+ assertTrue(sig.verify(data));
+ } finally {
+ Security.removeProvider(OpaqueProvider.NAME);
+ }
+ }
+
+ // Tests that an opaque key will be accepted by the ECDSA signature and that a broken
+ // alternative provider that throws UnsupportedOperationException will be skipped and
+ // a functioning provider that follows will work.
+ @Test
+ public void test_NONEwithECDSA_OpaqueKey_BrokenProvider() throws Exception {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
+ keyGen.initialize(256);
+ KeyPair kp = keyGen.generateKeyPair();
+
+ // Insert these at #2 so that Conscrypt is still the first provider and CryptoUpcalls
+ // has to drop to manual provider selection rather than relying on Signature's internals
+ Security.insertProviderAt(new OpaqueProvider(), 2);
+ Security.insertProviderAt(new BrokenProvider(), 2);
+ try {
+ Signature sig = Signature.getInstance(
+ "NONEwithECDSA", TestUtils.getConscryptProvider());
+ sig.initSign(OpaqueProvider.wrapKeyMarked(kp.getPrivate()));
+ sig.update(new byte[]{1, 2, 3, 4, 5, 6, 7, 8});
+ byte[] data = sig.sign();
+
+ sig.initVerify(kp.getPublic());
+ sig.update(new byte[]{1, 2, 3, 4, 5, 6, 7, 8});
+ assertTrue(sig.verify(data));
+ } finally {
+ Security.removeProvider(OpaqueProvider.NAME);
+ Security.removeProvider(BrokenProvider.NAME);
+ }
+ }
+
+ /*
+ * These tests were generated with this DSA private key:
+ *
+ * -----BEGIN DSA PRIVATE KEY-----
+ * MIIBugIBAAKBgQCeYcKJ73epThNnZB8JAf4kE1Pgt5CoTnb+iYJ/esU8TgwgVTCV
+ * QoXhQH0njwcN6NyZ77MHlDTWfP+cvmnT60Q3UO9J+OJb2NEQhJfq46UcwE5pynA9
+ * eLkW5f5hXYpasyxhtgE70AF8Mo3h82kOi1jGzwCU+EkqS+raAP9L0L5AIwIVAL/u
+ * qg8SNFBy+GAT2PFBARClL1dfAoGAd9R6EsyBfn7rOvvmhm1aEB2tqU+5A10hGuQw
+ * lXWOzV7RvQpF7uf3a2UCYNAurz28B90rjjPAk4DZK6dxV3a8jrng1/QjjUEal08s
+ * G9VLZuj60lANF6s0MT2kiNiOqKduFwO3D2h8ZHuSuGPkmmcYgSfUCxNI031O9qiP
+ * VhctCFECgYAz7i1DhjRGUkCdYQd5tVaI42lhXOV71MTYPbuFOIxTL/hny7Z0PZWR
+ * A1blmYE6vrArDEhzpmRvDJZSIMzMfJjUIGu1KO73zpo9siK0xY0/sw5r3QC9txP2
+ * 2Mv3BUIl5TLrs9outQJ0VMwldY2fElgCLWcSVkH44qZwWir1cq+cIwIUEGPDardb
+ * pNvWlWgTDD6a6ZTby+M=
+ * -----END DSA PRIVATE KEY-----
+ *
+ */
+
+ private static final BigInteger DSA_priv = new BigInteger(new byte[] {
+ (byte) 0x10, (byte) 0x63, (byte) 0xc3, (byte) 0x6a, (byte) 0xb7, (byte) 0x5b, (byte) 0xa4, (byte) 0xdb,
+ (byte) 0xd6, (byte) 0x95, (byte) 0x68, (byte) 0x13, (byte) 0x0c, (byte) 0x3e, (byte) 0x9a, (byte) 0xe9,
+ (byte) 0x94, (byte) 0xdb, (byte) 0xcb, (byte) 0xe3,
+ });
+
+ private static final BigInteger DSA_pub = new BigInteger(new byte[] {
+ (byte) 0x33, (byte) 0xee, (byte) 0x2d, (byte) 0x43, (byte) 0x86, (byte) 0x34, (byte) 0x46, (byte) 0x52,
+ (byte) 0x40, (byte) 0x9d, (byte) 0x61, (byte) 0x07, (byte) 0x79, (byte) 0xb5, (byte) 0x56, (byte) 0x88,
+ (byte) 0xe3, (byte) 0x69, (byte) 0x61, (byte) 0x5c, (byte) 0xe5, (byte) 0x7b, (byte) 0xd4, (byte) 0xc4,
+ (byte) 0xd8, (byte) 0x3d, (byte) 0xbb, (byte) 0x85, (byte) 0x38, (byte) 0x8c, (byte) 0x53, (byte) 0x2f,
+ (byte) 0xf8, (byte) 0x67, (byte) 0xcb, (byte) 0xb6, (byte) 0x74, (byte) 0x3d, (byte) 0x95, (byte) 0x91,
+ (byte) 0x03, (byte) 0x56, (byte) 0xe5, (byte) 0x99, (byte) 0x81, (byte) 0x3a, (byte) 0xbe, (byte) 0xb0,
+ (byte) 0x2b, (byte) 0x0c, (byte) 0x48, (byte) 0x73, (byte) 0xa6, (byte) 0x64, (byte) 0x6f, (byte) 0x0c,
+ (byte) 0x96, (byte) 0x52, (byte) 0x20, (byte) 0xcc, (byte) 0xcc, (byte) 0x7c, (byte) 0x98, (byte) 0xd4,
+ (byte) 0x20, (byte) 0x6b, (byte) 0xb5, (byte) 0x28, (byte) 0xee, (byte) 0xf7, (byte) 0xce, (byte) 0x9a,
+ (byte) 0x3d, (byte) 0xb2, (byte) 0x22, (byte) 0xb4, (byte) 0xc5, (byte) 0x8d, (byte) 0x3f, (byte) 0xb3,
+ (byte) 0x0e, (byte) 0x6b, (byte) 0xdd, (byte) 0x00, (byte) 0xbd, (byte) 0xb7, (byte) 0x13, (byte) 0xf6,
+ (byte) 0xd8, (byte) 0xcb, (byte) 0xf7, (byte) 0x05, (byte) 0x42, (byte) 0x25, (byte) 0xe5, (byte) 0x32,
+ (byte) 0xeb, (byte) 0xb3, (byte) 0xda, (byte) 0x2e, (byte) 0xb5, (byte) 0x02, (byte) 0x74, (byte) 0x54,
+ (byte) 0xcc, (byte) 0x25, (byte) 0x75, (byte) 0x8d, (byte) 0x9f, (byte) 0x12, (byte) 0x58, (byte) 0x02,
+ (byte) 0x2d, (byte) 0x67, (byte) 0x12, (byte) 0x56, (byte) 0x41, (byte) 0xf8, (byte) 0xe2, (byte) 0xa6,
+ (byte) 0x70, (byte) 0x5a, (byte) 0x2a, (byte) 0xf5, (byte) 0x72, (byte) 0xaf, (byte) 0x9c, (byte) 0x23,
+ });
+
+ private static final BigInteger DSA_P = new BigInteger(new byte[] {
+ (byte) 0x00, (byte) 0x9e, (byte) 0x61, (byte) 0xc2, (byte) 0x89, (byte) 0xef, (byte) 0x77, (byte) 0xa9,
+ (byte) 0x4e, (byte) 0x13, (byte) 0x67, (byte) 0x64, (byte) 0x1f, (byte) 0x09, (byte) 0x01, (byte) 0xfe,
+ (byte) 0x24, (byte) 0x13, (byte) 0x53, (byte) 0xe0, (byte) 0xb7, (byte) 0x90, (byte) 0xa8, (byte) 0x4e,
+ (byte) 0x76, (byte) 0xfe, (byte) 0x89, (byte) 0x82, (byte) 0x7f, (byte) 0x7a, (byte) 0xc5, (byte) 0x3c,
+ (byte) 0x4e, (byte) 0x0c, (byte) 0x20, (byte) 0x55, (byte) 0x30, (byte) 0x95, (byte) 0x42, (byte) 0x85,
+ (byte) 0xe1, (byte) 0x40, (byte) 0x7d, (byte) 0x27, (byte) 0x8f, (byte) 0x07, (byte) 0x0d, (byte) 0xe8,
+ (byte) 0xdc, (byte) 0x99, (byte) 0xef, (byte) 0xb3, (byte) 0x07, (byte) 0x94, (byte) 0x34, (byte) 0xd6,
+ (byte) 0x7c, (byte) 0xff, (byte) 0x9c, (byte) 0xbe, (byte) 0x69, (byte) 0xd3, (byte) 0xeb, (byte) 0x44,
+ (byte) 0x37, (byte) 0x50, (byte) 0xef, (byte) 0x49, (byte) 0xf8, (byte) 0xe2, (byte) 0x5b, (byte) 0xd8,
+ (byte) 0xd1, (byte) 0x10, (byte) 0x84, (byte) 0x97, (byte) 0xea, (byte) 0xe3, (byte) 0xa5, (byte) 0x1c,
+ (byte) 0xc0, (byte) 0x4e, (byte) 0x69, (byte) 0xca, (byte) 0x70, (byte) 0x3d, (byte) 0x78, (byte) 0xb9,
+ (byte) 0x16, (byte) 0xe5, (byte) 0xfe, (byte) 0x61, (byte) 0x5d, (byte) 0x8a, (byte) 0x5a, (byte) 0xb3,
+ (byte) 0x2c, (byte) 0x61, (byte) 0xb6, (byte) 0x01, (byte) 0x3b, (byte) 0xd0, (byte) 0x01, (byte) 0x7c,
+ (byte) 0x32, (byte) 0x8d, (byte) 0xe1, (byte) 0xf3, (byte) 0x69, (byte) 0x0e, (byte) 0x8b, (byte) 0x58,
+ (byte) 0xc6, (byte) 0xcf, (byte) 0x00, (byte) 0x94, (byte) 0xf8, (byte) 0x49, (byte) 0x2a, (byte) 0x4b,
+ (byte) 0xea, (byte) 0xda, (byte) 0x00, (byte) 0xff, (byte) 0x4b, (byte) 0xd0, (byte) 0xbe, (byte) 0x40,
+ (byte) 0x23,
+ });
+
+ private static final BigInteger DSA_Q = new BigInteger(new byte[] {
+ (byte) 0x00, (byte) 0xbf, (byte) 0xee, (byte) 0xaa, (byte) 0x0f, (byte) 0x12, (byte) 0x34, (byte) 0x50,
+ (byte) 0x72, (byte) 0xf8, (byte) 0x60, (byte) 0x13, (byte) 0xd8, (byte) 0xf1, (byte) 0x41, (byte) 0x01,
+ (byte) 0x10, (byte) 0xa5, (byte) 0x2f, (byte) 0x57, (byte) 0x5f,
+ });
+
+ private static final BigInteger DSA_G = new BigInteger(new byte[] {
+ (byte) 0x77, (byte) 0xd4, (byte) 0x7a, (byte) 0x12, (byte) 0xcc, (byte) 0x81, (byte) 0x7e, (byte) 0x7e,
+ (byte) 0xeb, (byte) 0x3a, (byte) 0xfb, (byte) 0xe6, (byte) 0x86, (byte) 0x6d, (byte) 0x5a, (byte) 0x10,
+ (byte) 0x1d, (byte) 0xad, (byte) 0xa9, (byte) 0x4f, (byte) 0xb9, (byte) 0x03, (byte) 0x5d, (byte) 0x21,
+ (byte) 0x1a, (byte) 0xe4, (byte) 0x30, (byte) 0x95, (byte) 0x75, (byte) 0x8e, (byte) 0xcd, (byte) 0x5e,
+ (byte) 0xd1, (byte) 0xbd, (byte) 0x0a, (byte) 0x45, (byte) 0xee, (byte) 0xe7, (byte) 0xf7, (byte) 0x6b,
+ (byte) 0x65, (byte) 0x02, (byte) 0x60, (byte) 0xd0, (byte) 0x2e, (byte) 0xaf, (byte) 0x3d, (byte) 0xbc,
+ (byte) 0x07, (byte) 0xdd, (byte) 0x2b, (byte) 0x8e, (byte) 0x33, (byte) 0xc0, (byte) 0x93, (byte) 0x80,
+ (byte) 0xd9, (byte) 0x2b, (byte) 0xa7, (byte) 0x71, (byte) 0x57, (byte) 0x76, (byte) 0xbc, (byte) 0x8e,
+ (byte) 0xb9, (byte) 0xe0, (byte) 0xd7, (byte) 0xf4, (byte) 0x23, (byte) 0x8d, (byte) 0x41, (byte) 0x1a,
+ (byte) 0x97, (byte) 0x4f, (byte) 0x2c, (byte) 0x1b, (byte) 0xd5, (byte) 0x4b, (byte) 0x66, (byte) 0xe8,
+ (byte) 0xfa, (byte) 0xd2, (byte) 0x50, (byte) 0x0d, (byte) 0x17, (byte) 0xab, (byte) 0x34, (byte) 0x31,
+ (byte) 0x3d, (byte) 0xa4, (byte) 0x88, (byte) 0xd8, (byte) 0x8e, (byte) 0xa8, (byte) 0xa7, (byte) 0x6e,
+ (byte) 0x17, (byte) 0x03, (byte) 0xb7, (byte) 0x0f, (byte) 0x68, (byte) 0x7c, (byte) 0x64, (byte) 0x7b,
+ (byte) 0x92, (byte) 0xb8, (byte) 0x63, (byte) 0xe4, (byte) 0x9a, (byte) 0x67, (byte) 0x18, (byte) 0x81,
+ (byte) 0x27, (byte) 0xd4, (byte) 0x0b, (byte) 0x13, (byte) 0x48, (byte) 0xd3, (byte) 0x7d, (byte) 0x4e,
+ (byte) 0xf6, (byte) 0xa8, (byte) 0x8f, (byte) 0x56, (byte) 0x17, (byte) 0x2d, (byte) 0x08, (byte) 0x51,
+ });
+
+ /**
+ * A possible signature using SHA1withDSA of Vector2Data. Note that DSS is
+ * randomized, so this won't be the exact signature you'll get out of
+ * another signing operation unless you use a fixed RNG.
+ */
+ private static final byte[] SHA1withDSA_Vector2Signature = new byte[] {
+ (byte) 0x30,
+ (byte) 0x2d,
+ (byte) 0x02,
+ (byte) 0x15,
+ (byte) 0x00,
+ (byte) 0x88,
+ (byte) 0xef,
+ (byte) 0xac,
+ (byte) 0x2b,
+ (byte) 0x8b,
+ (byte) 0xe2,
+ (byte) 0x61,
+ (byte) 0xc6,
+ (byte) 0x2b,
+ (byte) 0xea,
+ (byte) 0xd5,
+ (byte) 0x96,
+ (byte) 0xbc,
+ (byte) 0xb0,
+ (byte) 0xa1,
+ (byte) 0x30,
+ (byte) 0x0c,
+ (byte) 0x1f,
+ (byte) 0xed,
+ (byte) 0x11,
+ (byte) 0x02,
+ (byte) 0x14,
+ (byte) 0x15,
+ (byte) 0xc4,
+ (byte) 0xfc,
+ (byte) 0x82,
+ (byte) 0x6f,
+ (byte) 0x17,
+ (byte) 0xdc,
+ (byte) 0x87,
+ (byte) 0x82,
+ (byte) 0x75,
+ (byte) 0x23,
+ (byte) 0xd4,
+ (byte) 0x58,
+ (byte) 0xdc,
+ (byte) 0x73,
+ (byte) 0x3d,
+ (byte) 0xf3,
+ (byte) 0x51,
+ (byte) 0xc0,
+ (byte) 0x57,
+ };
+
+ /**
+ * A possible signature using SHA224withDSA of Vector2Data. Note that DSS is
+ * randomized, so this won't be the exact signature you'll get out of
+ * another signing operation unless you use a fixed RNG.
+ */
+ private static final byte[] SHA224withDSA_Vector2Signature =
+ new byte[] {(byte) 0x30, (byte) 0x2D, (byte) 0x02, (byte) 0x15, (byte) 0x00,
+ (byte) 0xAD, (byte) 0xE5, (byte) 0x6D, (byte) 0xF5, (byte) 0x11, (byte) 0x8D,
+ (byte) 0x2E, (byte) 0x62, (byte) 0x5D, (byte) 0x98, (byte) 0x8A, (byte) 0xC4,
+ (byte) 0x88, (byte) 0x7E, (byte) 0xE6, (byte) 0xA3, (byte) 0x44, (byte) 0x99,
+ (byte) 0xEF, (byte) 0x49, (byte) 0x02, (byte) 0x14, (byte) 0x15, (byte) 0x3E,
+ (byte) 0x32, (byte) 0xD6, (byte) 0xF9, (byte) 0x79, (byte) 0x2C, (byte) 0x60,
+ (byte) 0x6E, (byte) 0xF9, (byte) 0xA9, (byte) 0x78, (byte) 0xE7, (byte) 0x4B,
+ (byte) 0x87, (byte) 0x08, (byte) 0x96, (byte) 0x60, (byte) 0xDE, (byte) 0xB5};
+
+ /**
+ * A possible signature using SHA256withDSA of Vector2Data. Note that DSS is
+ * randomized, so this won't be the exact signature you'll get out of
+ * another signing operation unless you use a fixed RNG.
+ */
+ private static final byte[] SHA256withDSA_Vector2Signature =
+ new byte[] {(byte) 0x30, (byte) 0x2D, (byte) 0x02, (byte) 0x14, (byte) 0x0A,
+ (byte) 0xB1, (byte) 0x74, (byte) 0x45, (byte) 0xE1, (byte) 0x63, (byte) 0x43,
+ (byte) 0x68, (byte) 0x65, (byte) 0xBC, (byte) 0xCA, (byte) 0x45, (byte) 0x27,
+ (byte) 0x11, (byte) 0x4D, (byte) 0x52, (byte) 0xFB, (byte) 0x22, (byte) 0x93,
+ (byte) 0xDD, (byte) 0x02, (byte) 0x15, (byte) 0x00, (byte) 0x98, (byte) 0x32,
+ (byte) 0x1A, (byte) 0x16, (byte) 0x77, (byte) 0x49, (byte) 0xA7, (byte) 0x78,
+ (byte) 0xFD, (byte) 0xE0, (byte) 0xF7, (byte) 0x71, (byte) 0xD4, (byte) 0x80,
+ (byte) 0x50, (byte) 0xA7, (byte) 0xDD, (byte) 0x94, (byte) 0xD1, (byte) 0x6C};
+
+ @Test
+ public void testSign_SHA1withDSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("DSA");
+ DSAPrivateKeySpec keySpec = new DSAPrivateKeySpec(DSA_priv, DSA_P, DSA_Q, DSA_G);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA1withDSA");
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+
+ DSAPublicKeySpec pubKeySpec = new DSAPublicKeySpec(DSA_pub, DSA_P, DSA_Q, DSA_G);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testVerify_SHA1withDSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("DSA");
+ DSAPublicKeySpec pubKeySpec = new DSAPublicKeySpec(DSA_pub, DSA_P, DSA_Q, DSA_G);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+ Signature sig = Signature.getInstance("SHA1withDSA");
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(SHA1withDSA_Vector2Signature));
+ }
+
+ @Test
+ public void testSign_SHA224withDSA_Key_Success() throws Exception {
+ TestUtils.assumeSHA2WithDSAAvailable();
+ KeyFactory kf = KeyFactory.getInstance("DSA");
+ DSAPrivateKeySpec keySpec = new DSAPrivateKeySpec(DSA_priv, DSA_P, DSA_Q, DSA_G);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA224withDSA");
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+
+ DSAPublicKeySpec pubKeySpec = new DSAPublicKeySpec(DSA_pub, DSA_P, DSA_Q, DSA_G);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testVerify_SHA224withDSA_Key_Success() throws Exception {
+ TestUtils.assumeSHA2WithDSAAvailable();
+ KeyFactory kf = KeyFactory.getInstance("DSA");
+ DSAPublicKeySpec pubKeySpec = new DSAPublicKeySpec(DSA_pub, DSA_P, DSA_Q, DSA_G);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+ Signature sig = Signature.getInstance("SHA224withDSA");
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(SHA224withDSA_Vector2Signature));
+ }
+
+ @Test
+ public void testSign_SHA256withDSA_Key_Success() throws Exception {
+ TestUtils.assumeSHA2WithDSAAvailable();
+ KeyFactory kf = KeyFactory.getInstance("DSA");
+ DSAPrivateKeySpec keySpec = new DSAPrivateKeySpec(DSA_priv, DSA_P, DSA_Q, DSA_G);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA256withDSA");
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+
+ DSAPublicKeySpec pubKeySpec = new DSAPublicKeySpec(DSA_pub, DSA_P, DSA_Q, DSA_G);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ @Test
+ public void testVerify_SHA256withDSA_Key_Success() throws Exception {
+ TestUtils.assumeSHA2WithDSAAvailable();
+ KeyFactory kf = KeyFactory.getInstance("DSA");
+ DSAPublicKeySpec pubKeySpec = new DSAPublicKeySpec(DSA_pub, DSA_P, DSA_Q, DSA_G);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+ Signature sig = Signature.getInstance("SHA256withDSA");
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(SHA256withDSA_Vector2Signature));
+ }
+
+ private final int THREAD_COUNT = 10;
+
+ private void testSignature_MultipleThreads_Misuse(final Signature s, final PrivateKey p)
+ throws Exception {
+ ExecutorService es = Executors.newFixedThreadPool(THREAD_COUNT);
+
+ final CountDownLatch latch = new CountDownLatch(THREAD_COUNT);
+ final byte[] message = new byte[64];
+ List<Future<Void>> futures = new ArrayList<Future<Void>>();
+
+ for (int i = 0; i < THREAD_COUNT; i++) {
+ futures.add(es.submit(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ // Try to make sure all the threads are ready first.
+ latch.countDown();
+ latch.await();
+
+ for (int j = 0; j < 100; j++) {
+ s.initSign(p);
+ s.update(message);
+ s.sign();
+ }
+
+ return null;
+ }
+ }));
+ }
+ es.shutdown();
+ assertTrue("Test should not timeout", es.awaitTermination(1, TimeUnit.MINUTES));
+
+ for (Future<Void> f : futures) {
+ try {
+ f.get();
+ } catch (ExecutionException expected) {
+ // We expect concurrent execution to cause instances to eventually throw, though
+ // if they happen to get lucky and execute completely, that's fine.
+ }
+ }
+ }
+
+ private static final byte[] NAMED_CURVE_VECTOR = "Satoshi Nakamoto".getBytes(
+ Charset.defaultCharset());
+ // $ echo -n "Satoshi Nakamoto" > signed
+ // $ openssl dgst -ecdsa-with-SHA1 -sign key.pem -out sig signed
+ private static final byte[] NAMED_CURVE_SIGNATURE = TestUtils.decodeHex("304402205b41ece6dcc1c5bfcfdae74658d99c08c5e783f3926c11ecc1a8bea5d95cdf27022061a7d5fc687287e2e02dd7c6723e2e27fe0555f789590a37e96b1bb0355b4df0");
+
+ private static PublicKey getNamedCurveEcPublicKey() throws Exception {
+ // These are the parameters for the BitCoin curve (secp256k1). See
+ // https://en.bitcoin.it/wiki/Secp256k1.
+ final BigInteger p = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16);
+ final BigInteger a = BigInteger.valueOf(0);
+ final BigInteger b = BigInteger.valueOf(7);
+ final BigInteger x = new BigInteger("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16);
+ final BigInteger y = new BigInteger("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16);
+ final BigInteger order = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16);
+ final int cofactor = 1;
+
+ final ECParameterSpec spec = new ECParameterSpec(new EllipticCurve(new ECFieldFp(p), a, b), new ECPoint(x, y), order, cofactor);
+
+ // $ openssl ecparam -name secp256k1 -genkey > key.pem
+ // $ openssl ec -text -noout < key.pem
+ final BigInteger Px = new BigInteger("2d45572747a625db5fd23b30f97044a682f2d42d31959295043c1fa0034c8ed3", 16);
+ final BigInteger Py = new BigInteger("4d330f52e4bba00145a331041c8bbcf300c4fbfdf3d63d8de7608155b2793808", 16);
+
+ final KeyFactory factory = KeyFactory.getInstance("EC");
+ ECPublicKeySpec keySpec = new ECPublicKeySpec(new ECPoint(Px, Py), spec);
+ return factory.generatePublic(keySpec);
+ }
+
+ @Test
+ public void testArbitraryCurve() throws Exception {
+ final PublicKey pub = getNamedCurveEcPublicKey();
+
+ Signature ecdsaVerify = Signature.getInstance("SHA1withECDSA");
+ ecdsaVerify.initVerify(pub);
+ ecdsaVerify.update(NAMED_CURVE_VECTOR);
+ boolean result = ecdsaVerify.verify(NAMED_CURVE_SIGNATURE);
+ assertEquals(true, result);
+
+ ecdsaVerify = Signature.getInstance("SHA1withECDSA");
+ ecdsaVerify.initVerify(pub);
+ ecdsaVerify.update("Not Satoshi Nakamoto".getBytes("UTF-8"));
+ result = ecdsaVerify.verify(NAMED_CURVE_SIGNATURE);
+ assertEquals(false, result);
+ }
+
+ private static void assertPSSAlgorithmParametersEquals(
+ PSSParameterSpec expectedSpec, AlgorithmParameters actual)
+ throws InvalidParameterSpecException {
+ assertNotNull(actual);
+ assertEqualsIgnoreCase("PSS", actual.getAlgorithm());
+ PSSParameterSpec actualSpec = actual.getParameterSpec(PSSParameterSpec.class);
+ assertPSSParameterSpecEquals(expectedSpec, actualSpec);
+ }
+
+ private static void assertPSSParameterSpecEquals(
+ PSSParameterSpec expected, PSSParameterSpec actual) {
+ assertEqualsIgnoreCase(expected.getDigestAlgorithm(), actual.getDigestAlgorithm());
+ assertEqualsIgnoreCase(expected.getMGFAlgorithm(), actual.getMGFAlgorithm());
+ if (!"MGF1".equalsIgnoreCase(expected.getMGFAlgorithm())) {
+ fail("Unsupported MGF algorithm: " + expected.getMGFAlgorithm());
+ }
+ MGF1ParameterSpec expectedMgfParams = (MGF1ParameterSpec) expected.getMGFParameters();
+ MGF1ParameterSpec actualMgfParams = (MGF1ParameterSpec) actual.getMGFParameters();
+ assertEqualsIgnoreCase(
+ expectedMgfParams.getDigestAlgorithm(), actualMgfParams.getDigestAlgorithm());
+ assertEquals(expected.getSaltLength(), actual.getSaltLength());
+ assertEquals(expected.getTrailerField(), actual.getTrailerField());
+ }
+
+ private static void assertEqualsIgnoreCase(String expected, String actual) {
+ if (expected == null) {
+ if (actual == null) {
+ return;
+ }
+ fail("Expected null, actual: <" + actual + ">");
+ } else if (actual == null) {
+ fail("Expected: <" + expected + ">, actual: null");
+ } else {
+ if (!expected.equalsIgnoreCase(actual)) {
+ fail("Expected: <" + expected + ">, actual: <" + actual + ">");
+ }
+ }
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/TestECPrivateKey.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/TestECPrivateKey.java
new file mode 100644
index 0000000..fa23445
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/TestECPrivateKey.java
@@ -0,0 +1,62 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2020 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import java.math.BigInteger;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.ECParameterSpec;
+import java.util.Objects;
+
+class TestECPrivateKey implements ECPrivateKey {
+ private ECPrivateKey key;
+ private String format;
+
+ TestECPrivateKey(ECPrivateKey key) {
+ this(key, key.getFormat());
+ }
+
+ TestECPrivateKey(ECPrivateKey key, String format) {
+ Objects.requireNonNull(key);
+ this.key = key;
+ this.format = format;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return key.getAlgorithm();
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return key.getEncoded();
+ }
+
+ @Override
+ public String getFormat() {
+ return format;
+ }
+
+ @Override
+ public ECParameterSpec getParams() {
+ return key.getParams();
+ }
+
+ @Override
+ public BigInteger getS() {
+ return key.getS();
+ }
+}
\ No newline at end of file
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/TestECPublicKey.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/TestECPublicKey.java
new file mode 100644
index 0000000..31b97dd
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/TestECPublicKey.java
@@ -0,0 +1,62 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2020 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.util.Objects;
+
+class TestECPublicKey implements ECPublicKey {
+ private ECPublicKey key;
+ private String format;
+
+ TestECPublicKey(ECPublicKey key) {
+ this(key, key.getFormat());
+ }
+
+ TestECPublicKey(ECPublicKey key, String format) {
+ Objects.requireNonNull(key);
+ this.key = key;
+ this.format = format;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return key.getAlgorithm();
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return key.getEncoded();
+ }
+
+ @Override
+ public String getFormat() {
+ return format;
+ }
+
+ @Override
+ public ECParameterSpec getParams() {
+ return key.getParams();
+ }
+
+ @Override
+ public ECPoint getW() {
+ return key.getW();
+ }
+}
\ No newline at end of file
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/TestPrivateKey.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/TestPrivateKey.java
new file mode 100644
index 0000000..ce437f8
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/TestPrivateKey.java
@@ -0,0 +1,48 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2020 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import java.security.PrivateKey;
+
+class TestPrivateKey implements PrivateKey {
+ private PrivateKey key;
+ private String format;
+
+ TestPrivateKey(PrivateKey key) {
+ this(key, key.getFormat());
+ }
+
+ TestPrivateKey(PrivateKey key, String format) {
+ this.key = key;
+ this.format = format;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return key.getAlgorithm();
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return key.getEncoded();
+ }
+
+ @Override
+ public String getFormat() {
+ return format;
+ }
+}
\ No newline at end of file
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/TestPublicKey.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/TestPublicKey.java
new file mode 100644
index 0000000..e7ea5db
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/TestPublicKey.java
@@ -0,0 +1,48 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2020 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import java.security.PublicKey;
+
+class TestPublicKey implements PublicKey {
+ private PublicKey key;
+ private String format;
+
+ TestPublicKey(PublicKey key) {
+ this(key, key.getFormat());
+ }
+
+ TestPublicKey(PublicKey key, String format) {
+ this.key = key;
+ this.format = format;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return key.getAlgorithm();
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return key.getEncoded();
+ }
+
+ @Override
+ public String getFormat() {
+ return format;
+ }
+}
\ No newline at end of file
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/cert/CertificateFactoryTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/cert/CertificateFactoryTest.java
new file mode 100644
index 0000000..9146ca9
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/cert/CertificateFactoryTest.java
@@ -0,0 +1,959 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.java.security.cert;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.org.conscrypt.Conscrypt;
+import com.android.org.conscrypt.TestUtils;
+import com.android.org.conscrypt.java.security.StandardNames;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.nio.charset.Charset;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Iterator;
+import java.util.List;
+import java.util.TimeZone;
+import javax.security.auth.x500.X500Principal;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class CertificateFactoryTest {
+
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
+ private static final String VALID_CERTIFICATE_PEM =
+ "-----BEGIN CERTIFICATE-----\n"
+ + "MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BAQUFADBM\n"
+ + "MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg\n"
+ + "THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0x\n"
+ + "MTEyMTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh\n"
+ + "MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw\n"
+ + "FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC\n"
+ + "gYEA6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jN\n"
+ + "gtXj9xVoRaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L\n"
+ + "05vuuWciKh0R73mkszeK9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAM\n"
+ + "BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl\n"
+ + "LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF\n"
+ + "BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw\n"
+ + "Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0\n"
+ + "ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF\n"
+ + "AAOBgQCfQ89bxFApsb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5\n"
+ + "u2ONgJd8IyAPkU0Wueru9G2Jysa9zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6\n"
+ + "z5nRUP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqAibAxWEEHXw==\n"
+ + "-----END CERTIFICATE-----\n";
+
+ private static final String VALID_CERTIFICATE_PEM_CRLF =
+ "-----BEGIN CERTIFICATE-----\r\n"
+ + "MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BAQUFADBM\r\n"
+ + "MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg\r\n"
+ + "THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0x\r\n"
+ + "MTEyMTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh\r\n"
+ + "MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw\r\n"
+ + "FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC\r\n"
+ + "gYEA6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jN\r\n"
+ + "gtXj9xVoRaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L\r\n"
+ + "05vuuWciKh0R73mkszeK9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAM\r\n"
+ + "BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl\r\n"
+ + "LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF\r\n"
+ + "BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw\r\n"
+ + "Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0\r\n"
+ + "ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF\r\n"
+ + "AAOBgQCfQ89bxFApsb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5\r\n"
+ + "u2ONgJd8IyAPkU0Wueru9G2Jysa9zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6\r\n"
+ + "z5nRUP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqAibAxWEEHXw==\r\n"
+ + "-----END CERTIFICATE-----\r\n";
+
+ private static final byte[] VALID_CERTIFICATE_PEM_HEADER = "-----BEGIN CERTIFICATE-----\n"
+ .getBytes(Charset.defaultCharset());
+
+ private static final byte[] VALID_CERTIFICATE_PEM_DATA =
+ ("MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BAQUFADBM"
+ + "MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg"
+ + "THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0x"
+ + "MTEyMTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh"
+ + "MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw"
+ + "FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC"
+ + "gYEA6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jN"
+ + "gtXj9xVoRaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L"
+ + "05vuuWciKh0R73mkszeK9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAM"
+ + "BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl"
+ + "LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF"
+ + "BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw"
+ + "Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0"
+ + "ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF"
+ + "AAOBgQCfQ89bxFApsb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5"
+ + "u2ONgJd8IyAPkU0Wueru9G2Jysa9zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6"
+ + "z5nRUP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqAibAxWEEHXw==")
+ .getBytes(Charset.defaultCharset());
+
+ private static final byte[] VALID_CERTIFICATE_PEM_FOOTER = "\n-----END CERTIFICATE-----\n"
+ .getBytes(Charset.defaultCharset());
+
+ private static final String INVALID_CERTIFICATE_PEM =
+ "-----BEGIN CERTIFICATE-----\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAA\n"
+ + "-----END CERTIFICATE-----";
+
+ private static final String VALID_CERTIFICATE_DER_BASE64 =
+ "MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BAQUFADBMMQswCQYDVQQG"
+ + "EwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhh"
+ + "d3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0xMTEyMTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVT"
+ + "MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApH"
+ + "b29nbGUgSW5jMRcwFQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw"
+ + "gYkCgYEA6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jNgtXj9xVo"
+ + "RaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L05vuuWciKh0R73mkszeK"
+ + "9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAMBgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0w"
+ + "K6ApoCeGJWh0dHA6Ly9jcmwudGhhd3RlLmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYI"
+ + "KwYBBQUHAwEGCCsGAQUFBwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzAB"
+ + "hhZodHRwOi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0ZS5j"
+ + "b20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUFAAOBgQCfQ89bxFAp"
+ + "sb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5u2ONgJd8IyAPkU0Wueru9G2Jysa9"
+ + "zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6z5nRUP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqA"
+ + "ibAxWEEHXw==";
+
+ // Generated with openssl crl2pkcs7 -nocrl -certfile cert.pem
+ private static final String VALID_CERTIFICATE_PKCS7_PEM = "-----BEGIN PKCS7-----\n"
+ + "MIIDUgYJKoZIhvcNAQcCoIIDQzCCAz8CAQExADALBgkqhkiG9w0BBwGgggMlMIID\n"
+ + "ITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BAQUFADBMMQsw\n"
+ + "CQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkgTHRk\n"
+ + "LjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0xMTEy\n"
+ + "MTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYw\n"
+ + "FAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcwFQYD\n"
+ + "VQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n"
+ + "6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jNgtXj\n"
+ + "9xVoRaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L05vu\n"
+ + "uWciKh0R73mkszeK9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAMBgNV\n"
+ + "HRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3RlLmNv\n"
+ + "bS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUFBwMC\n"
+ + "BglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRwOi8v\n"
+ + "b2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0ZS5j\n"
+ + "b20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUFAAOB\n"
+ + "gQCfQ89bxFApsb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5u2ON\n"
+ + "gJd8IyAPkU0Wueru9G2Jysa9zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6z5nR\n"
+ + "UP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqAibAxWEEHX6EAMQA=\n"
+ + "-----END PKCS7-----\n";
+
+ private static final String VALID_CERTIFICATE_PKCS7_DER_BASE64 =
+ "MIIDUgYJKoZIhvcNAQcCoIIDQzCCAz8CAQExADALBgkqhkiG9w0BBwGgggMlMIID"
+ + "ITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BAQUFADBMMQsw"
+ + "CQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkgTHRk"
+ + "LjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0xMTEy"
+ + "MTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYw"
+ + "FAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcwFQYD"
+ + "VQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA"
+ + "6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jNgtXj"
+ + "9xVoRaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L05vu"
+ + "uWciKh0R73mkszeK9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAMBgNV"
+ + "HRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3RlLmNv"
+ + "bS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUFBwMC"
+ + "BglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRwOi8v"
+ + "b2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0ZS5j"
+ + "b20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUFAAOB"
+ + "gQCfQ89bxFApsb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5u2ON"
+ + "gJd8IyAPkU0Wueru9G2Jysa9zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6z5nR"
+ + "UP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqAibAxWEEHX6EAMQA=";
+
+ private static final String VALID_CRL_PEM =
+ "-----BEGIN X509 CRL-----\n"
+ + "MIIBUTCBuwIBATANBgkqhkiG9w0BAQsFADBVMQswCQYDVQQGEwJHQjEkMCIGA1UE\n"
+ + "ChMbQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IENBMQ4wDAYDVQQIEwVXYWxlczEQ\n"
+ + "MA4GA1UEBxMHRXJ3IFdlbhcNMTkwODA3MTAyNzEwWhcNMTkwOTA2MTAyNzEwWjAi\n"
+ + "MCACAQcXDTE5MDgwNzEwMjY1NFowDDAKBgNVHRUEAwoBAaAOMAwwCgYDVR0UBAMC\n"
+ + "AQIwDQYJKoZIhvcNAQELBQADgYEAzF/DLiIvZDX4FpSjNCnwKRblnhJLZ1NNBAHx\n"
+ + "cRbfFY3psobvbGGOjxzCQW/03gkngG5VrSfdVOLMmQDrAxpKqeYqFDj0HAenWugb\n"
+ + "CCHWAw8WN9XSJ4nGxdRiacG/5vEIx00ICUGCeGcnqWsSnFtagDtvry2c4MMexbSP\n"
+ + "nDN0LLg=\n"
+ + "-----END X509 CRL-----\n";
+
+ private static final String VALID_CRL_PEM_CRLF =
+ "-----BEGIN X509 CRL-----\r\n"
+ + "MIIBUTCBuwIBATANBgkqhkiG9w0BAQsFADBVMQswCQYDVQQGEwJHQjEkMCIGA1UE\r\n"
+ + "ChMbQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IENBMQ4wDAYDVQQIEwVXYWxlczEQ\r\n"
+ + "MA4GA1UEBxMHRXJ3IFdlbhcNMTkwODA3MTAyNzEwWhcNMTkwOTA2MTAyNzEwWjAi\r\n"
+ + "MCACAQcXDTE5MDgwNzEwMjY1NFowDDAKBgNVHRUEAwoBAaAOMAwwCgYDVR0UBAMC\r\n"
+ + "AQIwDQYJKoZIhvcNAQELBQADgYEAzF/DLiIvZDX4FpSjNCnwKRblnhJLZ1NNBAHx\r\n"
+ + "cRbfFY3psobvbGGOjxzCQW/03gkngG5VrSfdVOLMmQDrAxpKqeYqFDj0HAenWugb\r\n"
+ + "CCHWAw8WN9XSJ4nGxdRiacG/5vEIx00ICUGCeGcnqWsSnFtagDtvry2c4MMexbSP\r\n"
+ + "nDN0LLg=\r\n"
+ + "-----END X509 CRL-----\r\n";
+
+ private static final String VALID_CRL_DER_BASE64 =
+ "MIIBUTCBuwIBATANBgkqhkiG9w0BAQsFADBVMQswCQYDVQQGEwJHQjEkMCIGA1UE"
+ + "ChMbQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IENBMQ4wDAYDVQQIEwVXYWxlczEQ"
+ + "MA4GA1UEBxMHRXJ3IFdlbhcNMTkwODA3MTAyNzEwWhcNMTkwOTA2MTAyNzEwWjAi"
+ + "MCACAQcXDTE5MDgwNzEwMjY1NFowDDAKBgNVHRUEAwoBAaAOMAwwCgYDVR0UBAMC"
+ + "AQIwDQYJKoZIhvcNAQELBQADgYEAzF/DLiIvZDX4FpSjNCnwKRblnhJLZ1NNBAHx"
+ + "cRbfFY3psobvbGGOjxzCQW/03gkngG5VrSfdVOLMmQDrAxpKqeYqFDj0HAenWugb"
+ + "CCHWAw8WN9XSJ4nGxdRiacG/5vEIx00ICUGCeGcnqWsSnFtagDtvry2c4MMexbSP"
+ + "nDN0LLg=";
+
+ // Generated with openssl crl2pkcs7 -in crl.pem
+ private static final String VALID_CRL_PKCS7_PEM = "-----BEGIN PKCS7-----\n"
+ + "MIIBggYJKoZIhvcNAQcCoIIBczCCAW8CAQExADALBgkqhkiG9w0BBwGgAKGCAVUw\n"
+ + "ggFRMIG7AgEBMA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNVBAYTAkdCMSQwIgYDVQQK\n"
+ + "ExtDZXJ0aWZpY2F0ZSBUcmFuc3BhcmVuY3kgQ0ExDjAMBgNVBAgTBVdhbGVzMRAw\n"
+ + "DgYDVQQHEwdFcncgV2VuFw0xOTA4MDcxMDI3MTBaFw0xOTA5MDYxMDI3MTBaMCIw\n"
+ + "IAIBBxcNMTkwODA3MTAyNjU0WjAMMAoGA1UdFQQDCgEBoA4wDDAKBgNVHRQEAwIB\n"
+ + "AjANBgkqhkiG9w0BAQsFAAOBgQDMX8MuIi9kNfgWlKM0KfApFuWeEktnU00EAfFx\n"
+ + "Ft8Vjemyhu9sYY6PHMJBb/TeCSeAblWtJ91U4syZAOsDGkqp5ioUOPQcB6da6BsI\n"
+ + "IdYDDxY31dInicbF1GJpwb/m8QjHTQgJQYJ4ZyepaxKcW1qAO2+vLZzgwx7FtI+c\n"
+ + "M3QsuDEA\n"
+ + "-----END PKCS7-----\n";
+
+ private static final String VALID_CRL_PKCS7_DER_BASE64 =
+ "MIIBggYJKoZIhvcNAQcCoIIBczCCAW8CAQExADALBgkqhkiG9w0BBwGgAKGCAVUw"
+ + "ggFRMIG7AgEBMA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNVBAYTAkdCMSQwIgYDVQQK"
+ + "ExtDZXJ0aWZpY2F0ZSBUcmFuc3BhcmVuY3kgQ0ExDjAMBgNVBAgTBVdhbGVzMRAw"
+ + "DgYDVQQHEwdFcncgV2VuFw0xOTA4MDcxMDI3MTBaFw0xOTA5MDYxMDI3MTBaMCIw"
+ + "IAIBBxcNMTkwODA3MTAyNjU0WjAMMAoGA1UdFQQDCgEBoA4wDDAKBgNVHRQEAwIB"
+ + "AjANBgkqhkiG9w0BAQsFAAOBgQDMX8MuIi9kNfgWlKM0KfApFuWeEktnU00EAfFx"
+ + "Ft8Vjemyhu9sYY6PHMJBb/TeCSeAblWtJ91U4syZAOsDGkqp5ioUOPQcB6da6BsI"
+ + "IdYDDxY31dInicbF1GJpwb/m8QjHTQgJQYJ4ZyepaxKcW1qAO2+vLZzgwx7FtI+c"
+ + "M3QsuDEA";
+
+ private static final String INVALID_CRL_PEM =
+ "-----BEGIN X509 CRL-----\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ + "AAAAAAAA\n"
+ + "-----END X509 CRL-----\n";
+
+ // PKCS#7 file containing a small certificate. This input is small enough to use a two-byte
+ // length prefix.
+ private static final String SMALL_PKCS7_DER_BASE64 =
+ "MIHrBgkqhkiG9w0BBwKggd0wgdoCAQExADALBgkqhkiG9w0BBwGggcEwgb4wcgIB"
+ + "ADAFBgMrZXAwDDEKMAgGA1UEAxMBQTAeFw0xNDA0MjMyMzIxNTdaFw0xNDA1MjMy"
+ + "MzIxNTdaMAwxCjAIBgNVBAMTAUEwKjAFBgMrZXADIQDXWpgBgrEKt9VL/tPJZAc6"
+ + "DuFy89qmIyWvAhpo9wdRGjAFBgMrZXADQQBuCzqji8VP9xU8mHEMjXGChX7YP5J6"
+ + "64UyVKHKH9Z1u4wEbB8dJ3ScaWSLr+VHVKUhsrvcdCelnXRrrSD7xWALoQAxAA==";
+
+ @Test
+ public void test_generateCertificate() throws Exception {
+ ServiceTester.test("CertificateFactory")
+ .withAlgorithm("X509")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ CertificateFactory cf = CertificateFactory.getInstance("X509", p);
+ test_generateCertificate(cf);
+ test_generateCertificate_InputStream_Offset_Correct(cf);
+ test_generateCertificate_InputStream_Empty(cf);
+ test_generateCertificate_InputStream_InvalidStart_Failure(cf);
+ test_generateCertificate_AnyLineLength_Success(cf);
+ test_generateCertificate_PartialInput(cf);
+
+ test_generateCrl(cf);
+ }
+ });
+ }
+
+ private void test_generateCertificate(CertificateFactory cf) throws Exception {
+ Certificate cert;
+ {
+ byte[] valid = VALID_CERTIFICATE_PEM.getBytes(Charset.defaultCharset());
+ Certificate c = cf.generateCertificate(new ByteArrayInputStream(valid));
+ assertNotNull(c);
+ cert = c;
+ }
+
+ {
+ byte[] valid = VALID_CERTIFICATE_PEM_CRLF.getBytes(Charset.defaultCharset());
+ Certificate c = cf.generateCertificate(new ByteArrayInputStream(valid));
+ assertNotNull(c);
+ assertEquals(c, cert);
+ }
+
+ {
+ byte[] valid = TestUtils.decodeBase64(VALID_CERTIFICATE_DER_BASE64);
+ Certificate c = cf.generateCertificate(new ByteArrayInputStream(valid));
+ assertNotNull(c);
+ assertEquals(c, cert);
+ }
+
+ // The RI only supports PKCS#7 blobs with generateCertificates, not
+ // generateCertificate. See https://github.com/google/conscrypt/issues/987
+ if (!StandardNames.IS_RI) {
+ byte[] valid = TestUtils.decodeBase64(VALID_CERTIFICATE_PKCS7_DER_BASE64);
+ Certificate c = cf.generateCertificate(new ByteArrayInputStream(valid));
+ assertNotNull(c);
+ assertEquals(c, cert);
+ }
+
+ {
+ byte[] valid = VALID_CERTIFICATE_PKCS7_PEM.getBytes(Charset.defaultCharset());
+ Collection<? extends Certificate> cs =
+ cf.generateCertificates(new ByteArrayInputStream(valid));
+ assertEquals(1, cs.size());
+ assertEquals(cs.iterator().next(), cert);
+ }
+
+ {
+ byte[] valid = TestUtils.decodeBase64(VALID_CERTIFICATE_PKCS7_DER_BASE64);
+ Collection<? extends Certificate> cs =
+ cf.generateCertificates(new ByteArrayInputStream(valid));
+ assertEquals(1, cs.size());
+ assertEquals(cs.iterator().next(), cert);
+ }
+
+ {
+ byte[] valid = TestUtils.decodeBase64(SMALL_PKCS7_DER_BASE64);
+ Collection<? extends Certificate> cs =
+ cf.generateCertificates(new ByteArrayInputStream(valid));
+ assertEquals(1, cs.size());
+ assertNotNull(cs.iterator().next());
+ }
+
+ try {
+ byte[] invalid = INVALID_CERTIFICATE_PEM.getBytes(Charset.defaultCharset());
+ cf.generateCertificate(new ByteArrayInputStream(invalid));
+ fail();
+ } catch (CertificateException expected) {
+ }
+
+ try {
+ Certificate c = cf.generateCertificate(new ByteArrayInputStream(new byte[0]));
+ // Bouncy Castle returns null on empty inputs rather than throwing an exception,
+ // which technically doesn't satisfy the method contract, but we'll accept it
+ assertTrue((c == null) && cf.getProvider().getName().equals("BC"));
+ } catch (CertificateException maybeExpected) {
+ assertFalse(cf.getProvider().getName().equals("BC"));
+ }
+
+ try {
+ Certificate c = cf.generateCertificate(new ByteArrayInputStream(new byte[] { 0x00 }));
+ // Bouncy Castle returns null on short inputs rather than throwing an exception,
+ // which technically doesn't satisfy the method contract, but we'll accept it
+ assertTrue((c == null) && cf.getProvider().getName().equals("BC"));
+ } catch (CertificateException maybeExpected) {
+ assertFalse(cf.getProvider().getName().equals("BC"));
+ }
+ }
+
+ /*
+ * Checks all possible line lengths for PEM input data.
+ */
+ private void test_generateCertificate_AnyLineLength_Success(CertificateFactory cf)
+ throws Exception {
+ // RI barfs on this
+ if (StandardNames.IS_RI) {
+ return;
+ }
+
+ int lineLength = 1;
+ int maxLineLength = VALID_CERTIFICATE_PEM_DATA.length;
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ baos.write(VALID_CERTIFICATE_PEM_HEADER);
+ int offset = 0;
+ while (lineLength < (maxLineLength - 4)) {
+ int end = offset + lineLength;
+ if (end > VALID_CERTIFICATE_PEM_DATA.length) {
+ end = VALID_CERTIFICATE_PEM_DATA.length;
+ }
+ baos.write(Arrays.copyOfRange(VALID_CERTIFICATE_PEM_DATA, offset, end));
+ baos.write('\n');
+ offset += lineLength;
+ if (offset >= maxLineLength) {
+ baos.write(VALID_CERTIFICATE_PEM_FOOTER);
+ try {
+ Certificate c =
+ cf.generateCertificate(new ByteArrayInputStream(baos.toByteArray()));
+ assertNotNull(c);
+ } catch (Exception e) {
+ throw new Exception("Fail at line length " + lineLength, e);
+ }
+ baos.reset();
+ baos.write(VALID_CERTIFICATE_PEM_HEADER);
+ offset = 0;
+ } else {
+ lineLength++;
+ }
+ }
+
+ }
+
+ private void test_generateCertificate_InputStream_Empty(CertificateFactory cf) throws Exception {
+ try {
+ Certificate c = cf.generateCertificate(new ByteArrayInputStream(new byte[0]));
+ if (!"BC".equals(cf.getProvider().getName())) {
+ fail("should throw CertificateException: " + cf.getProvider().getName());
+ }
+ assertNull(c);
+ } catch (CertificateException e) {
+ if ("BC".equals(cf.getProvider().getName())) {
+ fail("should return null: " + cf.getProvider().getName());
+ }
+ }
+ }
+
+ private void test_generateCertificate_InputStream_InvalidStart_Failure(CertificateFactory cf)
+ throws Exception {
+ try {
+ Certificate c = cf.generateCertificate(new ByteArrayInputStream(
+ "-----BEGIN CERTIFICATE-----".getBytes(Charset.defaultCharset())));
+ if (!"BC".equals(cf.getProvider().getName())) {
+ fail("should throw CertificateException: " + cf.getProvider().getName());
+ }
+ assertNull(c);
+ } catch (CertificateException expected) {
+ if ("BC".equals(cf.getProvider().getName())) {
+ fail("should return null: " + cf.getProvider().getName());
+ }
+ }
+ }
+
+ private void test_generateCertificate_InputStream_Offset_Correct(CertificateFactory cf)
+ throws Exception {
+ byte[] valid = VALID_CERTIFICATE_PEM.getBytes(Charset.defaultCharset());
+
+ byte[] doubleCertificateData = new byte[valid.length * 2];
+ System.arraycopy(valid, 0, doubleCertificateData, 0, valid.length);
+ System.arraycopy(valid, 0, doubleCertificateData, valid.length, valid.length);
+ MeasuredInputStream certStream = new MeasuredInputStream(new ByteArrayInputStream(
+ doubleCertificateData));
+ Certificate certificate = cf.generateCertificate(certStream);
+ assertNotNull(certificate);
+ assertEquals(valid.length, certStream.getCount());
+ }
+
+ /**
+ * Proxy that counts the number of bytes read from an InputStream.
+ */
+ private static class MeasuredInputStream extends InputStream {
+ private long mCount = 0;
+
+ private long mMarked = 0;
+
+ private InputStream mStream;
+
+ public MeasuredInputStream(InputStream is) {
+ mStream = is;
+ }
+
+ public long getCount() {
+ return mCount;
+ }
+
+ @Override
+ public int read() throws IOException {
+ int nextByte = mStream.read();
+ mCount++;
+ return nextByte;
+ }
+
+ @Override
+ public int read(byte[] buffer) throws IOException {
+ int count = mStream.read(buffer);
+ mCount += count;
+ return count;
+ }
+
+ @Override
+ public int read(byte[] buffer, int offset, int length) throws IOException {
+ int count = mStream.read(buffer, offset, length);
+ mCount += count;
+ return count;
+ }
+
+ @Override
+ public long skip(long byteCount) throws IOException {
+ long count = mStream.skip(byteCount);
+ mCount += count;
+ return count;
+ }
+
+ @Override
+ public int available() throws IOException {
+ return mStream.available();
+ }
+
+ @Override
+ public void close() throws IOException {
+ mStream.close();
+ }
+
+ @Override
+ public void mark(int readlimit) {
+ mMarked = mCount;
+ mStream.mark(readlimit);
+ }
+
+ @Override
+ public boolean markSupported() {
+ return mStream.markSupported();
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ mCount = mMarked;
+ mStream.reset();
+ }
+ }
+
+ /**
+ * An InputStream that only returns two bytes at a time, no matter how many were requested.
+ */
+ private static class SlowInputStream extends FilterInputStream {
+ protected SlowInputStream(InputStream inputStream) {
+ super(inputStream);
+ }
+
+ @Override
+ public int read(byte[] buffer) throws IOException {
+ if (buffer.length < 2) {
+ return super.read(buffer);
+ }
+ return super.read(buffer, 0, 2);
+ }
+
+ @Override
+ public int read(byte[] buffer, int offset, int len) throws IOException {
+ if (len < 2) {
+ return super.read(buffer, offset, len);
+ }
+ return super.read(buffer, offset, 2);
+ }
+ }
+
+ // Test that certificates are decoded properly even if the InputStream is unhelpful and only
+ // returns partial inputs on basically every request.
+ private void test_generateCertificate_PartialInput(CertificateFactory cf) throws Exception {
+ byte[] valid = VALID_CERTIFICATE_PEM.getBytes(Charset.defaultCharset());
+ Certificate c = cf.generateCertificate(new SlowInputStream(new ByteArrayInputStream(valid)));
+ assertNotNull(c);
+
+ valid = TestUtils.decodeBase64(VALID_CERTIFICATE_DER_BASE64);
+ c = cf.generateCertificate(new SlowInputStream(new ByteArrayInputStream(valid)));
+ assertNotNull(c);
+ }
+
+ /* CertPath tests */
+ @Test
+ public void testGenerateCertPath() throws Exception {
+ KeyHolder ca = generateCertificate(true, null);
+ KeyHolder cert1 = generateCertificate(true, ca);
+ KeyHolder cert2 = generateCertificate(false, cert1);
+ KeyHolder cert3 = generateCertificate(false, cert2);
+
+ List<X509Certificate> certs = new ArrayList<X509Certificate>();
+ certs.add(cert3.certificate);
+ certs.add(cert2.certificate);
+ certs.add(cert1.certificate);
+
+ List<X509Certificate> duplicatedCerts = new ArrayList<X509Certificate>(certs);
+ duplicatedCerts.add(cert2.certificate);
+
+ Provider[] providers = Security.getProviders("CertificateFactory.X509");
+ for (Provider p : providers) {
+ final CertificateFactory cf = CertificateFactory.getInstance("X.509", p);
+
+ if (Conscrypt.isConscrypt(p)) {
+ // It's not specified whether duplicated certs should work, but we want Conscrypt
+ // to accept them
+ {
+ final CertPath duplicatedPath = cf.generateCertPath(duplicatedCerts);
+ // This shouldn't cause an exception
+ duplicatedPath.getEncoded();
+ }
+ }
+
+ testCertPathEncoding(cf, certs, null);
+
+ /* Make sure all encoding entries are the same. */
+ final Iterator<String> it1 = cf.getCertPathEncodings();
+ final Iterator<String> it2 = cf.generateCertPath(certs).getEncodings();
+ for (;;) {
+ assertEquals(p.getName(), it1.hasNext(), it2.hasNext());
+ if (!it1.hasNext()) {
+ break;
+ }
+
+ String encoding = it1.next();
+ assertEquals(p.getName(), encoding, it2.next());
+
+ try {
+ it1.remove();
+ fail("Should not be able to remove from iterator");
+ } catch (UnsupportedOperationException expected) {
+ }
+
+ try {
+ it2.remove();
+ fail("Should not be able to remove from iterator");
+ } catch (UnsupportedOperationException expected) {
+ }
+
+ /* Now test using this encoding. */
+ testCertPathEncoding(cf, certs, encoding);
+ }
+ }
+ }
+
+ private void testCertPathEncoding(CertificateFactory cf, List<X509Certificate> expectedCerts,
+ String encoding) throws Exception {
+ final String providerName = cf.getProvider().getName() + "[" + encoding + "]";
+
+ final CertPath pathFromList = cf.generateCertPath(expectedCerts);
+
+ // Create a copy we can modify and discard.
+ final byte[] encodedCopy;
+ if (encoding == null) {
+ encodedCopy = pathFromList.getEncoded();
+ assertNotNull(providerName, encodedCopy);
+
+ // check idempotence
+ assertEquals(providerName, Arrays.toString(pathFromList.getEncoded()),
+ Arrays.toString(encodedCopy));
+ } else {
+ encodedCopy = pathFromList.getEncoded(encoding);
+ assertNotNull(providerName, encodedCopy);
+
+ // check idempotence
+ assertEquals(providerName, Arrays.toString(pathFromList.getEncoded(encoding)),
+ Arrays.toString(encodedCopy));
+ }
+
+ // Try to modify byte array.
+ encodedCopy[0] ^= (byte) 0xFF;
+
+ // Get a real copy we will use if the test proceeds.
+ final byte[] encoded;
+ if (encoding == null) {
+ encoded = pathFromList.getEncoded();
+ assertNotNull(providerName, encodedCopy);
+
+ // check idempotence
+ assertEquals(providerName, Arrays.toString(pathFromList.getEncoded()),
+ Arrays.toString(encoded));
+ } else {
+ encoded = pathFromList.getEncoded(encoding);
+ assertNotNull(providerName, encodedCopy);
+
+ // check idempotence
+ assertEquals(providerName, Arrays.toString(pathFromList.getEncoded(encoding)),
+ Arrays.toString(encoded));
+ }
+ assertNotEquals(providerName, Arrays.toString(encoded), Arrays.toString(encodedCopy));
+
+ encodedCopy[0] ^= (byte) 0xFF;
+ assertEquals(providerName, Arrays.toString(encoded), Arrays.toString(encodedCopy));
+
+ final CertPath actualPath;
+ if (encoding == null) {
+ actualPath = cf.generateCertPath(new ByteArrayInputStream(encoded));
+ } else {
+ actualPath = cf.generateCertPath(new ByteArrayInputStream(encoded), encoding);
+ }
+
+ // PKCS7 certificate bags are not guaranteed to be in order.
+ final List<? extends Certificate> actualCerts;
+ if (!"PKCS7".equals(encoding)) {
+ actualCerts = actualPath.getCertificates();
+ assertEquals(providerName, expectedCerts, actualCerts);
+ } else {
+ actualCerts = pathFromList.getCertificates();
+ }
+
+ try {
+ actualCerts.remove(0);
+ fail("List of certificate should be immutable");
+ } catch (UnsupportedOperationException expected) {
+ }
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(actualPath);
+ oos.close();
+
+ byte[] serialized = baos.toByteArray();
+ ByteArrayInputStream bais = new ByteArrayInputStream(serialized);
+ ObjectInputStream ois = new ObjectInputStream(bais);
+ Object output = ois.readObject();
+ assertTrue(providerName, output instanceof CertPath);
+
+ assertEquals(providerName, actualPath, output);
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class KeyHolder {
+ public X509Certificate certificate;
+
+ public PrivateKey privateKey;
+ }
+
+ @SuppressWarnings("deprecation")
+ private static KeyHolder generateCertificate(boolean isCa, KeyHolder issuer) throws Exception {
+ Date startDate = new Date();
+
+ GregorianCalendar cal = new GregorianCalendar();
+ cal.setTimeZone(TimeZone.getTimeZone("UTC"));
+ cal.set(2100, 0, 1, 0, 0, 0); // Jan 1, 2100 UTC
+ Date expiryDate = cal.getTime();
+
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ KeyPair keyPair = kpg.generateKeyPair();
+
+ BigInteger serial;
+ X500Principal issuerPrincipal;
+ X500Principal subjectPrincipal;
+ PrivateKey caKey;
+ if (issuer != null) {
+ serial = issuer.certificate.getSerialNumber().add(BigInteger.ONE);
+ subjectPrincipal = new X500Principal("CN=Test Certificate Serial #" + serial.toString());
+ issuerPrincipal = issuer.certificate.getSubjectX500Principal();
+ caKey = issuer.privateKey;
+ } else {
+ serial = BigInteger.ONE;
+ subjectPrincipal = new X500Principal("CN=Test CA, O=Tests, C=US");
+ issuerPrincipal = subjectPrincipal;
+ caKey = keyPair.getPrivate();
+ }
+
+ BasicConstraints basicConstraints;
+ if (isCa) {
+ basicConstraints = new BasicConstraints(10 - serial.intValue());
+ } else {
+ basicConstraints = new BasicConstraints(false);
+ }
+
+ org.bouncycastle.x509.X509V3CertificateGenerator certGen =
+ new org.bouncycastle.x509.X509V3CertificateGenerator();
+
+ PublicKey pubKey = keyPair.getPublic();
+ certGen.setSerialNumber(serial);
+ certGen.setIssuerDN(issuerPrincipal);
+ certGen.setNotBefore(startDate);
+ certGen.setNotAfter(expiryDate);
+ certGen.setSubjectDN(subjectPrincipal);
+ certGen.setPublicKey(pubKey);
+ certGen.setSignatureAlgorithm("SHA1withRSA");
+
+ if (issuer != null) {
+ certGen.addExtension(Extension.authorityKeyIdentifier, false,
+ new org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure(
+ issuer.certificate));
+ } else {
+ certGen.addExtension(Extension.authorityKeyIdentifier, false,
+ new AuthorityKeyIdentifier(generatePublicKeyDigest(pubKey)));
+ }
+
+ certGen.addExtension(Extension.subjectKeyIdentifier, false,
+ new SubjectKeyIdentifier(generatePublicKeyDigest(pubKey)));
+ certGen.addExtension(Extension.basicConstraints, true, basicConstraints);
+
+ X509Certificate cert = certGen.generate(caKey);
+
+ KeyHolder holder = new KeyHolder();
+ holder.certificate = cert;
+ holder.privateKey = keyPair.getPrivate();
+
+ return holder;
+ }
+
+ /**
+ * Generates a type 1 key identifier according to RFC 3280 4.2.1.2.
+ */
+ private static byte[] generatePublicKeyDigest(PublicKey pubKey) {
+ SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
+ MessageDigest sha1digest;
+ try {
+ sha1digest = MessageDigest.getInstance("SHA-1");
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("SHA-1 not available");
+ }
+ return sha1digest.digest(spki.getPublicKeyData().getBytes());
+ }
+
+ private void test_generateCrl(CertificateFactory cf) throws Exception {
+ byte[] valid = VALID_CRL_PEM.getBytes(Charset.defaultCharset());
+ CRL c = cf.generateCRL(new ByteArrayInputStream(valid));
+ assertNotNull(c);
+
+ valid = VALID_CRL_PEM_CRLF.getBytes(Charset.defaultCharset());
+ CRL c2 = cf.generateCRL(new ByteArrayInputStream(valid));
+ assertNotNull(c2);
+ assertEquals(c, c2);
+
+ valid = TestUtils.decodeBase64(VALID_CRL_DER_BASE64);
+ c2 = cf.generateCRL(new ByteArrayInputStream(valid));
+ assertNotNull(c);
+ assertEquals(c, c2);
+
+ // The RI only supports PKCS#7 with generateCRLs, not generateCRL.
+ // See https://github.com/google/conscrypt/issues/987
+ if (!StandardNames.IS_RI) {
+ valid = TestUtils.decodeBase64(VALID_CRL_PKCS7_DER_BASE64);
+ c2 = cf.generateCRL(new ByteArrayInputStream(valid));
+ assertNotNull(c);
+ assertEquals(c, c2);
+ }
+
+ valid = TestUtils.decodeBase64(VALID_CRL_PKCS7_DER_BASE64);
+ Collection<? extends CRL> crls = cf.generateCRLs(new ByteArrayInputStream(valid));
+ assertEquals(1, crls.size());
+ assertEquals(c, crls.iterator().next());
+
+ valid = VALID_CRL_PKCS7_PEM.getBytes(Charset.defaultCharset());
+ crls = cf.generateCRLs(new ByteArrayInputStream(valid));
+ assertEquals(1, crls.size());
+ assertEquals(c, crls.iterator().next());
+
+ try {
+ byte[] invalid = INVALID_CRL_PEM.getBytes(Charset.defaultCharset());
+ cf.generateCRL(new ByteArrayInputStream(invalid));
+ fail();
+ } catch (CRLException expected) {
+ }
+
+ try {
+ c = cf.generateCRL(new ByteArrayInputStream(new byte[0]));
+ // Bouncy Castle returns null on empty inputs rather than throwing an exception,
+ // which technically doesn't satisfy the method contract, but we'll accept it
+ assertTrue((c == null) && cf.getProvider().getName().equals("BC"));
+ } catch (CRLException maybeExpected) {
+ assertFalse(cf.getProvider().getName().equals("BC"));
+ }
+
+ try {
+ c = cf.generateCRL(new ByteArrayInputStream(new byte[] { 0x00 }));
+ // Bouncy Castle returns null on short inputs rather than throwing an exception,
+ // which technically doesn't satisfy the method contract, but we'll accept it
+ assertTrue((c == null) && cf.getProvider().getName().equals("BC"));
+ } catch (CRLException maybeExpected) {
+ assertFalse(cf.getProvider().getName().equals("BC"));
+ }
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/cert/X509CRLTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/cert/X509CRLTest.java
new file mode 100644
index 0000000..ac3ee2b
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/cert/X509CRLTest.java
@@ -0,0 +1,184 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package com.android.org.conscrypt.java.security.cert;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.org.conscrypt.TestUtils;
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.Provider;
+import java.security.SignatureException;
+import java.security.cert.CRLReason;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class X509CRLTest {
+
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
+ private static final String CA_CERT =
+ "-----BEGIN CERTIFICATE-----\n"
+ + "MIIC0DCCAjmgAwIBAgIBADANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJHQjEk\n"
+ + "MCIGA1UEChMbQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IENBMQ4wDAYDVQQIEwVX\n"
+ + "YWxlczEQMA4GA1UEBxMHRXJ3IFdlbjAeFw0xMjA2MDEwMDAwMDBaFw0yMjA2MDEw\n"
+ + "MDAwMDBaMFUxCzAJBgNVBAYTAkdCMSQwIgYDVQQKExtDZXJ0aWZpY2F0ZSBUcmFu\n"
+ + "c3BhcmVuY3kgQ0ExDjAMBgNVBAgTBVdhbGVzMRAwDgYDVQQHEwdFcncgV2VuMIGf\n"
+ + "MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVimhTYhCicRmTbneDIRgcKkATxtB7\n"
+ + "jHbrkVfT0PtLO1FuzsvRyY2RxS90P6tjXVUJnNE6uvMa5UFEJFGnTHgW8iQ8+EjP\n"
+ + "KDHM5nugSlojgZ88ujfmJNnDvbKZuDnd/iYx0ss6hPx7srXFL8/BT/9Ab1zURmnL\n"
+ + "svfP34b7arnRsQIDAQABo4GvMIGsMB0GA1UdDgQWBBRfnYgNyHPmVNT4DdjmsMEk\n"
+ + "tEfDVTB9BgNVHSMEdjB0gBRfnYgNyHPmVNT4DdjmsMEktEfDVaFZpFcwVTELMAkG\n"
+ + "A1UEBhMCR0IxJDAiBgNVBAoTG0NlcnRpZmljYXRlIFRyYW5zcGFyZW5jeSBDQTEO\n"
+ + "MAwGA1UECBMFV2FsZXMxEDAOBgNVBAcTB0VydyBXZW6CAQAwDAYDVR0TBAUwAwEB\n"
+ + "/zANBgkqhkiG9w0BAQUFAAOBgQAGCMxKbWTyIF4UbASydvkrDvqUpdryOvw4BmBt\n"
+ + "OZDQoeojPUApV2lGOwRmYef6HReZFSCa6i4Kd1F2QRIn18ADB8dHDmFYT9czQiRy\n"
+ + "f1HWkLxHqd81TbD26yWVXeGJPE3VICskovPkQNJ0tU4b03YmnKliibduyqQQkOFP\n"
+ + "OwqULg==\n"
+ + "-----END CERTIFICATE-----\n";
+
+ private static final String REVOKED_CERT =
+ "-----BEGIN CERTIFICATE-----\n"
+ + "MIICyjCCAjOgAwIBAgIBBzANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJHQjEk\n"
+ + "MCIGA1UEChMbQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IENBMQ4wDAYDVQQIEwVX\n"
+ + "YWxlczEQMA4GA1UEBxMHRXJ3IFdlbjAeFw0xMjA2MDEwMDAwMDBaFw0yMjA2MDEw\n"
+ + "MDAwMDBaMFIxCzAJBgNVBAYTAkdCMSEwHwYDVQQKExhDZXJ0aWZpY2F0ZSBUcmFu\n"
+ + "c3BhcmVuY3kxDjAMBgNVBAgTBVdhbGVzMRAwDgYDVQQHEwdFcncgV2VuMIGfMA0G\n"
+ + "CSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+75jnwmh3rjhfdTJaDB0ym+3xj6r015a/\n"
+ + "BH634c4VyVui+A7kWL19uG+KSyUhkaeb1wDDjpwDibRc1NyaEgqyHgy0HNDnKAWk\n"
+ + "EM2cW9tdSSdyba8XEPYBhzd+olsaHjnu0LiBGdwVTcaPfajjDK8VijPmyVCfSgWw\n"
+ + "FAn/Xdh+tQIDAQABo4GsMIGpMB0GA1UdDgQWBBQgMVQa8lwF/9hli2hDeU9ekDb3\n"
+ + "tDB9BgNVHSMEdjB0gBRfnYgNyHPmVNT4DdjmsMEktEfDVaFZpFcwVTELMAkGA1UE\n"
+ + "BhMCR0IxJDAiBgNVBAoTG0NlcnRpZmljYXRlIFRyYW5zcGFyZW5jeSBDQTEOMAwG\n"
+ + "A1UECBMFV2FsZXMxEDAOBgNVBAcTB0VydyBXZW6CAQAwCQYDVR0TBAIwADANBgkq\n"
+ + "hkiG9w0BAQUFAAOBgQAEWQDIDds2NTDt4ySO6fDthUXoBcp+LM1ipk6dKKgC94J5\n"
+ + "k1lta//1sl4/PEgEKnuk5APH87zgzG0it8EjurQg2SNlHlhGZ86AmZSCwHvmk8z9\n"
+ + "g7HSVIKtrKOdMhrHE3nW649PWUdRcbGjCeaC9MTxWv9cGC7NqDKRNcGWWiN3Dg==\n"
+ + "-----END CERTIFICATE-----\n";
+
+ private static final String CRL =
+ "-----BEGIN X509 CRL-----\n"
+ + "MIIBUTCBuwIBATANBgkqhkiG9w0BAQsFADBVMQswCQYDVQQGEwJHQjEkMCIGA1UE\n"
+ + "ChMbQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IENBMQ4wDAYDVQQIEwVXYWxlczEQ\n"
+ + "MA4GA1UEBxMHRXJ3IFdlbhcNMTkwODA3MTAyNzEwWhcNMTkwOTA2MTAyNzEwWjAi\n"
+ + "MCACAQcXDTE5MDgwNzEwMjY1NFowDDAKBgNVHRUEAwoBAaAOMAwwCgYDVR0UBAMC\n"
+ + "AQIwDQYJKoZIhvcNAQELBQADgYEAzF/DLiIvZDX4FpSjNCnwKRblnhJLZ1NNBAHx\n"
+ + "cRbfFY3psobvbGGOjxzCQW/03gkngG5VrSfdVOLMmQDrAxpKqeYqFDj0HAenWugb\n"
+ + "CCHWAw8WN9XSJ4nGxdRiacG/5vEIx00ICUGCeGcnqWsSnFtagDtvry2c4MMexbSP\n"
+ + "nDN0LLg=\n"
+ + "-----END X509 CRL-----\n";
+
+ private static final String CRL_TBS_BASE64 =
+ "MIG7AgEBMA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNVBAYTAkdCMSQwIgYDVQQKExtD"
+ + "ZXJ0aWZpY2F0ZSBUcmFuc3BhcmVuY3kgQ0ExDjAMBgNVBAgTBVdhbGVzMRAwDgYD"
+ + "VQQHEwdFcncgV2VuFw0xOTA4MDcxMDI3MTBaFw0xOTA5MDYxMDI3MTBaMCIwIAIB"
+ + "BxcNMTkwODA3MTAyNjU0WjAMMAoGA1UdFQQDCgEBoA4wDDAKBgNVHRQEAwIBAg==";
+
+ private static final String UNKNOWN_SIGNATURE_OID = "-----BEGIN X509 CRL-----\n"
+ + "MIIBVzCBvgIBATAQBgwqhkiG9xIEAYS3CQIFADBVMQswCQYDVQQGEwJHQjEkMCIG\n"
+ + "A1UEChMbQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IENBMQ4wDAYDVQQIEwVXYWxl\n"
+ + "czEQMA4GA1UEBxMHRXJ3IFdlbhcNMTkwODA3MTAyNzEwWhcNMTkwOTA2MTAyNzEw\n"
+ + "WjAiMCACAQcXDTE5MDgwNzEwMjY1NFowDDAKBgNVHRUEAwoBAaAOMAwwCgYDVR0U\n"
+ + "BAMCAQIwEAYMKoZIhvcSBAGEtwkCBQADgYEAzF/DLiIvZDX4FpSjNCnwKRblnhJL\n"
+ + "Z1NNBAHxcRbfFY3psobvbGGOjxzCQW/03gkngG5VrSfdVOLMmQDrAxpKqeYqFDj0\n"
+ + "HAenWugbCCHWAw8WN9XSJ4nGxdRiacG/5vEIx00ICUGCeGcnqWsSnFtagDtvry2c\n"
+ + "4MMexbSPnDN0LLg=\n"
+ + "-----END X509 CRL-----\n";
+
+ @Test
+ public void testCrl() throws Exception {
+ ServiceTester.test("CertificateFactory")
+ .withAlgorithm("X509")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ CertificateFactory cf = CertificateFactory.getInstance("X509", p);
+
+ X509CRL crl = (X509CRL) cf.generateCRL(new ByteArrayInputStream(CRL.getBytes(
+ StandardCharsets.US_ASCII)));
+ X509Certificate revoked = (X509Certificate) cf.generateCertificate(
+ new ByteArrayInputStream(REVOKED_CERT.getBytes(StandardCharsets.US_ASCII)));
+ X509Certificate ca = (X509Certificate) cf.generateCertificate(
+ new ByteArrayInputStream(CA_CERT.getBytes(StandardCharsets.US_ASCII)));
+
+ assertEquals("SHA256WITHRSA", crl.getSigAlgName().toUpperCase());
+ crl.verify(ca.getPublicKey());
+ try {
+ crl.verify(revoked.getPublicKey());
+ fail();
+ } catch (SignatureException expected) {
+ }
+
+ byte[] expectedTBSCertList = TestUtils.decodeBase64(CRL_TBS_BASE64);
+ assertArrayEquals(expectedTBSCertList, crl.getTBSCertList());
+
+ assertTrue(crl.isRevoked(revoked));
+ X509CRLEntry entry = crl.getRevokedCertificate(revoked);
+ assertEquals(CRLReason.KEY_COMPROMISE, entry.getRevocationReason());
+ assertTrue(entry.getCriticalExtensionOIDs().isEmpty());
+ assertEquals(Collections.singleton("2.5.29.21"), entry.getNonCriticalExtensionOIDs());
+ assertFalse(entry.hasUnsupportedCriticalExtension());
+
+ assertFalse(crl.isRevoked(ca));
+ assertNull(crl.getRevokedCertificate(ca));
+
+ assertEquals(Collections.singleton(entry), crl.getRevokedCertificates());
+ }
+ });
+ }
+
+ @Test
+ public void testUnknownSigAlgOID() throws Exception {
+ ServiceTester.test("CertificateFactory")
+ .withAlgorithm("X509")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ CertificateFactory cf = CertificateFactory.getInstance("X509", p);
+ X509CRL crl = (X509CRL) cf.generateCRL(new ByteArrayInputStream(
+ UNKNOWN_SIGNATURE_OID.getBytes(StandardCharsets.US_ASCII)));
+ assertEquals("1.2.840.113554.4.1.72585.2", crl.getSigAlgOID());
+ }
+ });
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/cert/X509CertificateTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/cert/X509CertificateTest.java
new file mode 100644
index 0000000..30e73fd
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/java/security/cert/X509CertificateTest.java
@@ -0,0 +1,733 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * 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.
+ */
+
+package com.android.org.conscrypt.java.security.cert;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.org.conscrypt.TestUtils;
+import java.io.ByteArrayInputStream;
+import java.math.BigInteger;
+import java.nio.charset.Charset;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
+import javax.security.auth.x500.X500Principal;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.Pair;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class X509CertificateTest {
+
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
+ private static final String VALID_CERT =
+ "-----BEGIN CERTIFICATE-----\n"
+ + "MIIFMjCCAxqgAwIBAgIJAL0mG5fOeJ7xMA0GCSqGSIb3DQEBCwUAMC0xCzAJBgNV\n"
+ + "BAYTAkdCMQ8wDQYDVQQHDAZMb25kb24xDTALBgNVBAoMBFRlc3QwIBcNMTgwOTE3\n"
+ + "MTIxNzU3WhgPMjExODA4MjQxMjE3NTdaMC0xCzAJBgNVBAYTAkdCMQ8wDQYDVQQH\n"
+ + "DAZMb25kb24xDTALBgNVBAoMBFRlc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\n"
+ + "ggIKAoICAQDCMhBrRAGGw+n2GdctBr/cEK4FZA6ajiHjihgpCHoSBdyL4R2jGKLS\n"
+ + "g0WgaMXa1HpkKN7LcIySosEBPlmcRkr1RqbEvQStOSvoFCXYvtx3alM6HTbXMcDR\n"
+ + "mqoKoABP6LXsPSoMWIgqMtP2X9EOppzHVIK1yFYFfbIlvYUV2Ka+MuMe0Vh5wvD1\n"
+ + "4GanPb+cWSKgdRSVQovCCMY3yWtZKVEaxRpCsk/mYYIFWz0tcgMjIKwDx1XXgiAV\n"
+ + "nU6NK43xbaw3XhtnaD/pv9lhTTbNrlcln9LjTD097BaK4R+1AEPHnpfxA9Ui3upn\n"
+ + "kbsNUdGdOB0ksZi/vd7lh833YgquQUIAhYrbfvq/HFCpVV1gljzlS3sqULYpLE//\n"
+ + "i3OsuL2mE+CYIJGpIi2GeJJWXciNMTJDOqTn+fRDtVb4RPp4Y70DJirp7XzaBi3q\n"
+ + "H0edANCzPSRCDbZsOhzIXhXshldiXVRX666DDlbMQgLTEnNKrkwv6DmU8o15XQsb\n"
+ + "8k1Os2YwXmkEOxUQ7AJZXVTZSf6UK9Znmdq1ZrHjybMfRUkHVxJcnKvrxfryralv\n"
+ + "gzfvu+D6HuxrCo3Ojqa+nDgIbxKEBtdrcsMhq1jWPFhjwo1fSadAkKOfdCAuXJRD\n"
+ + "THg3b4Sf+W7Cpc570YHrIpBf7WFl2XsPcEM0mJZ5+yATASCubNozQwIDAQABo1Mw\n"
+ + "UTAdBgNVHQ4EFgQUES0hupZSqY21JOba10QyZuxm91EwHwYDVR0jBBgwFoAUES0h\n"
+ + "upZSqY21JOba10QyZuxm91EwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsF\n"
+ + "AAOCAgEABTN5S30ng/RMpBweDm2N561PdpaCdiRXtAFCRVWR2mkDYC/Xj9Vqe6be\n"
+ + "PyM7L/5OKYVjzF1yJu67z/dx+ja5o+41g17jdqla7hyPx+9B4uRyDh+1KJTa+duj\n"
+ + "mw/aA1LCr6O6W4WizDOsChJ6FaB2Y1+GlFnKWb5nUdhVJqXQE1WOX9dZnw8Y4Npd\n"
+ + "VmAsjWot0BZorJrt3fwfcv3QfA896twkbo7Llv/8qzg4sXZXZ4ZtgAOqnPngiSn+\n"
+ + "JT/vYCXZ406VvAFpFqMcVz2dO/VGuL8lGIMHRKNyafrsV81EzH1W/XmRWOgvgj6r\n"
+ + "yQI63ln/AMY72HQ97xLkE1xKunGz6bK5Ug5+O43Uftc4Mb6MUgzo+ZqEQ3Ob+cAV\n"
+ + "cvjmtwDaPO/O39O5Xq0tLTlkn2/cKf4OQ6S++GDxzyRVHh5JXgP4j9+jfZY57Woy\n"
+ + "R1bE7N50JjY4cDermBJKdlBIjL7UPhqmLyaG7V0hBitFlgGBUCcJtJOV0xYd5aF3\n"
+ + "pxNkvMXhBmh95fjxJ0cJjpO7tN1RAwtMMNgsl7OUbuVRQCHOPW5DgP5qY21jDeRn\n"
+ + "BY82382l+9QzykmJLI5MZnmj4BA9uIDCwMtoTTvP++SsvhUAbuvh7MOOUQL0EY4m\n"
+ + "KStYq7X9PKseN+PvmfeoffIKc5R/Ha39oi7cGMVHCr8aiEhsf94=\n"
+ + "-----END CERTIFICATE-----";
+
+ /*
+ This certificate is a modified version of the above self-signed cert. The cert has
+ been modified to change the certificate data's signature algorithm
+ declaration from sha256withRSAEncryption to sha512withRSAEncryption. This causes
+ the signature block's algorithm (which is unmodified) to not match the cert info.
+ */
+ private static final String MISMATCHED_ALGORITHM_CERT =
+ "-----BEGIN CERTIFICATE-----\n"
+ + "MIIFMjCCAxqgAwIBAgIJAL0mG5fOeJ7xMA0GCSqGSIb3DQEBDQUAMC0xCzAJBgNV\n"
+ + "BAYTAkdCMQ8wDQYDVQQHDAZMb25kb24xDTALBgNVBAoMBFRlc3QwIBcNMTgwOTE3\n"
+ + "MTIxNzU3WhgPMjExODA4MjQxMjE3NTdaMC0xCzAJBgNVBAYTAkdCMQ8wDQYDVQQH\n"
+ + "DAZMb25kb24xDTALBgNVBAoMBFRlc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\n"
+ + "ggIKAoICAQDCMhBrRAGGw+n2GdctBr/cEK4FZA6ajiHjihgpCHoSBdyL4R2jGKLS\n"
+ + "g0WgaMXa1HpkKN7LcIySosEBPlmcRkr1RqbEvQStOSvoFCXYvtx3alM6HTbXMcDR\n"
+ + "mqoKoABP6LXsPSoMWIgqMtP2X9EOppzHVIK1yFYFfbIlvYUV2Ka+MuMe0Vh5wvD1\n"
+ + "4GanPb+cWSKgdRSVQovCCMY3yWtZKVEaxRpCsk/mYYIFWz0tcgMjIKwDx1XXgiAV\n"
+ + "nU6NK43xbaw3XhtnaD/pv9lhTTbNrlcln9LjTD097BaK4R+1AEPHnpfxA9Ui3upn\n"
+ + "kbsNUdGdOB0ksZi/vd7lh833YgquQUIAhYrbfvq/HFCpVV1gljzlS3sqULYpLE//\n"
+ + "i3OsuL2mE+CYIJGpIi2GeJJWXciNMTJDOqTn+fRDtVb4RPp4Y70DJirp7XzaBi3q\n"
+ + "H0edANCzPSRCDbZsOhzIXhXshldiXVRX666DDlbMQgLTEnNKrkwv6DmU8o15XQsb\n"
+ + "8k1Os2YwXmkEOxUQ7AJZXVTZSf6UK9Znmdq1ZrHjybMfRUkHVxJcnKvrxfryralv\n"
+ + "gzfvu+D6HuxrCo3Ojqa+nDgIbxKEBtdrcsMhq1jWPFhjwo1fSadAkKOfdCAuXJRD\n"
+ + "THg3b4Sf+W7Cpc570YHrIpBf7WFl2XsPcEM0mJZ5+yATASCubNozQwIDAQABo1Mw\n"
+ + "UTAdBgNVHQ4EFgQUES0hupZSqY21JOba10QyZuxm91EwHwYDVR0jBBgwFoAUES0h\n"
+ + "upZSqY21JOba10QyZuxm91EwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsF\n"
+ + "AAOCAgEABTN5S30ng/RMpBweDm2N561PdpaCdiRXtAFCRVWR2mkDYC/Xj9Vqe6be\n"
+ + "PyM7L/5OKYVjzF1yJu67z/dx+ja5o+41g17jdqla7hyPx+9B4uRyDh+1KJTa+duj\n"
+ + "mw/aA1LCr6O6W4WizDOsChJ6FaB2Y1+GlFnKWb5nUdhVJqXQE1WOX9dZnw8Y4Npd\n"
+ + "VmAsjWot0BZorJrt3fwfcv3QfA896twkbo7Llv/8qzg4sXZXZ4ZtgAOqnPngiSn+\n"
+ + "JT/vYCXZ406VvAFpFqMcVz2dO/VGuL8lGIMHRKNyafrsV81EzH1W/XmRWOgvgj6r\n"
+ + "yQI63ln/AMY72HQ97xLkE1xKunGz6bK5Ug5+O43Uftc4Mb6MUgzo+ZqEQ3Ob+cAV\n"
+ + "cvjmtwDaPO/O39O5Xq0tLTlkn2/cKf4OQ6S++GDxzyRVHh5JXgP4j9+jfZY57Woy\n"
+ + "R1bE7N50JjY4cDermBJKdlBIjL7UPhqmLyaG7V0hBitFlgGBUCcJtJOV0xYd5aF3\n"
+ + "pxNkvMXhBmh95fjxJ0cJjpO7tN1RAwtMMNgsl7OUbuVRQCHOPW5DgP5qY21jDeRn\n"
+ + "BY82382l+9QzykmJLI5MZnmj4BA9uIDCwMtoTTvP++SsvhUAbuvh7MOOUQL0EY4m\n"
+ + "KStYq7X9PKseN+PvmfeoffIKc5R/Ha39oi7cGMVHCr8aiEhsf94=\n"
+ + "-----END CERTIFICATE-----\n";
+
+ /**
+ * This cert has an EC key with curve prime256v1 encoded using explicit params.
+ */
+ private static final String EC_EXPLICIT_KEY_CERT =
+ "-----BEGIN CERTIFICATE-----\n"
+ + "MIICAjCCAagCCQCrIzClvU58azAKBggqhkjOPQQDAjAPMQ0wCwYDVQQDDARUZXN0\n"
+ + "MB4XDTE4MTAwMjEyNDQzMloXDTE4MTEwMTEyNDQzMlowDzENMAsGA1UEAwwEVGVz\n"
+ + "dDCCAUswggEDBgcqhkjOPQIBMIH3AgEBMCwGByqGSM49AQECIQD/////AAAAAQAA\n"
+ + "AAAAAAAAAAAAAP///////////////zBbBCD/////AAAAAQAAAAAAAAAAAAAAAP//\n"
+ + "/////////////AQgWsY12Ko6k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsDFQDE\n"
+ + "nTYIhucEk2pmeOETnSa3gZ9+kARBBGsX0fLhLEJH+Lzm5WOkQPJ3A32BLeszoPSh\n"
+ + "OUXYmMKWT+NC4v4af5uO5+tKfA+eFivOM1drMV7Oy7ZAaDe/UfUCIQD/////AAAA\n"
+ + "AP//////////vOb6racXnoTzucrC/GMlUQIBAQNCAAQXU+GFdLabcY/RvzoNjLhC\n"
+ + "6uN1Yt1baN2NYyKYEhwR9nb8nLa/m7f30OOi/8OrxQhnUl5qW0I0IbHflGnsqQ6s\n"
+ + "MAoGCCqGSM49BAMCA0gAMEUCIQDRXoZwmnsIJfg4mTemkM+heMS1iXRYUO0Dar5u\n"
+ + "Qhy0YgIgYWr0qSCLqxUQv3oQHMUpSmfHtP0Pwvb3DbbH6lY7TkI=\n"
+ + "-----END CERTIFICATE-----\n";
+
+ /**
+ * This cert is signed with OID 1.2.840.113554.4.1.72585.2 instead of a
+ * standard one.
+ */
+ private static final String UNKNOWN_SIGNATURE_OID = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIB2TCCAXugAwIBAgIJANlMBNpJfb/rMA4GDCqGSIb3EgQBhLcJAjBFMQswCQYD\n"
+ + "VQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQg\n"
+ + "V2lkZ2l0cyBQdHkgTHRkMB4XDTE0MDQyMzIzMjE1N1oXDTE0MDUyMzIzMjE1N1ow\n"
+ + "RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu\n"
+ + "dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA\n"
+ + "BOYraeK/ZZ+Xvi8eDZSKTNWXa7epHg1G+92pqR6d3LpaAefWl6gKGPnDxKMeVuJ8\n"
+ + "g0jbFhoc9R1+8ZQtS89yIsGjUDBOMB0GA1UdDgQWBBSrhNKsq5Xwgk4WeAdVV1/k\n"
+ + "Jo2C0TAfBgNVHSMEGDAWgBSrhNKsq5Xwgk4WeAdVV1/kJo2C0TAMBgNVHRMEBTAD\n"
+ + "AQH/MA4GDCqGSIb3EgQBhLcJAgNIADBFAiEA8qA1XlE6NsOCeZvuJ1CFjnAGdJVX\n"
+ + "0il0APS+FYddxAcCIHweeRRqIYPwenRoeV8UmZpotPHLnhVe5h8yUmFedckU\n"
+ + "-----END CERTIFICATE-----\n";
+
+ /**
+ * This cert is signed using MD5, which is no longer supported by BoringSSL.
+ */
+ private static final String MD5_SIGNATURE = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx\n"
+ + "FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD\n"
+ + "VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv\n"
+ + "biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy\n"
+ + "dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t\n"
+ + "MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB\n"
+ + "MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG\n"
+ + "A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp\n"
+ + "b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl\n"
+ + "cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv\n"
+ + "bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE\n"
+ + "VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ\n"
+ + "ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR\n"
+ + "uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG\n"
+ + "9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI\n"
+ + "hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM\n"
+ + "pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==\n"
+ + "-----END CERTIFICATE-----";
+
+ /**
+ * This is an X.509v1 certificatea, so most fields are missing. It exists to test accessors
+ * correctly handle the lack of fields. It was constructed by hand, so the signature itself is
+ * invalid.
+ */
+ private static final String X509V1_CERT = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIBGjCBwgIJANlMBNpJfb/rMAkGByqGSM49BAEwFjEUMBIGA1UEAwwLVGVzdCBJ\n"
+ + "c3N1ZXIwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3WjAXMRUwEwYDVQQD\n"
+ + "DAxUZXN0IFN1YmplY3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATmK2niv2Wf\n"
+ + "l74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8SjHlbifINI2xYaHPUd\n"
+ + "fvGULUvPciLBMAkGByqGSM49BAEDSAAwRQIhAPKgNV5ROjbDgnmb7idQhY5wBnSV\n"
+ + "V9IpdAD0vhWHXcQHAiB8HnkUaiGD8Hp0aHlfFJmaaLTxy54VXuYfMlJhXnXJFA==\n"
+ + "-----END CERTIFICATE-----\n";
+
+ /**
+ * This is a certificate with many extensions filled it. It exists to test accessors correctly
+ * report fields. It was constructed by hand, so the signature itself is invalid. Add more
+ * fields as necessary with https://github.com/google/der-ascii.
+ */
+ private static final String MANY_EXTENSIONS = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIEADCCAuigAwIBAgIJALW2IrlaBKUhMA0GCSqGSIb3DQEBCwUAMBYxFDASBgNV\n"
+ + "BAMMC1Rlc3QgSXNzdWVyMB4XDTE2MDcwOTA0MzgwOVoXDTE2MDgwODA0MzgwOVow\n"
+ + "FzEVMBMGA1UEAwwMVGVzdCBTdWJqZWN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n"
+ + "MIIBCgKCAQEAugvahBkSAUF1fC49vb1bvlPrcl80kop1iLpiuYoz4Qptwy57+EWs\n"
+ + "sZBcHprZ5BkWf6PeGZ7F5AX1PyJbGHZLqvMCvViP6pd4MFox/igESISEHEixoiXC\n"
+ + "zepBrhtp5UQSjHD4D4hKtgdMgVxX+LRtwgW3mnu/vBu7rzpr/DS8io99p3lqZ1Ak\n"
+ + "y+aNlcMj6MYy8U+YFEevb/V0lRY9oqwmW7BHnXikm/vi6sjIS350U8zb/mRzYeIs\n"
+ + "2R65LUduTL50+UMgat9ocewI2dv8aO9Dph+8NdGtg8LFYyTTHcUxJoMr1PTOgnmE\n"
+ + "T19WJH4PrFwk7ZE1QJQQ1L4iKmPeQistuQIDAQABgQIEoIICA1CjggFGMIIBQjAP\n"
+ + "BgNVHRMECDAGAQH/AgEKMCEGA1UdJQQaMBgGCCsGAQUFBwMBBgwqhkiG9xIEAYS3\n"
+ + "CQIwfwYDVR0RBHgwdoETc3ViamVjdEBleGFtcGxlLmNvbYITc3ViamVjdC5leGFt\n"
+ + "cGxlLmNvbaQZMBcxFTATBgNVBAMMDFRlc3QgU3ViamVjdIYbaHR0cHM6Ly9leGFt\n"
+ + "cGxlLmNvbS9zdWJqZWN0hwR/AAABiAwqhkiG9xIEAYS3CQIwewYDVR0SBHQwcoES\n"
+ + "aXNzdWVyQGV4YW1wbGUuY29tghJpc3N1ZXIuZXhhbXBsZS5jb22kGDAWMRQwEgYD\n"
+ + "VQQDDAtUZXN0IElzc3VlcoYaaHR0cHM6Ly9leGFtcGxlLmNvbS9pc3N1ZXKHBH8A\n"
+ + "AAGIDCqGSIb3EgQBhLcJAjAOBgNVHQ8BAf8EBAMCBaAwDQYJKoZIhvcNAQELBQAD\n"
+ + "ggEBAD7Jg68SArYWlcoHfZAB90Pmyrt5H6D8LRi+W2Ri1fBNxREELnezWJ2scjl4\n"
+ + "UMcsKYp4Pi950gVN+62IgrImcCNvtb5I1Cfy/MNNur9ffas6X334D0hYVIQTePyF\n"
+ + "k3umI+2mJQrtZZyMPIKSY/sYGQHhGGX6wGK+GO/og0PQk/Vu6D+GU2XRnDV0YZg1\n"
+ + "lsAsHd21XryK6fDmNkEMwbIWrts4xc7scRrGHWy+iMf6/7p/Ak/SIicM4XSwmlQ8\n"
+ + "pPxAZPr+E2LoVd9pMpWUwpW2UbtO5wsGTrY5sO45tFNN/y+jtUheB1C2ijObG/tX\n"
+ + "ELaiyCdM+S/waeuv0MXtI4xnn1A=\n"
+ + "-----END CERTIFICATE-----\n";
+
+ /**
+ * This is a certificate whose basicConstraints extension marks it as a CA, with no pathlen
+ * constraint.
+ */
+ private static final String BASIC_CONSTRAINTS_NO_PATHLEN = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIBMzCB2qADAgECAgkA2UwE2kl9v+swCgYIKoZIzj0EAwIwFjEUMBIGA1UEAwwL\n"
+ + "VGVzdCBJc3N1ZXIwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3WjAXMRUw\n"
+ + "EwYDVQQDDAxUZXN0IFN1YmplY3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATm\n"
+ + "K2niv2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8SjHlbifINI\n"
+ + "2xYaHPUdfvGULUvPciLBoxAwDjAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0gA\n"
+ + "MEUCIQDyoDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13EBwIgfB55FGohg/B6\n"
+ + "dGh5XxSZmmi08cueFV7mHzJSYV51yRQ=\n"
+ + "-----END CERTIFICATE-----\n";
+
+ /**
+ * This is a certificate whose basicConstraints extension marks it as a CA with a pathlen
+ * constraint of zero.
+ */
+ private static final String BASIC_CONSTRAINTS_PATHLEN_0 = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIBNjCB3aADAgECAgkA2UwE2kl9v+swCgYIKoZIzj0EAwIwFjEUMBIGA1UEAwwL\n"
+ + "VGVzdCBJc3N1ZXIwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3WjAXMRUw\n"
+ + "EwYDVQQDDAxUZXN0IFN1YmplY3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATm\n"
+ + "K2niv2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8SjHlbifINI\n"
+ + "2xYaHPUdfvGULUvPciLBoxMwETAPBgNVHRMECDAGAQH/AgEAMAoGCCqGSM49BAMC\n"
+ + "A0gAMEUCIQDyoDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13EBwIgfB55FGoh\n"
+ + "g/B6dGh5XxSZmmi08cueFV7mHzJSYV51yRQ=\n"
+ + "-----END CERTIFICATE-----\n";
+
+ /**
+ * This is a certificate whose basicConstraints extension marks it as a leaf certificate.
+ */
+ private static final String BASIC_CONSTRAINTS_LEAF = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIBMDCB16ADAgECAgkA2UwE2kl9v+swCgYIKoZIzj0EAwIwFjEUMBIGA1UEAwwL\n"
+ + "VGVzdCBJc3N1ZXIwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3WjAXMRUw\n"
+ + "EwYDVQQDDAxUZXN0IFN1YmplY3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATm\n"
+ + "K2niv2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8SjHlbifINI\n"
+ + "2xYaHPUdfvGULUvPciLBow0wCzAJBgNVHRMEAjAAMAoGCCqGSM49BAMCA0gAMEUC\n"
+ + "IQDyoDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13EBwIgfB55FGohg/B6dGh5\n"
+ + "XxSZmmi08cueFV7mHzJSYV51yRQ=\n"
+ + "-----END CERTIFICATE-----\n";
+
+ /**
+ * This is a certificate with a pathlen constraint of 10, but there is an unrelated invalid
+ * subjectAltNames extension.
+ */
+ private static final String BASIC_CONSTRAINTS_PATHLEN_10_BAD_SAN =
+ "-----BEGIN CERTIFICATE-----\n"
+ + "MIIBRjCB7aADAgECAgkA2UwE2kl9v+swCgYIKoZIzj0EAwIwFjEUMBIGA1UEAwwL\n"
+ + "VGVzdCBJc3N1ZXIwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3WjAXMRUw\n"
+ + "EwYDVQQDDAxUZXN0IFN1YmplY3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATm\n"
+ + "K2niv2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8SjHlbifINI\n"
+ + "2xYaHPUdfvGULUvPciLBoyMwITAPBgNVHRMECDAGAQH/AgEKMA4GA1UdEQQHSU5W\n"
+ + "QUxJRDAKBggqhkjOPQQDAgNIADBFAiEA8qA1XlE6NsOCeZvuJ1CFjnAGdJVX0il0\n"
+ + "APS+FYddxAcCIHweeRRqIYPwenRoeV8UmZpotPHLnhVe5h8yUmFedckU\n"
+ + "-----END CERTIFICATE-----\n";
+
+ /**
+ * This is a certificate whose keyUsage extension has more than nine bits. The getKeyUsage()
+ * method internally rounds up to nine bits, so this tests what happens when it does not need to
+ * round.
+ */
+ private static final String LARGE_KEY_USAGE = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIBNjCB3aADAgECAgkA2UwE2kl9v+swCgYIKoZIzj0EAwIwFjEUMBIGA1UEAwwL\n"
+ + "VGVzdCBJc3N1ZXIwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3WjAXMRUw\n"
+ + "EwYDVQQDDAxUZXN0IFN1YmplY3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATm\n"
+ + "K2niv2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8SjHlbifINI\n"
+ + "2xYaHPUdfvGULUvPciLBoxMwETAPBgNVHQ8BAf8EBQMDBaAAMAoGCCqGSM49BAMC\n"
+ + "A0gAMEUCIQDyoDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13EBwIgfB55FGoh\n"
+ + "g/B6dGh5XxSZmmi08cueFV7mHzJSYV51yRQ=\n"
+ + "-----END CERTIFICATE-----\n";
+
+ /*
+ * OpenSSLX509Certificate needs to compensate for OpenSSL's AlgorithmIdentifier representation
+ * by re-encoding the parameter field. Test this behaves correctly against a variety of
+ * different parameter types.
+ */
+ private static final String SIGALG_NO_PARAMETER = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIBKTCBzKADAgECAgkA2UwE2kl9v+swDgYMKoZIhvcSBAGEtwkCMBYxFDASBgNV\n"
+ + "BAMMC1Rlc3QgSXNzdWVyMB4XDTE0MDQyMzIzMjE1N1oXDTE0MDUyMzIzMjE1N1ow\n"
+ + "FzEVMBMGA1UEAwwMVGVzdCBTdWJqZWN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\n"
+ + "QgAE5itp4r9ln5e+Lx4NlIpM1Zdrt6keDUb73ampHp3culoB59aXqAoY+cPEox5W\n"
+ + "4nyDSNsWGhz1HX7xlC1Lz3IiwTAOBgwqhkiG9xIEAYS3CQIDSAAwRQIhAPKgNV5R\n"
+ + "OjbDgnmb7idQhY5wBnSVV9IpdAD0vhWHXcQHAiB8HnkUaiGD8Hp0aHlfFJmaaLTx\n"
+ + "y54VXuYfMlJhXnXJFA==\n"
+ + "-----END CERTIFICATE-----\n";
+ private static final String SIGALG_NULL_PARAMETER = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIBLTCBzqADAgECAgkA2UwE2kl9v+swEAYMKoZIhvcSBAGEtwkCBQAwFjEUMBIG\n"
+ + "A1UEAwwLVGVzdCBJc3N1ZXIwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3\n"
+ + "WjAXMRUwEwYDVQQDDAxUZXN0IFN1YmplY3QwWTATBgcqhkjOPQIBBggqhkjOPQMB\n"
+ + "BwNCAATmK2niv2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8Sj\n"
+ + "HlbifINI2xYaHPUdfvGULUvPciLBMBAGDCqGSIb3EgQBhLcJAgUAA0gAMEUCIQDy\n"
+ + "oDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13EBwIgfB55FGohg/B6dGh5XxSZ\n"
+ + "mmi08cueFV7mHzJSYV51yRQ=\n"
+ + "-----END CERTIFICATE-----\n";
+ private static final String SIGALG_STRING_PARAMETER = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIBNzCB06ADAgECAgkA2UwE2kl9v+swFQYMKoZIhvcSBAGEtwkCDAVwYXJhbTAW\n"
+ + "MRQwEgYDVQQDDAtUZXN0IElzc3VlcjAeFw0xNDA0MjMyMzIxNTdaFw0xNDA1MjMy\n"
+ + "MzIxNTdaMBcxFTATBgNVBAMMDFRlc3QgU3ViamVjdDBZMBMGByqGSM49AgEGCCqG\n"
+ + "SM49AwEHA0IABOYraeK/ZZ+Xvi8eDZSKTNWXa7epHg1G+92pqR6d3LpaAefWl6gK\n"
+ + "GPnDxKMeVuJ8g0jbFhoc9R1+8ZQtS89yIsEwFQYMKoZIhvcSBAGEtwkCDAVwYXJh\n"
+ + "bQNIADBFAiEA8qA1XlE6NsOCeZvuJ1CFjnAGdJVX0il0APS+FYddxAcCIHweeRRq\n"
+ + "IYPwenRoeV8UmZpotPHLnhVe5h8yUmFedckU\n"
+ + "-----END CERTIFICATE-----\n";
+ private static final String SIGALG_BOOLEAN_PARAMETER = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIBLzCBz6ADAgECAgkA2UwE2kl9v+swEQYMKoZIhvcSBAGEtwkCAQH/MBYxFDAS\n"
+ + "BgNVBAMMC1Rlc3QgSXNzdWVyMB4XDTE0MDQyMzIzMjE1N1oXDTE0MDUyMzIzMjE1\n"
+ + "N1owFzEVMBMGA1UEAwwMVGVzdCBTdWJqZWN0MFkwEwYHKoZIzj0CAQYIKoZIzj0D\n"
+ + "AQcDQgAE5itp4r9ln5e+Lx4NlIpM1Zdrt6keDUb73ampHp3culoB59aXqAoY+cPE\n"
+ + "ox5W4nyDSNsWGhz1HX7xlC1Lz3IiwTARBgwqhkiG9xIEAYS3CQIBAf8DSAAwRQIh\n"
+ + "APKgNV5ROjbDgnmb7idQhY5wBnSVV9IpdAD0vhWHXcQHAiB8HnkUaiGD8Hp0aHlf\n"
+ + "FJmaaLTxy54VXuYfMlJhXnXJFA==\n"
+ + "-----END CERTIFICATE-----\n";
+ private static final String SIGALG_SEQUENCE_PARAMETER = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIBLTCBzqADAgECAgkA2UwE2kl9v+swEAYMKoZIhvcSBAGEtwkCMAAwFjEUMBIG\n"
+ + "A1UEAwwLVGVzdCBJc3N1ZXIwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3\n"
+ + "WjAXMRUwEwYDVQQDDAxUZXN0IFN1YmplY3QwWTATBgcqhkjOPQIBBggqhkjOPQMB\n"
+ + "BwNCAATmK2niv2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8Sj\n"
+ + "HlbifINI2xYaHPUdfvGULUvPciLBMBAGDCqGSIb3EgQBhLcJAjAAA0gAMEUCIQDy\n"
+ + "oDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13EBwIgfB55FGohg/B6dGh5XxSZ\n"
+ + "mmi08cueFV7mHzJSYV51yRQ=\n"
+ + "-----END CERTIFICATE-----\n";
+
+ private static Date dateFromUTC(int year, int month, int day, int hour, int minute, int second)
+ throws Exception {
+ Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ c.set(year, month, day, hour, minute, second);
+ c.set(Calendar.MILLISECOND, 0);
+ return c.getTime();
+ }
+
+ private static X509Certificate certificateFromPEM(Provider p, String pem)
+ throws CertificateException {
+ CertificateFactory cf = CertificateFactory.getInstance("X509", p);
+ return (X509Certificate) cf.generateCertificate(
+ new ByteArrayInputStream(pem.getBytes(Charset.forName("US-ASCII"))));
+ }
+
+ private static List<Pair<Integer, String>> normalizeGeneralNames(Collection<List<?>> names) {
+ // Extract a more convenient type than Java's Collection<List<?>>.
+ List<Pair<Integer, String>> result = new ArrayList<Pair<Integer, String>>();
+ for (List<?> tuple : names) {
+ assertEquals(2, tuple.size());
+ int type = ((Integer) tuple.get(0)).intValue();
+ // TODO(davidben): Most name types are expected to have a String value, but some use
+ // byte[]. Update this logic when testing those name types. See
+ // X509Certificate.getSubjectAlternativeNames().
+ String value = (String) tuple.get(1);
+ result.add(Pair.of(type, value));
+ }
+ // Although there is a natural order (the order in the certificate), Java's API returns a
+ // Collection, so there is no guarantee of the provider using a particular order. Normalize
+ // the order before comparing.
+ Collections.sort(result, new Comparator<Pair<Integer, String>>() {
+ @Override
+ public int compare(Pair<Integer, String> a, Pair<Integer, String> b) {
+ int cmp = a.getFirst().compareTo(b.getFirst());
+ if (cmp != 0) {
+ return cmp;
+ }
+ return a.getSecond().compareTo(b.getSecond());
+ }
+ });
+ return result;
+ }
+
+ private static void assertGeneralNamesEqual(
+ Collection<List<?>> expected, Collection<List<?>> actual) throws Exception {
+ assertEquals(normalizeGeneralNames(expected), normalizeGeneralNames(actual));
+ }
+
+ // Error Prone flags Date.equals(), but Instant and LocalDateTime are not available in Java 7.
+ // We could compare Date.getTime(), but this trips another warning in Error Prone. We do not use
+ // Date subclasses, so stick with Date.equals for now.
+ //
+ // https://errorprone.info/bugpattern/UndefinedEquals
+ @SuppressWarnings("UndefinedEquals")
+ private static void assertDatesEqual(Date expected, Date actual) throws Exception {
+ assertEquals(expected, actual);
+ }
+
+ // See issue #539.
+ @Test
+ public void testMismatchedAlgorithm() throws Exception {
+ ServiceTester.test("CertificateFactory")
+ .withAlgorithm("X509")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ try {
+ X509Certificate c = certificateFromPEM(p, MISMATCHED_ALGORITHM_CERT);
+ c.verify(c.getPublicKey());
+ fail();
+ } catch (CertificateException expected) {
+ }
+ }
+ });
+ }
+
+ /**
+ * Confirm that explicit EC params aren't accepted in certificates.
+ */
+ @Test
+ public void testExplicitEcParams() throws Exception {
+ ServiceTester.test("CertificateFactory")
+ .withAlgorithm("X509")
+ // Bouncy Castle allows explicit EC params in certificates, even though they're
+ // barred by RFC 5480
+ .skipProvider("BC")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ try {
+ X509Certificate c = certificateFromPEM(p, EC_EXPLICIT_KEY_CERT);
+ c.verify(c.getPublicKey());
+ fail();
+ } catch (InvalidKeyException expected) {
+ // TODO: Should we throw CertificateParsingException at parse time
+ // instead of waiting for when the user accesses the key?
+ } catch (CertificateParsingException expected) {
+ }
+ }
+ });
+ }
+
+ @Test
+ public void testSigAlgName() throws Exception {
+ ServiceTester.test("CertificateFactory")
+ .withAlgorithm("X509")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ X509Certificate c = certificateFromPEM(p, VALID_CERT);
+ assertEquals("SHA256WITHRSA", c.getSigAlgName().toUpperCase());
+ c.verify(c.getPublicKey());
+ }
+ });
+ }
+
+ @Test
+ public void testUnknownSigAlgOID() throws Exception {
+ ServiceTester.test("CertificateFactory")
+ .withAlgorithm("X509")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ X509Certificate c = certificateFromPEM(p, UNKNOWN_SIGNATURE_OID);
+ assertEquals("1.2.840.113554.4.1.72585.2", c.getSigAlgOID());
+ assertThrows(
+ NoSuchAlgorithmException.class, () -> c.verify(c.getPublicKey()));
+ }
+ });
+ }
+
+ // MD5 signed certificates no longer supported by BoringSSL but still supported by OpenJDK 8
+ // and by BC where present (up until Android 12)
+ @Test
+ public void unsupportedDigestType() {
+ ServiceTester.test("CertificateFactory")
+ .withAlgorithm("X509")
+ .skipProvider("SUN")
+ .skipProvider("BC")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ X509Certificate c = certificateFromPEM(p, MD5_SIGNATURE);
+ assertThrows(
+ NoSuchAlgorithmException.class, () -> c.verify(c.getPublicKey()));
+ }
+ });
+ }
+
+ @Test
+ public void invalidSignature() {
+ // Mutate the signature of VALID_CERT slightly
+ int index = VALID_CERT.lastIndexOf('9');
+ assertTrue(index > 0);
+ String invalidCert = VALID_CERT.substring(0, index) + "8" + VALID_CERT.substring(index + 1);
+ ServiceTester.test("CertificateFactory")
+ .withAlgorithm("X509")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ X509Certificate c = certificateFromPEM(p, invalidCert);
+ assertThrows(SignatureException.class, () -> c.verify(c.getPublicKey()));
+ }
+ });
+ }
+
+ @Test
+ public void testV1Cert() throws Exception {
+ ServiceTester tester = ServiceTester.test("CertificateFactory").withAlgorithm("X509");
+ tester.run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ X509Certificate c = certificateFromPEM(p, X509V1_CERT);
+
+ // Check basic certificate properties.
+ assertEquals(1, c.getVersion());
+ assertEquals(new BigInteger("d94c04da497dbfeb", 16), c.getSerialNumber());
+ assertDatesEqual(
+ dateFromUTC(2014, Calendar.APRIL, 23, 23, 21, 57), c.getNotBefore());
+ assertDatesEqual(dateFromUTC(2014, Calendar.MAY, 23, 23, 21, 57), c.getNotAfter());
+ assertEquals(new X500Principal("CN=Test Issuer"), c.getIssuerX500Principal());
+ assertEquals(new X500Principal("CN=Test Subject"), c.getSubjectX500Principal());
+ assertEquals("1.2.840.10045.4.1", c.getSigAlgOID());
+ String signatureHex = "3045022100f2a0355e513a36c382799bee27"
+ + "50858e7006749557d2297400f4be15875dc4"
+ + "0702207c1e79146a2183f07a7468795f1499"
+ + "9a68b4f1cb9e155ee61f3252615e75c914";
+ assertArrayEquals(TestUtils.decodeHex(signatureHex), c.getSignature());
+
+ // ECDSA signature AlgorithmIdentifiers omit parameters.
+ assertNull(c.getSigAlgParams());
+
+ // The certificate does not have UIDs.
+ assertNull(c.getIssuerUniqueID());
+ assertNull(c.getSubjectUniqueID());
+
+ // The certificate does not have any extensions.
+ assertEquals(-1, c.getBasicConstraints());
+ assertNull(c.getExtendedKeyUsage());
+ assertNull(c.getIssuerAlternativeNames());
+ assertNull(c.getKeyUsage());
+ assertNull(c.getSubjectAlternativeNames());
+ }
+ });
+ }
+
+ @Test
+ public void testManyExtensions() throws Exception {
+ ServiceTester tester = ServiceTester.test("CertificateFactory").withAlgorithm("X509");
+ tester.run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ X509Certificate c = certificateFromPEM(p, MANY_EXTENSIONS);
+
+ assertEquals(3, c.getVersion());
+ assertEquals(new BigInteger("b5b622b95a04a521", 16), c.getSerialNumber());
+ assertDatesEqual(dateFromUTC(2016, Calendar.JULY, 9, 4, 38, 9), c.getNotBefore());
+ assertDatesEqual(dateFromUTC(2016, Calendar.AUGUST, 8, 4, 38, 9), c.getNotAfter());
+ assertEquals(new X500Principal("CN=Test Issuer"), c.getIssuerX500Principal());
+ assertEquals(new X500Principal("CN=Test Subject"), c.getSubjectX500Principal());
+ assertEquals("1.2.840.113549.1.1.11", c.getSigAlgOID());
+ String signatureHex = "3ec983af1202b61695ca077d9001f743e6ca"
+ + "bb791fa0fc2d18be5b6462d5f04dc511042e"
+ + "77b3589dac72397850c72c298a783e2f79d2"
+ + "054dfbad8882b22670236fb5be48d427f2fc"
+ + "c34dbabf5f7dab3a5f7df80f485854841378"
+ + "fc85937ba623eda6250aed659c8c3c829263"
+ + "fb181901e11865fac062be18efe88343d093"
+ + "f56ee83f865365d19c357461983596c02c1d"
+ + "ddb55ebc8ae9f0e636410cc1b216aedb38c5"
+ + "ceec711ac61d6cbe88c7faffba7f024fd222"
+ + "270ce174b09a543ca4fc4064fafe1362e855"
+ + "df69329594c295b651bb4ee70b064eb639b0"
+ + "ee39b4534dff2fa3b5485e0750b68a339b1b"
+ + "fb5710b6a2c8274cf92ff069ebafd0c5ed23"
+ + "8c679f50";
+ assertArrayEquals(TestUtils.decodeHex(signatureHex), c.getSignature());
+
+ // Although documented to only return null when there are no parameters, the SUN
+ // provider also returns null when the algorithm uses an explicit parameter with a
+ // value of ASN.1 NULL.
+ if (c.getSigAlgParams() != null) {
+ assertArrayEquals(TestUtils.decodeHex("0500"), c.getSigAlgParams());
+ }
+
+ assertArrayEquals(new boolean[] {true, false, true, false}, c.getIssuerUniqueID());
+ assertArrayEquals(
+ new boolean[] {false, true, false, true, false}, c.getSubjectUniqueID());
+ assertEquals(10, c.getBasicConstraints());
+ assertEquals(Arrays.asList("1.3.6.1.5.5.7.3.1", "1.2.840.113554.4.1.72585.2"),
+ c.getExtendedKeyUsage());
+
+ // TODO(davidben): Test the other name types.
+ assertGeneralNamesEqual(
+ Arrays.<List<?>>asList(Arrays.asList(1, "issuer@example.com"),
+ Arrays.asList(2, "issuer.example.com"),
+ Arrays.asList(4, "CN=Test Issuer"),
+ Arrays.asList(6, "https://example.com/issuer"),
+ // TODO(https://github.com/google/conscrypt/issues/938): Fix IPv6
+ // handling and include it in this test.
+ Arrays.asList(7, "127.0.0.1"),
+ Arrays.asList(8, "1.2.840.113554.4.1.72585.2")),
+ c.getIssuerAlternativeNames());
+ assertGeneralNamesEqual(
+ Arrays.<List<?>>asList(Arrays.asList(1, "subject@example.com"),
+ Arrays.asList(2, "subject.example.com"),
+ Arrays.asList(4, "CN=Test Subject"),
+ Arrays.asList(6, "https://example.com/subject"),
+ // TODO(https://github.com/google/conscrypt/issues/938): Fix IPv6
+ // handling and include it in this test.
+ Arrays.asList(7, "127.0.0.1"),
+ Arrays.asList(8, "1.2.840.113554.4.1.72585.2")),
+ c.getSubjectAlternativeNames());
+
+ // Although the BIT STRING in the certificate only has three bits, getKeyUsage()
+ // rounds up to at least 9 bits.
+ assertArrayEquals(
+ new boolean[] {true, false, true, false, false, false, false, false, false},
+ c.getKeyUsage());
+ }
+ });
+ }
+
+ @Test
+ public void testBasicConstraints() throws Exception {
+ ServiceTester tester = ServiceTester.test("CertificateFactory").withAlgorithm("X509");
+ tester.run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ // Test some additional edge cases in getBasicConstraints() beyond that
+ // testManyExtensions() and testV1Cert() covered.
+
+ // If there is no pathLen constraint but the certificate is a CA,
+ // getBasicConstraints() returns Integer.MAX_VALUE.
+ X509Certificate c = certificateFromPEM(p, BASIC_CONSTRAINTS_NO_PATHLEN);
+ assertEquals(Integer.MAX_VALUE, c.getBasicConstraints());
+
+ // If there is a pathLen constraint of zero, getBasicConstraints() returns it.
+ c = certificateFromPEM(p, BASIC_CONSTRAINTS_PATHLEN_0);
+ assertEquals(0, c.getBasicConstraints());
+
+ // If there is basicConstraints extension indicating a leaf certficate,
+ // getBasicConstraints() returns -1. The accessor does not distinguish between no
+ // basicConstraints extension and a leaf one.
+ c = certificateFromPEM(p, BASIC_CONSTRAINTS_LEAF);
+ assertEquals(-1, c.getBasicConstraints());
+
+ // If some unrelated extension has a syntax error, and that syntax error does not
+ // fail when constructing the certificate, it should not interfere with
+ // getBasicConstraints().
+ try {
+ c = certificateFromPEM(p, BASIC_CONSTRAINTS_PATHLEN_10_BAD_SAN);
+ } catch (CertificateParsingException e) {
+ // The certificate has a syntax error, so it would also be valid for the
+ // provider to reject the certificate at construction. X.509 is an extensible
+ // format, so different implementations may notice errors at different points.
+ c = null;
+ }
+ if (c != null) {
+ assertEquals(10, c.getBasicConstraints());
+ }
+ }
+ });
+ }
+
+ @Test
+ public void testLargeKeyUsage() throws Exception {
+ ServiceTester tester = ServiceTester.test("CertificateFactory").withAlgorithm("X509");
+ tester.run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ X509Certificate c = certificateFromPEM(p, LARGE_KEY_USAGE);
+ assertArrayEquals(new boolean[] {true, false, true, false, false, false, false,
+ false, false, false, false},
+ c.getKeyUsage());
+ }
+ });
+ }
+
+ @Test
+ public void testSigAlgParams() throws Exception {
+ ServiceTester tester = ServiceTester.test("CertificateFactory").withAlgorithm("X509");
+ tester.run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ X509Certificate c = certificateFromPEM(p, SIGALG_NO_PARAMETER);
+ assertNull(c.getSigAlgParams());
+
+ c = certificateFromPEM(p, SIGALG_NULL_PARAMETER);
+ // Although documented to only return null when there are no parameters, the SUN
+ // provider also returns null when the algorithm uses an explicit parameter with a
+ // value of ASN.1 NULL.
+ if (c.getSigAlgParams() != null) {
+ assertArrayEquals(TestUtils.decodeHex("0500"), c.getSigAlgParams());
+ }
+
+ c = certificateFromPEM(p, SIGALG_STRING_PARAMETER);
+ assertArrayEquals(TestUtils.decodeHex("0c05706172616d"), c.getSigAlgParams());
+
+ c = certificateFromPEM(p, SIGALG_BOOLEAN_PARAMETER);
+ assertArrayEquals(TestUtils.decodeHex("0101ff"), c.getSigAlgParams());
+
+ c = certificateFromPEM(p, SIGALG_SEQUENCE_PARAMETER);
+ assertArrayEquals(TestUtils.decodeHex("3000"), c.getSigAlgParams());
+ }
+ });
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/crypto/AeadCipherTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/crypto/AeadCipherTest.java
new file mode 100644
index 0000000..fd70f86
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/crypto/AeadCipherTest.java
@@ -0,0 +1,330 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt.javax.crypto;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Arrays;
+import javax.crypto.Cipher;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import com.android.org.conscrypt.TestUtils;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(Parameterized.class)
+public class AeadCipherTest {
+
+ @BeforeClass
+ public static void setUp() {
+ TestUtils.assumeAllowsUnsignedCrypto();
+ }
+
+ @Parameterized.Parameters(name = "{0}")
+ public static Iterable<String> ciphers() {
+ return Arrays.asList(
+ "AES/GCM/NoPadding",
+ "AES/GCM-SIV/NoPadding",
+ "ChaCha20/Poly1305/NoPadding");
+ }
+
+ private final String cipher;
+ private byte counter;
+
+ public AeadCipherTest(String cipher) {
+ this.cipher = cipher;
+ }
+
+ private Key newKey() {
+ if (cipher.startsWith("AES/")) {
+ byte[] keyData = new byte[16];
+ keyData[0] = counter++;
+ return new SecretKeySpec(keyData, "AES");
+ } else if (cipher.startsWith("ChaCha20/")) {
+ byte[] keyData = new byte[32];
+ keyData[0] = counter++;
+ return new SecretKeySpec(keyData, "ChaCha20");
+ } else {
+ throw new IllegalStateException("Couldn't generate key for " + cipher);
+ }
+ }
+
+ private AlgorithmParameterSpec newParamSpec() {
+ if (cipher.startsWith("AES/GCM")) {
+ byte[] nonce = new byte[12];
+ nonce[0] = counter++;
+ return new GCMParameterSpec(128, nonce);
+ } else if (cipher.startsWith("ChaCha20/")) {
+ byte[] nonce = new byte[12];
+ nonce[0] = counter++;
+ return new IvParameterSpec(nonce);
+ } else {
+ throw new IllegalStateException("Couldn't generate algorithm parameter spec for " + cipher);
+ }
+ }
+
+ @Test
+ public void testUpdateAAD_AfterInit() throws Exception {
+ Cipher c = Cipher.getInstance(cipher);
+ c.init(Cipher.ENCRYPT_MODE, newKey());
+ c.updateAAD(new byte[8]);
+ c.updateAAD(ByteBuffer.wrap(new byte[8]));
+ }
+
+ @Test
+ public void testUpdateAAD_AfterUpdate() throws Exception {
+ Cipher c = Cipher.getInstance(cipher);
+ c.init(Cipher.ENCRYPT_MODE, newKey());
+ c.updateAAD(new byte[8]);
+ c.update(new byte[8]);
+ c.updateAAD(ByteBuffer.wrap(new byte[8]));
+ }
+
+ /*
+ * Check that two AAD updates are equivalent to one.
+ * http://b/27371173
+ */
+ @Test
+ public void testUpdateAAD_Twice() throws Exception {
+ Key key = newKey();
+ AlgorithmParameterSpec spec = newParamSpec();
+ Cipher c1 = Cipher.getInstance(cipher);
+ Cipher c2 = Cipher.getInstance(cipher);
+
+ c1.init(Cipher.ENCRYPT_MODE, key, spec);
+ c1.updateAAD(new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ });
+ c1.updateAAD(new byte[] {
+ 0x06, 0x07, 0x08, 0x09, 0x10,
+ });
+
+ c2.init(Cipher.ENCRYPT_MODE, key, spec);
+ c2.updateAAD(new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x10,
+ });
+
+ assertEquals(Arrays.toString(c1.doFinal()), Arrays.toString(c2.doFinal()));
+ }
+
+ @Test
+ public void testUpdateAAD_ByteBuffer() throws Exception {
+ Key key = newKey();
+ AlgorithmParameterSpec spec = newParamSpec();
+ Cipher c1 = Cipher.getInstance(cipher);
+ Cipher c2 = Cipher.getInstance(cipher);
+ Cipher c3 = Cipher.getInstance(cipher);
+
+ c1.init(Cipher.ENCRYPT_MODE, key, spec);
+ c1.updateAAD(new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x10,
+ });
+
+ c2.init(Cipher.ENCRYPT_MODE, key, spec);
+ c2.updateAAD(ByteBuffer.wrap(new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x10,
+ }));
+
+ c3.init(Cipher.ENCRYPT_MODE, key, spec);
+ ByteBuffer buf = ByteBuffer.allocateDirect(10);
+ buf.put(new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x10,
+ });
+ buf.flip();
+ c3.updateAAD(buf);
+
+ byte[] c1Final = c1.doFinal();
+ byte[] c2Final = c2.doFinal();
+ byte[] c3Final = c3.doFinal();
+ assertEquals(Arrays.toString(c1Final), Arrays.toString(c2Final));
+ assertEquals(Arrays.toString(c1Final), Arrays.toString(c3Final));
+ }
+
+ @Test
+ public void testUpdateAAD_ByteBuffer_MultipleUpdates() throws Exception {
+ Key key = newKey();
+ AlgorithmParameterSpec spec = newParamSpec();
+ Cipher c1 = Cipher.getInstance(cipher);
+ Cipher c2 = Cipher.getInstance(cipher);
+ Cipher c3 = Cipher.getInstance(cipher);
+
+ c1.init(Cipher.ENCRYPT_MODE, key, spec);
+ c1.updateAAD(new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ });
+ c1.updateAAD(new byte[] {
+ 0x06, 0x07, 0x08, 0x09, 0x10,
+ });
+
+ c2.init(Cipher.ENCRYPT_MODE, key, spec);
+ c2.updateAAD(ByteBuffer.wrap(new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ }));
+ c2.updateAAD(ByteBuffer.wrap(new byte[] {
+ 0x06, 0x07, 0x08, 0x09, 0x10,
+ }));
+
+ c3.init(Cipher.ENCRYPT_MODE, key, spec);
+ ByteBuffer buf = ByteBuffer.allocateDirect(10);
+ buf.put(new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x10,
+ });
+ buf.flip();
+ buf.limit(5);
+ c3.updateAAD(buf);
+ buf.limit(10);
+ c3.updateAAD(buf);
+
+ byte[] c1Final = c1.doFinal();
+ byte[] c2Final = c2.doFinal();
+ byte[] c3Final = c3.doFinal();
+ assertEquals(Arrays.toString(c1Final), Arrays.toString(c2Final));
+ assertEquals(Arrays.toString(c1Final), Arrays.toString(c3Final));
+ }
+
+ @Test
+ public void testUpdateAAD_ByteBuffer_MixedCalls() throws Exception {
+ Key key = newKey();
+ AlgorithmParameterSpec spec = newParamSpec();
+ Cipher c1 = Cipher.getInstance(cipher);
+ Cipher c2 = Cipher.getInstance(cipher);
+ Cipher c3 = Cipher.getInstance(cipher);
+
+ c1.init(Cipher.ENCRYPT_MODE, key, spec);
+ c1.updateAAD(new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x10,
+ });
+
+ c2.init(Cipher.ENCRYPT_MODE, key, spec);
+ c2.updateAAD(new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ });
+ c2.updateAAD(ByteBuffer.wrap(new byte[] {
+ 0x06, 0x07, 0x08, 0x09, 0x10,
+ }));
+
+ c3.init(Cipher.ENCRYPT_MODE, key, spec);
+ ByteBuffer buf = ByteBuffer.allocateDirect(10);
+ buf.put(new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x10,
+ });
+ buf.flip();
+ buf.limit(5);
+ c3.updateAAD(buf);
+ c3.updateAAD(new byte[] {
+ 0x06, 0x07, 0x08, 0x09, 0x10,
+ });
+
+ byte[] c1Final = c1.doFinal();
+ byte[] c2Final = c2.doFinal();
+ byte[] c3Final = c3.doFinal();
+ assertEquals(Arrays.toString(c1Final), Arrays.toString(c2Final));
+ assertEquals(Arrays.toString(c1Final), Arrays.toString(c3Final));
+ }
+
+ @Test
+ public void testUpdateAAD_ByteBuffer_Unequal() throws Exception {
+ Key key = newKey();
+ AlgorithmParameterSpec spec = newParamSpec();
+ Cipher c1 = Cipher.getInstance(cipher);
+ Cipher c2 = Cipher.getInstance(cipher);
+ Cipher c3 = Cipher.getInstance(cipher);
+
+ c1.init(Cipher.ENCRYPT_MODE, key, spec);
+ c1.updateAAD(ByteBuffer.wrap(new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ }));
+
+ c2.init(Cipher.ENCRYPT_MODE, key, spec);
+ c2.updateAAD(new byte[] {
+ 0x06, 0x07, 0x08, 0x09, 0x10,
+ });
+
+ c3.init(Cipher.ENCRYPT_MODE, key, spec);
+ ByteBuffer buf = ByteBuffer.allocateDirect(10);
+ buf.put(new byte[] {
+ 0x11, 0x12, 0x13, 0x14, 0x15,
+ });
+ buf.flip();
+ c3.updateAAD(buf);
+
+ byte[] c1Final = c1.doFinal();
+ byte[] c2Final = c2.doFinal();
+ byte[] c3Final = c3.doFinal();
+ assertFalse(Arrays.equals(c1Final, c2Final));
+ assertFalse(Arrays.equals(c2Final, c3Final));
+ assertFalse(Arrays.equals(c1Final, c3Final));
+ }
+
+ /*
+ * Check that encryption with old and new instances update correctly.
+ * http://b/27324690
+ */
+ @Test
+ public void testReuse() throws Exception {
+ Key key = newKey();
+ Key key2 = newKey();
+ AlgorithmParameterSpec spec = newParamSpec();
+ Cipher c1 = Cipher.getInstance(cipher);
+ Cipher c2 = Cipher.getInstance(cipher);
+
+ // Pollute the c1 cipher with AAD
+ c1.init(Cipher.ENCRYPT_MODE, key, spec);
+ c1.updateAAD(new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ });
+
+ // Now init each again and make sure the outputs are the same. We have to use a
+ // different key because reiniting an AEAD cipher with the same key and IV should fail.
+ c1.init(Cipher.ENCRYPT_MODE, key2, spec);
+ c2.init(Cipher.ENCRYPT_MODE, key2, spec);
+
+ byte[] aad = new byte[] {
+ 0x10, 0x20, 0x30, 0x40, 0x50, 0x60,
+ };
+ c1.updateAAD(aad);
+ c2.updateAAD(aad);
+
+ assertEquals(Arrays.toString(c1.doFinal()), Arrays.toString(c2.doFinal()));
+
+ // .doFinal should also not allow reuse without re-initialization
+ byte[] aad2 = new byte[] {
+ 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11,
+ };
+ try {
+ c1.updateAAD(aad2);
+ fail("Should not allow updateAAD without re-initialization");
+ } catch (IllegalStateException expected) {
+ }
+
+ try {
+ c1.update(new byte[8]);
+ fail("Should not allow update without re-initialization");
+ } catch (IllegalStateException expected) {
+ }
+
+ try {
+ c1.doFinal();
+ fail("Should not allow doFinal without re-initialization");
+ } catch (IllegalStateException expected) {
+ }
+ }
+
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/crypto/CipherBasicsTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/crypto/CipherBasicsTest.java
new file mode 100644
index 0000000..2c09f04
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/crypto/CipherBasicsTest.java
@@ -0,0 +1,480 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt.javax.crypto;
+
+import static com.android.org.conscrypt.TestUtils.decodeHex;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import com.android.org.conscrypt.TestUtils;
+import java.nio.ByteBuffer;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Security;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.crypto.Cipher;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for basic compliance for ciphers. This test uses reference vectors produced by
+ * standards bodies and confirms that all implementations produce the correct answer
+ * for the given inputs.
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public final class CipherBasicsTest {
+ private static final Map<String, String> BASIC_CIPHER_TO_TEST_DATA = new HashMap<>();
+ static {
+ BASIC_CIPHER_TO_TEST_DATA.put("AES/ECB/NoPadding", "crypto/aes-ecb.csv");
+ BASIC_CIPHER_TO_TEST_DATA.put("AES/CBC/NoPadding", "crypto/aes-cbc.csv");
+ BASIC_CIPHER_TO_TEST_DATA.put("AES/CFB8/NoPadding", "crypto/aes-cfb8.csv");
+ BASIC_CIPHER_TO_TEST_DATA.put("AES/CFB128/NoPadding", "crypto/aes-cfb128.csv");
+ BASIC_CIPHER_TO_TEST_DATA.put("AES/OFB/NoPadding", "crypto/aes-ofb.csv");
+ BASIC_CIPHER_TO_TEST_DATA.put("DESEDE/ECB/NoPadding", "crypto/desede-ecb.csv");
+ BASIC_CIPHER_TO_TEST_DATA.put("DESEDE/CBC/NoPadding", "crypto/desede-cbc.csv");
+ BASIC_CIPHER_TO_TEST_DATA.put("DESEDE/CFB8/NoPadding", "crypto/desede-cfb8.csv");
+ BASIC_CIPHER_TO_TEST_DATA.put("DESEDE/CFB64/NoPadding", "crypto/desede-cfb64.csv");
+ BASIC_CIPHER_TO_TEST_DATA.put("DESEDE/OFB/NoPadding", "crypto/desede-ofb.csv");
+ BASIC_CIPHER_TO_TEST_DATA.put("ChaCha20", "crypto/chacha20.csv");
+ }
+
+ private static final Map<String, String> AEAD_CIPHER_TO_TEST_DATA = new HashMap<>();
+ static {
+ AEAD_CIPHER_TO_TEST_DATA.put("AES/GCM/NoPadding", "crypto/aes-gcm.csv");
+ AEAD_CIPHER_TO_TEST_DATA.put("AES/GCM-SIV/NoPadding", "crypto/aes-gcm-siv.csv");
+ AEAD_CIPHER_TO_TEST_DATA.put("ChaCha20/Poly1305/NoPadding", "crypto/chacha20-poly1305.csv");
+ }
+
+ private static final int KEY_INDEX = 0;
+ private static final int IV_INDEX = 1;
+ private static final int PLAINTEXT_INDEX = 2;
+ private static final int CIPHERTEXT_INDEX = 3;
+ private static final int TAG_INDEX = 4;
+ private static final int AAD_INDEX = 5;
+
+ @BeforeClass
+ public static void setUp() {
+ TestUtils.assumeAllowsUnsignedCrypto();
+ }
+
+ @Test
+ public void testBasicEncryption() throws Exception {
+ for (Provider p : Security.getProviders()) {
+ for (Map.Entry<String, String> entry : BASIC_CIPHER_TO_TEST_DATA.entrySet()) {
+ String transformation = entry.getKey();
+
+ // In OpenJDK 6, the SunPKCS11-NSS implementation of AES/ECB/NoPadding thinks
+ // that it's AES/CTR/NoPadding during init() for some reason, which causes it
+ // to throw an exception due to a lack of IV (required for CTR, prohibited for ECB).
+ // We don't strongly care about checking this implementation, so just skip it.
+ if (p.getName().equals("SunPKCS11-NSS")
+ && transformation.equals("AES/ECB/NoPadding")) {
+ continue;
+ }
+
+ // The SunJCE implementation of ChaCha20 only supports initializing with
+ // ChaCha20ParameterSpec, introduced in Java 11. For now, just skip testing it.
+ if (transformation.equals("ChaCha20") && p.getName().equals("SunJCE")) {
+ continue;
+ }
+
+ Cipher cipher;
+ try {
+ cipher = Cipher.getInstance(transformation, p);
+ } catch (NoSuchAlgorithmException e) {
+ // This provider doesn't provide this algorithm, ignore it
+ continue;
+ }
+
+ List<String[]> data = TestUtils.readCsvResource(entry.getValue());
+ for (String[] line : data) {
+ Key key = new SecretKeySpec(
+ decodeHex(line[KEY_INDEX]), getBaseAlgorithm(transformation));
+ byte[] iv = decodeHex(line[IV_INDEX]);
+ byte[] plaintext = decodeHex(line[PLAINTEXT_INDEX]);
+ byte[] ciphertext = decodeHex(line[CIPHERTEXT_INDEX]);
+
+ // Initialize the IV, if there is one
+ AlgorithmParameters params;
+ if (iv.length > 0) {
+ params = AlgorithmParameters.getInstance(getBaseAlgorithm(transformation));
+ params.init(iv, "RAW");
+ } else {
+ params = null;
+ }
+
+ try {
+ cipher.init(Cipher.ENCRYPT_MODE, key, params);
+ assertEquals("Provider " + p.getName()
+ + ", algorithm " + transformation
+ + " reported the wrong output size",
+ ciphertext.length, cipher.getOutputSize(plaintext.length));
+ assertArrayEquals("Provider " + p.getName() + ", algorithm "
+ + transformation + " failed on encryption, data is "
+ + Arrays.toString(line),
+ ciphertext, cipher.doFinal(plaintext));
+
+ cipher.init(Cipher.DECRYPT_MODE, key, params);
+ assertEquals("Provider " + p.getName()
+ + ", algorithm " + transformation
+ + " reported the wrong output size",
+ plaintext.length, cipher.getOutputSize(ciphertext.length));
+ assertArrayEquals("Provider " + p.getName() + ", algorithm "
+ + transformation + " failed on decryption, data is "
+ + Arrays.toString(line),
+ plaintext, cipher.doFinal(ciphertext));
+ } catch (InvalidKeyException e) {
+ // Some providers may not support raw SecretKeySpec keys, that's allowed
+ }
+ }
+ }
+ }
+ }
+
+ public void arrayBasedAssessment(Cipher cipher, byte[] aad, byte[] tag, byte[] plaintext,
+ byte[] ciphertext, Key key, AlgorithmParameterSpec params, String transformation,
+ Provider p, String[] line) throws Exception {
+ cipher.init(Cipher.ENCRYPT_MODE, key, params);
+ if (aad.length > 0) {
+ cipher.updateAAD(aad);
+ }
+ byte[] combinedOutput = new byte[ciphertext.length + tag.length];
+ assertEquals("Provider " + p.getName() + ", algorithm " + transformation
+ + " reported the wrong output size",
+ combinedOutput.length, cipher.getOutputSize(plaintext.length));
+ System.arraycopy(ciphertext, 0, combinedOutput, 0, ciphertext.length);
+ System.arraycopy(tag, 0, combinedOutput, ciphertext.length, tag.length);
+ assertArrayEquals("Provider " + p.getName() + ", algorithm " + transformation
+ + " failed on encryption, data is " + Arrays.toString(line),
+ combinedOutput, cipher.doFinal(plaintext));
+
+ cipher.init(Cipher.DECRYPT_MODE, key, params);
+ if (aad.length > 0) {
+ cipher.updateAAD(aad);
+ }
+ assertEquals("Provider " + p.getName() + ", algorithm " + transformation
+ + " reported the wrong output size",
+ plaintext.length, cipher.getOutputSize(combinedOutput.length));
+ assertArrayEquals("Provider " + p.getName() + ", algorithm " + transformation
+ + " failed on decryption, data is " + Arrays.toString(line),
+ plaintext, cipher.doFinal(combinedOutput));
+ }
+
+ @Test
+ public void testAeadEncryption() throws Exception {
+ TestUtils.assumeAEADAvailable();
+ for (Provider p : Security.getProviders()) {
+ for (Map.Entry<String, String> entry : AEAD_CIPHER_TO_TEST_DATA.entrySet()) {
+ String transformation = entry.getKey();
+
+ // On Android 10 and below, BC can return AES/GCM/NoPadding when asked for
+ // AES/GCM-SIV/NoPadding. Android will never actually ship AES/GCM-SIV/NoPadding
+ // in BC, so skip that combination.
+ if (p.getName().equals("BC") && transformation.equals("AES/GCM-SIV/NoPadding")) {
+ continue;
+ }
+
+ Cipher cipher;
+ try {
+ cipher = Cipher.getInstance(transformation, p);
+ } catch (NoSuchAlgorithmException e) {
+ // This provider doesn't provide this algorithm, ignore it
+ continue;
+ }
+
+ List<String[]> data = TestUtils.readCsvResource(entry.getValue());
+ for (String[] line : data) {
+ Key key = new SecretKeySpec(
+ decodeHex(line[KEY_INDEX]), getBaseAlgorithm(transformation));
+ byte[] iv = decodeHex(line[IV_INDEX]);
+ byte[] plaintext = decodeHex(line[PLAINTEXT_INDEX]);
+ byte[] ciphertext = decodeHex(line[CIPHERTEXT_INDEX]);
+ byte[] tag = decodeHex(line[TAG_INDEX]);
+ byte[] aad = decodeHex(line[AAD_INDEX]);
+
+ // Some ChaCha20 tests include truncated tags, which the Java API doesn't
+ // support. Skip those tests.
+ if (transformation.startsWith("ChaCha20") && tag.length < 16) {
+ continue;
+ }
+
+ AlgorithmParameterSpec params;
+ if (transformation.contains("GCM")) {
+ params = new GCMParameterSpec(8 * tag.length, iv);
+ } else {
+ params = new IvParameterSpec(iv);
+ }
+
+ try {
+ arrayBasedAssessment(cipher, aad, tag, plaintext, ciphertext, key, params,
+ transformation, p, line);
+ bufferBasedAssessment(cipher, aad, tag, plaintext, ciphertext, key, params,
+ transformation, p, false, false);
+ bufferBasedAssessment(cipher, aad, tag, plaintext, ciphertext, key, params,
+ transformation, p, true, true);
+ bufferBasedAssessment(cipher, aad, tag, plaintext, ciphertext, key, params,
+ transformation, p, true, false);
+ bufferBasedAssessment(cipher, aad, tag, plaintext, ciphertext, key, params,
+ transformation, p, false, true);
+ sharedBufferBasedAssessment(cipher, aad, tag, plaintext, ciphertext, key,
+ params, transformation, p);
+ } catch (InvalidKeyException e) {
+ // Some providers may not support raw SecretKeySpec keys, that's allowed
+ } catch (InvalidAlgorithmParameterException e) {
+ // Some providers may not support all tag lengths or nonce lengths,
+ // that's allowed
+ }
+ }
+ }
+ }
+ }
+
+ public void sharedBufferBasedAssessment(Cipher cipher, byte[] aad, byte[] tag,
+ byte[] _plaintext, byte[] _ciphertext, Key key, AlgorithmParameterSpec params,
+ String transformation, Provider p) throws Exception {
+ cipher.init(Cipher.ENCRYPT_MODE, key, params);
+ if (aad.length > 0) {
+ cipher.updateAAD(aad);
+ }
+ byte[] _combinedOutput = new byte[_ciphertext.length + tag.length];
+ byte[] _commonBacking = new byte[_plaintext.length + _combinedOutput.length];
+
+ assertEquals("Provider " + p.getName() + ", algorithm " + transformation
+ + " reported the wrong output size",
+ _combinedOutput.length, cipher.getOutputSize(_plaintext.length));
+ System.arraycopy(_ciphertext, 0, _combinedOutput, 0, _ciphertext.length);
+ System.arraycopy(tag, 0, _combinedOutput, _ciphertext.length, tag.length);
+ System.arraycopy(_plaintext, 0, _commonBacking, 0, _plaintext.length);
+ System.arraycopy(
+ _combinedOutput, 0, _commonBacking, _plaintext.length, _combinedOutput.length);
+ ByteBuffer combinedOutput = ByteBuffer.wrap(_commonBacking);
+ ByteBuffer plaintext = combinedOutput.slice();
+ plaintext.limit(_plaintext.length);
+ combinedOutput.position(_plaintext.length);
+ // both byte buffers have been created from common backed array and have correct respecting
+ // positions and limits
+
+ combinedOutput.position(combinedOutput.limit());
+ ByteBuffer outputbuffer = ByteBuffer.allocate(cipher.getOutputSize(plaintext.remaining()));
+
+ cipher.doFinal(plaintext, outputbuffer);
+ assertEquals("Cipher doFinal did not encrypt correctly", combinedOutput, outputbuffer);
+ assertEquals(" input was not shifted", plaintext.position(), plaintext.limit());
+
+ cipher.init(Cipher.DECRYPT_MODE, key, params);
+ if (aad.length > 0) {
+ cipher.updateAAD(aad);
+ }
+ assertEquals("Provider " + p.getName() + ", algorithm " + transformation
+ + " reported the wrong output size",
+ _plaintext.length, cipher.getOutputSize(_combinedOutput.length));
+ combinedOutput.position(_plaintext.length);
+
+ outputbuffer = ByteBuffer.allocate(cipher.getOutputSize(combinedOutput.remaining()));
+
+ combinedOutput.position(_plaintext.length);
+ plaintext.position(plaintext.limit());
+ cipher.doFinal(combinedOutput, outputbuffer);
+ assertEquals("Cipher doFinal did not decrypt correctly", plaintext, outputbuffer);
+ assertEquals(" input was not shifted", combinedOutput.position(), combinedOutput.limit());
+ }
+
+ public void bufferBasedAssessment(Cipher cipher, byte[] aad, byte[] tag, byte[] _plaintext,
+ byte[] _ciphertext, Key key, AlgorithmParameterSpec params, String transformation,
+ Provider p, boolean inBoolDirect, boolean outBoolDirect) throws Exception {
+ cipher.init(Cipher.ENCRYPT_MODE, key, params);
+ if (aad.length > 0) {
+ cipher.updateAAD(aad);
+ }
+ byte[] _combinedOutput = new byte[_ciphertext.length + tag.length];
+ ByteBuffer plaintext = ByteBuffer.wrap(_plaintext);
+ if (inBoolDirect) {
+ ByteBuffer plaintext_ = plaintext;
+ int incap = plaintext_.remaining();
+ plaintext = ByteBuffer.allocateDirect(incap);
+ plaintext.mark();
+ plaintext.put(plaintext_);
+ plaintext.reset();
+ }
+
+ assertEquals("Provider " + p.getName() + ", algorithm " + transformation
+ + " reported the wrong output size",
+ _combinedOutput.length, cipher.getOutputSize(_plaintext.length));
+ System.arraycopy(_ciphertext, 0, _combinedOutput, 0, _ciphertext.length);
+ System.arraycopy(tag, 0, _combinedOutput, _ciphertext.length, tag.length);
+
+ ByteBuffer combinedOutput = ByteBuffer.wrap(_combinedOutput);
+ if (outBoolDirect) {
+ ByteBuffer combinedOutput_ = combinedOutput;
+ int outcap = combinedOutput_.remaining();
+ combinedOutput = ByteBuffer.allocateDirect(outcap);
+ combinedOutput.mark();
+ combinedOutput.put(combinedOutput_);
+ }
+ combinedOutput.position(combinedOutput.limit());
+ ByteBuffer outputbuffer;
+ if (outBoolDirect) {
+ outputbuffer = ByteBuffer.allocateDirect(cipher.getOutputSize(plaintext.remaining()));
+ } else {
+ outputbuffer = ByteBuffer.allocate(cipher.getOutputSize(plaintext.remaining()));
+ }
+
+ cipher.doFinal(plaintext, outputbuffer);
+ assertEquals("Cipher doFinal did not encrypt correctly", combinedOutput, outputbuffer);
+ assertEquals(" input was not shifted", plaintext.position(), plaintext.limit());
+
+ cipher.init(Cipher.DECRYPT_MODE, key, params);
+ if (aad.length > 0) {
+ cipher.updateAAD(aad);
+ }
+ assertEquals("Provider " + p.getName() + ", algorithm " + transformation
+ + " reported the wrong output size",
+ _plaintext.length, cipher.getOutputSize(_combinedOutput.length));
+ combinedOutput = ByteBuffer.wrap(_combinedOutput);
+ if (inBoolDirect) {
+ ByteBuffer combinedOutput_ = combinedOutput;
+ int incap = combinedOutput_.remaining();
+ combinedOutput = ByteBuffer.allocateDirect(incap);
+ combinedOutput.mark();
+ combinedOutput.put(combinedOutput_);
+ combinedOutput.reset();
+ }
+ if (outBoolDirect) {
+ outputbuffer =
+ ByteBuffer.allocateDirect(cipher.getOutputSize(combinedOutput.remaining()));
+ } else {
+ outputbuffer = ByteBuffer.allocate(cipher.getOutputSize(combinedOutput.remaining()));
+ }
+ combinedOutput.position(0);
+ plaintext.position(plaintext.limit());
+ cipher.doFinal(combinedOutput, outputbuffer);
+ assertEquals("Cipher doFinal did not decrypt correctly", plaintext, outputbuffer);
+ assertEquals(" input was not shifted", combinedOutput.position(), combinedOutput.limit());
+ }
+
+ /**
+ * Returns the underlying cipher name given a cipher transformation. For example,
+ * passing {@code AES/CBC/NoPadding} returns {@code AES}.
+ */
+ private static String getBaseAlgorithm(String transformation) {
+ if (transformation.contains("/")) {
+ return transformation.substring(0, transformation.indexOf('/'));
+ }
+ return transformation;
+ }
+
+ /**
+ * Encryption with ByteBuffers should be copy-safe even if the buffers have different starting
+ * offsets and/or do not make the backing array visible.
+ *
+ * <p>Note that bugs in this often require a sizeable input to reproduce; the default
+ * implementation of engineUpdate(ByteBuffer, ByteBuffer) copies through 4KB bounce buffers, so
+ * we need to use something larger to see any problems - 8KB is what we use here.
+ *
+ * @see https://bugs.openjdk.java.net/browse/JDK-8181386
+ */
+ @Test
+ public void testByteBufferShiftedAlias() throws Exception {
+ byte[] ptVector = new byte[8192];
+
+ for (int i = 0; i < 3; i++) {
+ // outputOffset = offset relative to start of input.
+ for (int outputOffset = -1; outputOffset <= 1; outputOffset++) {
+ SecretKeySpec key = new SecretKeySpec(new byte[16], "AES");
+ GCMParameterSpec parameters = new GCMParameterSpec(128, new byte[12]);
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ cipher.init(Cipher.ENCRYPT_MODE, key, parameters);
+
+ ByteBuffer output, input, inputRO;
+
+ // We'll try three scenarios: Ordinary array backed buffers, array backed buffers
+ // where one is read-only, and direct byte buffers.
+ String mode;
+ // offsets relative to start of buffer
+ int inputOffsetInBuffer = 1;
+ int outputOffsetInBuffer = inputOffsetInBuffer + outputOffset;
+ int sliceLength = cipher.getOutputSize(ptVector.length);
+ int bufferSize = sliceLength + Math.max(inputOffsetInBuffer, outputOffsetInBuffer);
+
+ mode = "direct buffers";
+ ByteBuffer buf = ByteBuffer.allocateDirect(bufferSize);
+ output = buf.duplicate();
+ output.position(outputOffsetInBuffer);
+ output.limit(sliceLength + outputOffsetInBuffer);
+ output = output.slice();
+
+ input = buf.duplicate();
+ input.position(inputOffsetInBuffer);
+ input.limit(sliceLength + inputOffsetInBuffer);
+ input = input.slice();
+
+ inputRO = input.duplicate();
+
+ // Now that we have our overlapping 'input' and 'output' buffers, we can write our
+ // plaintext into the input buffer.
+ input.put(ptVector);
+ input.flip();
+ // Make sure the RO input buffer has the same limit in case the plaintext is shorter
+ // than sliceLength (which it generally will be for anything other than ECB or CTR
+ // mode)
+ inputRO.limit(input.limit());
+
+ try {
+ int ctSize = cipher.doFinal(inputRO, output);
+
+ // Now flip the buffers around and undo everything
+ byte[] tmp = new byte[ctSize];
+ output.flip();
+ output.get(tmp);
+
+ output.clear();
+ input.clear();
+ inputRO.clear();
+
+ input.put(tmp);
+ input.flip();
+ inputRO.limit(input.limit());
+
+ cipher.init(Cipher.DECRYPT_MODE, key, parameters);
+ cipher.doFinal(inputRO, output);
+
+ output.flip();
+ assertEquals(ByteBuffer.wrap(ptVector), output);
+ } catch (Throwable t) {
+ throw new AssertionError("Overlapping buffers test failed with buffer type: "
+ + mode + " and output offset " + outputOffset,
+ t);
+ }
+ }
+ }
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/crypto/CipherTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/crypto/CipherTest.java
new file mode 100644
index 0000000..0d8a5c8
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/crypto/CipherTest.java
@@ -0,0 +1,4735 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2011 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.
+ */
+
+package com.android.org.conscrypt.javax.crypto;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.org.conscrypt.Conscrypt;
+import com.android.org.conscrypt.TestUtils;
+import com.android.org.conscrypt.java.security.StandardNames;
+import com.android.org.conscrypt.java.security.TestKeyStore;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.cert.Certificate;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import javax.crypto.AEADBadTagException;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.PSource;
+import javax.crypto.spec.SecretKeySpec;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.bouncycastle.asn1.x509.KeyUsage;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public final class CipherTest {
+
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
+ @BeforeClass
+ public static void setUp() {
+ TestUtils.assumeAllowsUnsignedCrypto();
+ }
+
+ /** GCM tag size used for tests. */
+ private static final int GCM_TAG_SIZE_BITS = 96;
+ private static final int GCM_SIV_TAG_SIZE_BITS = 128;
+
+ private static final String[] RSA_PROVIDERS = StandardNames.IS_RI
+ ? new String[] { "SunJCE", StandardNames.JSSE_PROVIDER_NAME }
+ : new String[] { "BC" , StandardNames.JSSE_PROVIDER_NAME };
+
+ private static final String[] AES_PROVIDERS = StandardNames.IS_RI
+ ? new String[] { "SunJCE", StandardNames.JSSE_PROVIDER_NAME }
+ : new String[] { "BC", StandardNames.JSSE_PROVIDER_NAME };
+
+ private static boolean isSupported(String algorithm, String provider) {
+ if (algorithm.equals("RC2")) {
+ return false;
+ }
+ if (algorithm.equals("PBEWITHMD5ANDRC2")) {
+ return false;
+ }
+ if (algorithm.startsWith("PBEWITHSHA1ANDRC2")) {
+ return false;
+ }
+ if (algorithm.equals("PBEWITHSHAAND40BITRC2-CBC")) {
+ return false;
+ }
+ if (algorithm.equals("PBEWITHSHAAND128BITRC2-CBC")) {
+ return false;
+ }
+ if (algorithm.equals("PBEWITHSHAANDTWOFISH-CBC")) {
+ return false;
+ }
+ if (!IS_UNLIMITED) {
+ if (algorithm.equals("PBEWITHMD5ANDTRIPLEDES")) {
+ return false;
+ }
+ }
+ // stream modes CFB, CTR, CTS, OFB with PKCS5Padding or PKCS7Padding don't really make sense
+ if (!provider.equals("AndroidOpenSSL") &&
+ (algorithm.equals("AES/CFB/PKCS5PADDING")
+ || algorithm.equals("AES/CFB/PKCS7PADDING")
+ || algorithm.equals("AES/CTR/PKCS5PADDING")
+ || algorithm.equals("AES/CTR/PKCS7PADDING")
+ || algorithm.equals("AES/CTS/PKCS5PADDING")
+ || algorithm.equals("AES/CTS/PKCS7PADDING")
+ || algorithm.equals("AES/OFB/PKCS5PADDING")
+ || algorithm.equals("AES/OFB/PKCS7PADDING"))) {
+ return false;
+ }
+
+ if (provider.equals("BC")) {
+ return isSupportedByBC(algorithm);
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks for algorithms removed from BC in Android 12 and so not usable for these
+ * tests.
+ *
+ * TODO(prb): make this version aware, as this test runs against BC on older Android
+ * versions via MTS and should continue to test these algorithms there.
+ *
+ */
+ private static boolean isSupportedByBC(String algorithm) {
+ String[] removedBcPrefices = new String[] {"AES/ECB", "AES/CBC", "AES/GCM"};
+ for (String prefix : removedBcPrefices) {
+ if (algorithm.startsWith(prefix)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean isSupportedForWrapping(String algorithm) {
+ if (isOnlyWrappingAlgorithm(algorithm)) {
+ return true;
+ }
+ // http://b/9097343 RSA with NoPadding won't work since
+ // leading zeroes in the underlying key material are lost.
+ if (algorithm.equals("RSA/ECB/NOPADDING")) {
+ return false;
+ }
+ // AESWRAP should be used instead, fails with BC and SunJCE otherwise.
+ if (algorithm.startsWith("AES") || algorithm.startsWith("DESEDE")) {
+ return false;
+ }
+ return true;
+ }
+
+ private synchronized static int getEncryptMode(String algorithm) throws Exception {
+ if (isOnlyWrappingAlgorithm(algorithm)) {
+ return Cipher.WRAP_MODE;
+ }
+ return Cipher.ENCRYPT_MODE;
+ }
+
+ private synchronized static int getDecryptMode(String algorithm) throws Exception {
+ if (isOnlyWrappingAlgorithm(algorithm)) {
+ return Cipher.UNWRAP_MODE;
+ }
+ return Cipher.DECRYPT_MODE;
+ }
+
+ private static String getBaseAlgorithm(String algorithm) {
+ if (algorithm.equals("AESWRAP")) {
+ return "AES";
+ }
+ if (algorithm.startsWith("AES/")) {
+ return "AES";
+ }
+ if (algorithm.startsWith("AES_128/") || algorithm.startsWith("AES_256/")) {
+ return "AES";
+ }
+ if (algorithm.equals("GCM")) {
+ return "AES";
+ }
+ if (algorithm.startsWith("CHACHA20/")) {
+ return "CHACHA20";
+ }
+ if (algorithm.startsWith("DESEDE/")) {
+ return "DESEDE";
+ }
+ if (algorithm.equals("PBEWITHMD5AND128BITAES-CBC-OPENSSL")) {
+ return "AES";
+ }
+ if (algorithm.equals("PBEWITHMD5AND192BITAES-CBC-OPENSSL")) {
+ return "AES";
+ }
+ if (algorithm.equals("PBEWITHMD5AND256BITAES-CBC-OPENSSL")) {
+ return "AES";
+ }
+ if (algorithm.equals("PBEWITHSHA256AND128BITAES-CBC-BC")) {
+ return "AES";
+ }
+ if (algorithm.equals("PBEWITHSHA256AND192BITAES-CBC-BC")) {
+ return "AES";
+ }
+ if (algorithm.equals("PBEWITHSHA256AND256BITAES-CBC-BC")) {
+ return "AES";
+ }
+ if (algorithm.equals("PBEWITHSHAAND128BITAES-CBC-BC")) {
+ return "AES";
+ }
+ if (algorithm.equals("PBEWITHSHAAND192BITAES-CBC-BC")) {
+ return "AES";
+ }
+ if (algorithm.equals("PBEWITHSHAAND256BITAES-CBC-BC")) {
+ return "AES";
+ }
+ if (algorithm.equals("PBEWITHMD5ANDDES")) {
+ return "DES";
+ }
+ if (algorithm.equals("PBEWITHSHA1ANDDES")) {
+ return "DES";
+ }
+ if (algorithm.equals("DESEDEWRAP")) {
+ return "DESEDE";
+ }
+ if (algorithm.equals("PBEWITHSHAAND2-KEYTRIPLEDES-CBC")) {
+ return "DESEDE";
+ }
+ if (algorithm.equals("PBEWITHSHAAND3-KEYTRIPLEDES-CBC")) {
+ return "DESEDE";
+ }
+ if (algorithm.equals("PBEWITHMD5ANDTRIPLEDES")) {
+ return "DESEDE";
+ }
+ if (algorithm.equals("PBEWITHSHA1ANDDESEDE")) {
+ return "DESEDE";
+ }
+ if (algorithm.equals("RSA/ECB/NOPADDING")) {
+ return "RSA";
+ }
+ if (algorithm.equals("RSA/ECB/PKCS1PADDING")) {
+ return "RSA";
+ }
+ if (algorithm.equals("PBEWITHSHAAND40BITRC4")) {
+ return "ARC4";
+ }
+ if (algorithm.equals("PBEWITHSHAAND128BITRC4")) {
+ return "ARC4";
+ }
+ return algorithm;
+ }
+
+ private static boolean isAsymmetric(String algorithm) {
+ return getBaseAlgorithm(algorithm).equals("RSA");
+ }
+
+ private static boolean isOnlyWrappingAlgorithm(String algorithm) {
+ return algorithm.endsWith("WRAP");
+ }
+
+ private static boolean isPBE(String algorithm) {
+ return algorithm.startsWith("PBE");
+ }
+
+ private static boolean isAEAD(String algorithm) {
+ return "GCM".equals(algorithm) || algorithm.contains("/GCM/")
+ || algorithm.contains("/GCM-SIV/")
+ || algorithm.equals("CHACHA20/POLY1305/NOPADDING");
+ }
+
+ private static boolean isStreamMode(String algorithm) {
+ return algorithm.contains("/CTR/") || algorithm.contains("/OFB")
+ || algorithm.contains("/CFB");
+ }
+
+ private static boolean isRandomizedEncryption(String algorithm) {
+ return algorithm.endsWith("/PKCS1PADDING") || algorithm.endsWith("/OAEPPADDING")
+ || algorithm.contains("/OAEPWITH");
+ }
+
+ private static Map<String, Key> ENCRYPT_KEYS = new HashMap<String, Key>();
+
+ /**
+ * Returns the key meant for enciphering for {@code algorithm}.
+ */
+ private synchronized static Key getEncryptKey(String algorithm) {
+ Key key = ENCRYPT_KEYS.get(algorithm);
+ if (key != null) {
+ return key;
+ }
+ try {
+ if (algorithm.startsWith("RSA")) {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ key = kf.generatePublic(keySpec);
+ } else if (isPBE(algorithm)) {
+ SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm);
+ key = skf.generateSecret(new PBEKeySpec("secret".toCharArray()));
+ } else {
+ KeyGenerator kg = KeyGenerator.getInstance(getBaseAlgorithm(algorithm));
+ if (algorithm.startsWith("AES_256/")) {
+ // This is the 256-bit constrained version, so we have to switch from the
+ // default of 128-bit keys.
+ kg.init(256);
+ }
+ key = kg.generateKey();
+ }
+ } catch (Exception e) {
+ throw new AssertionError("Error generating keys for test setup", e);
+ }
+ ENCRYPT_KEYS.put(algorithm, key);
+ return key;
+ }
+
+ private static Map<String, Key> DECRYPT_KEYS = new HashMap<String, Key>();
+
+ /**
+ * Returns the key meant for deciphering for {@code algorithm}.
+ */
+ private synchronized static Key getDecryptKey(String algorithm) {
+ Key key = DECRYPT_KEYS.get(algorithm);
+ if (key != null) {
+ return key;
+ }
+ try {
+ if (algorithm.startsWith("RSA")) {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent, RSA_2048_privateExponent, RSA_2048_primeP,
+ RSA_2048_primeQ, RSA_2048_primeExponentP, RSA_2048_primeExponentQ,
+ RSA_2048_crtCoefficient);
+ key = kf.generatePrivate(keySpec);
+ } else {
+ assertFalse(algorithm, isAsymmetric(algorithm));
+ key = getEncryptKey(algorithm);
+ }
+ } catch (Exception e) {
+ throw new AssertionError("Error generating keys for test setup", e);
+ }
+ DECRYPT_KEYS.put(algorithm, key);
+ return key;
+ }
+
+ private static Map<String, Integer> EXPECTED_BLOCK_SIZE = new HashMap<String, Integer>();
+ static {
+ setExpectedBlockSize("AES", 16);
+ setExpectedBlockSize("AES/CBC/PKCS5PADDING", 16);
+ setExpectedBlockSize("AES/CBC/PKCS7PADDING", 16);
+ setExpectedBlockSize("AES/CBC/NOPADDING", 16);
+ setExpectedBlockSize("AES/CFB/PKCS5PADDING", 16);
+ setExpectedBlockSize("AES/CFB/PKCS7PADDING", 16);
+ setExpectedBlockSize("AES/CFB/NOPADDING", 16);
+ setExpectedBlockSize("AES/CTR/PKCS5PADDING", 16);
+ setExpectedBlockSize("AES/CTR/PKCS7PADDING", 16);
+ setExpectedBlockSize("AES/CTR/NOPADDING", 16);
+ setExpectedBlockSize("AES/CTS/PKCS5PADDING", 16);
+ setExpectedBlockSize("AES/CTS/PKCS7PADDING", 16);
+ setExpectedBlockSize("AES/CTS/NOPADDING", 16);
+ setExpectedBlockSize("AES/ECB/PKCS5PADDING", 16);
+ setExpectedBlockSize("AES/ECB/PKCS7PADDING", 16);
+ setExpectedBlockSize("AES/ECB/NOPADDING", 16);
+ setExpectedBlockSize("AES/GCM/NOPADDING", 16);
+ setExpectedBlockSize("AES/GCM-SIV/NOPADDING", 16);
+ setExpectedBlockSize("AES/OFB/PKCS5PADDING", 16);
+ setExpectedBlockSize("AES/OFB/PKCS7PADDING", 16);
+ setExpectedBlockSize("AES/OFB/NOPADDING", 16);
+ setExpectedBlockSize("AES_128/CBC/PKCS5PADDING", 16);
+ setExpectedBlockSize("AES_128/CBC/NOPADDING", 16);
+ setExpectedBlockSize("AES_128/ECB/PKCS5PADDING", 16);
+ setExpectedBlockSize("AES_128/ECB/NOPADDING", 16);
+ setExpectedBlockSize("AES_128/GCM/NOPADDING", 16);
+ setExpectedBlockSize("AES_128/GCM-SIV/NOPADDING", 16);
+ setExpectedBlockSize("AES_256/CBC/PKCS5PADDING", 16);
+ setExpectedBlockSize("AES_256/CBC/NOPADDING", 16);
+ setExpectedBlockSize("AES_256/ECB/PKCS5PADDING", 16);
+ setExpectedBlockSize("AES_256/ECB/NOPADDING", 16);
+ setExpectedBlockSize("AES_256/GCM/NOPADDING", 16);
+ setExpectedBlockSize("AES_256/GCM-SIV/NOPADDING", 16);
+ setExpectedBlockSize("PBEWITHMD5AND128BITAES-CBC-OPENSSL", 16);
+ setExpectedBlockSize("PBEWITHMD5AND192BITAES-CBC-OPENSSL", 16);
+ setExpectedBlockSize("PBEWITHMD5AND256BITAES-CBC-OPENSSL", 16);
+ setExpectedBlockSize("PBEWITHSHA256AND128BITAES-CBC-BC", 16);
+ setExpectedBlockSize("PBEWITHSHA256AND192BITAES-CBC-BC", 16);
+ setExpectedBlockSize("PBEWITHSHA256AND256BITAES-CBC-BC", 16);
+ setExpectedBlockSize("PBEWITHSHAAND128BITAES-CBC-BC", 16);
+ setExpectedBlockSize("PBEWITHSHAAND192BITAES-CBC-BC", 16);
+ setExpectedBlockSize("PBEWITHSHAAND256BITAES-CBC-BC", 16);
+
+ if (StandardNames.IS_RI) {
+ setExpectedBlockSize("AESWRAP", 16);
+ } else {
+ setExpectedBlockSize("AESWRAP", 0);
+ }
+
+ setExpectedBlockSize("ARC4", 0);
+ setExpectedBlockSize("CHACHA20", 0);
+ setExpectedBlockSize("CHACHA20/POLY1305/NOPADDING", 0);
+ setExpectedBlockSize("PBEWITHSHAAND40BITRC4", 0);
+ setExpectedBlockSize("PBEWITHSHAAND128BITRC4", 0);
+
+ setExpectedBlockSize("BLOWFISH", 8);
+
+ setExpectedBlockSize("DES", 8);
+ setExpectedBlockSize("PBEWITHMD5ANDDES", 8);
+ setExpectedBlockSize("PBEWITHSHA1ANDDES", 8);
+
+ setExpectedBlockSize("DESEDE", 8);
+ setExpectedBlockSize("DESEDE/CBC/PKCS5PADDING", 8);
+ setExpectedBlockSize("DESEDE/CBC/NOPADDING", 8);
+ setExpectedBlockSize("PBEWITHSHAAND2-KEYTRIPLEDES-CBC", 8);
+ setExpectedBlockSize("PBEWITHSHAAND3-KEYTRIPLEDES-CBC", 8);
+
+
+ if (StandardNames.IS_RI) {
+ setExpectedBlockSize("DESEDEWRAP", 8);
+ } else {
+ setExpectedBlockSize("DESEDEWRAP", 0);
+ }
+
+ setExpectedBlockSize("RSA", "SunJCE",0);
+ setExpectedBlockSize("RSA/ECB/NoPadding", "SunJCE", 0);
+ setExpectedBlockSize("RSA/ECB/PKCS1Padding", "SunJCE", 0);
+ setExpectedBlockSize("RSA/ECB/OAEPPadding", "SunJCE", 0);
+ setExpectedBlockSize("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", "SunJCE", 0);
+ setExpectedBlockSize("RSA/ECB/OAEPWithSHA-224AndMGF1Padding", "SunJCE", 0);
+ setExpectedBlockSize("RSA/ECB/OAEPWithSHA-256AndMGF1Padding", "SunJCE", 0);
+ setExpectedBlockSize("RSA/ECB/OAEPWithSHA-384AndMGF1Padding", "SunJCE", 0);
+ setExpectedBlockSize("RSA/ECB/OAEPWithSHA-512AndMGF1Padding", "SunJCE", 0);
+
+ setExpectedBlockSize("RSA", Cipher.ENCRYPT_MODE, 256);
+ setExpectedBlockSize("RSA/ECB/NoPadding", Cipher.ENCRYPT_MODE, 256);
+ setExpectedBlockSize("RSA/ECB/PKCS1Padding", Cipher.ENCRYPT_MODE, 245);
+
+ // BC strips the leading 0 for us even when NoPadding is specified
+ setExpectedBlockSize("RSA", Cipher.ENCRYPT_MODE, "BC", 255);
+ setExpectedBlockSize("RSA/ECB/NoPadding", Cipher.ENCRYPT_MODE, "BC", 255);
+
+ setExpectedBlockSize("RSA", Cipher.DECRYPT_MODE, 256);
+ setExpectedBlockSize("RSA/ECB/NoPadding", Cipher.DECRYPT_MODE, 256);
+ setExpectedBlockSize("RSA/ECB/PKCS1Padding", Cipher.DECRYPT_MODE, 256);
+
+ // OAEP padding modes change the output and block size. SHA-1 is the default.
+ setExpectedBlockSize("RSA/ECB/OAEPPadding", Cipher.ENCRYPT_MODE, 214);
+ setExpectedBlockSize("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", Cipher.ENCRYPT_MODE, 214);
+ setExpectedBlockSize("RSA/ECB/OAEPWithSHA-224AndMGF1Padding", Cipher.ENCRYPT_MODE, 198);
+ setExpectedBlockSize("RSA/ECB/OAEPWithSHA-256AndMGF1Padding", Cipher.ENCRYPT_MODE, 190);
+ setExpectedBlockSize("RSA/ECB/OAEPWithSHA-384AndMGF1Padding", Cipher.ENCRYPT_MODE, 158);
+ setExpectedBlockSize("RSA/ECB/OAEPWithSHA-512AndMGF1Padding", Cipher.ENCRYPT_MODE, 126);
+
+ setExpectedBlockSize("RSA/ECB/OAEPPadding", Cipher.DECRYPT_MODE, 256);
+ setExpectedBlockSize("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", Cipher.DECRYPT_MODE, 256);
+ setExpectedBlockSize("RSA/ECB/OAEPWithSHA-224AndMGF1Padding", Cipher.DECRYPT_MODE, 256);
+ setExpectedBlockSize("RSA/ECB/OAEPWithSHA-256AndMGF1Padding", Cipher.DECRYPT_MODE, 256);
+ setExpectedBlockSize("RSA/ECB/OAEPWithSHA-384AndMGF1Padding", Cipher.DECRYPT_MODE, 256);
+ setExpectedBlockSize("RSA/ECB/OAEPWithSHA-512AndMGF1Padding", Cipher.DECRYPT_MODE, 256);
+ }
+
+ private static String modeKey(String algorithm, int mode) {
+ return algorithm + ":" + mode;
+ }
+
+ private static String modeProviderKey(String algorithm, int mode, String provider) {
+ return algorithm + ":" + mode + ":" + provider;
+ }
+
+ private static String providerKey(String algorithm, String provider) {
+ return algorithm + ":" + provider;
+ }
+
+ private static void setExpectedSize(Map<String, Integer> map,
+ String algorithm, int value) {
+ algorithm = algorithm.toUpperCase(Locale.US);
+ map.put(algorithm, value);
+ }
+
+ private static void setExpectedSize(Map<String, Integer> map,
+ String algorithm, int mode, int value) {
+ setExpectedSize(map, modeKey(algorithm, mode), value);
+ }
+
+ private static void setExpectedSize(Map<String, Integer> map,
+ String algorithm, int mode, String provider, int value) {
+ setExpectedSize(map, modeProviderKey(algorithm, mode, provider), value);
+ }
+
+ private static void setExpectedSize(Map<String, Integer> map,
+ String algorithm, String provider, int value) {
+ setExpectedSize(map, providerKey(algorithm, provider), value);
+ }
+
+ private static int getExpectedSize(Map<String, Integer> map, String algorithm, int mode, String provider) {
+ algorithm = algorithm.toUpperCase(Locale.US);
+ provider = provider.toUpperCase(Locale.US);
+ Integer expected = map.get(modeProviderKey(algorithm, mode, provider));
+ if (expected != null) {
+ return expected;
+ }
+ expected = map.get(providerKey(algorithm, provider));
+ if (expected != null) {
+ return expected;
+ }
+ expected = map.get(modeKey(algorithm, mode));
+ if (expected != null) {
+ return expected;
+ }
+ expected = map.get(algorithm);
+ assertNotNull("Algorithm " + algorithm + " with mode " + mode + " and provider " + provider
+ + " not found in " + map, expected);
+ return expected;
+ }
+
+ private static void setExpectedBlockSize(String algorithm, int value) {
+ setExpectedSize(EXPECTED_BLOCK_SIZE, algorithm, value);
+ }
+
+ private static void setExpectedBlockSize(String algorithm, int mode, int value) {
+ setExpectedSize(EXPECTED_BLOCK_SIZE, algorithm, mode, value);
+ }
+
+ private static void setExpectedBlockSize(String algorithm, String provider, int value) {
+ setExpectedSize(EXPECTED_BLOCK_SIZE, algorithm, provider, value);
+ }
+
+ private static void setExpectedBlockSize(String algorithm, int mode, String provider, int value) {
+ setExpectedSize(EXPECTED_BLOCK_SIZE, algorithm, mode, provider, value);
+ }
+
+ private static int getExpectedBlockSize(String algorithm, int mode, String provider) {
+ return getExpectedSize(EXPECTED_BLOCK_SIZE, algorithm, mode, provider);
+ }
+
+ private static Map<String, Integer> EXPECTED_OUTPUT_SIZE = new HashMap<String, Integer>();
+ static {
+ setExpectedOutputSize("AES/CBC/NOPADDING", 0);
+ setExpectedOutputSize("AES/CFB/NOPADDING", 0);
+ setExpectedOutputSize("AES/CTR/NOPADDING", 0);
+ setExpectedOutputSize("AES/CTS/NOPADDING", 0);
+ setExpectedOutputSize("AES/ECB/NOPADDING", 0);
+ setExpectedOutputSize("AES/OFB/NOPADDING", 0);
+ setExpectedOutputSize("AES_128/CBC/NOPADDING", 0);
+ setExpectedOutputSize("AES_128/ECB/NOPADDING", 0);
+ setExpectedOutputSize("AES_256/CBC/NOPADDING", 0);
+ setExpectedOutputSize("AES_256/ECB/NOPADDING", 0);
+
+ setExpectedOutputSize("AES", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES/CBC/PKCS5PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES/CBC/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES/CFB/PKCS5PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES/CFB/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES/CTR/PKCS5PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES/CTR/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES/CTS/PKCS5PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES/CTS/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES/ECB/PKCS5PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES/ECB/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES/GCM/NOPADDING", Cipher.ENCRYPT_MODE, GCM_TAG_SIZE_BITS / 8);
+ setExpectedOutputSize("AES/GCM-SIV/NOPADDING", Cipher.ENCRYPT_MODE, GCM_SIV_TAG_SIZE_BITS / 8);
+ setExpectedOutputSize("AES/OFB/PKCS5PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES/OFB/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES_128/CBC/PKCS5PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES_128/CBC/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES_128/ECB/PKCS5PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES_128/ECB/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES_128/GCM/NOPADDING", Cipher.ENCRYPT_MODE, GCM_TAG_SIZE_BITS / 8);
+ setExpectedOutputSize("AES_128/GCM-SIV/NOPADDING", Cipher.ENCRYPT_MODE, GCM_SIV_TAG_SIZE_BITS / 8);
+ setExpectedOutputSize("AES_256/CBC/PKCS5PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES_256/CBC/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES_256/ECB/PKCS5PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES_256/ECB/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES_256/GCM/NOPADDING", Cipher.ENCRYPT_MODE, GCM_TAG_SIZE_BITS / 8);
+ setExpectedOutputSize("AES_256/GCM-SIV/NOPADDING", Cipher.ENCRYPT_MODE, GCM_SIV_TAG_SIZE_BITS / 8);
+ setExpectedOutputSize("PBEWITHMD5AND128BITAES-CBC-OPENSSL", 16);
+ setExpectedOutputSize("PBEWITHMD5AND192BITAES-CBC-OPENSSL", 16);
+ setExpectedOutputSize("PBEWITHMD5AND256BITAES-CBC-OPENSSL", 16);
+ setExpectedOutputSize("PBEWITHSHA256AND128BITAES-CBC-BC", 16);
+ setExpectedOutputSize("PBEWITHSHA256AND192BITAES-CBC-BC", 16);
+ setExpectedOutputSize("PBEWITHSHA256AND256BITAES-CBC-BC", 16);
+ setExpectedOutputSize("PBEWITHSHAAND128BITAES-CBC-BC", 16);
+ setExpectedOutputSize("PBEWITHSHAAND192BITAES-CBC-BC", 16);
+ setExpectedOutputSize("PBEWITHSHAAND256BITAES-CBC-BC", 16);
+ // AndroidOpenSSL returns zero for the non-block ciphers
+ setExpectedOutputSize("AES/CFB/PKCS5PADDING", Cipher.ENCRYPT_MODE, "AndroidOpenSSL", 0);
+ setExpectedOutputSize("AES/CFB/PKCS7PADDING", Cipher.ENCRYPT_MODE, "AndroidOpenSSL", 0);
+ setExpectedOutputSize("AES/CTR/PKCS5PADDING", Cipher.ENCRYPT_MODE, "AndroidOpenSSL", 0);
+ setExpectedOutputSize("AES/CTR/PKCS7PADDING", Cipher.ENCRYPT_MODE, "AndroidOpenSSL", 0);
+ setExpectedOutputSize("AES/CTS/PKCS5PADDING", Cipher.ENCRYPT_MODE, "AndroidOpenSSL", 0);
+ setExpectedOutputSize("AES/CTS/PKCS7PADDING", Cipher.ENCRYPT_MODE, "AndroidOpenSSL", 0);
+ setExpectedOutputSize("AES/OFB/PKCS5PADDING", Cipher.ENCRYPT_MODE, "AndroidOpenSSL", 0);
+ setExpectedOutputSize("AES/OFB/PKCS7PADDING", Cipher.ENCRYPT_MODE, "AndroidOpenSSL", 0);
+
+ setExpectedOutputSize("AES", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES/CBC/PKCS5PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES/CBC/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES/CFB/PKCS5PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES/CFB/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES/CTR/PKCS5PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES/CTR/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES/CTS/PKCS5PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES/CTS/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES/ECB/PKCS5PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES/ECB/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES/GCM/NOPADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES/GCM-SIV/NOPADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES/OFB/PKCS5PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES/OFB/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES_128/CBC/PKCS5PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES_128/CBC/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES_128/ECB/PKCS5PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES_128/ECB/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES_128/GCM/NOPADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES_128/GCM-SIV/NOPADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES_256/CBC/PKCS5PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES_256/CBC/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES_256/ECB/PKCS5PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES_256/ECB/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES_256/GCM/NOPADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES_256/GCM-SIV/NOPADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("PBEWITHMD5AND128BITAES-CBC-OPENSSL", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("PBEWITHMD5AND192BITAES-CBC-OPENSSL", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("PBEWITHMD5AND256BITAES-CBC-OPENSSL", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("PBEWITHSHA256AND128BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("PBEWITHSHA256AND192BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("PBEWITHSHA256AND256BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("PBEWITHSHAAND128BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("PBEWITHSHAAND192BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("PBEWITHSHAAND256BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("DESEDE/CBC/PKCS5PADDING", Cipher.DECRYPT_MODE, "AndroidOpenSSL", 0);
+ setExpectedOutputSize("DESEDE/CBC/PKCS7PADDING", Cipher.DECRYPT_MODE, "AndroidOpenSSL", 0);
+
+ if (StandardNames.IS_RI) {
+ setExpectedOutputSize("AESWRAP", Cipher.WRAP_MODE, 8);
+ setExpectedOutputSize("AESWRAP", Cipher.UNWRAP_MODE, 0);
+ } else {
+ setExpectedOutputSize("AESWRAP", -1);
+ }
+
+ setExpectedOutputSize("ARC4", 0);
+ setExpectedOutputSize("ARCFOUR", 0);
+ setExpectedOutputSize("CHACHA20", 0);
+ setExpectedOutputSize("CHACHA20/POLY1305/NOPADDING", 0);
+ setExpectedOutputSize("PBEWITHSHAAND40BITRC4", 0);
+ setExpectedOutputSize("PBEWITHSHAAND128BITRC4", 0);
+
+ setExpectedOutputSize("BLOWFISH", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("BLOWFISH", Cipher.DECRYPT_MODE, 0);
+
+ setExpectedOutputSize("DES", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("PBEWITHMD5ANDDES", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("PBEWITHSHA1ANDDES", Cipher.ENCRYPT_MODE, 8);
+
+ setExpectedOutputSize("DES", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("PBEWITHMD5ANDDES", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("PBEWITHSHA1ANDDES", Cipher.DECRYPT_MODE, 0);
+
+ setExpectedOutputSize("DESEDE/CBC/NOPADDING", 0);
+ setExpectedOutputSize("DESEDE/CFB/NOPADDING", 0);
+ setExpectedOutputSize("DESEDE/CTR/NOPADDING", 0);
+ setExpectedOutputSize("DESEDE/CTS/NOPADDING", 0);
+ setExpectedOutputSize("DESEDE/ECB/NOPADDING", 0);
+ setExpectedOutputSize("DESEDE/OFB/NOPADDING", 0);
+
+ setExpectedOutputSize("DESEDE", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("DESEDE/CBC/PKCS5PADDING", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("DESEDE/CBC/PKCS7PADDING", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("DESEDE/CFB/PKCS5PADDING", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("DESEDE/CFB/PKCS7PADDING", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("DESEDE/CTR/PKCS5PADDING", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("DESEDE/CTR/PKCS7PADDING", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("DESEDE/CTS/PKCS5PADDING", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("DESEDE/CTS/PKCS7PADDING", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("DESEDE/ECB/PKCS5PADDING", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("DESEDE/ECB/PKCS7PADDING", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("DESEDE/OFB/PKCS5PADDING", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("DESEDE/OFB/PKCS7PADDING", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("PBEWITHSHAAND2-KEYTRIPLEDES-CBC", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("PBEWITHSHAAND3-KEYTRIPLEDES-CBC", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("PBEWITHMD5ANDTRIPLEDES", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("PBEWITHSHA1ANDDESEDE", Cipher.ENCRYPT_MODE, 8);
+
+ setExpectedOutputSize("DESEDE", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("DESEDE/CBC/PKCS5PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("DESEDE/CBC/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("DESEDE/CFB/PKCS5PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("DESEDE/CFB/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("DESEDE/CTR/PKCS5PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("DESEDE/CTR/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("DESEDE/CTS/PKCS5PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("DESEDE/CTS/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("DESEDE/ECB/PKCS5PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("DESEDE/ECB/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("DESEDE/OFB/PKCS5PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("DESEDE/OFB/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("PBEWITHSHAAND2-KEYTRIPLEDES-CBC", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("PBEWITHSHAAND3-KEYTRIPLEDES-CBC", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("PBEWITHMD5ANDTRIPLEDES", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("PBEWITHSHA1ANDDESEDE", Cipher.DECRYPT_MODE, 0);
+
+ if (StandardNames.IS_RI) {
+ setExpectedOutputSize("DESEDEWRAP", Cipher.WRAP_MODE, 16);
+ setExpectedOutputSize("DESEDEWRAP", Cipher.UNWRAP_MODE, 0);
+ } else {
+ setExpectedOutputSize("DESEDEWRAP", -1);
+ }
+
+ setExpectedOutputSize("RSA", Cipher.ENCRYPT_MODE, 256);
+ setExpectedOutputSize("RSA/ECB/NoPadding", Cipher.ENCRYPT_MODE, 256);
+ setExpectedOutputSize("RSA/ECB/PKCS1Padding", Cipher.ENCRYPT_MODE, 256);
+
+ setExpectedOutputSize("RSA", Cipher.DECRYPT_MODE, 256);
+ setExpectedOutputSize("RSA/ECB/NoPadding", Cipher.DECRYPT_MODE, 256);
+ setExpectedOutputSize("RSA/ECB/PKCS1Padding", Cipher.DECRYPT_MODE, 245);
+ setExpectedOutputSize("RSA/ECB/OAEPPadding", Cipher.DECRYPT_MODE, 256);
+
+ // SunJCE returns the full for size even when PKCS1Padding is specified
+ setExpectedOutputSize("RSA/ECB/PKCS1Padding", Cipher.DECRYPT_MODE, "SunJCE", 256);
+
+ // BC strips the leading 0 for us even when NoPadding is specified
+ setExpectedOutputSize("RSA", Cipher.DECRYPT_MODE, "BC", 255);
+ setExpectedOutputSize("RSA/ECB/NoPadding", Cipher.DECRYPT_MODE, "BC", 255);
+
+ // OAEP padding modes change the output and block size. SHA-1 is the default.
+ setExpectedOutputSize("RSA/ECB/OAEPPadding", Cipher.DECRYPT_MODE, 214);
+ setExpectedOutputSize("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", Cipher.DECRYPT_MODE, 214);
+ setExpectedOutputSize("RSA/ECB/OAEPWithSHA-224AndMGF1Padding", Cipher.DECRYPT_MODE, 198);
+ setExpectedOutputSize("RSA/ECB/OAEPWithSHA-256AndMGF1Padding", Cipher.DECRYPT_MODE, 190);
+ setExpectedOutputSize("RSA/ECB/OAEPWithSHA-384AndMGF1Padding", Cipher.DECRYPT_MODE, 158);
+ setExpectedOutputSize("RSA/ECB/OAEPWithSHA-512AndMGF1Padding", Cipher.DECRYPT_MODE, 126);
+
+ setExpectedOutputSize("RSA/ECB/OAEPPadding", Cipher.ENCRYPT_MODE, 256);
+ setExpectedOutputSize("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", Cipher.ENCRYPT_MODE, 256);
+ setExpectedOutputSize("RSA/ECB/OAEPWithSHA-224AndMGF1Padding", Cipher.ENCRYPT_MODE, 256);
+ setExpectedOutputSize("RSA/ECB/OAEPWithSHA-256AndMGF1Padding", Cipher.ENCRYPT_MODE, 256);
+ setExpectedOutputSize("RSA/ECB/OAEPWithSHA-384AndMGF1Padding", Cipher.ENCRYPT_MODE, 256);
+ setExpectedOutputSize("RSA/ECB/OAEPWithSHA-512AndMGF1Padding", Cipher.ENCRYPT_MODE, 256);
+ }
+
+ private static void setExpectedOutputSize(String algorithm, int value) {
+ setExpectedSize(EXPECTED_OUTPUT_SIZE, algorithm, value);
+ }
+
+ private static void setExpectedOutputSize(String algorithm, int mode, int value) {
+ setExpectedSize(EXPECTED_OUTPUT_SIZE, algorithm, mode, value);
+ }
+
+ private static void setExpectedOutputSize(String algorithm, int mode, String provider, int value) {
+ setExpectedSize(EXPECTED_OUTPUT_SIZE, algorithm, mode, provider, value);
+ }
+
+ private static int getExpectedOutputSize(String algorithm, int mode, String provider) {
+ return getExpectedSize(EXPECTED_OUTPUT_SIZE, algorithm, mode, provider);
+ }
+
+ private static byte[] ORIGINAL_PLAIN_TEXT = new byte[] { 0x0a, 0x0b, 0x0c };
+ private static byte[] SIXTEEN_BYTE_BLOCK_PLAIN_TEXT = new byte[] { 0x0a, 0x0b, 0x0c, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+ private static byte[] EIGHT_BYTE_BLOCK_PLAIN_TEXT = new byte[] { 0x0a, 0x0b, 0x0c, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+ private static byte[] PKCS1_BLOCK_TYPE_00_PADDED_PLAIN_TEXT = new byte[] {
+ 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, 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, 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, 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, 0, 0x0a, 0x0b, 0x0c
+ };
+ private static byte[] PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT = new byte[] {
+ (byte) 0x00, (byte) 0x01, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c
+ };
+ private static byte[] PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT = new byte[] {
+ (byte) 0x00, (byte) 0x02, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c
+ };
+
+
+ private static byte[] getActualPlainText(String algorithm) {
+ // Block mode AES with NoPadding needs to match underlying block size
+ if (algorithm.equals("AES")
+ || algorithm.equals("AES/CBC/NOPADDING")
+ || algorithm.equals("AES/CTS/NOPADDING")
+ || algorithm.equals("AES/ECB/NOPADDING")
+ || algorithm.equals("AES_128/CBC/NOPADDING")
+ || algorithm.equals("AES_128/ECB/NOPADDING")
+ || algorithm.equals("AES_256/CBC/NOPADDING")
+ || algorithm.equals("AES_256/ECB/NOPADDING")) {
+ return SIXTEEN_BYTE_BLOCK_PLAIN_TEXT;
+ }
+ if (algorithm.equals("DESEDE")
+ || algorithm.equals("DESEDE/CBC/NOPADDING")
+ || algorithm.equals("DESEDE/ECB/NOPADDING")) {
+ return EIGHT_BYTE_BLOCK_PLAIN_TEXT;
+ }
+ return ORIGINAL_PLAIN_TEXT;
+ }
+
+ private static byte[] getExpectedPlainText(String algorithm, String provider) {
+ // Block mode AES with NoPadding needs to match underlying block size
+ if (algorithm.equals("AES")
+ || algorithm.equals("AES/CBC/NOPADDING")
+ || algorithm.equals("AES/CTS/NOPADDING")
+ || algorithm.equals("AES/ECB/NOPADDING")
+ || algorithm.equals("AES_128/CBC/NOPADDING")
+ || algorithm.equals("AES_128/ECB/NOPADDING")
+ || algorithm.equals("AES_256/CBC/NOPADDING")
+ || algorithm.equals("AES_256/ECB/NOPADDING")) {
+ return SIXTEEN_BYTE_BLOCK_PLAIN_TEXT;
+ }
+ if (algorithm.equals("DESEDE")
+ || algorithm.equals("DESEDE/CBC/NOPADDING")
+ || algorithm.equals("DESEDE/ECB/NOPADDING")) {
+ return EIGHT_BYTE_BLOCK_PLAIN_TEXT;
+ }
+ // BC strips the leading 0 for us even when NoPadding is specified
+ if (!provider.equals("BC") && algorithm.equals("RSA/ECB/NOPADDING")) {
+ return PKCS1_BLOCK_TYPE_00_PADDED_PLAIN_TEXT;
+ }
+ return ORIGINAL_PLAIN_TEXT;
+ }
+
+ private static AlgorithmParameterSpec getEncryptAlgorithmParameterSpec(String algorithm) {
+ if (isPBE(algorithm)) {
+ final byte[] salt = new byte[8];
+ new SecureRandom().nextBytes(salt);
+ return new PBEParameterSpec(salt, 1024);
+ }
+ if (algorithm.equals("AES/GCM/NOPADDING")
+ || algorithm.equals("AES_128/GCM/NOPADDING")
+ || algorithm.equals("AES_256/GCM/NOPADDING")) {
+ final byte[] iv = new byte[12];
+ new SecureRandom().nextBytes(iv);
+ return new GCMParameterSpec(GCM_TAG_SIZE_BITS, iv);
+ }
+ if (algorithm.equals("AES/GCM-SIV/NOPADDING")
+ || algorithm.equals("AES_128/GCM-SIV/NOPADDING")
+ || algorithm.equals("AES_256/GCM-SIV/NOPADDING")) {
+ final byte[] iv = new byte[12];
+ new SecureRandom().nextBytes(iv);
+ return new GCMParameterSpec(GCM_SIV_TAG_SIZE_BITS, iv);
+ }
+ if (algorithm.equals("AES/CBC/NOPADDING")
+ || algorithm.equals("AES/CBC/PKCS5PADDING")
+ || algorithm.equals("AES/CBC/PKCS7PADDING")
+ || algorithm.equals("AES/CFB/NOPADDING")
+ || algorithm.equals("AES/CTR/NOPADDING")
+ || algorithm.equals("AES/CTS/NOPADDING")
+ || algorithm.equals("AES/OFB/NOPADDING")
+ || algorithm.equals("AES_128/CBC/NOPADDING")
+ || algorithm.equals("AES_128/CBC/PKCS5PADDING")
+ || algorithm.equals("AES_128/CBC/PKCS7PADDING")
+ || algorithm.equals("AES_256/CBC/NOPADDING")
+ || algorithm.equals("AES_256/CBC/PKCS5PADDING")
+ || algorithm.equals("AES_256/CBC/PKCS7PADDING")) {
+ final byte[] iv = new byte[16];
+ new SecureRandom().nextBytes(iv);
+ return new IvParameterSpec(iv);
+ }
+ if (algorithm.equals("DESEDE/CBC/NOPADDING")
+ || algorithm.equals("DESEDE/CBC/PKCS5PADDING")
+ || algorithm.equals("DESEDE/CBC/PKCS7PADDING")
+ || algorithm.equals("DESEDE/CFB/NOPADDING")
+ || algorithm.equals("DESEDE/CTR/NOPADDING")
+ || algorithm.equals("DESEDE/CTS/NOPADDING")
+ || algorithm.equals("DESEDE/OFB/NOPADDING")) {
+ final byte[] iv = new byte[8];
+ new SecureRandom().nextBytes(iv);
+ return new IvParameterSpec(iv);
+ }
+ if (algorithm.equals("CHACHA20")
+ || algorithm.equals("CHACHA20/POLY1305/NOPADDING")) {
+ final byte[] iv = new byte[12];
+ new SecureRandom().nextBytes(iv);
+ return new IvParameterSpec(iv);
+ }
+ return null;
+ }
+
+ private static AlgorithmParameterSpec getDecryptAlgorithmParameterSpec(AlgorithmParameterSpec encryptSpec,
+ Cipher encryptCipher) {
+ String algorithm = encryptCipher.getAlgorithm().toUpperCase(Locale.US);
+ if (isPBE(algorithm)) {
+ return encryptSpec;
+ }
+ if (isOnlyWrappingAlgorithm(algorithm)) {
+ return null;
+ }
+ byte[] iv = encryptCipher.getIV();
+ if (iv != null) {
+ if ("AES/GCM/NOPADDING".equals(algorithm)
+ || "AES_128/GCM/NOPADDING".equals(algorithm)
+ || "AES_256/GCM/NOPADDING".equals(algorithm)) {
+ return new GCMParameterSpec(GCM_TAG_SIZE_BITS, iv);
+ }
+ if ("AES/GCM-SIV/NOPADDING".equals(algorithm)
+ || "AES_128/GCM-SIV/NOPADDING".equals(algorithm)
+ || "AES_256/GCM-SIV/NOPADDING".equals(algorithm)) {
+ return new GCMParameterSpec(GCM_SIV_TAG_SIZE_BITS, iv);
+ }
+ return new IvParameterSpec(iv);
+ }
+ return null;
+ }
+
+ /*
+ * This must be below everything else to make sure the other static blocks
+ * have run first.
+ */
+ private static final boolean IS_UNLIMITED;
+ static {
+ boolean is_unlimited;
+ if (StandardNames.IS_RI) {
+ try {
+ String algorithm = "PBEWITHMD5ANDTRIPLEDES";
+ Cipher.getInstance(algorithm).init(getEncryptMode(algorithm),
+ getEncryptKey(algorithm),
+ getEncryptAlgorithmParameterSpec(algorithm));
+ is_unlimited = true;
+ } catch (Exception e) {
+ is_unlimited = false;
+ System.out.println("WARNING: Some tests disabled due to lack of "
+ + "'Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files'");
+ }
+ } else {
+ is_unlimited = true;
+ }
+ IS_UNLIMITED = is_unlimited;
+ }
+
+ @Test
+ public void test_getInstance() throws Exception {
+ final ByteArrayOutputStream errBuffer = new ByteArrayOutputStream();
+ PrintStream out = new PrintStream(errBuffer);
+
+ Set<String> seenBaseCipherNames = new HashSet<String>();
+ Set<String> seenCiphersWithModeAndPadding = new HashSet<String>();
+
+ Provider[] providers = Security.getProviders();
+ for (Provider provider : providers) {
+ Set<Provider.Service> services = provider.getServices();
+ for (Provider.Service service : services) {
+ String type = service.getType();
+ if (!type.equals("Cipher")) {
+ continue;
+ }
+
+ String algorithm = service.getAlgorithm().toUpperCase(Locale.US);
+
+ /*
+ * Any specific modes and paddings aren't tested directly here,
+ * but we need to make sure we see the bare algorithm from some
+ * provider. We will test each mode specifically when we get the
+ * base cipher.
+ */
+ final int firstSlash = algorithm.indexOf('/');
+ if (firstSlash == -1) {
+ seenBaseCipherNames.add(algorithm);
+ } else {
+ final int secondSlash = algorithm.indexOf('/', firstSlash + 1);
+ if (secondSlash > 0) {
+ // Only look for a base Cipher if there are two slashes, to avoid SunJCE
+ // quirks like PBEWithHmacSHA512/224AndAES_128
+ final String baseCipherName = algorithm.substring(0, firstSlash);
+ if (!seenBaseCipherNames.contains(baseCipherName)
+ && !(baseCipherName.equals("AES_128")
+ || baseCipherName.equals("AES_192")
+ || baseCipherName.equals("AES_256"))) {
+ seenCiphersWithModeAndPadding.add(baseCipherName);
+ }
+ if (!Conscrypt.isConscrypt(provider)) {
+ continue;
+ }
+ }
+ }
+
+ if (provider.getName().equals("SunJCE")) {
+ // The SunJCE provider acts in numerous idiosyncratic ways that don't
+ // match any other provider. Examples include returning non-null IVs
+ // when no IV was provided on init, NullPointerExceptions when null
+ // SecureRandoms are supplied (but only to PBE ciphers), and not
+ // supplying KeyGenerators for some algorithms. We aren't sufficiently
+ // interested in verifying this provider's behavior to adapt the
+ // tests and Oracle presumably tests them well anyway, so just skip
+ // verifying them.
+ continue;
+ }
+
+ try {
+ test_Cipher_Algorithm(provider, algorithm);
+ } catch (Throwable e) {
+ out.append("Error encountered checking " + algorithm
+ + " with provider " + provider.getName() + "\n");
+ e.printStackTrace(out);
+ }
+
+ Set<String> modes = StandardNames.getModesForCipher(algorithm);
+ if (modes != null) {
+ for (String mode : modes) {
+ Set<String> paddings = StandardNames.getPaddingsForCipher(algorithm);
+ if (paddings != null) {
+ for (String padding : paddings) {
+ final String algorithmName = algorithm + "/" + mode + "/" + padding;
+ try {
+ if (isSupported(algorithmName, provider.getName())) {
+ test_Cipher_Algorithm(provider, algorithmName);
+ }
+ } catch (Throwable e) {
+ out.append("Error encountered checking " + algorithmName
+ + " with provider " + provider.getName() + "\n");
+ e.printStackTrace(out);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ seenCiphersWithModeAndPadding.removeAll(seenBaseCipherNames);
+ assertEquals("Ciphers seen with mode and padding but not base cipher",
+ Collections.EMPTY_SET, seenCiphersWithModeAndPadding);
+
+ out.flush();
+ if (errBuffer.size() > 0) {
+ throw new Exception("Errors encountered:\n\n" + errBuffer.toString() + "\n\n");
+ }
+ }
+
+ private void test_Cipher_Algorithm(Provider provider, String algorithm) throws Exception {
+ if (algorithm.equals("RSA") && provider.getName().equals("BC")) {
+ // http://b/9097343 BC's Cipher.RSA defaults to NoPadding
+ // which makes it fail the key wrapping test if the
+ // generated AES key to wrap starts with a leading
+ // zero. For the purposes of the test, use the same
+ // default behavior as the RI. Real code really should
+ // specify the exact mode and padding they need and not
+ // rely on defaults. http://b/9097343
+ algorithm = "RSA/ECB/PKCS1Padding";
+ }
+
+ // SunMSCAPI seems to have different opinion on what RSA should do compared to other
+ // providers. As such it fails many tests, so we will skip it for now.
+ if (algorithm.startsWith("RSA") && provider.getName().equals("SunMSCAPI")) {
+ return;
+ }
+
+ // Cipher.getInstance(String)
+ Cipher c1 = Cipher.getInstance(algorithm);
+ if (provider.equals(c1.getProvider())) {
+ assertEquals(algorithm, c1.getAlgorithm());
+ test_Cipher(c1);
+ }
+
+ // Cipher.getInstance(String, Provider)
+ Cipher c2 = Cipher.getInstance(algorithm, provider);
+ assertEquals(algorithm, c2.getAlgorithm());
+ assertEquals(provider, c2.getProvider());
+ test_Cipher(c2);
+
+ // Cipher.getInstance(String, String)
+ Cipher c3 = Cipher.getInstance(algorithm, provider.getName());
+ assertEquals(algorithm, c3.getAlgorithm());
+ assertEquals(provider, c3.getProvider());
+ test_Cipher(c3);
+ }
+
+ private void test_Cipher(Cipher c) throws Exception {
+ String algorithm = c.getAlgorithm().toUpperCase(Locale.US);
+ String providerName = c.getProvider().getName();
+ if (!isSupported(algorithm, providerName)) {
+ return;
+ }
+ String cipherID = algorithm + ":" + providerName;
+
+ try {
+ c.getOutputSize(0);
+ fail("getOutputSize() should throw if called before Cipher initialization");
+ } catch (IllegalStateException expected) {
+ }
+
+ // TODO: test keys from different factories (e.g. OpenSSLRSAPrivateKey vs BCRSAPrivateKey)
+ Key encryptKey = getEncryptKey(algorithm);
+
+ AlgorithmParameterSpec encryptSpec = getEncryptAlgorithmParameterSpec(algorithm);
+ int encryptMode = getEncryptMode(algorithm);
+
+ // Bouncycastle doesn't return a default PBEParameterSpec
+ if (isPBE(algorithm) && !"BC".equals(providerName)) {
+ assertNotNull(cipherID + " getParameters()", c.getParameters());
+ assertNotNull(c.getParameters().getParameterSpec(PBEParameterSpec.class));
+ } else {
+ assertNull(cipherID + " getParameters()", c.getParameters());
+ }
+ try {
+ assertNull(cipherID + " getIV()", c.getIV());
+ } catch (NullPointerException e) {
+ // Bouncycastle apparently has a bug here with AESWRAP, et al.
+ if (!("BC".equals(providerName) && isOnlyWrappingAlgorithm(algorithm))) {
+ throw e;
+ }
+ }
+
+ test_Cipher_init_NullParameters(c, encryptMode, encryptKey);
+
+ c.init(encryptMode, encryptKey, encryptSpec);
+ assertEquals(cipherID + " getBlockSize() encryptMode",
+ getExpectedBlockSize(algorithm, encryptMode, providerName), c.getBlockSize());
+ assertTrue(cipherID + " getOutputSize(0) encryptMode",
+ getExpectedOutputSize(algorithm, encryptMode, providerName) <= c.getOutputSize(0));
+ if ((algorithm.endsWith("/PKCS5PADDING") || algorithm.endsWith("/PKCS7PADDING"))
+ && isStreamMode(algorithm)) {
+ assertEquals(getExpectedOutputSize(algorithm, encryptMode, providerName),
+ c.doFinal(new byte[1]).length);
+ }
+
+ if (isPBE(algorithm)) {
+ if (algorithm.endsWith("RC4")) {
+ assertNull(cipherID + " getIV()", c.getIV());
+ } else {
+ assertNotNull(cipherID + " getIV()", c.getIV());
+ }
+ } else if (encryptSpec instanceof IvParameterSpec) {
+ assertEquals(cipherID + " getIV()",
+ Arrays.toString(((IvParameterSpec) encryptSpec).getIV()),
+ Arrays.toString(c.getIV()));
+ } else if (encryptSpec instanceof GCMParameterSpec) {
+ assertNotNull(c.getIV());
+ assertEquals(cipherID + " getIV()",
+ Arrays.toString(((GCMParameterSpec) encryptSpec).getIV()),
+ Arrays.toString(c.getIV()));
+ } else {
+ try {
+ assertNull(cipherID + " getIV()", c.getIV());
+ } catch (NullPointerException e) {
+ // Bouncycastle apparently has a bug here with AESWRAP, et al.
+ if (!("BC".equals(providerName) && isOnlyWrappingAlgorithm(algorithm))) {
+ throw e;
+ }
+ }
+ }
+
+ AlgorithmParameters encParams = c.getParameters();
+ assertCorrectAlgorithmParameters(providerName, cipherID, encryptSpec, encParams);
+
+ AlgorithmParameterSpec decryptSpec = getDecryptAlgorithmParameterSpec(encryptSpec, c);
+ int decryptMode = getDecryptMode(algorithm);
+
+ Key decryptKey = getDecryptKey(algorithm);
+
+ test_Cipher_init_Decrypt_NullParameters(c, decryptMode, decryptKey, decryptSpec != null);
+
+ c.init(decryptMode, decryptKey, decryptSpec);
+ assertEquals(cipherID + " getBlockSize() decryptMode",
+ getExpectedBlockSize(algorithm, decryptMode, providerName), c.getBlockSize());
+ assertEquals(cipherID + " getOutputSize(0) decryptMode",
+ getExpectedOutputSize(algorithm, decryptMode, providerName), c.getOutputSize(0));
+
+ if (isPBE(algorithm)) {
+ if (algorithm.endsWith("RC4")) {
+ assertNull(cipherID + " getIV()", c.getIV());
+ } else {
+ assertNotNull(cipherID + " getIV()", c.getIV());
+ }
+ } else if (decryptSpec instanceof IvParameterSpec) {
+ assertEquals(cipherID + " getIV()",
+ Arrays.toString(((IvParameterSpec) decryptSpec).getIV()),
+ Arrays.toString(c.getIV()));
+ } else if (decryptSpec instanceof GCMParameterSpec) {
+ assertNotNull(c.getIV());
+ assertEquals(cipherID + " getIV()",
+ Arrays.toString(((GCMParameterSpec) decryptSpec).getIV()),
+ Arrays.toString(c.getIV()));
+ } else {
+ try {
+ assertNull(cipherID + " getIV()", c.getIV());
+ } catch (NullPointerException e) {
+ // Bouncycastle apparently has a bug here with AESWRAP, et al.
+ if (!("BC".equals(providerName) && isOnlyWrappingAlgorithm(algorithm))) {
+ throw e;
+ }
+ }
+ }
+
+ AlgorithmParameters decParams = c.getParameters();
+ assertCorrectAlgorithmParameters(providerName, cipherID, decryptSpec, decParams);
+
+ assertNull(cipherID, c.getExemptionMechanism());
+
+ // Test wrapping a key. Every cipher should be able to wrap. Except those that can't.
+ /* Bouncycastle is broken for wrapping because getIV() fails. */
+ if (isSupportedForWrapping(algorithm) && !providerName.equals("BC")) {
+ // Generate a small SecretKey for AES.
+ KeyGenerator kg = KeyGenerator.getInstance("AES");
+ kg.init(128);
+ SecretKey sk = kg.generateKey();
+
+ // Wrap it. Use a new encrypt spec so that AEAD algorithms that prohibit IV reuse
+ // don't complain.
+ encryptSpec = getEncryptAlgorithmParameterSpec(algorithm);
+ c.init(Cipher.WRAP_MODE, encryptKey, encryptSpec);
+ byte[] cipherText = c.wrap(sk);
+
+ // Unwrap it
+ c.init(Cipher.UNWRAP_MODE, decryptKey, getDecryptAlgorithmParameterSpec(encryptSpec, c));
+ Key decryptedKey = c.unwrap(cipherText, sk.getAlgorithm(), Cipher.SECRET_KEY);
+
+ assertEquals(cipherID
+ + " sk.getAlgorithm()=" + sk.getAlgorithm()
+ + " decryptedKey.getAlgorithm()=" + decryptedKey.getAlgorithm()
+ + " encryptKey.getEncoded()=" + Arrays.toString(sk.getEncoded())
+ + " decryptedKey.getEncoded()=" + Arrays.toString(decryptedKey.getEncoded()),
+ sk, decryptedKey);
+ }
+
+ if (!isOnlyWrappingAlgorithm(algorithm)) {
+ // Use a new encrypt spec so that AEAD algorithms that prohibit IV reuse don't complain
+ encryptSpec = getEncryptAlgorithmParameterSpec(algorithm);
+ c.init(Cipher.ENCRYPT_MODE, encryptKey, encryptSpec);
+ if (isAEAD(algorithm)) {
+ c.updateAAD(new byte[24]);
+ }
+ byte[] cipherText = c.doFinal(getActualPlainText(algorithm));
+ if (!isRandomizedEncryption(algorithm) && !isAEAD(algorithm)) {
+ byte[] cipherText2 = c.doFinal(getActualPlainText(algorithm));
+ assertEquals(cipherID, Arrays.toString(cipherText), Arrays.toString(cipherText2));
+ }
+ decryptSpec = getDecryptAlgorithmParameterSpec(encryptSpec, c);
+ c.init(Cipher.DECRYPT_MODE, decryptKey, decryptSpec);
+ if (isAEAD(algorithm)) {
+ c.updateAAD(new byte[24]);
+ }
+ byte[] decryptedPlainText = c.doFinal(cipherText);
+ assertEquals(cipherID,
+ Arrays.toString(getExpectedPlainText(algorithm, providerName)),
+ Arrays.toString(decryptedPlainText));
+ if (isAEAD(algorithm)) {
+ c.updateAAD(new byte[24]);
+ }
+ byte[] decryptedPlainText2 = c.doFinal(cipherText);
+ assertEquals(cipherID,
+ Arrays.toString(decryptedPlainText),
+ Arrays.toString(decryptedPlainText2));
+
+ // Use a new encrypt spec so that AEAD algorithms that prohibit IV reuse don't complain
+ encryptSpec = getEncryptAlgorithmParameterSpec(algorithm);
+ test_Cipher_ShortBufferException(c, algorithm, Cipher.ENCRYPT_MODE, encryptSpec,
+ encryptKey, getActualPlainText(algorithm));
+ decryptSpec = getDecryptAlgorithmParameterSpec(encryptSpec, c);
+ test_Cipher_ShortBufferException(c, algorithm, Cipher.DECRYPT_MODE, decryptSpec,
+ decryptKey, cipherText);
+
+ test_Cipher_aborted_doFinal(c, algorithm, providerName, encryptKey, decryptKey);
+ }
+ }
+
+ private void assertCorrectAlgorithmParameters(String providerName, String cipherID,
+ final AlgorithmParameterSpec spec, AlgorithmParameters params)
+ throws InvalidParameterSpecException, Exception {
+ if (spec == null) {
+ return;
+ }
+
+ // Bouncycastle has a bug where PBE algorithms sometimes return null parameters.
+ if ("BC".equals(providerName) && isPBE(cipherID) && params == null) {
+ return;
+ }
+
+ assertNotNull(cipherID + " getParameters() should not be null", params);
+
+ if (spec instanceof GCMParameterSpec) {
+ GCMParameterSpec gcmDecryptSpec = params.getParameterSpec(GCMParameterSpec.class);
+ assertEquals(cipherID + " getIV()", Arrays.toString(((GCMParameterSpec) spec).getIV()),
+ Arrays.toString(gcmDecryptSpec.getIV()));
+ assertEquals(cipherID + " getTLen()", ((GCMParameterSpec) spec).getTLen(),
+ gcmDecryptSpec.getTLen());
+ } else if (spec instanceof IvParameterSpec) {
+ IvParameterSpec ivDecryptSpec = params.getParameterSpec(IvParameterSpec.class);
+ assertEquals(cipherID + " getIV()", Arrays.toString(((IvParameterSpec) spec).getIV()),
+ Arrays.toString(ivDecryptSpec.getIV()));
+ } else if (spec instanceof PBEParameterSpec) {
+ // Bouncycastle seems to be undecided about whether it returns this
+ // or not
+ if (!"BC".equals(providerName)) {
+ assertNotNull(cipherID + " getParameters()", params);
+ }
+ } else if (spec instanceof OAEPParameterSpec) {
+ assertOAEPParametersEqual((OAEPParameterSpec) spec,
+ params.getParameterSpec(OAEPParameterSpec.class));
+ } else {
+ fail("Unhandled algorithm specification class: " + spec.getClass().getName());
+ }
+ }
+
+ private static void assertOAEPParametersEqual(OAEPParameterSpec expectedOaepSpec,
+ OAEPParameterSpec actualOaepSpec) throws Exception {
+ assertEquals(expectedOaepSpec.getDigestAlgorithm(), actualOaepSpec.getDigestAlgorithm());
+
+ assertEquals(expectedOaepSpec.getMGFAlgorithm(), actualOaepSpec.getMGFAlgorithm());
+ if ("MGF1".equals(expectedOaepSpec.getMGFAlgorithm())) {
+ MGF1ParameterSpec expectedMgf1Spec = (MGF1ParameterSpec) expectedOaepSpec
+ .getMGFParameters();
+ MGF1ParameterSpec actualMgf1Spec = (MGF1ParameterSpec) actualOaepSpec
+ .getMGFParameters();
+ assertEquals(expectedMgf1Spec.getDigestAlgorithm(),
+ actualMgf1Spec.getDigestAlgorithm());
+ } else {
+ fail("Unknown MGF algorithm: " + expectedOaepSpec.getMGFAlgorithm());
+ }
+
+ if (expectedOaepSpec.getPSource() instanceof PSource.PSpecified
+ && actualOaepSpec.getPSource() instanceof PSource.PSpecified) {
+ assertEquals(
+ Arrays.toString(
+ ((PSource.PSpecified) expectedOaepSpec.getPSource()).getValue()),
+ Arrays.toString(
+ ((PSource.PSpecified) actualOaepSpec.getPSource()).getValue()));
+ } else {
+ fail("Unknown PSource type");
+ }
+ }
+
+ /**
+ * Try various .init(...) calls with null parameters to make sure it is
+ * handled.
+ */
+ private void test_Cipher_init_NullParameters(Cipher c, int encryptMode, Key encryptKey)
+ throws Exception {
+ try {
+ c.init(encryptMode, encryptKey, (AlgorithmParameterSpec) null);
+ } catch (InvalidAlgorithmParameterException e) {
+ if (!isPBE(c.getAlgorithm())) {
+ throw e;
+ }
+ }
+
+ try {
+ c.init(encryptMode, encryptKey, (AlgorithmParameterSpec) null, (SecureRandom) null);
+ } catch (InvalidAlgorithmParameterException e) {
+ if (!isPBE(c.getAlgorithm())) {
+ throw e;
+ }
+ }
+
+ try {
+ c.init(encryptMode, encryptKey, (AlgorithmParameters) null);
+ } catch (InvalidAlgorithmParameterException e) {
+ if (!isPBE(c.getAlgorithm())) {
+ throw e;
+ }
+ }
+
+ try {
+ c.init(encryptMode, encryptKey, (AlgorithmParameters) null, (SecureRandom) null);
+ } catch (InvalidAlgorithmParameterException e) {
+ if (!isPBE(c.getAlgorithm())) {
+ throw e;
+ }
+ }
+ }
+
+ private void test_Cipher_init_Decrypt_NullParameters(Cipher c, int decryptMode, Key encryptKey,
+ boolean needsParameters) throws Exception {
+ try {
+ c.init(decryptMode, encryptKey, (AlgorithmParameterSpec) null);
+ if (needsParameters) {
+ fail("Should throw InvalidAlgorithmParameterException with null parameters");
+ }
+ } catch (InvalidAlgorithmParameterException e) {
+ if (!needsParameters) {
+ throw e;
+ }
+ }
+
+ try {
+ c.init(decryptMode, encryptKey, (AlgorithmParameterSpec) null, (SecureRandom) null);
+ if (needsParameters) {
+ fail("Should throw InvalidAlgorithmParameterException with null parameters");
+ }
+ } catch (InvalidAlgorithmParameterException e) {
+ if (!needsParameters) {
+ throw e;
+ }
+ }
+
+ try {
+ c.init(decryptMode, encryptKey, (AlgorithmParameters) null);
+ if (needsParameters) {
+ fail("Should throw InvalidAlgorithmParameterException with null parameters");
+ }
+ } catch (InvalidAlgorithmParameterException e) {
+ if (!needsParameters) {
+ throw e;
+ }
+ }
+
+ try {
+ c.init(decryptMode, encryptKey, (AlgorithmParameters) null, (SecureRandom) null);
+ if (needsParameters) {
+ fail("Should throw InvalidAlgorithmParameterException with null parameters");
+ }
+ } catch (InvalidAlgorithmParameterException e) {
+ if (!needsParameters) {
+ throw e;
+ }
+ }
+ }
+
+ // Checks that the Cipher throws ShortBufferException when given a too-short buffer
+ private void test_Cipher_ShortBufferException(Cipher c, String algorithm, int encryptMode,
+ AlgorithmParameterSpec spec, Key key, byte[] text) throws Exception {
+ c.init(encryptMode, key, spec);
+ if (isAEAD(algorithm)) {
+ c.updateAAD(new byte[24]);
+ }
+ if (c.getOutputSize(text.length) > 0) {
+ byte[] output;
+ if (algorithm.startsWith("RSA/")) {
+ // RSA encryption pads the input data to a full block before encrypting,
+ // so unlike most algorithms, getOutputSize can't determine how much space
+ // is necessary until the data is actually decrypted.
+ output = new byte[1];
+ } else {
+ // Other algorithms can much more easily forsee how much output data there
+ // will be, so don't let them get away with being overly conservative.
+ output = new byte[c.getOutputSize(text.length) - 1];
+ }
+ try {
+ c.doFinal(text, 0, text.length, output);
+ fail("Short buffer should have thrown ShortBufferException");
+ } catch (ShortBufferException expected) {
+ // Ignored
+ }
+ }
+ }
+
+ // Checks that if the cipher operation is aborted by a ShortBufferException the output
+ // is still correct.
+ private void test_Cipher_aborted_doFinal(Cipher c, String algorithm, String provider,
+ Key encryptKey, Key decryptKey) throws Exception {
+ byte[] text = getActualPlainText(algorithm);
+ AlgorithmParameterSpec encryptSpec = getEncryptAlgorithmParameterSpec(algorithm);
+ c.init(Cipher.ENCRYPT_MODE, encryptKey, encryptSpec);
+ if (isAEAD(algorithm)) {
+ c.updateAAD(new byte[24]);
+ }
+ try {
+ c.doFinal(text, 0, text.length, new byte[0]);
+ fail("Short buffer should have thrown ShortBufferException");
+ } catch (ShortBufferException expected) {
+ // Ignored
+ }
+ byte[] cipherText = c.doFinal(text);
+ c.init(Cipher.DECRYPT_MODE, decryptKey, getDecryptAlgorithmParameterSpec(encryptSpec, c));
+ if (isAEAD(algorithm)) {
+ c.updateAAD(new byte[24]);
+ }
+ byte[] plainText = c.doFinal(cipherText);
+ byte[] expectedPlainText = getExpectedPlainText(algorithm, provider);
+ assertTrue("Expected " + Arrays.toString(expectedPlainText)
+ + " but was " + Arrays.toString(plainText),
+ Arrays.equals(expectedPlainText, plainText));
+ }
+
+ @Test
+ public void testInputPKCS1Padding() throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testInputPKCS1Padding(provider);
+ }
+ }
+
+ private void testInputPKCS1Padding(String provider) throws Exception {
+ // Type 1 is for signatures (PrivateKey to "encrypt")
+ testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT, getDecryptKey("RSA"), getEncryptKey("RSA"));
+ try {
+ testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT, getDecryptKey("RSA"), getEncryptKey("RSA"));
+ fail();
+ } catch (BadPaddingException expected) {
+ }
+
+ // Type 2 is for enciphering (PublicKey to "encrypt")
+ testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT, getEncryptKey("RSA"), getDecryptKey("RSA"));
+ try {
+ testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT, getEncryptKey("RSA"), getDecryptKey("RSA"));
+ fail();
+ } catch (BadPaddingException expected) {
+ }
+ }
+
+ private void testInputPKCS1Padding(String provider, byte[] prePaddedPlainText, Key encryptKey, Key decryptKey) throws Exception {
+ Cipher encryptCipher = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+ encryptCipher.init(Cipher.ENCRYPT_MODE, encryptKey);
+ byte[] cipherText = encryptCipher.doFinal(prePaddedPlainText);
+ encryptCipher.update(prePaddedPlainText);
+ encryptCipher.init(Cipher.ENCRYPT_MODE, encryptKey);
+ byte[] cipherText2 = encryptCipher.doFinal(prePaddedPlainText);
+ assertEquals(Arrays.toString(cipherText),
+ Arrays.toString(cipherText2));
+
+ Cipher decryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
+ decryptCipher.init(Cipher.DECRYPT_MODE, decryptKey);
+ byte[] plainText = decryptCipher.doFinal(cipherText);
+ assertEquals(Arrays.toString(ORIGINAL_PLAIN_TEXT),
+ Arrays.toString(plainText));
+ decryptCipher.update(prePaddedPlainText);
+ decryptCipher.init(Cipher.DECRYPT_MODE, decryptKey);
+ byte[] plainText2 = decryptCipher.doFinal(cipherText);
+ assertEquals(Arrays.toString(plainText),
+ Arrays.toString(plainText2));
+ }
+
+ @Test
+ public void testOutputPKCS1Padding() throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testOutputPKCS1Padding(provider);
+ }
+ }
+
+ private void testOutputPKCS1Padding(String provider) throws Exception {
+ // Type 1 is for signatures (PrivateKey to "encrypt")
+ testOutputPKCS1Padding(provider, (byte) 1, getDecryptKey("RSA"), getEncryptKey("RSA"));
+ // Type 2 is for enciphering (PublicKey to "encrypt")
+ testOutputPKCS1Padding(provider, (byte) 2, getEncryptKey("RSA"), getDecryptKey("RSA"));
+ }
+
+ private void testOutputPKCS1Padding(String provider, byte expectedBlockType, Key encryptKey, Key decryptKey) throws Exception {
+ Cipher encryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
+ encryptCipher.init(Cipher.ENCRYPT_MODE, encryptKey);
+ byte[] cipherText = encryptCipher.doFinal(ORIGINAL_PLAIN_TEXT);
+ Cipher decryptCipher = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+ decryptCipher.init(Cipher.DECRYPT_MODE, decryptKey);
+ byte[] plainText = decryptCipher.doFinal(cipherText);
+ assertPadding(provider, expectedBlockType, ORIGINAL_PLAIN_TEXT, plainText);
+ }
+
+ private void assertPadding(String provider, byte expectedBlockType, byte[] expectedData, byte[] actualDataWithPadding) {
+ assertNotNull(provider, actualDataWithPadding);
+ int expectedOutputSize = getExpectedOutputSize("RSA", Cipher.DECRYPT_MODE, provider);
+ assertEquals(provider, expectedOutputSize, actualDataWithPadding.length);
+ int expectedBlockTypeOffset;
+ if (provider.equals("BC")) {
+ // BC strips the leading 0 for us on decrypt even when NoPadding is specified...
+ expectedBlockTypeOffset = 0;
+ } else {
+ expectedBlockTypeOffset = 1;
+ assertEquals(provider, 0, actualDataWithPadding[0]);
+ }
+ byte actualBlockType = actualDataWithPadding[expectedBlockTypeOffset];
+ assertEquals(provider, expectedBlockType, actualBlockType);
+ int actualDataOffset = actualDataWithPadding.length - expectedData.length;
+ if (actualBlockType == 1) {
+ int expectedDataOffset = expectedBlockTypeOffset + 1;
+ for (int i = expectedDataOffset; i < actualDataOffset - 1; i++) {
+ assertEquals(provider, (byte) 0xFF, actualDataWithPadding[i]);
+ }
+ }
+ assertEquals(provider, 0x00, actualDataWithPadding[actualDataOffset-1]);
+ byte[] actualData = new byte[expectedData.length];
+ System.arraycopy(actualDataWithPadding, actualDataOffset, actualData, 0, actualData.length);
+ assertEquals(provider, Arrays.toString(expectedData), Arrays.toString(actualData));
+ }
+
+ @Test
+ public void testCipherInitWithCertificate () throws Exception {
+ // no key usage specified, everything is fine
+ assertCipherInitWithKeyUsage(0, true, true, true, true);
+
+ // common case is that encrypt/wrap is prohibited when special usage is specified
+ assertCipherInitWithKeyUsage(KeyUsage.digitalSignature, false, true, false, true);
+ assertCipherInitWithKeyUsage(KeyUsage.nonRepudiation, false, true, false, true);
+ assertCipherInitWithKeyUsage(KeyUsage.keyAgreement, false, true, false, true);
+ assertCipherInitWithKeyUsage(KeyUsage.keyCertSign, false, true, false, true);
+ assertCipherInitWithKeyUsage(KeyUsage.cRLSign, false, true, false, true);
+
+ // Note they encipherOnly/decipherOnly don't have to do with
+ // ENCRYPT_MODE or DECRYPT_MODE, but restrict usage relative
+ // to keyAgreement. There is not a *_MODE option that
+ // corresponds to this in Cipher, the RI does not enforce
+ // anything in Cipher.
+ // http://code.google.com/p/android/issues/detail?id=12955
+ assertCipherInitWithKeyUsage(KeyUsage.encipherOnly, false, true, false, true);
+ assertCipherInitWithKeyUsage(KeyUsage.decipherOnly, false, true, false, true);
+ assertCipherInitWithKeyUsage(KeyUsage.keyAgreement | KeyUsage.encipherOnly,
+ false, true, false, true);
+ assertCipherInitWithKeyUsage(KeyUsage.keyAgreement | KeyUsage.decipherOnly,
+ false, true, false, true);
+
+ // except when wrapping a key is specifically allowed or
+ assertCipherInitWithKeyUsage(KeyUsage.keyEncipherment, false, true, true, true);
+ // except when wrapping data encryption is specifically allowed
+ assertCipherInitWithKeyUsage(KeyUsage.dataEncipherment, true, true, false, true);
+ }
+
+ private void assertCipherInitWithKeyUsage (int keyUsage,
+ boolean allowEncrypt,
+ boolean allowDecrypt,
+ boolean allowWrap,
+ boolean allowUnwrap) throws Exception {
+ Certificate certificate = certificateWithKeyUsage(keyUsage);
+ assertCipherInitWithKeyUsage(certificate, allowEncrypt, Cipher.ENCRYPT_MODE);
+ assertCipherInitWithKeyUsage(certificate, allowDecrypt, Cipher.DECRYPT_MODE);
+ assertCipherInitWithKeyUsage(certificate, allowWrap, Cipher.WRAP_MODE);
+ assertCipherInitWithKeyUsage(certificate, allowUnwrap, Cipher.UNWRAP_MODE);
+ }
+
+ private void assertCipherInitWithKeyUsage(Certificate certificate,
+ boolean allowMode,
+ int mode) throws Exception {
+ Cipher cipher = Cipher.getInstance("RSA");
+ if (allowMode) {
+ cipher.init(mode, certificate);
+ } else {
+ try {
+ cipher.init(mode, certificate);
+ String modeString;
+ switch (mode) {
+ case Cipher.ENCRYPT_MODE:
+ modeString = "ENCRYPT_MODE";
+ break;
+ case Cipher.DECRYPT_MODE:
+ modeString = "DECRYPT_MODE";
+ break;
+ case Cipher.WRAP_MODE:
+ modeString = "WRAP_MODE";
+ break;
+ case Cipher.UNWRAP_MODE:
+ modeString = "UNWRAP_MODE";
+ break;
+ default:
+ throw new AssertionError("Unknown Cipher.*_MODE " + mode);
+ }
+ fail("Should have had InvalidKeyException for " + modeString
+ + " for " + certificate);
+ } catch (InvalidKeyException expected) {
+ }
+ }
+ }
+
+ private Certificate certificateWithKeyUsage(int keyUsage) throws Exception {
+ // note the rare usage of non-zero keyUsage
+ return new TestKeyStore.Builder()
+ .aliasPrefix("rsa-dsa-ec")
+ .keyUsage(keyUsage)
+ .build()
+ .getPrivateKey("RSA", "RSA").getCertificate();
+ }
+
+ /*
+ * Test vectors generated with this private key:
+ *
+ * -----BEGIN RSA PRIVATE KEY-----
+ * MIIEpAIBAAKCAQEA4Ec+irjyKE/rnnQv+XSPoRjtmGM8kvUq63ouvg075gMpvnZq
+ * 0Q62pRXQ0s/ZvqeTDwwwZTeJn3lYzT6FsB+IGFJNMSWEqUslHjYltUFB7b/uGYgI
+ * 4buX/Hy0m56qr2jpyY19DtxTu8D6ADQ1bWMF+7zDxwAUBThqu8hzyw8+90JfPTPf
+ * ezFa4DbSoLZq/UdQOxab8247UWJRW3Ff2oPeryxYrrmr+zCXw8yd2dvl7ylsF2E5
+ * Ao6KZx5jBW1F9AGI0sQTNJCEXeUsJTTpxrJHjAe9rpKII7YtBmx3cPn2Pz26JH9T
+ * CER0e+eqqF2FO4vSRKzsPePImrRkU6tNJMOsaQIDAQABAoIBADd4R3al8XaY9ayW
+ * DfuDobZ1ZOZIvQWXz4q4CHGG8macJ6nsvdSA8Bl6gNBzCebGqW+SUzHlf4tKxvTU
+ * XtpFojJpwJ/EKMB6Tm7fc4oV3sl/q9Lyu0ehTyDqcvz+TDbgGtp3vRN82NTaELsW
+ * LpSkZilx8XX5hfoYjwVsuX7igW9Dq503R2Ekhs2owWGWwwgYqZXshdOEZ3kSZ7O/
+ * IfJzcQppJYYldoQcW2cSwS1L0govMpmtt8E12l6VFavadufK8qO+gFUdBzt4vxFi
+ * xIrSt/R0OgI47k0lL31efmUzzK5kzLOTYAdaL9HgNOw65c6cQIzL8OJeQRQCFoez
+ * 3UdUroECgYEA9UGIS8Nzeyki1BGe9F4t7izUy7dfRVBaFXqlAJ+Zxzot8HJKxGAk
+ * MGMy6omBd2NFRl3G3x4KbxQK/ztzluaomUrF2qloc0cv43dJ0U6z4HXmKdvrNYMz
+ * im82SdCiZUp6Qv2atr+krE1IHTkLsimwZL3DEcwb4bYxidp8QM3s8rECgYEA6hp0
+ * LduIHO23KIyH442GjdekCdFaQ/RF1Td6C1cx3b/KLa8oqOE81cCvzsM0fXSjniNa
+ * PNljPydN4rlPkt9DgzkR2enxz1jyfeLgj/RZZMcg0+whOdx8r8kSlTzeyy81Wi4s
+ * NaUPrXVMs7IxZkJLo7bjESoriYw4xcFe2yOGkzkCgYBRgo8exv2ZYCmQG68dfjN7
+ * pfCvJ+mE6tiVrOYr199O5FoiQInyzBUa880XP84EdLywTzhqLNzA4ANrokGfVFeS
+ * YtRxAL6TGYSj76Bb7PFBV03AebOpXEqD5sQ/MhTW3zLVEt4ZgIXlMeYWuD/X3Z0f
+ * TiYHwzM9B8VdEH0dOJNYcQKBgQDbT7UPUN6O21P/NMgJMYigUShn2izKBIl3WeWH
+ * wkQBDa+GZNWegIPRbBZHiTAfZ6nweAYNg0oq29NnV1toqKhCwrAqibPzH8zsiiL+
+ * OVeVxcbHQitOXXSh6ajzDndZufwtY5wfFWc+hOk6XvFQb0MVODw41Fy9GxQEj0ch
+ * 3IIyYQKBgQDYEUWTr0FfthLb8ZI3ENVNB0hiBadqO0MZSWjA3/HxHvD2GkozfV/T
+ * dBu8lkDkR7i2tsR8OsEgQ1fTsMVbqShr2nP2KSlvX6kUbYl2NX08dR51FIaWpAt0
+ * aFyCzjCQLWOdck/yTV4ulAfuNO3tLjtN9lqpvP623yjQe6aQPxZXaA==
+ * -----END RSA PRIVATE KEY-----
+ *
+ */
+
+ private static final BigInteger RSA_2048_modulus = new BigInteger(new byte[] {
+ (byte) 0x00, (byte) 0xe0, (byte) 0x47, (byte) 0x3e, (byte) 0x8a, (byte) 0xb8, (byte) 0xf2, (byte) 0x28,
+ (byte) 0x4f, (byte) 0xeb, (byte) 0x9e, (byte) 0x74, (byte) 0x2f, (byte) 0xf9, (byte) 0x74, (byte) 0x8f,
+ (byte) 0xa1, (byte) 0x18, (byte) 0xed, (byte) 0x98, (byte) 0x63, (byte) 0x3c, (byte) 0x92, (byte) 0xf5,
+ (byte) 0x2a, (byte) 0xeb, (byte) 0x7a, (byte) 0x2e, (byte) 0xbe, (byte) 0x0d, (byte) 0x3b, (byte) 0xe6,
+ (byte) 0x03, (byte) 0x29, (byte) 0xbe, (byte) 0x76, (byte) 0x6a, (byte) 0xd1, (byte) 0x0e, (byte) 0xb6,
+ (byte) 0xa5, (byte) 0x15, (byte) 0xd0, (byte) 0xd2, (byte) 0xcf, (byte) 0xd9, (byte) 0xbe, (byte) 0xa7,
+ (byte) 0x93, (byte) 0x0f, (byte) 0x0c, (byte) 0x30, (byte) 0x65, (byte) 0x37, (byte) 0x89, (byte) 0x9f,
+ (byte) 0x79, (byte) 0x58, (byte) 0xcd, (byte) 0x3e, (byte) 0x85, (byte) 0xb0, (byte) 0x1f, (byte) 0x88,
+ (byte) 0x18, (byte) 0x52, (byte) 0x4d, (byte) 0x31, (byte) 0x25, (byte) 0x84, (byte) 0xa9, (byte) 0x4b,
+ (byte) 0x25, (byte) 0x1e, (byte) 0x36, (byte) 0x25, (byte) 0xb5, (byte) 0x41, (byte) 0x41, (byte) 0xed,
+ (byte) 0xbf, (byte) 0xee, (byte) 0x19, (byte) 0x88, (byte) 0x08, (byte) 0xe1, (byte) 0xbb, (byte) 0x97,
+ (byte) 0xfc, (byte) 0x7c, (byte) 0xb4, (byte) 0x9b, (byte) 0x9e, (byte) 0xaa, (byte) 0xaf, (byte) 0x68,
+ (byte) 0xe9, (byte) 0xc9, (byte) 0x8d, (byte) 0x7d, (byte) 0x0e, (byte) 0xdc, (byte) 0x53, (byte) 0xbb,
+ (byte) 0xc0, (byte) 0xfa, (byte) 0x00, (byte) 0x34, (byte) 0x35, (byte) 0x6d, (byte) 0x63, (byte) 0x05,
+ (byte) 0xfb, (byte) 0xbc, (byte) 0xc3, (byte) 0xc7, (byte) 0x00, (byte) 0x14, (byte) 0x05, (byte) 0x38,
+ (byte) 0x6a, (byte) 0xbb, (byte) 0xc8, (byte) 0x73, (byte) 0xcb, (byte) 0x0f, (byte) 0x3e, (byte) 0xf7,
+ (byte) 0x42, (byte) 0x5f, (byte) 0x3d, (byte) 0x33, (byte) 0xdf, (byte) 0x7b, (byte) 0x31, (byte) 0x5a,
+ (byte) 0xe0, (byte) 0x36, (byte) 0xd2, (byte) 0xa0, (byte) 0xb6, (byte) 0x6a, (byte) 0xfd, (byte) 0x47,
+ (byte) 0x50, (byte) 0x3b, (byte) 0x16, (byte) 0x9b, (byte) 0xf3, (byte) 0x6e, (byte) 0x3b, (byte) 0x51,
+ (byte) 0x62, (byte) 0x51, (byte) 0x5b, (byte) 0x71, (byte) 0x5f, (byte) 0xda, (byte) 0x83, (byte) 0xde,
+ (byte) 0xaf, (byte) 0x2c, (byte) 0x58, (byte) 0xae, (byte) 0xb9, (byte) 0xab, (byte) 0xfb, (byte) 0x30,
+ (byte) 0x97, (byte) 0xc3, (byte) 0xcc, (byte) 0x9d, (byte) 0xd9, (byte) 0xdb, (byte) 0xe5, (byte) 0xef,
+ (byte) 0x29, (byte) 0x6c, (byte) 0x17, (byte) 0x61, (byte) 0x39, (byte) 0x02, (byte) 0x8e, (byte) 0x8a,
+ (byte) 0x67, (byte) 0x1e, (byte) 0x63, (byte) 0x05, (byte) 0x6d, (byte) 0x45, (byte) 0xf4, (byte) 0x01,
+ (byte) 0x88, (byte) 0xd2, (byte) 0xc4, (byte) 0x13, (byte) 0x34, (byte) 0x90, (byte) 0x84, (byte) 0x5d,
+ (byte) 0xe5, (byte) 0x2c, (byte) 0x25, (byte) 0x34, (byte) 0xe9, (byte) 0xc6, (byte) 0xb2, (byte) 0x47,
+ (byte) 0x8c, (byte) 0x07, (byte) 0xbd, (byte) 0xae, (byte) 0x92, (byte) 0x88, (byte) 0x23, (byte) 0xb6,
+ (byte) 0x2d, (byte) 0x06, (byte) 0x6c, (byte) 0x77, (byte) 0x70, (byte) 0xf9, (byte) 0xf6, (byte) 0x3f,
+ (byte) 0x3d, (byte) 0xba, (byte) 0x24, (byte) 0x7f, (byte) 0x53, (byte) 0x08, (byte) 0x44, (byte) 0x74,
+ (byte) 0x7b, (byte) 0xe7, (byte) 0xaa, (byte) 0xa8, (byte) 0x5d, (byte) 0x85, (byte) 0x3b, (byte) 0x8b,
+ (byte) 0xd2, (byte) 0x44, (byte) 0xac, (byte) 0xec, (byte) 0x3d, (byte) 0xe3, (byte) 0xc8, (byte) 0x9a,
+ (byte) 0xb4, (byte) 0x64, (byte) 0x53, (byte) 0xab, (byte) 0x4d, (byte) 0x24, (byte) 0xc3, (byte) 0xac,
+ (byte) 0x69,
+ });
+
+ private static final BigInteger RSA_2048_privateExponent = new BigInteger(new byte[] {
+ (byte) 0x37, (byte) 0x78, (byte) 0x47, (byte) 0x76, (byte) 0xa5, (byte) 0xf1, (byte) 0x76, (byte) 0x98,
+ (byte) 0xf5, (byte) 0xac, (byte) 0x96, (byte) 0x0d, (byte) 0xfb, (byte) 0x83, (byte) 0xa1, (byte) 0xb6,
+ (byte) 0x75, (byte) 0x64, (byte) 0xe6, (byte) 0x48, (byte) 0xbd, (byte) 0x05, (byte) 0x97, (byte) 0xcf,
+ (byte) 0x8a, (byte) 0xb8, (byte) 0x08, (byte) 0x71, (byte) 0x86, (byte) 0xf2, (byte) 0x66, (byte) 0x9c,
+ (byte) 0x27, (byte) 0xa9, (byte) 0xec, (byte) 0xbd, (byte) 0xd4, (byte) 0x80, (byte) 0xf0, (byte) 0x19,
+ (byte) 0x7a, (byte) 0x80, (byte) 0xd0, (byte) 0x73, (byte) 0x09, (byte) 0xe6, (byte) 0xc6, (byte) 0xa9,
+ (byte) 0x6f, (byte) 0x92, (byte) 0x53, (byte) 0x31, (byte) 0xe5, (byte) 0x7f, (byte) 0x8b, (byte) 0x4a,
+ (byte) 0xc6, (byte) 0xf4, (byte) 0xd4, (byte) 0x5e, (byte) 0xda, (byte) 0x45, (byte) 0xa2, (byte) 0x32,
+ (byte) 0x69, (byte) 0xc0, (byte) 0x9f, (byte) 0xc4, (byte) 0x28, (byte) 0xc0, (byte) 0x7a, (byte) 0x4e,
+ (byte) 0x6e, (byte) 0xdf, (byte) 0x73, (byte) 0x8a, (byte) 0x15, (byte) 0xde, (byte) 0xc9, (byte) 0x7f,
+ (byte) 0xab, (byte) 0xd2, (byte) 0xf2, (byte) 0xbb, (byte) 0x47, (byte) 0xa1, (byte) 0x4f, (byte) 0x20,
+ (byte) 0xea, (byte) 0x72, (byte) 0xfc, (byte) 0xfe, (byte) 0x4c, (byte) 0x36, (byte) 0xe0, (byte) 0x1a,
+ (byte) 0xda, (byte) 0x77, (byte) 0xbd, (byte) 0x13, (byte) 0x7c, (byte) 0xd8, (byte) 0xd4, (byte) 0xda,
+ (byte) 0x10, (byte) 0xbb, (byte) 0x16, (byte) 0x2e, (byte) 0x94, (byte) 0xa4, (byte) 0x66, (byte) 0x29,
+ (byte) 0x71, (byte) 0xf1, (byte) 0x75, (byte) 0xf9, (byte) 0x85, (byte) 0xfa, (byte) 0x18, (byte) 0x8f,
+ (byte) 0x05, (byte) 0x6c, (byte) 0xb9, (byte) 0x7e, (byte) 0xe2, (byte) 0x81, (byte) 0x6f, (byte) 0x43,
+ (byte) 0xab, (byte) 0x9d, (byte) 0x37, (byte) 0x47, (byte) 0x61, (byte) 0x24, (byte) 0x86, (byte) 0xcd,
+ (byte) 0xa8, (byte) 0xc1, (byte) 0x61, (byte) 0x96, (byte) 0xc3, (byte) 0x08, (byte) 0x18, (byte) 0xa9,
+ (byte) 0x95, (byte) 0xec, (byte) 0x85, (byte) 0xd3, (byte) 0x84, (byte) 0x67, (byte) 0x79, (byte) 0x12,
+ (byte) 0x67, (byte) 0xb3, (byte) 0xbf, (byte) 0x21, (byte) 0xf2, (byte) 0x73, (byte) 0x71, (byte) 0x0a,
+ (byte) 0x69, (byte) 0x25, (byte) 0x86, (byte) 0x25, (byte) 0x76, (byte) 0x84, (byte) 0x1c, (byte) 0x5b,
+ (byte) 0x67, (byte) 0x12, (byte) 0xc1, (byte) 0x2d, (byte) 0x4b, (byte) 0xd2, (byte) 0x0a, (byte) 0x2f,
+ (byte) 0x32, (byte) 0x99, (byte) 0xad, (byte) 0xb7, (byte) 0xc1, (byte) 0x35, (byte) 0xda, (byte) 0x5e,
+ (byte) 0x95, (byte) 0x15, (byte) 0xab, (byte) 0xda, (byte) 0x76, (byte) 0xe7, (byte) 0xca, (byte) 0xf2,
+ (byte) 0xa3, (byte) 0xbe, (byte) 0x80, (byte) 0x55, (byte) 0x1d, (byte) 0x07, (byte) 0x3b, (byte) 0x78,
+ (byte) 0xbf, (byte) 0x11, (byte) 0x62, (byte) 0xc4, (byte) 0x8a, (byte) 0xd2, (byte) 0xb7, (byte) 0xf4,
+ (byte) 0x74, (byte) 0x3a, (byte) 0x02, (byte) 0x38, (byte) 0xee, (byte) 0x4d, (byte) 0x25, (byte) 0x2f,
+ (byte) 0x7d, (byte) 0x5e, (byte) 0x7e, (byte) 0x65, (byte) 0x33, (byte) 0xcc, (byte) 0xae, (byte) 0x64,
+ (byte) 0xcc, (byte) 0xb3, (byte) 0x93, (byte) 0x60, (byte) 0x07, (byte) 0x5a, (byte) 0x2f, (byte) 0xd1,
+ (byte) 0xe0, (byte) 0x34, (byte) 0xec, (byte) 0x3a, (byte) 0xe5, (byte) 0xce, (byte) 0x9c, (byte) 0x40,
+ (byte) 0x8c, (byte) 0xcb, (byte) 0xf0, (byte) 0xe2, (byte) 0x5e, (byte) 0x41, (byte) 0x14, (byte) 0x02,
+ (byte) 0x16, (byte) 0x87, (byte) 0xb3, (byte) 0xdd, (byte) 0x47, (byte) 0x54, (byte) 0xae, (byte) 0x81,
+ });
+
+ private static final BigInteger RSA_2048_publicExponent = new BigInteger(new byte[] {
+ (byte) 0x01, (byte) 0x00, (byte) 0x01,
+ });
+
+ private static final BigInteger RSA_2048_primeP = new BigInteger(new byte[] {
+ (byte) 0x00, (byte) 0xf5, (byte) 0x41, (byte) 0x88, (byte) 0x4b, (byte) 0xc3, (byte) 0x73, (byte) 0x7b,
+ (byte) 0x29, (byte) 0x22, (byte) 0xd4, (byte) 0x11, (byte) 0x9e, (byte) 0xf4, (byte) 0x5e, (byte) 0x2d,
+ (byte) 0xee, (byte) 0x2c, (byte) 0xd4, (byte) 0xcb, (byte) 0xb7, (byte) 0x5f, (byte) 0x45, (byte) 0x50,
+ (byte) 0x5a, (byte) 0x15, (byte) 0x7a, (byte) 0xa5, (byte) 0x00, (byte) 0x9f, (byte) 0x99, (byte) 0xc7,
+ (byte) 0x3a, (byte) 0x2d, (byte) 0xf0, (byte) 0x72, (byte) 0x4a, (byte) 0xc4, (byte) 0x60, (byte) 0x24,
+ (byte) 0x30, (byte) 0x63, (byte) 0x32, (byte) 0xea, (byte) 0x89, (byte) 0x81, (byte) 0x77, (byte) 0x63,
+ (byte) 0x45, (byte) 0x46, (byte) 0x5d, (byte) 0xc6, (byte) 0xdf, (byte) 0x1e, (byte) 0x0a, (byte) 0x6f,
+ (byte) 0x14, (byte) 0x0a, (byte) 0xff, (byte) 0x3b, (byte) 0x73, (byte) 0x96, (byte) 0xe6, (byte) 0xa8,
+ (byte) 0x99, (byte) 0x4a, (byte) 0xc5, (byte) 0xda, (byte) 0xa9, (byte) 0x68, (byte) 0x73, (byte) 0x47,
+ (byte) 0x2f, (byte) 0xe3, (byte) 0x77, (byte) 0x49, (byte) 0xd1, (byte) 0x4e, (byte) 0xb3, (byte) 0xe0,
+ (byte) 0x75, (byte) 0xe6, (byte) 0x29, (byte) 0xdb, (byte) 0xeb, (byte) 0x35, (byte) 0x83, (byte) 0x33,
+ (byte) 0x8a, (byte) 0x6f, (byte) 0x36, (byte) 0x49, (byte) 0xd0, (byte) 0xa2, (byte) 0x65, (byte) 0x4a,
+ (byte) 0x7a, (byte) 0x42, (byte) 0xfd, (byte) 0x9a, (byte) 0xb6, (byte) 0xbf, (byte) 0xa4, (byte) 0xac,
+ (byte) 0x4d, (byte) 0x48, (byte) 0x1d, (byte) 0x39, (byte) 0x0b, (byte) 0xb2, (byte) 0x29, (byte) 0xb0,
+ (byte) 0x64, (byte) 0xbd, (byte) 0xc3, (byte) 0x11, (byte) 0xcc, (byte) 0x1b, (byte) 0xe1, (byte) 0xb6,
+ (byte) 0x31, (byte) 0x89, (byte) 0xda, (byte) 0x7c, (byte) 0x40, (byte) 0xcd, (byte) 0xec, (byte) 0xf2,
+ (byte) 0xb1,
+ });
+
+ private static final BigInteger RSA_2048_primeQ = new BigInteger(new byte[] {
+ (byte) 0x00, (byte) 0xea, (byte) 0x1a, (byte) 0x74, (byte) 0x2d, (byte) 0xdb, (byte) 0x88, (byte) 0x1c,
+ (byte) 0xed, (byte) 0xb7, (byte) 0x28, (byte) 0x8c, (byte) 0x87, (byte) 0xe3, (byte) 0x8d, (byte) 0x86,
+ (byte) 0x8d, (byte) 0xd7, (byte) 0xa4, (byte) 0x09, (byte) 0xd1, (byte) 0x5a, (byte) 0x43, (byte) 0xf4,
+ (byte) 0x45, (byte) 0xd5, (byte) 0x37, (byte) 0x7a, (byte) 0x0b, (byte) 0x57, (byte) 0x31, (byte) 0xdd,
+ (byte) 0xbf, (byte) 0xca, (byte) 0x2d, (byte) 0xaf, (byte) 0x28, (byte) 0xa8, (byte) 0xe1, (byte) 0x3c,
+ (byte) 0xd5, (byte) 0xc0, (byte) 0xaf, (byte) 0xce, (byte) 0xc3, (byte) 0x34, (byte) 0x7d, (byte) 0x74,
+ (byte) 0xa3, (byte) 0x9e, (byte) 0x23, (byte) 0x5a, (byte) 0x3c, (byte) 0xd9, (byte) 0x63, (byte) 0x3f,
+ (byte) 0x27, (byte) 0x4d, (byte) 0xe2, (byte) 0xb9, (byte) 0x4f, (byte) 0x92, (byte) 0xdf, (byte) 0x43,
+ (byte) 0x83, (byte) 0x39, (byte) 0x11, (byte) 0xd9, (byte) 0xe9, (byte) 0xf1, (byte) 0xcf, (byte) 0x58,
+ (byte) 0xf2, (byte) 0x7d, (byte) 0xe2, (byte) 0xe0, (byte) 0x8f, (byte) 0xf4, (byte) 0x59, (byte) 0x64,
+ (byte) 0xc7, (byte) 0x20, (byte) 0xd3, (byte) 0xec, (byte) 0x21, (byte) 0x39, (byte) 0xdc, (byte) 0x7c,
+ (byte) 0xaf, (byte) 0xc9, (byte) 0x12, (byte) 0x95, (byte) 0x3c, (byte) 0xde, (byte) 0xcb, (byte) 0x2f,
+ (byte) 0x35, (byte) 0x5a, (byte) 0x2e, (byte) 0x2c, (byte) 0x35, (byte) 0xa5, (byte) 0x0f, (byte) 0xad,
+ (byte) 0x75, (byte) 0x4c, (byte) 0xb3, (byte) 0xb2, (byte) 0x31, (byte) 0x66, (byte) 0x42, (byte) 0x4b,
+ (byte) 0xa3, (byte) 0xb6, (byte) 0xe3, (byte) 0x11, (byte) 0x2a, (byte) 0x2b, (byte) 0x89, (byte) 0x8c,
+ (byte) 0x38, (byte) 0xc5, (byte) 0xc1, (byte) 0x5e, (byte) 0xdb, (byte) 0x23, (byte) 0x86, (byte) 0x93,
+ (byte) 0x39,
+ });
+
+ private static final BigInteger RSA_2048_primeExponentP = new BigInteger(1, new byte[] {
+ (byte) 0x51, (byte) 0x82, (byte) 0x8F, (byte) 0x1E, (byte) 0xC6, (byte) 0xFD, (byte) 0x99, (byte) 0x60,
+ (byte) 0x29, (byte) 0x90, (byte) 0x1B, (byte) 0xAF, (byte) 0x1D, (byte) 0x7E, (byte) 0x33, (byte) 0x7B,
+ (byte) 0xA5, (byte) 0xF0, (byte) 0xAF, (byte) 0x27, (byte) 0xE9, (byte) 0x84, (byte) 0xEA, (byte) 0xD8,
+ (byte) 0x95, (byte) 0xAC, (byte) 0xE6, (byte) 0x2B, (byte) 0xD7, (byte) 0xDF, (byte) 0x4E, (byte) 0xE4,
+ (byte) 0x5A, (byte) 0x22, (byte) 0x40, (byte) 0x89, (byte) 0xF2, (byte) 0xCC, (byte) 0x15, (byte) 0x1A,
+ (byte) 0xF3, (byte) 0xCD, (byte) 0x17, (byte) 0x3F, (byte) 0xCE, (byte) 0x04, (byte) 0x74, (byte) 0xBC,
+ (byte) 0xB0, (byte) 0x4F, (byte) 0x38, (byte) 0x6A, (byte) 0x2C, (byte) 0xDC, (byte) 0xC0, (byte) 0xE0,
+ (byte) 0x03, (byte) 0x6B, (byte) 0xA2, (byte) 0x41, (byte) 0x9F, (byte) 0x54, (byte) 0x57, (byte) 0x92,
+ (byte) 0x62, (byte) 0xD4, (byte) 0x71, (byte) 0x00, (byte) 0xBE, (byte) 0x93, (byte) 0x19, (byte) 0x84,
+ (byte) 0xA3, (byte) 0xEF, (byte) 0xA0, (byte) 0x5B, (byte) 0xEC, (byte) 0xF1, (byte) 0x41, (byte) 0x57,
+ (byte) 0x4D, (byte) 0xC0, (byte) 0x79, (byte) 0xB3, (byte) 0xA9, (byte) 0x5C, (byte) 0x4A, (byte) 0x83,
+ (byte) 0xE6, (byte) 0xC4, (byte) 0x3F, (byte) 0x32, (byte) 0x14, (byte) 0xD6, (byte) 0xDF, (byte) 0x32,
+ (byte) 0xD5, (byte) 0x12, (byte) 0xDE, (byte) 0x19, (byte) 0x80, (byte) 0x85, (byte) 0xE5, (byte) 0x31,
+ (byte) 0xE6, (byte) 0x16, (byte) 0xB8, (byte) 0x3F, (byte) 0xD7, (byte) 0xDD, (byte) 0x9D, (byte) 0x1F,
+ (byte) 0x4E, (byte) 0x26, (byte) 0x07, (byte) 0xC3, (byte) 0x33, (byte) 0x3D, (byte) 0x07, (byte) 0xC5,
+ (byte) 0x5D, (byte) 0x10, (byte) 0x7D, (byte) 0x1D, (byte) 0x38, (byte) 0x93, (byte) 0x58, (byte) 0x71,
+ });
+
+ private static final BigInteger RSA_2048_primeExponentQ = new BigInteger(1, new byte[] {
+ (byte) 0xDB, (byte) 0x4F, (byte) 0xB5, (byte) 0x0F, (byte) 0x50, (byte) 0xDE, (byte) 0x8E, (byte) 0xDB,
+ (byte) 0x53, (byte) 0xFF, (byte) 0x34, (byte) 0xC8, (byte) 0x09, (byte) 0x31, (byte) 0x88, (byte) 0xA0,
+ (byte) 0x51, (byte) 0x28, (byte) 0x67, (byte) 0xDA, (byte) 0x2C, (byte) 0xCA, (byte) 0x04, (byte) 0x89,
+ (byte) 0x77, (byte) 0x59, (byte) 0xE5, (byte) 0x87, (byte) 0xC2, (byte) 0x44, (byte) 0x01, (byte) 0x0D,
+ (byte) 0xAF, (byte) 0x86, (byte) 0x64, (byte) 0xD5, (byte) 0x9E, (byte) 0x80, (byte) 0x83, (byte) 0xD1,
+ (byte) 0x6C, (byte) 0x16, (byte) 0x47, (byte) 0x89, (byte) 0x30, (byte) 0x1F, (byte) 0x67, (byte) 0xA9,
+ (byte) 0xF0, (byte) 0x78, (byte) 0x06, (byte) 0x0D, (byte) 0x83, (byte) 0x4A, (byte) 0x2A, (byte) 0xDB,
+ (byte) 0xD3, (byte) 0x67, (byte) 0x57, (byte) 0x5B, (byte) 0x68, (byte) 0xA8, (byte) 0xA8, (byte) 0x42,
+ (byte) 0xC2, (byte) 0xB0, (byte) 0x2A, (byte) 0x89, (byte) 0xB3, (byte) 0xF3, (byte) 0x1F, (byte) 0xCC,
+ (byte) 0xEC, (byte) 0x8A, (byte) 0x22, (byte) 0xFE, (byte) 0x39, (byte) 0x57, (byte) 0x95, (byte) 0xC5,
+ (byte) 0xC6, (byte) 0xC7, (byte) 0x42, (byte) 0x2B, (byte) 0x4E, (byte) 0x5D, (byte) 0x74, (byte) 0xA1,
+ (byte) 0xE9, (byte) 0xA8, (byte) 0xF3, (byte) 0x0E, (byte) 0x77, (byte) 0x59, (byte) 0xB9, (byte) 0xFC,
+ (byte) 0x2D, (byte) 0x63, (byte) 0x9C, (byte) 0x1F, (byte) 0x15, (byte) 0x67, (byte) 0x3E, (byte) 0x84,
+ (byte) 0xE9, (byte) 0x3A, (byte) 0x5E, (byte) 0xF1, (byte) 0x50, (byte) 0x6F, (byte) 0x43, (byte) 0x15,
+ (byte) 0x38, (byte) 0x3C, (byte) 0x38, (byte) 0xD4, (byte) 0x5C, (byte) 0xBD, (byte) 0x1B, (byte) 0x14,
+ (byte) 0x04, (byte) 0x8F, (byte) 0x47, (byte) 0x21, (byte) 0xDC, (byte) 0x82, (byte) 0x32, (byte) 0x61,
+ });
+
+ private static final BigInteger RSA_2048_crtCoefficient = new BigInteger(1, new byte[] {
+ (byte) 0xD8, (byte) 0x11, (byte) 0x45, (byte) 0x93, (byte) 0xAF, (byte) 0x41, (byte) 0x5F, (byte) 0xB6,
+ (byte) 0x12, (byte) 0xDB, (byte) 0xF1, (byte) 0x92, (byte) 0x37, (byte) 0x10, (byte) 0xD5, (byte) 0x4D,
+ (byte) 0x07, (byte) 0x48, (byte) 0x62, (byte) 0x05, (byte) 0xA7, (byte) 0x6A, (byte) 0x3B, (byte) 0x43,
+ (byte) 0x19, (byte) 0x49, (byte) 0x68, (byte) 0xC0, (byte) 0xDF, (byte) 0xF1, (byte) 0xF1, (byte) 0x1E,
+ (byte) 0xF0, (byte) 0xF6, (byte) 0x1A, (byte) 0x4A, (byte) 0x33, (byte) 0x7D, (byte) 0x5F, (byte) 0xD3,
+ (byte) 0x74, (byte) 0x1B, (byte) 0xBC, (byte) 0x96, (byte) 0x40, (byte) 0xE4, (byte) 0x47, (byte) 0xB8,
+ (byte) 0xB6, (byte) 0xB6, (byte) 0xC4, (byte) 0x7C, (byte) 0x3A, (byte) 0xC1, (byte) 0x20, (byte) 0x43,
+ (byte) 0x57, (byte) 0xD3, (byte) 0xB0, (byte) 0xC5, (byte) 0x5B, (byte) 0xA9, (byte) 0x28, (byte) 0x6B,
+ (byte) 0xDA, (byte) 0x73, (byte) 0xF6, (byte) 0x29, (byte) 0x29, (byte) 0x6F, (byte) 0x5F, (byte) 0xA9,
+ (byte) 0x14, (byte) 0x6D, (byte) 0x89, (byte) 0x76, (byte) 0x35, (byte) 0x7D, (byte) 0x3C, (byte) 0x75,
+ (byte) 0x1E, (byte) 0x75, (byte) 0x14, (byte) 0x86, (byte) 0x96, (byte) 0xA4, (byte) 0x0B, (byte) 0x74,
+ (byte) 0x68, (byte) 0x5C, (byte) 0x82, (byte) 0xCE, (byte) 0x30, (byte) 0x90, (byte) 0x2D, (byte) 0x63,
+ (byte) 0x9D, (byte) 0x72, (byte) 0x4F, (byte) 0xF2, (byte) 0x4D, (byte) 0x5E, (byte) 0x2E, (byte) 0x94,
+ (byte) 0x07, (byte) 0xEE, (byte) 0x34, (byte) 0xED, (byte) 0xED, (byte) 0x2E, (byte) 0x3B, (byte) 0x4D,
+ (byte) 0xF6, (byte) 0x5A, (byte) 0xA9, (byte) 0xBC, (byte) 0xFE, (byte) 0xB6, (byte) 0xDF, (byte) 0x28,
+ (byte) 0xD0, (byte) 0x7B, (byte) 0xA6, (byte) 0x90, (byte) 0x3F, (byte) 0x16, (byte) 0x57, (byte) 0x68,
+ });
+
+ /**
+ * Test data is PKCS#1 padded "Android.\n" which can be generated by:
+ * echo "Android." | openssl rsautl -inkey rsa.key -sign | openssl rsautl -inkey rsa.key -raw -verify | recode ../x1
+ */
+ private static final byte[] RSA_2048_Vector1 = new byte[] {
+ (byte) 0x00, (byte) 0x01, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0x00, (byte) 0x41, (byte) 0x6E, (byte) 0x64, (byte) 0x72, (byte) 0x6F,
+ (byte) 0x69, (byte) 0x64, (byte) 0x2E, (byte) 0x0A,
+ };
+
+ /**
+ * This vector is simply "Android.\n" which is too short.
+ */
+ private static final byte[] TooShort_Vector = new byte[] {
+ (byte) 0x41, (byte) 0x6E, (byte) 0x64, (byte) 0x72, (byte) 0x6F, (byte) 0x69,
+ (byte) 0x64, (byte) 0x2E, (byte) 0x0A,
+ };
+
+ /**
+ * This vector is simply "Android.\n" padded with zeros.
+ */
+ private static final byte[] TooShort_Vector_Zero_Padded = new byte[] {
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f,
+ (byte) 0x69, (byte) 0x64, (byte) 0x2e, (byte) 0x0a,
+ };
+
+ /**
+ * openssl rsautl -raw -sign -inkey rsa.key | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] RSA_Vector1_Encrypt_Private = new byte[] {
+ (byte) 0x35, (byte) 0x43, (byte) 0x38, (byte) 0x44, (byte) 0xAD, (byte) 0x3F,
+ (byte) 0x97, (byte) 0x02, (byte) 0xFB, (byte) 0x59, (byte) 0x1F, (byte) 0x4A,
+ (byte) 0x2B, (byte) 0xB9, (byte) 0x06, (byte) 0xEC, (byte) 0x66, (byte) 0xE6,
+ (byte) 0xD2, (byte) 0xC5, (byte) 0x8B, (byte) 0x7B, (byte) 0xE3, (byte) 0x18,
+ (byte) 0xBF, (byte) 0x07, (byte) 0xD6, (byte) 0x01, (byte) 0xF9, (byte) 0xD9,
+ (byte) 0x89, (byte) 0xC4, (byte) 0xDB, (byte) 0x00, (byte) 0x68, (byte) 0xFF,
+ (byte) 0x9B, (byte) 0x43, (byte) 0x90, (byte) 0xF2, (byte) 0xDB, (byte) 0x83,
+ (byte) 0xF4, (byte) 0x7E, (byte) 0xC6, (byte) 0x81, (byte) 0x01, (byte) 0x3A,
+ (byte) 0x0B, (byte) 0xE5, (byte) 0xED, (byte) 0x08, (byte) 0x73, (byte) 0x3E,
+ (byte) 0xE1, (byte) 0x3F, (byte) 0xDF, (byte) 0x1F, (byte) 0x07, (byte) 0x6D,
+ (byte) 0x22, (byte) 0x8D, (byte) 0xCC, (byte) 0x4E, (byte) 0xE3, (byte) 0x9A,
+ (byte) 0xBC, (byte) 0xCC, (byte) 0x8F, (byte) 0x9E, (byte) 0x9B, (byte) 0x02,
+ (byte) 0x48, (byte) 0x00, (byte) 0xAC, (byte) 0x9F, (byte) 0xA4, (byte) 0x8F,
+ (byte) 0x87, (byte) 0xA1, (byte) 0xA8, (byte) 0xE6, (byte) 0x9D, (byte) 0xCD,
+ (byte) 0x8B, (byte) 0x05, (byte) 0xE9, (byte) 0xD2, (byte) 0x05, (byte) 0x8D,
+ (byte) 0xC9, (byte) 0x95, (byte) 0x16, (byte) 0xD0, (byte) 0xCD, (byte) 0x43,
+ (byte) 0x25, (byte) 0x8A, (byte) 0x11, (byte) 0x46, (byte) 0xD7, (byte) 0x74,
+ (byte) 0x4C, (byte) 0xCF, (byte) 0x58, (byte) 0xF9, (byte) 0xA1, (byte) 0x30,
+ (byte) 0x84, (byte) 0x52, (byte) 0xC9, (byte) 0x01, (byte) 0x5F, (byte) 0x24,
+ (byte) 0x4C, (byte) 0xB1, (byte) 0x9F, (byte) 0x7D, (byte) 0x12, (byte) 0x38,
+ (byte) 0x27, (byte) 0x0F, (byte) 0x5E, (byte) 0xFF, (byte) 0xE0, (byte) 0x55,
+ (byte) 0x8B, (byte) 0xA3, (byte) 0xAD, (byte) 0x60, (byte) 0x35, (byte) 0x83,
+ (byte) 0x58, (byte) 0xAF, (byte) 0x99, (byte) 0xDE, (byte) 0x3F, (byte) 0x5D,
+ (byte) 0x80, (byte) 0x80, (byte) 0xFF, (byte) 0x9B, (byte) 0xDE, (byte) 0x5C,
+ (byte) 0xAB, (byte) 0x97, (byte) 0x43, (byte) 0x64, (byte) 0xD9, (byte) 0x9F,
+ (byte) 0xFB, (byte) 0x67, (byte) 0x65, (byte) 0xA5, (byte) 0x99, (byte) 0xE7,
+ (byte) 0xE6, (byte) 0xEB, (byte) 0x05, (byte) 0x95, (byte) 0xFC, (byte) 0x46,
+ (byte) 0x28, (byte) 0x4B, (byte) 0xD8, (byte) 0x8C, (byte) 0xF5, (byte) 0x0A,
+ (byte) 0xEB, (byte) 0x1F, (byte) 0x30, (byte) 0xEA, (byte) 0xE7, (byte) 0x67,
+ (byte) 0x11, (byte) 0x25, (byte) 0xF0, (byte) 0x44, (byte) 0x75, (byte) 0x74,
+ (byte) 0x94, (byte) 0x06, (byte) 0x78, (byte) 0xD0, (byte) 0x21, (byte) 0xF4,
+ (byte) 0x3F, (byte) 0xC8, (byte) 0xC4, (byte) 0x4A, (byte) 0x57, (byte) 0xBE,
+ (byte) 0x02, (byte) 0x3C, (byte) 0x93, (byte) 0xF6, (byte) 0x95, (byte) 0xFB,
+ (byte) 0xD1, (byte) 0x77, (byte) 0x8B, (byte) 0x43, (byte) 0xF0, (byte) 0xB9,
+ (byte) 0x7D, (byte) 0xE0, (byte) 0x32, (byte) 0xE1, (byte) 0x72, (byte) 0xB5,
+ (byte) 0x62, (byte) 0x3F, (byte) 0x86, (byte) 0xC3, (byte) 0xD4, (byte) 0x5F,
+ (byte) 0x5E, (byte) 0x54, (byte) 0x1B, (byte) 0x5B, (byte) 0xE6, (byte) 0x74,
+ (byte) 0xA1, (byte) 0x0B, (byte) 0xE5, (byte) 0x18, (byte) 0xD2, (byte) 0x4F,
+ (byte) 0x93, (byte) 0xF3, (byte) 0x09, (byte) 0x58, (byte) 0xCE, (byte) 0xF0,
+ (byte) 0xA3, (byte) 0x61, (byte) 0xE4, (byte) 0x6E, (byte) 0x46, (byte) 0x45,
+ (byte) 0x89, (byte) 0x50, (byte) 0xBD, (byte) 0x03, (byte) 0x3F, (byte) 0x38,
+ (byte) 0xDA, (byte) 0x5D, (byte) 0xD0, (byte) 0x1B, (byte) 0x1F, (byte) 0xB1,
+ (byte) 0xEE, (byte) 0x89, (byte) 0x59, (byte) 0xC5,
+ };
+
+ private static final byte[] RSA_Vector1_ZeroPadded_Encrypted = new byte[] {
+ (byte) 0x60, (byte) 0x4a, (byte) 0x12, (byte) 0xa3, (byte) 0xa7, (byte) 0x4a,
+ (byte) 0xa4, (byte) 0xbf, (byte) 0x6c, (byte) 0x36, (byte) 0xad, (byte) 0x66,
+ (byte) 0xdf, (byte) 0xce, (byte) 0xf1, (byte) 0xe4, (byte) 0x0f, (byte) 0xd4,
+ (byte) 0x54, (byte) 0x5f, (byte) 0x03, (byte) 0x15, (byte) 0x4b, (byte) 0x9e,
+ (byte) 0xeb, (byte) 0xfe, (byte) 0x9e, (byte) 0x24, (byte) 0xce, (byte) 0x8e,
+ (byte) 0xc3, (byte) 0x36, (byte) 0xa5, (byte) 0x76, (byte) 0xf6, (byte) 0x54,
+ (byte) 0xb7, (byte) 0x84, (byte) 0x48, (byte) 0x2f, (byte) 0xd4, (byte) 0x45,
+ (byte) 0x74, (byte) 0x48, (byte) 0x5f, (byte) 0x08, (byte) 0x4e, (byte) 0x9c,
+ (byte) 0x89, (byte) 0xcc, (byte) 0x34, (byte) 0x40, (byte) 0xb1, (byte) 0x5f,
+ (byte) 0xa7, (byte) 0x0e, (byte) 0x11, (byte) 0x4b, (byte) 0xb5, (byte) 0x94,
+ (byte) 0xbe, (byte) 0x14, (byte) 0xaa, (byte) 0xaa, (byte) 0xe0, (byte) 0x38,
+ (byte) 0x1c, (byte) 0xce, (byte) 0x40, (byte) 0x61, (byte) 0xfc, (byte) 0x08,
+ (byte) 0xcb, (byte) 0x14, (byte) 0x2b, (byte) 0xa6, (byte) 0x54, (byte) 0xdf,
+ (byte) 0x05, (byte) 0x5c, (byte) 0x9b, (byte) 0x4f, (byte) 0x14, (byte) 0x93,
+ (byte) 0xb0, (byte) 0x70, (byte) 0xd9, (byte) 0x32, (byte) 0xdc, (byte) 0x24,
+ (byte) 0xe0, (byte) 0xae, (byte) 0x48, (byte) 0xfc, (byte) 0x53, (byte) 0xee,
+ (byte) 0x7c, (byte) 0x9f, (byte) 0x69, (byte) 0x34, (byte) 0xf4, (byte) 0x76,
+ (byte) 0xee, (byte) 0x67, (byte) 0xb2, (byte) 0xa7, (byte) 0x33, (byte) 0x1c,
+ (byte) 0x47, (byte) 0xff, (byte) 0x5c, (byte) 0xf0, (byte) 0xb8, (byte) 0x04,
+ (byte) 0x2c, (byte) 0xfd, (byte) 0xe2, (byte) 0xb1, (byte) 0x4a, (byte) 0x0a,
+ (byte) 0x69, (byte) 0x1c, (byte) 0x80, (byte) 0x2b, (byte) 0xb4, (byte) 0x50,
+ (byte) 0x65, (byte) 0x5c, (byte) 0x76, (byte) 0x78, (byte) 0x9a, (byte) 0x0c,
+ (byte) 0x05, (byte) 0x62, (byte) 0xf0, (byte) 0xc4, (byte) 0x1c, (byte) 0x38,
+ (byte) 0x15, (byte) 0xd0, (byte) 0xe2, (byte) 0x5a, (byte) 0x3d, (byte) 0xb6,
+ (byte) 0xe0, (byte) 0x88, (byte) 0x85, (byte) 0xd1, (byte) 0x4f, (byte) 0x7e,
+ (byte) 0xfc, (byte) 0x77, (byte) 0x0d, (byte) 0x2a, (byte) 0x45, (byte) 0xd5,
+ (byte) 0xf8, (byte) 0x3c, (byte) 0x7b, (byte) 0x2d, (byte) 0x1b, (byte) 0x82,
+ (byte) 0xfe, (byte) 0x58, (byte) 0x22, (byte) 0x47, (byte) 0x06, (byte) 0x58,
+ (byte) 0x8b, (byte) 0x4f, (byte) 0xfb, (byte) 0x9b, (byte) 0x1c, (byte) 0x70,
+ (byte) 0x36, (byte) 0x12, (byte) 0x04, (byte) 0x17, (byte) 0x47, (byte) 0x8a,
+ (byte) 0x0a, (byte) 0xec, (byte) 0x12, (byte) 0x3b, (byte) 0xf8, (byte) 0xd2,
+ (byte) 0xdc, (byte) 0x3c, (byte) 0xc8, (byte) 0x46, (byte) 0xc6, (byte) 0x51,
+ (byte) 0x06, (byte) 0x06, (byte) 0xcb, (byte) 0x84, (byte) 0x67, (byte) 0xb5,
+ (byte) 0x68, (byte) 0xd9, (byte) 0x9c, (byte) 0xd4, (byte) 0x16, (byte) 0x5c,
+ (byte) 0xb4, (byte) 0xe2, (byte) 0x55, (byte) 0xe6, (byte) 0x3a, (byte) 0x73,
+ (byte) 0x01, (byte) 0x1d, (byte) 0x6f, (byte) 0x30, (byte) 0x31, (byte) 0x59,
+ (byte) 0x8b, (byte) 0x2f, (byte) 0x4c, (byte) 0xe7, (byte) 0x86, (byte) 0x4c,
+ (byte) 0x39, (byte) 0x4e, (byte) 0x67, (byte) 0x3b, (byte) 0x22, (byte) 0x9b,
+ (byte) 0x85, (byte) 0x5a, (byte) 0xc3, (byte) 0x29, (byte) 0xaf, (byte) 0x8c,
+ (byte) 0x7c, (byte) 0x59, (byte) 0x4a, (byte) 0x24, (byte) 0xfa, (byte) 0xba,
+ (byte) 0x55, (byte) 0x40, (byte) 0x13, (byte) 0x64, (byte) 0xd8, (byte) 0xcb,
+ (byte) 0x4b, (byte) 0x98, (byte) 0x3f, (byte) 0xae, (byte) 0x20, (byte) 0xfd,
+ (byte) 0x8a, (byte) 0x50, (byte) 0x73, (byte) 0xe4,
+ };
+ /*
+ * echo -n 'This is a test of OAEP' | xxd -p -i | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] RSA_Vector2_Plaintext =
+ new byte[] {(byte) 0x54, (byte) 0x68, (byte) 0x69, (byte) 0x73, (byte) 0x20,
+ (byte) 0x69, (byte) 0x73, (byte) 0x20, (byte) 0x61, (byte) 0x20, (byte) 0x74,
+ (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x6f, (byte) 0x66,
+ (byte) 0x20, (byte) 0x4f, (byte) 0x41, (byte) 0x45, (byte) 0x50};
+
+ /*
+ * echo -n 'This is a test of OAEP' | openssl pkeyutl -encrypt -inkey rsakey.pem \
+ * -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha1 -pkeyopt rsa_mgf1_md:sha1 \
+ * | xxd -p -i | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] RSA_Vector2_OAEP_SHA1_MGF1_SHA1 =
+ new byte[] {(byte) 0x53, (byte) 0x71, (byte) 0x84, (byte) 0x2e, (byte) 0x01,
+ (byte) 0x74, (byte) 0x82, (byte) 0xb3, (byte) 0x01, (byte) 0xac, (byte) 0x2b,
+ (byte) 0xbd, (byte) 0x40, (byte) 0xa7, (byte) 0x5b, (byte) 0x60, (byte) 0xf1,
+ (byte) 0xde, (byte) 0x54, (byte) 0x1d, (byte) 0x94, (byte) 0xc1, (byte) 0x10,
+ (byte) 0x31, (byte) 0x6f, (byte) 0xa3, (byte) 0xd8, (byte) 0x41, (byte) 0x2e,
+ (byte) 0x82, (byte) 0xad, (byte) 0x07, (byte) 0x6f, (byte) 0x25, (byte) 0x6c,
+ (byte) 0xb5, (byte) 0xef, (byte) 0xc6, (byte) 0xa6, (byte) 0xfb, (byte) 0xb1,
+ (byte) 0x9d, (byte) 0x75, (byte) 0x67, (byte) 0xb0, (byte) 0x97, (byte) 0x21,
+ (byte) 0x3c, (byte) 0x17, (byte) 0x04, (byte) 0xdc, (byte) 0x4e, (byte) 0x7e,
+ (byte) 0x3f, (byte) 0x5c, (byte) 0x13, (byte) 0x5e, (byte) 0x15, (byte) 0x0f,
+ (byte) 0xe2, (byte) 0xa7, (byte) 0x62, (byte) 0x6a, (byte) 0x08, (byte) 0xb1,
+ (byte) 0xbc, (byte) 0x2f, (byte) 0xcb, (byte) 0xb5, (byte) 0x96, (byte) 0x2d,
+ (byte) 0xec, (byte) 0x71, (byte) 0x4d, (byte) 0x59, (byte) 0x6e, (byte) 0x27,
+ (byte) 0x85, (byte) 0x87, (byte) 0x9b, (byte) 0xcc, (byte) 0x40, (byte) 0x32,
+ (byte) 0x09, (byte) 0x06, (byte) 0xe6, (byte) 0x7d, (byte) 0xdf, (byte) 0xeb,
+ (byte) 0x2f, (byte) 0xa8, (byte) 0x1c, (byte) 0x53, (byte) 0xdb, (byte) 0xa7,
+ (byte) 0x48, (byte) 0xf5, (byte) 0xbf, (byte) 0x2f, (byte) 0xbb, (byte) 0xee,
+ (byte) 0xc7, (byte) 0x55, (byte) 0x5e, (byte) 0xc4, (byte) 0x1c, (byte) 0x84,
+ (byte) 0xed, (byte) 0x97, (byte) 0x7e, (byte) 0xce, (byte) 0xa5, (byte) 0x69,
+ (byte) 0x73, (byte) 0xb3, (byte) 0xe0, (byte) 0x8c, (byte) 0x2a, (byte) 0xf2,
+ (byte) 0xc7, (byte) 0x65, (byte) 0xff, (byte) 0x10, (byte) 0xed, (byte) 0x25,
+ (byte) 0xf0, (byte) 0xf8, (byte) 0xda, (byte) 0x2f, (byte) 0x7f, (byte) 0xe0,
+ (byte) 0x69, (byte) 0xed, (byte) 0xb1, (byte) 0x0e, (byte) 0xcb, (byte) 0x43,
+ (byte) 0xe4, (byte) 0x31, (byte) 0xe6, (byte) 0x52, (byte) 0xfd, (byte) 0xa7,
+ (byte) 0xe5, (byte) 0x21, (byte) 0xd0, (byte) 0x67, (byte) 0x0a, (byte) 0xc1,
+ (byte) 0xa1, (byte) 0xb9, (byte) 0x04, (byte) 0xdb, (byte) 0x98, (byte) 0x4f,
+ (byte) 0xf9, (byte) 0x5c, (byte) 0x60, (byte) 0x4d, (byte) 0xac, (byte) 0x7a,
+ (byte) 0x69, (byte) 0xbd, (byte) 0x63, (byte) 0x0d, (byte) 0xb2, (byte) 0x01,
+ (byte) 0x83, (byte) 0xd7, (byte) 0x22, (byte) 0x5d, (byte) 0xed, (byte) 0xbd,
+ (byte) 0x32, (byte) 0x98, (byte) 0xd1, (byte) 0x4a, (byte) 0x2e, (byte) 0xb7,
+ (byte) 0xb1, (byte) 0x6d, (byte) 0x8a, (byte) 0x8f, (byte) 0xef, (byte) 0xc3,
+ (byte) 0x89, (byte) 0xdf, (byte) 0xa5, (byte) 0xac, (byte) 0xfb, (byte) 0x38,
+ (byte) 0x61, (byte) 0x32, (byte) 0xc5, (byte) 0x19, (byte) 0x83, (byte) 0x1f,
+ (byte) 0x9c, (byte) 0x45, (byte) 0x58, (byte) 0xdd, (byte) 0xa3, (byte) 0x57,
+ (byte) 0xe4, (byte) 0x91, (byte) 0xd2, (byte) 0x11, (byte) 0xf8, (byte) 0x96,
+ (byte) 0x36, (byte) 0x67, (byte) 0x99, (byte) 0x2b, (byte) 0x62, (byte) 0x21,
+ (byte) 0xe3, (byte) 0xa8, (byte) 0x5e, (byte) 0xa4, (byte) 0x2e, (byte) 0x0c,
+ (byte) 0x29, (byte) 0xf9, (byte) 0xcd, (byte) 0xfa, (byte) 0xbe, (byte) 0x3f,
+ (byte) 0xd8, (byte) 0xec, (byte) 0x6b, (byte) 0x32, (byte) 0xb3, (byte) 0x40,
+ (byte) 0x4f, (byte) 0x48, (byte) 0xe3, (byte) 0x14, (byte) 0x87, (byte) 0xa7,
+ (byte) 0x5c, (byte) 0xba, (byte) 0xdf, (byte) 0x0e, (byte) 0x64, (byte) 0xdc,
+ (byte) 0xe2, (byte) 0x51, (byte) 0xf4, (byte) 0x41, (byte) 0x25, (byte) 0x23,
+ (byte) 0xc8, (byte) 0x50, (byte) 0x1e, (byte) 0x9e, (byte) 0xb0};
+
+ /*
+ * echo -n 'This is a test of OAEP' | openssl pkeyutl -encrypt -inkey rsakey.pem -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha1 | xxd -p -i | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] RSA_Vector2_OAEP_SHA256_MGF1_SHA1 =
+ new byte[] {(byte) 0x25, (byte) 0x9f, (byte) 0xc3, (byte) 0x69, (byte) 0xbc,
+ (byte) 0x3f, (byte) 0xe7, (byte) 0x9e, (byte) 0x76, (byte) 0xef, (byte) 0x6c,
+ (byte) 0xd2, (byte) 0x2b, (byte) 0x7b, (byte) 0xf0, (byte) 0xeb, (byte) 0xc2,
+ (byte) 0x28, (byte) 0x40, (byte) 0x4e, (byte) 0x9b, (byte) 0x2a, (byte) 0x4e,
+ (byte) 0xa4, (byte) 0x79, (byte) 0x66, (byte) 0xf1, (byte) 0x10, (byte) 0x96,
+ (byte) 0x8c, (byte) 0x58, (byte) 0x92, (byte) 0xb7, (byte) 0x70, (byte) 0xed,
+ (byte) 0x3a, (byte) 0xe0, (byte) 0x99, (byte) 0xd1, (byte) 0x80, (byte) 0x4b,
+ (byte) 0x53, (byte) 0x70, (byte) 0x9b, (byte) 0x51, (byte) 0xbf, (byte) 0xc1,
+ (byte) 0x3a, (byte) 0x70, (byte) 0xc5, (byte) 0x79, (byte) 0x21, (byte) 0x6e,
+ (byte) 0xb3, (byte) 0xf7, (byte) 0xa9, (byte) 0xe6, (byte) 0xcb, (byte) 0x70,
+ (byte) 0xe4, (byte) 0xf3, (byte) 0x4f, (byte) 0x45, (byte) 0xcf, (byte) 0xb7,
+ (byte) 0x2b, (byte) 0x38, (byte) 0xfd, (byte) 0x5d, (byte) 0x9a, (byte) 0x53,
+ (byte) 0xc5, (byte) 0x05, (byte) 0x74, (byte) 0x8d, (byte) 0x1d, (byte) 0x6e,
+ (byte) 0x83, (byte) 0xaa, (byte) 0x71, (byte) 0xc5, (byte) 0xe1, (byte) 0xa1,
+ (byte) 0xa6, (byte) 0xf3, (byte) 0xee, (byte) 0x5f, (byte) 0x9e, (byte) 0x4f,
+ (byte) 0xe8, (byte) 0x15, (byte) 0xd5, (byte) 0xa9, (byte) 0x1b, (byte) 0xa6,
+ (byte) 0x41, (byte) 0x2b, (byte) 0x18, (byte) 0x13, (byte) 0x20, (byte) 0x9f,
+ (byte) 0x6b, (byte) 0xf1, (byte) 0xd8, (byte) 0xf4, (byte) 0x87, (byte) 0xfa,
+ (byte) 0x80, (byte) 0xec, (byte) 0x0e, (byte) 0xa4, (byte) 0x4b, (byte) 0x24,
+ (byte) 0x03, (byte) 0x14, (byte) 0x25, (byte) 0xf2, (byte) 0x20, (byte) 0xfc,
+ (byte) 0x52, (byte) 0xf9, (byte) 0xd6, (byte) 0x7a, (byte) 0x4a, (byte) 0x45,
+ (byte) 0x33, (byte) 0xec, (byte) 0xde, (byte) 0x3c, (byte) 0x5b, (byte) 0xf2,
+ (byte) 0xdc, (byte) 0x8e, (byte) 0xc6, (byte) 0xb3, (byte) 0x26, (byte) 0xd3,
+ (byte) 0x68, (byte) 0xa7, (byte) 0xd8, (byte) 0x3a, (byte) 0xde, (byte) 0xa9,
+ (byte) 0x25, (byte) 0x1d, (byte) 0x42, (byte) 0x75, (byte) 0x66, (byte) 0x16,
+ (byte) 0x29, (byte) 0xad, (byte) 0x09, (byte) 0x74, (byte) 0x41, (byte) 0xbb,
+ (byte) 0x45, (byte) 0x39, (byte) 0x04, (byte) 0x7a, (byte) 0x93, (byte) 0xad,
+ (byte) 0x1c, (byte) 0xa6, (byte) 0x38, (byte) 0xf4, (byte) 0xac, (byte) 0xca,
+ (byte) 0x5a, (byte) 0xab, (byte) 0x92, (byte) 0x76, (byte) 0x26, (byte) 0x3c,
+ (byte) 0xeb, (byte) 0xda, (byte) 0xfc, (byte) 0x25, (byte) 0x93, (byte) 0x23,
+ (byte) 0x01, (byte) 0xe2, (byte) 0xac, (byte) 0x5e, (byte) 0x4c, (byte) 0xb7,
+ (byte) 0xbc, (byte) 0x5b, (byte) 0xaa, (byte) 0x14, (byte) 0xe9, (byte) 0xbf,
+ (byte) 0x2d, (byte) 0x3a, (byte) 0xdc, (byte) 0x2f, (byte) 0x6b, (byte) 0x4d,
+ (byte) 0x0e, (byte) 0x0a, (byte) 0x82, (byte) 0x3c, (byte) 0xd9, (byte) 0x32,
+ (byte) 0xc1, (byte) 0xc4, (byte) 0xa2, (byte) 0x46, (byte) 0x71, (byte) 0x10,
+ (byte) 0x54, (byte) 0x1a, (byte) 0xa6, (byte) 0xaa, (byte) 0x64, (byte) 0xe7,
+ (byte) 0xc2, (byte) 0xae, (byte) 0xbc, (byte) 0x3d, (byte) 0xa4, (byte) 0xa8,
+ (byte) 0xd1, (byte) 0xb7, (byte) 0x27, (byte) 0xef, (byte) 0x5f, (byte) 0xe7,
+ (byte) 0xa7, (byte) 0x5d, (byte) 0xa0, (byte) 0xcd, (byte) 0x57, (byte) 0xf1,
+ (byte) 0xe0, (byte) 0xd8, (byte) 0x42, (byte) 0x10, (byte) 0x77, (byte) 0xc3,
+ (byte) 0xa7, (byte) 0x1e, (byte) 0x0c, (byte) 0x37, (byte) 0x16, (byte) 0x11,
+ (byte) 0x94, (byte) 0x21, (byte) 0xf2, (byte) 0xca, (byte) 0x60, (byte) 0xce,
+ (byte) 0xca, (byte) 0x59, (byte) 0xf9, (byte) 0xe5, (byte) 0xe4};
+
+ /*
+ * echo -n 'This is a test of OAEP' | openssl pkeyutl -encrypt -inkey /tmp/rsakey.txt -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha1 -pkeyopt rsa_oaep_label:010203FFA00A | xxd -p -i | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] RSA_Vector2_OAEP_SHA256_MGF1_SHA1_LABEL =
+ new byte[] {(byte) 0x80, (byte) 0xb1, (byte) 0xf2, (byte) 0xc2, (byte) 0x03,
+ (byte) 0xc5, (byte) 0xdf, (byte) 0xbd, (byte) 0xed, (byte) 0xfe, (byte) 0xe6,
+ (byte) 0xff, (byte) 0xd3, (byte) 0x38, (byte) 0x1e, (byte) 0x6d, (byte) 0xae,
+ (byte) 0x47, (byte) 0xfe, (byte) 0x19, (byte) 0xf9, (byte) 0x8c, (byte) 0xf1,
+ (byte) 0x4d, (byte) 0x18, (byte) 0x2b, (byte) 0x7e, (byte) 0x8e, (byte) 0x47,
+ (byte) 0x39, (byte) 0xa8, (byte) 0x04, (byte) 0xc4, (byte) 0x7d, (byte) 0x56,
+ (byte) 0x03, (byte) 0x15, (byte) 0x92, (byte) 0x18, (byte) 0xde, (byte) 0x56,
+ (byte) 0xb3, (byte) 0x01, (byte) 0x93, (byte) 0x16, (byte) 0xe3, (byte) 0xfa,
+ (byte) 0xaa, (byte) 0xf3, (byte) 0x73, (byte) 0x39, (byte) 0x26, (byte) 0xfb,
+ (byte) 0xb0, (byte) 0x18, (byte) 0x20, (byte) 0xdb, (byte) 0xa1, (byte) 0xbf,
+ (byte) 0x31, (byte) 0x22, (byte) 0xc8, (byte) 0x1d, (byte) 0xdb, (byte) 0xa0,
+ (byte) 0x5a, (byte) 0x22, (byte) 0xcd, (byte) 0x09, (byte) 0xb3, (byte) 0xcb,
+ (byte) 0xa2, (byte) 0x46, (byte) 0x14, (byte) 0x35, (byte) 0x66, (byte) 0xe8,
+ (byte) 0xb8, (byte) 0x07, (byte) 0x23, (byte) 0xc5, (byte) 0xae, (byte) 0xe6,
+ (byte) 0xf1, (byte) 0x7a, (byte) 0x8f, (byte) 0x5c, (byte) 0x44, (byte) 0x34,
+ (byte) 0xbf, (byte) 0xd6, (byte) 0xf8, (byte) 0x0c, (byte) 0xc7, (byte) 0x8d,
+ (byte) 0xcd, (byte) 0x23, (byte) 0x84, (byte) 0xbe, (byte) 0x9b, (byte) 0xbf,
+ (byte) 0x9a, (byte) 0x70, (byte) 0x0f, (byte) 0x18, (byte) 0xc0, (byte) 0x6f,
+ (byte) 0x23, (byte) 0x67, (byte) 0xf8, (byte) 0xbb, (byte) 0xce, (byte) 0xc2,
+ (byte) 0x47, (byte) 0x82, (byte) 0xa0, (byte) 0xa5, (byte) 0x60, (byte) 0xcd,
+ (byte) 0x25, (byte) 0xa5, (byte) 0x4b, (byte) 0xe4, (byte) 0x06, (byte) 0x7f,
+ (byte) 0x46, (byte) 0x62, (byte) 0x86, (byte) 0x94, (byte) 0xbc, (byte) 0x7f,
+ (byte) 0xb0, (byte) 0x2e, (byte) 0xc1, (byte) 0x8c, (byte) 0x6c, (byte) 0x58,
+ (byte) 0x05, (byte) 0x6f, (byte) 0x35, (byte) 0x76, (byte) 0xd3, (byte) 0xdf,
+ (byte) 0xc0, (byte) 0xdd, (byte) 0x66, (byte) 0xbe, (byte) 0xa1, (byte) 0x7e,
+ (byte) 0x52, (byte) 0xed, (byte) 0x81, (byte) 0x0e, (byte) 0x2d, (byte) 0x5b,
+ (byte) 0x2b, (byte) 0xe3, (byte) 0x52, (byte) 0x0e, (byte) 0x56, (byte) 0x9b,
+ (byte) 0x05, (byte) 0x72, (byte) 0xa8, (byte) 0xc8, (byte) 0x57, (byte) 0x22,
+ (byte) 0x67, (byte) 0x0e, (byte) 0x5f, (byte) 0x01, (byte) 0xf2, (byte) 0x69,
+ (byte) 0x66, (byte) 0x6a, (byte) 0x47, (byte) 0x4f, (byte) 0x78, (byte) 0xb3,
+ (byte) 0x1e, (byte) 0x7d, (byte) 0xce, (byte) 0xb3, (byte) 0x35, (byte) 0xdf,
+ (byte) 0x23, (byte) 0xac, (byte) 0xf8, (byte) 0x88, (byte) 0xa1, (byte) 0xde,
+ (byte) 0x38, (byte) 0x96, (byte) 0xfd, (byte) 0xa2, (byte) 0x5d, (byte) 0x09,
+ (byte) 0x52, (byte) 0x11, (byte) 0x2b, (byte) 0x21, (byte) 0xf0, (byte) 0x0d,
+ (byte) 0x4c, (byte) 0x15, (byte) 0xc3, (byte) 0x88, (byte) 0x2b, (byte) 0xf6,
+ (byte) 0x2b, (byte) 0xe3, (byte) 0xfd, (byte) 0x52, (byte) 0xf0, (byte) 0x09,
+ (byte) 0x5c, (byte) 0x4f, (byte) 0x5b, (byte) 0x8b, (byte) 0x84, (byte) 0x71,
+ (byte) 0x72, (byte) 0x8d, (byte) 0xaa, (byte) 0x6c, (byte) 0x55, (byte) 0xba,
+ (byte) 0xe7, (byte) 0x9c, (byte) 0xba, (byte) 0xbf, (byte) 0xf4, (byte) 0x09,
+ (byte) 0x0a, (byte) 0x60, (byte) 0xec, (byte) 0x53, (byte) 0xa4, (byte) 0x01,
+ (byte) 0xa5, (byte) 0xf2, (byte) 0x58, (byte) 0xab, (byte) 0x95, (byte) 0x68,
+ (byte) 0x79, (byte) 0x0b, (byte) 0xc3, (byte) 0xc4, (byte) 0x00, (byte) 0x68,
+ (byte) 0x19, (byte) 0xca, (byte) 0x07, (byte) 0x0d, (byte) 0x32};
+
+ /*
+ * echo -n 'This is a test of OAEP' | openssl pkeyutl -encrypt -inkey rsakey.pem \
+ * -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha224 -pkeyopt rsa_mgf1_md:sha224 \
+ * | xxd -p -i | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] RSA_Vector2_OAEP_SHA224_MGF1_SHA224 =
+ new byte[] {(byte) 0xae, (byte) 0xdd, (byte) 0xe6, (byte) 0xab, (byte) 0x00,
+ (byte) 0xd6, (byte) 0x1e, (byte) 0x7e, (byte) 0x85, (byte) 0x63, (byte) 0xab,
+ (byte) 0x51, (byte) 0x79, (byte) 0x92, (byte) 0xf1, (byte) 0xb9, (byte) 0x4f,
+ (byte) 0x23, (byte) 0xae, (byte) 0xf7, (byte) 0x1b, (byte) 0x5f, (byte) 0x10,
+ (byte) 0x5b, (byte) 0xa5, (byte) 0x15, (byte) 0x87, (byte) 0xa3, (byte) 0xbb,
+ (byte) 0x26, (byte) 0xfe, (byte) 0x7f, (byte) 0xc0, (byte) 0xa3, (byte) 0x67,
+ (byte) 0x95, (byte) 0xda, (byte) 0xc4, (byte) 0x6f, (byte) 0x6e, (byte) 0x08,
+ (byte) 0x23, (byte) 0x28, (byte) 0x0b, (byte) 0xdd, (byte) 0x29, (byte) 0x29,
+ (byte) 0xdc, (byte) 0xb0, (byte) 0x35, (byte) 0x16, (byte) 0x2e, (byte) 0x0f,
+ (byte) 0xb9, (byte) 0x1d, (byte) 0x90, (byte) 0x27, (byte) 0x68, (byte) 0xc7,
+ (byte) 0x92, (byte) 0x52, (byte) 0x8a, (byte) 0x1d, (byte) 0x48, (byte) 0x6a,
+ (byte) 0x7d, (byte) 0x0b, (byte) 0xf6, (byte) 0x35, (byte) 0xca, (byte) 0xe1,
+ (byte) 0x57, (byte) 0xdd, (byte) 0x36, (byte) 0x3b, (byte) 0x51, (byte) 0x45,
+ (byte) 0x77, (byte) 0x28, (byte) 0x4f, (byte) 0x98, (byte) 0xc0, (byte) 0xe0,
+ (byte) 0xa7, (byte) 0x51, (byte) 0x98, (byte) 0x84, (byte) 0x7a, (byte) 0x29,
+ (byte) 0x05, (byte) 0x9f, (byte) 0x60, (byte) 0x66, (byte) 0xf6, (byte) 0x83,
+ (byte) 0xcd, (byte) 0x03, (byte) 0x3e, (byte) 0x82, (byte) 0x0f, (byte) 0x57,
+ (byte) 0x4b, (byte) 0x27, (byte) 0x14, (byte) 0xf6, (byte) 0xc8, (byte) 0x5b,
+ (byte) 0xed, (byte) 0xc3, (byte) 0x77, (byte) 0x6f, (byte) 0xec, (byte) 0x0e,
+ (byte) 0xae, (byte) 0x59, (byte) 0xbe, (byte) 0x68, (byte) 0x76, (byte) 0x16,
+ (byte) 0x17, (byte) 0x77, (byte) 0xe2, (byte) 0xbd, (byte) 0xe0, (byte) 0x5a,
+ (byte) 0x14, (byte) 0xd9, (byte) 0xf4, (byte) 0x3f, (byte) 0x50, (byte) 0x31,
+ (byte) 0xf0, (byte) 0x0c, (byte) 0x82, (byte) 0x6c, (byte) 0xcc, (byte) 0x81,
+ (byte) 0x84, (byte) 0x3e, (byte) 0x63, (byte) 0x93, (byte) 0xe7, (byte) 0x12,
+ (byte) 0x2d, (byte) 0xc9, (byte) 0xa3, (byte) 0xe3, (byte) 0xce, (byte) 0xfd,
+ (byte) 0xc7, (byte) 0xe1, (byte) 0xef, (byte) 0xa4, (byte) 0x16, (byte) 0x5c,
+ (byte) 0x60, (byte) 0xb1, (byte) 0x80, (byte) 0x31, (byte) 0x15, (byte) 0x5c,
+ (byte) 0x35, (byte) 0x25, (byte) 0x0b, (byte) 0x89, (byte) 0xe4, (byte) 0x56,
+ (byte) 0x74, (byte) 0x8b, (byte) 0xaf, (byte) 0x8e, (byte) 0xe9, (byte) 0xe2,
+ (byte) 0x37, (byte) 0x17, (byte) 0xe6, (byte) 0x7b, (byte) 0x78, (byte) 0xd8,
+ (byte) 0x2c, (byte) 0x27, (byte) 0x52, (byte) 0x21, (byte) 0x96, (byte) 0xa0,
+ (byte) 0x92, (byte) 0x95, (byte) 0x64, (byte) 0xc3, (byte) 0x7f, (byte) 0x45,
+ (byte) 0xfc, (byte) 0x3d, (byte) 0x48, (byte) 0x4a, (byte) 0xd5, (byte) 0xa4,
+ (byte) 0x0a, (byte) 0x57, (byte) 0x07, (byte) 0x57, (byte) 0x95, (byte) 0x9f,
+ (byte) 0x2f, (byte) 0x75, (byte) 0x32, (byte) 0x2a, (byte) 0x4d, (byte) 0x64,
+ (byte) 0xbd, (byte) 0xb1, (byte) 0xe0, (byte) 0x46, (byte) 0x4f, (byte) 0xe8,
+ (byte) 0x6c, (byte) 0x4b, (byte) 0x77, (byte) 0xcc, (byte) 0x36, (byte) 0x87,
+ (byte) 0x05, (byte) 0x56, (byte) 0x9a, (byte) 0xe4, (byte) 0x2c, (byte) 0x43,
+ (byte) 0xfd, (byte) 0x34, (byte) 0x97, (byte) 0xf8, (byte) 0xd7, (byte) 0x91,
+ (byte) 0xff, (byte) 0x56, (byte) 0x86, (byte) 0x17, (byte) 0x49, (byte) 0x0a,
+ (byte) 0x52, (byte) 0xfb, (byte) 0xe5, (byte) 0x49, (byte) 0xdf, (byte) 0xc1,
+ (byte) 0x28, (byte) 0x9d, (byte) 0x85, (byte) 0x66, (byte) 0x9d, (byte) 0x1d,
+ (byte) 0xa4, (byte) 0x7e, (byte) 0x9a, (byte) 0x5b, (byte) 0x30};
+
+ /*
+ * echo -n 'This is a test of OAEP' | openssl pkeyutl -encrypt -inkey /tmp/rsakey.txt \
+ * -pkeyopt rsa_padding_mode:oaep -pkey rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256 \
+ * | xxd -p -i | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] RSA_Vector2_OAEP_SHA256_MGF1_SHA256 =
+ new byte[] {(byte) 0x6a, (byte) 0x2b, (byte) 0xb2, (byte) 0xa3, (byte) 0x26,
+ (byte) 0xa6, (byte) 0x7a, (byte) 0x4a, (byte) 0x1f, (byte) 0xe5, (byte) 0xc8,
+ (byte) 0x94, (byte) 0x11, (byte) 0x1a, (byte) 0x92, (byte) 0x07, (byte) 0x0a,
+ (byte) 0xf4, (byte) 0x07, (byte) 0x0b, (byte) 0xd6, (byte) 0x37, (byte) 0xa5,
+ (byte) 0x5d, (byte) 0x16, (byte) 0x0a, (byte) 0x7d, (byte) 0x13, (byte) 0x27,
+ (byte) 0x32, (byte) 0x5a, (byte) 0xc3, (byte) 0x0d, (byte) 0x7a, (byte) 0x54,
+ (byte) 0xfe, (byte) 0x02, (byte) 0x28, (byte) 0xc6, (byte) 0x8e, (byte) 0x32,
+ (byte) 0x7b, (byte) 0x0a, (byte) 0x52, (byte) 0xf8, (byte) 0xe6, (byte) 0xab,
+ (byte) 0x16, (byte) 0x77, (byte) 0x7c, (byte) 0x53, (byte) 0xcd, (byte) 0xb0,
+ (byte) 0xb6, (byte) 0x90, (byte) 0xce, (byte) 0x7b, (byte) 0xa5, (byte) 0xdb,
+ (byte) 0xab, (byte) 0xfd, (byte) 0xf5, (byte) 0xbb, (byte) 0x49, (byte) 0x63,
+ (byte) 0xb7, (byte) 0xa8, (byte) 0x3e, (byte) 0x53, (byte) 0xf1, (byte) 0x00,
+ (byte) 0x4d, (byte) 0x72, (byte) 0x15, (byte) 0x34, (byte) 0xa8, (byte) 0x5b,
+ (byte) 0x00, (byte) 0x01, (byte) 0x75, (byte) 0xdc, (byte) 0xb6, (byte) 0xd1,
+ (byte) 0xdf, (byte) 0xcb, (byte) 0x93, (byte) 0xf3, (byte) 0x31, (byte) 0x04,
+ (byte) 0x7e, (byte) 0x48, (byte) 0x3e, (byte) 0xc9, (byte) 0xaf, (byte) 0xd7,
+ (byte) 0xbd, (byte) 0x9e, (byte) 0x73, (byte) 0x01, (byte) 0x79, (byte) 0xf8,
+ (byte) 0xdc, (byte) 0x46, (byte) 0x31, (byte) 0x55, (byte) 0x83, (byte) 0x21,
+ (byte) 0xd1, (byte) 0x19, (byte) 0x0b, (byte) 0x57, (byte) 0xf1, (byte) 0x06,
+ (byte) 0xb9, (byte) 0x32, (byte) 0x0e, (byte) 0x9d, (byte) 0x38, (byte) 0x53,
+ (byte) 0x94, (byte) 0x96, (byte) 0xd4, (byte) 0x6d, (byte) 0x18, (byte) 0xe2,
+ (byte) 0xe3, (byte) 0xcd, (byte) 0xfa, (byte) 0xfe, (byte) 0xb3, (byte) 0xe3,
+ (byte) 0x27, (byte) 0xd7, (byte) 0x45, (byte) 0xe8, (byte) 0x46, (byte) 0x6b,
+ (byte) 0x06, (byte) 0x0f, (byte) 0x5e, (byte) 0x24, (byte) 0x02, (byte) 0xef,
+ (byte) 0xa2, (byte) 0x69, (byte) 0xe6, (byte) 0x15, (byte) 0xb3, (byte) 0x8f,
+ (byte) 0x71, (byte) 0x97, (byte) 0x39, (byte) 0xfb, (byte) 0x32, (byte) 0xe0,
+ (byte) 0xe5, (byte) 0xac, (byte) 0x46, (byte) 0xb4, (byte) 0xe7, (byte) 0x3d,
+ (byte) 0x89, (byte) 0xba, (byte) 0xd9, (byte) 0x4c, (byte) 0x25, (byte) 0x97,
+ (byte) 0xef, (byte) 0xe6, (byte) 0x17, (byte) 0x23, (byte) 0x4e, (byte) 0xc8,
+ (byte) 0xdb, (byte) 0x18, (byte) 0x9b, (byte) 0xba, (byte) 0xb5, (byte) 0x7e,
+ (byte) 0x19, (byte) 0x4d, (byte) 0x95, (byte) 0x7d, (byte) 0x60, (byte) 0x1b,
+ (byte) 0xa7, (byte) 0x06, (byte) 0x1e, (byte) 0x99, (byte) 0x4a, (byte) 0xf2,
+ (byte) 0x82, (byte) 0x71, (byte) 0x62, (byte) 0x41, (byte) 0xa4, (byte) 0xa7,
+ (byte) 0xdb, (byte) 0x88, (byte) 0xb0, (byte) 0x4a, (byte) 0xc7, (byte) 0x3b,
+ (byte) 0xce, (byte) 0x91, (byte) 0x4f, (byte) 0xc7, (byte) 0xca, (byte) 0x6f,
+ (byte) 0x89, (byte) 0xac, (byte) 0x1a, (byte) 0x36, (byte) 0x84, (byte) 0x0c,
+ (byte) 0x97, (byte) 0xa0, (byte) 0x1a, (byte) 0x08, (byte) 0x6f, (byte) 0x70,
+ (byte) 0xf3, (byte) 0x94, (byte) 0xa0, (byte) 0x0f, (byte) 0x44, (byte) 0xdd,
+ (byte) 0x86, (byte) 0x9d, (byte) 0x2c, (byte) 0xac, (byte) 0x43, (byte) 0xed,
+ (byte) 0xb8, (byte) 0xa1, (byte) 0x66, (byte) 0xf3, (byte) 0xd3, (byte) 0x5c,
+ (byte) 0xe5, (byte) 0xe2, (byte) 0x4c, (byte) 0x7e, (byte) 0xda, (byte) 0x20,
+ (byte) 0xbd, (byte) 0x5a, (byte) 0x75, (byte) 0x12, (byte) 0x31, (byte) 0x23,
+ (byte) 0x02, (byte) 0xb5, (byte) 0x1f, (byte) 0x38, (byte) 0x98};
+
+ /*
+ * echo -n 'This is a test of OAEP' | openssl pkeyutl -encrypt -inkey /tmp/rsakey.txt \
+ * -pkeyopt rsa_padding_mode:oaep -pkey rsa_oaep_md:sha384 -pkeyopt rsa_mgf1_md:sha384 \
+ * | xxd -p -i | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] RSA_Vector2_OAEP_SHA384_MGF1_SHA384 =
+ new byte[] {(byte) 0xa1, (byte) 0xb3, (byte) 0x3b, (byte) 0x34, (byte) 0x69,
+ (byte) 0x9e, (byte) 0xd8, (byte) 0xa0, (byte) 0x37, (byte) 0x2c, (byte) 0xeb,
+ (byte) 0xef, (byte) 0xf2, (byte) 0xaf, (byte) 0xfa, (byte) 0x63, (byte) 0x5d,
+ (byte) 0x88, (byte) 0xac, (byte) 0x51, (byte) 0xd4, (byte) 0x7f, (byte) 0x85,
+ (byte) 0xf0, (byte) 0x5e, (byte) 0xb4, (byte) 0x81, (byte) 0x7c, (byte) 0x82,
+ (byte) 0x4f, (byte) 0x92, (byte) 0xf7, (byte) 0x77, (byte) 0x48, (byte) 0x4c,
+ (byte) 0xb1, (byte) 0x42, (byte) 0xb3, (byte) 0x0e, (byte) 0x94, (byte) 0xc8,
+ (byte) 0x5a, (byte) 0xae, (byte) 0xed, (byte) 0x8d, (byte) 0x51, (byte) 0x72,
+ (byte) 0x6b, (byte) 0xa9, (byte) 0xd4, (byte) 0x1e, (byte) 0xbe, (byte) 0x38,
+ (byte) 0x2c, (byte) 0xd0, (byte) 0x43, (byte) 0xae, (byte) 0xb4, (byte) 0x30,
+ (byte) 0xa9, (byte) 0x93, (byte) 0x47, (byte) 0xb5, (byte) 0x9d, (byte) 0x03,
+ (byte) 0x92, (byte) 0x25, (byte) 0x74, (byte) 0xed, (byte) 0xfa, (byte) 0xfe,
+ (byte) 0xf1, (byte) 0xba, (byte) 0x04, (byte) 0x3a, (byte) 0x4d, (byte) 0x6d,
+ (byte) 0x9a, (byte) 0x0d, (byte) 0x95, (byte) 0x02, (byte) 0xb0, (byte) 0xac,
+ (byte) 0x77, (byte) 0x11, (byte) 0x44, (byte) 0xeb, (byte) 0xd2, (byte) 0x02,
+ (byte) 0x90, (byte) 0xea, (byte) 0x2f, (byte) 0x68, (byte) 0x2a, (byte) 0x69,
+ (byte) 0xcf, (byte) 0x45, (byte) 0x34, (byte) 0xff, (byte) 0x00, (byte) 0xc6,
+ (byte) 0x3c, (byte) 0x0b, (byte) 0x2c, (byte) 0x5f, (byte) 0x8c, (byte) 0x2c,
+ (byte) 0xbf, (byte) 0xc2, (byte) 0x4b, (byte) 0x16, (byte) 0x07, (byte) 0x84,
+ (byte) 0x74, (byte) 0xf0, (byte) 0x7a, (byte) 0x01, (byte) 0x7e, (byte) 0x74,
+ (byte) 0x01, (byte) 0x88, (byte) 0xce, (byte) 0xda, (byte) 0xe4, (byte) 0x21,
+ (byte) 0x89, (byte) 0xfc, (byte) 0xac, (byte) 0x68, (byte) 0xdb, (byte) 0xfc,
+ (byte) 0x5f, (byte) 0x3f, (byte) 0x00, (byte) 0xd9, (byte) 0x32, (byte) 0x1d,
+ (byte) 0xa5, (byte) 0xec, (byte) 0x72, (byte) 0x46, (byte) 0x23, (byte) 0xe5,
+ (byte) 0x7f, (byte) 0x49, (byte) 0x0e, (byte) 0x3e, (byte) 0xf2, (byte) 0x2b,
+ (byte) 0x16, (byte) 0x52, (byte) 0x9f, (byte) 0x9d, (byte) 0x0c, (byte) 0xfe,
+ (byte) 0xab, (byte) 0xdd, (byte) 0x77, (byte) 0x77, (byte) 0x94, (byte) 0xa4,
+ (byte) 0x92, (byte) 0xa2, (byte) 0x41, (byte) 0x0d, (byte) 0x4b, (byte) 0x57,
+ (byte) 0x80, (byte) 0xd6, (byte) 0x74, (byte) 0x63, (byte) 0xd5, (byte) 0xbf,
+ (byte) 0x5c, (byte) 0xa0, (byte) 0xda, (byte) 0x3c, (byte) 0xe6, (byte) 0xbf,
+ (byte) 0xa4, (byte) 0xc3, (byte) 0xfb, (byte) 0x46, (byte) 0x3b, (byte) 0x73,
+ (byte) 0x30, (byte) 0x4b, (byte) 0x57, (byte) 0x27, (byte) 0x0c, (byte) 0x81,
+ (byte) 0xde, (byte) 0x8a, (byte) 0x01, (byte) 0xe5, (byte) 0x7e, (byte) 0xe0,
+ (byte) 0x16, (byte) 0x11, (byte) 0x24, (byte) 0x34, (byte) 0x22, (byte) 0x01,
+ (byte) 0x9f, (byte) 0xe6, (byte) 0xa9, (byte) 0xfb, (byte) 0xad, (byte) 0x55,
+ (byte) 0x17, (byte) 0x2a, (byte) 0x92, (byte) 0x87, (byte) 0xf3, (byte) 0x72,
+ (byte) 0xc9, (byte) 0x3d, (byte) 0xc9, (byte) 0x2e, (byte) 0x32, (byte) 0x8e,
+ (byte) 0xbb, (byte) 0xdc, (byte) 0x1b, (byte) 0xa7, (byte) 0x7b, (byte) 0x73,
+ (byte) 0xd7, (byte) 0xf4, (byte) 0xad, (byte) 0xa9, (byte) 0x3a, (byte) 0xf7,
+ (byte) 0xa8, (byte) 0x82, (byte) 0x92, (byte) 0x40, (byte) 0xd4, (byte) 0x51,
+ (byte) 0x87, (byte) 0xe1, (byte) 0xb7, (byte) 0x4f, (byte) 0x91, (byte) 0x75,
+ (byte) 0x5b, (byte) 0x03, (byte) 0x9d, (byte) 0xa1, (byte) 0xd4, (byte) 0x00,
+ (byte) 0x05, (byte) 0x79, (byte) 0x42, (byte) 0x93, (byte) 0x76};
+
+ /*
+ * echo -n 'This is a test of OAEP' | openssl pkeyutl -encrypt -inkey /tmp/rsakey.txt \
+ * -pkeyopt rsa_padding_mode:oaep -pkey rsa_oaep_md:sha512 -pkeyopt rsa_mgf1_md:sha512 \
+ * | xxd -p -i | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] RSA_Vector2_OAEP_SHA512_MGF1_SHA512 =
+ new byte[] {(byte) 0x75, (byte) 0x0f, (byte) 0xf9, (byte) 0x21, (byte) 0xca,
+ (byte) 0xcc, (byte) 0x0e, (byte) 0x13, (byte) 0x9e, (byte) 0x38, (byte) 0xa4,
+ (byte) 0xa7, (byte) 0xee, (byte) 0x61, (byte) 0x6d, (byte) 0x56, (byte) 0xea,
+ (byte) 0x36, (byte) 0xeb, (byte) 0xec, (byte) 0xfa, (byte) 0x1a, (byte) 0xeb,
+ (byte) 0x0c, (byte) 0xb2, (byte) 0x58, (byte) 0x9d, (byte) 0xde, (byte) 0x47,
+ (byte) 0x27, (byte) 0x2d, (byte) 0xbd, (byte) 0x8b, (byte) 0xa7, (byte) 0xf1,
+ (byte) 0x8b, (byte) 0xba, (byte) 0x4c, (byte) 0xab, (byte) 0x39, (byte) 0x6a,
+ (byte) 0x82, (byte) 0x0d, (byte) 0xaf, (byte) 0x4c, (byte) 0xde, (byte) 0xdb,
+ (byte) 0x5e, (byte) 0xdb, (byte) 0x08, (byte) 0x98, (byte) 0x06, (byte) 0xc5,
+ (byte) 0x99, (byte) 0xb6, (byte) 0x6d, (byte) 0xbc, (byte) 0x5b, (byte) 0xf9,
+ (byte) 0xe4, (byte) 0x97, (byte) 0x0b, (byte) 0xba, (byte) 0xe3, (byte) 0x17,
+ (byte) 0xa9, (byte) 0x3c, (byte) 0x4b, (byte) 0x21, (byte) 0xd8, (byte) 0x29,
+ (byte) 0xf8, (byte) 0xa7, (byte) 0x1c, (byte) 0x15, (byte) 0xd7, (byte) 0xf6,
+ (byte) 0xfc, (byte) 0x53, (byte) 0x64, (byte) 0x97, (byte) 0x9e, (byte) 0x22,
+ (byte) 0xb1, (byte) 0x93, (byte) 0x26, (byte) 0x80, (byte) 0xdc, (byte) 0xaa,
+ (byte) 0x1b, (byte) 0xae, (byte) 0x69, (byte) 0x0f, (byte) 0x74, (byte) 0x3d,
+ (byte) 0x61, (byte) 0x80, (byte) 0x68, (byte) 0xb8, (byte) 0xaf, (byte) 0x63,
+ (byte) 0x72, (byte) 0x37, (byte) 0x4f, (byte) 0xf3, (byte) 0x29, (byte) 0x4a,
+ (byte) 0x75, (byte) 0x4f, (byte) 0x29, (byte) 0x40, (byte) 0x01, (byte) 0xd3,
+ (byte) 0xc6, (byte) 0x56, (byte) 0x1a, (byte) 0xaf, (byte) 0xc3, (byte) 0xb3,
+ (byte) 0xd2, (byte) 0xb9, (byte) 0x91, (byte) 0x35, (byte) 0x1b, (byte) 0x89,
+ (byte) 0x4c, (byte) 0x61, (byte) 0xa2, (byte) 0x8e, (byte) 0x6f, (byte) 0x12,
+ (byte) 0x4a, (byte) 0x10, (byte) 0xc2, (byte) 0xcc, (byte) 0xab, (byte) 0x51,
+ (byte) 0xec, (byte) 0x1b, (byte) 0xb5, (byte) 0xfe, (byte) 0x20, (byte) 0x16,
+ (byte) 0xb2, (byte) 0xc5, (byte) 0x0f, (byte) 0xe1, (byte) 0x6a, (byte) 0xb4,
+ (byte) 0x6c, (byte) 0x27, (byte) 0xd9, (byte) 0x42, (byte) 0xb9, (byte) 0xb6,
+ (byte) 0x55, (byte) 0xa8, (byte) 0xbc, (byte) 0x1c, (byte) 0x32, (byte) 0x54,
+ (byte) 0x84, (byte) 0xec, (byte) 0x1e, (byte) 0x95, (byte) 0xd8, (byte) 0xae,
+ (byte) 0xca, (byte) 0xc1, (byte) 0xad, (byte) 0x4c, (byte) 0x65, (byte) 0xd6,
+ (byte) 0xc2, (byte) 0x19, (byte) 0x66, (byte) 0xad, (byte) 0x9f, (byte) 0x55,
+ (byte) 0x15, (byte) 0xe1, (byte) 0x5d, (byte) 0x8f, (byte) 0xab, (byte) 0x18,
+ (byte) 0x68, (byte) 0x42, (byte) 0x7c, (byte) 0x48, (byte) 0xb7, (byte) 0x2c,
+ (byte) 0xfd, (byte) 0x1a, (byte) 0x07, (byte) 0xa1, (byte) 0x6a, (byte) 0xfb,
+ (byte) 0x81, (byte) 0xc6, (byte) 0x93, (byte) 0xbf, (byte) 0xa3, (byte) 0x5d,
+ (byte) 0xfd, (byte) 0xce, (byte) 0xf3, (byte) 0x17, (byte) 0x26, (byte) 0xf0,
+ (byte) 0xda, (byte) 0x0e, (byte) 0xd1, (byte) 0x86, (byte) 0x9d, (byte) 0x61,
+ (byte) 0xd1, (byte) 0x8a, (byte) 0xdb, (byte) 0x36, (byte) 0x39, (byte) 0x1c,
+ (byte) 0xd4, (byte) 0x99, (byte) 0x53, (byte) 0x30, (byte) 0x5a, (byte) 0x01,
+ (byte) 0xf4, (byte) 0xa0, (byte) 0xca, (byte) 0x94, (byte) 0x72, (byte) 0x3d,
+ (byte) 0xe3, (byte) 0x50, (byte) 0x95, (byte) 0xcb, (byte) 0xa9, (byte) 0x37,
+ (byte) 0xeb, (byte) 0x66, (byte) 0x21, (byte) 0x20, (byte) 0x2e, (byte) 0xf2,
+ (byte) 0xfd, (byte) 0xfa, (byte) 0x54, (byte) 0xbf, (byte) 0x17, (byte) 0x23,
+ (byte) 0xbb, (byte) 0x9e, (byte) 0x77, (byte) 0xe0, (byte) 0xaa};
+
+ /*
+ * echo -n 'This is a test of OAEP' | openssl pkeyutl -encrypt -inkey /tmp/rsakey.txt -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha512 -pkeyopt rsa_mgf1_md:sha512 -pkeyopt rsa_oaep_label:010203FFA00A | xxd -p -i | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] RSA_Vector2_OAEP_SHA512_MGF1_SHA512_LABEL =
+ new byte[] {(byte) 0x31, (byte) 0x3b, (byte) 0x23, (byte) 0xcf, (byte) 0x40,
+ (byte) 0xfe, (byte) 0x15, (byte) 0x94, (byte) 0xd6, (byte) 0x81, (byte) 0x21,
+ (byte) 0x69, (byte) 0x8e, (byte) 0x58, (byte) 0xd5, (byte) 0x0f, (byte) 0xa8,
+ (byte) 0x72, (byte) 0x94, (byte) 0x13, (byte) 0xfe, (byte) 0xf9, (byte) 0xa1,
+ (byte) 0x47, (byte) 0x49, (byte) 0x91, (byte) 0xcb, (byte) 0x66, (byte) 0xe6,
+ (byte) 0x5d, (byte) 0x02, (byte) 0xad, (byte) 0xd4, (byte) 0x2f, (byte) 0x4f,
+ (byte) 0xab, (byte) 0xb7, (byte) 0x9e, (byte) 0xc0, (byte) 0xf0, (byte) 0x3d,
+ (byte) 0x66, (byte) 0x0e, (byte) 0x20, (byte) 0x82, (byte) 0x7f, (byte) 0x22,
+ (byte) 0x8f, (byte) 0x81, (byte) 0xba, (byte) 0x47, (byte) 0xc7, (byte) 0xaf,
+ (byte) 0xb6, (byte) 0x0e, (byte) 0x78, (byte) 0xe3, (byte) 0x30, (byte) 0xd7,
+ (byte) 0x6c, (byte) 0x81, (byte) 0xc2, (byte) 0x05, (byte) 0x7e, (byte) 0xe9,
+ (byte) 0xac, (byte) 0x8d, (byte) 0x45, (byte) 0x25, (byte) 0xe8, (byte) 0x26,
+ (byte) 0x39, (byte) 0x88, (byte) 0x64, (byte) 0x2e, (byte) 0xc6, (byte) 0xed,
+ (byte) 0xd4, (byte) 0xad, (byte) 0x94, (byte) 0xc8, (byte) 0x4e, (byte) 0x4a,
+ (byte) 0x71, (byte) 0x1e, (byte) 0x11, (byte) 0x14, (byte) 0x03, (byte) 0x56,
+ (byte) 0x02, (byte) 0x28, (byte) 0x32, (byte) 0x8f, (byte) 0xe2, (byte) 0x16,
+ (byte) 0x4a, (byte) 0x62, (byte) 0xa6, (byte) 0x9a, (byte) 0x8d, (byte) 0xf8,
+ (byte) 0x33, (byte) 0x35, (byte) 0xa2, (byte) 0xc7, (byte) 0x70, (byte) 0xcc,
+ (byte) 0x26, (byte) 0x1e, (byte) 0x4d, (byte) 0x9c, (byte) 0x4e, (byte) 0x2b,
+ (byte) 0xe8, (byte) 0xfd, (byte) 0x07, (byte) 0x33, (byte) 0x15, (byte) 0x53,
+ (byte) 0x11, (byte) 0x5c, (byte) 0x6f, (byte) 0x5d, (byte) 0x23, (byte) 0x7b,
+ (byte) 0x3f, (byte) 0x73, (byte) 0xff, (byte) 0xf4, (byte) 0xbe, (byte) 0x1f,
+ (byte) 0xe6, (byte) 0x5a, (byte) 0xb8, (byte) 0x2b, (byte) 0xd2, (byte) 0xbe,
+ (byte) 0xa0, (byte) 0x91, (byte) 0x5d, (byte) 0xca, (byte) 0x89, (byte) 0xb3,
+ (byte) 0xce, (byte) 0x0a, (byte) 0x2b, (byte) 0xce, (byte) 0xb9, (byte) 0xbe,
+ (byte) 0x5d, (byte) 0xb2, (byte) 0xc2, (byte) 0xd6, (byte) 0xa9, (byte) 0xbc,
+ (byte) 0x37, (byte) 0xed, (byte) 0x9a, (byte) 0xba, (byte) 0x35, (byte) 0xf8,
+ (byte) 0x6e, (byte) 0x63, (byte) 0x76, (byte) 0xd1, (byte) 0x12, (byte) 0xf5,
+ (byte) 0x89, (byte) 0xf0, (byte) 0x13, (byte) 0x86, (byte) 0xe7, (byte) 0x1b,
+ (byte) 0x94, (byte) 0xcb, (byte) 0xc8, (byte) 0x5c, (byte) 0x4c, (byte) 0x1b,
+ (byte) 0x8a, (byte) 0x2d, (byte) 0x6b, (byte) 0x24, (byte) 0x1a, (byte) 0x38,
+ (byte) 0x14, (byte) 0x77, (byte) 0x49, (byte) 0xe5, (byte) 0x08, (byte) 0x25,
+ (byte) 0xe4, (byte) 0xa6, (byte) 0xcf, (byte) 0x62, (byte) 0xfd, (byte) 0x66,
+ (byte) 0x28, (byte) 0xf0, (byte) 0x3a, (byte) 0x9c, (byte) 0x31, (byte) 0xef,
+ (byte) 0x48, (byte) 0x2a, (byte) 0xd3, (byte) 0x3e, (byte) 0x29, (byte) 0xfa,
+ (byte) 0x18, (byte) 0x8f, (byte) 0xd6, (byte) 0xaa, (byte) 0x1d, (byte) 0x10,
+ (byte) 0xcd, (byte) 0x35, (byte) 0x25, (byte) 0x92, (byte) 0x48, (byte) 0xa0,
+ (byte) 0x2c, (byte) 0xc1, (byte) 0x31, (byte) 0xeb, (byte) 0x47, (byte) 0x5b,
+ (byte) 0x22, (byte) 0x52, (byte) 0x7c, (byte) 0xf5, (byte) 0xec, (byte) 0x76,
+ (byte) 0x90, (byte) 0x94, (byte) 0x58, (byte) 0xd9, (byte) 0xd6, (byte) 0xe0,
+ (byte) 0x0a, (byte) 0x3f, (byte) 0x09, (byte) 0x98, (byte) 0x03, (byte) 0xc5,
+ (byte) 0x07, (byte) 0x8f, (byte) 0x89, (byte) 0x1e, (byte) 0x62, (byte) 0x2c,
+ (byte) 0xea, (byte) 0x17, (byte) 0x0a, (byte) 0x2e, (byte) 0x68};
+
+ @Test
+ public void testRSA_ECB_NoPadding_Private_OnlyDoFinal_Success() throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testRSA_ECB_NoPadding_Private_OnlyDoFinal_Success(provider);
+ }
+ }
+
+ private void testRSA_ECB_NoPadding_Private_OnlyDoFinal_Success(String provider) throws Exception {
+ final PrivateKey privKey = (PrivateKey) getDecryptKey("RSA");
+
+ Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+
+ /*
+ * You're actually decrypting with private keys, but there is no
+ * distinction made here. It's all keyed off of what kind of key you're
+ * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+ */
+ c.init(Cipher.ENCRYPT_MODE, privKey);
+ byte[] encrypted = c.doFinal(RSA_2048_Vector1);
+ assertTrue("Encrypted should match expected",
+ Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted));
+
+ c.init(Cipher.DECRYPT_MODE, privKey);
+ encrypted = c.doFinal(RSA_2048_Vector1);
+ assertTrue("Encrypted should match expected",
+ Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted));
+ }
+
+ @Test
+ public void testRSA_ECB_NoPadding_Private_UpdateThenEmptyDoFinal_Success() throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testRSA_ECB_NoPadding_Private_UpdateThenEmptyDoFinal_Success(provider);
+ }
+ }
+
+ private void testRSA_ECB_NoPadding_Private_UpdateThenEmptyDoFinal_Success(String provider) throws Exception {
+ final PrivateKey privKey = (PrivateKey) getDecryptKey("RSA");
+
+ Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+
+ /*
+ * You're actually decrypting with private keys, but there is no
+ * distinction made here. It's all keyed off of what kind of key you're
+ * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+ */
+ c.init(Cipher.ENCRYPT_MODE, privKey);
+ c.update(RSA_2048_Vector1);
+ byte[] encrypted = c.doFinal();
+ assertTrue("Encrypted should match expected",
+ Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted));
+
+ c.init(Cipher.DECRYPT_MODE, privKey);
+ c.update(RSA_2048_Vector1);
+ encrypted = c.doFinal();
+ assertTrue("Encrypted should match expected",
+ Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted));
+ }
+
+ @Test
+ public void testRSA_ECB_NoPadding_Private_SingleByteUpdateThenEmptyDoFinal_Success()
+ throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testRSA_ECB_NoPadding_Private_SingleByteUpdateThenEmptyDoFinal_Success(provider);
+ }
+ }
+
+ private void testRSA_ECB_NoPadding_Private_SingleByteUpdateThenEmptyDoFinal_Success(String provider)
+ throws Exception {
+ final PrivateKey privKey = (PrivateKey) getDecryptKey("RSA");
+
+ Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+
+ /*
+ * You're actually decrypting with private keys, but there is no
+ * distinction made here. It's all keyed off of what kind of key you're
+ * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+ */
+ c.init(Cipher.ENCRYPT_MODE, privKey);
+ int i;
+ for (i = 0; i < RSA_2048_Vector1.length / 2; i++) {
+ c.update(RSA_2048_Vector1, i, 1);
+ }
+ byte[] encrypted = c.doFinal(RSA_2048_Vector1, i, RSA_2048_Vector1.length - i);
+ assertTrue("Encrypted should match expected",
+ Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted));
+
+ c.init(Cipher.DECRYPT_MODE, privKey);
+ for (i = 0; i < RSA_2048_Vector1.length / 2; i++) {
+ c.update(RSA_2048_Vector1, i, 1);
+ }
+ encrypted = c.doFinal(RSA_2048_Vector1, i, RSA_2048_Vector1.length - i);
+ assertTrue("Encrypted should match expected",
+ Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted));
+ }
+
+ @Test
+ public void testRSA_ECB_NoPadding_Private_OnlyDoFinalWithOffset_Success() throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testRSA_ECB_NoPadding_Private_OnlyDoFinalWithOffset_Success(provider);
+ }
+ }
+
+ private void testRSA_ECB_NoPadding_Private_OnlyDoFinalWithOffset_Success(String provider) throws Exception {
+ final PrivateKey privKey = (PrivateKey) getDecryptKey("RSA");
+
+ Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+
+ /*
+ * You're actually decrypting with private keys, but there is no
+ * distinction made here. It's all keyed off of what kind of key you're
+ * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+ */
+ c.init(Cipher.ENCRYPT_MODE, privKey);
+ byte[] encrypted = new byte[RSA_Vector1_Encrypt_Private.length];
+ final int encryptLen = c
+ .doFinal(RSA_2048_Vector1, 0, RSA_2048_Vector1.length, encrypted, 0);
+ assertEquals("Encrypted size should match expected", RSA_Vector1_Encrypt_Private.length,
+ encryptLen);
+ assertTrue("Encrypted should match expected",
+ Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted));
+
+ c.init(Cipher.DECRYPT_MODE, privKey);
+ final int decryptLen = c
+ .doFinal(RSA_2048_Vector1, 0, RSA_2048_Vector1.length, encrypted, 0);
+ assertEquals("Encrypted size should match expected", RSA_Vector1_Encrypt_Private.length,
+ decryptLen);
+ assertTrue("Encrypted should match expected",
+ Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted));
+ }
+
+ @Test
+ public void testRSA_ECB_NoPadding_Public_OnlyDoFinal_Success() throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testRSA_ECB_NoPadding_Public_OnlyDoFinal_Success(provider);
+ }
+ }
+
+ private void testRSA_ECB_NoPadding_Public_OnlyDoFinal_Success(String provider) throws Exception {
+ final PublicKey pubKey = (PublicKey) getEncryptKey("RSA");
+
+ Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+
+ /*
+ * You're actually encrypting with public keys, but there is no
+ * distinction made here. It's all keyed off of what kind of key you're
+ * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+ */
+ c.init(Cipher.ENCRYPT_MODE, pubKey);
+ byte[] encrypted = c.doFinal(RSA_Vector1_Encrypt_Private);
+ assertEncryptedEqualsNoPadding(provider, Cipher.ENCRYPT_MODE, RSA_2048_Vector1, encrypted);
+
+ c.init(Cipher.DECRYPT_MODE, pubKey);
+ encrypted = c.doFinal(RSA_Vector1_Encrypt_Private);
+ assertEncryptedEqualsNoPadding(provider, Cipher.DECRYPT_MODE, RSA_2048_Vector1, encrypted);
+ }
+
+ @Test
+ public void testRSA_ECB_NoPadding_Public_OnlyDoFinalWithOffset_Success() throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testRSA_ECB_NoPadding_Public_OnlyDoFinalWithOffset_Success(provider);
+ }
+ }
+
+ private void testRSA_ECB_NoPadding_Public_OnlyDoFinalWithOffset_Success(String provider) throws Exception {
+ final PublicKey pubKey = (PublicKey) getEncryptKey("RSA");
+
+ Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+
+ /*
+ * You're actually encrypting with public keys, but there is no
+ * distinction made here. It's all keyed off of what kind of key you're
+ * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+ */
+ c.init(Cipher.ENCRYPT_MODE, pubKey);
+ byte[] encrypted = new byte[RSA_2048_Vector1.length];
+ final int encryptLen = c.doFinal(RSA_Vector1_Encrypt_Private, 0,
+ RSA_Vector1_Encrypt_Private.length, encrypted, 0);
+ assertEquals("Encrypted size should match expected", RSA_2048_Vector1.length, encryptLen);
+ assertEncryptedEqualsNoPadding(provider, Cipher.ENCRYPT_MODE, RSA_2048_Vector1, encrypted);
+
+ c.init(Cipher.DECRYPT_MODE, pubKey);
+ int decryptLen = c.doFinal(RSA_Vector1_Encrypt_Private, 0,
+ RSA_Vector1_Encrypt_Private.length, encrypted, 0);
+ if (provider.equals("BC")) {
+ // BC strips the leading 0 for us on decrypt even when NoPadding is specified...
+ decryptLen++;
+ encrypted = Arrays.copyOf(encrypted, encrypted.length - 1);
+ }
+ assertEquals("Encrypted size should match expected", RSA_2048_Vector1.length, decryptLen);
+ assertEncryptedEqualsNoPadding(provider, Cipher.DECRYPT_MODE, RSA_2048_Vector1, encrypted);
+ }
+
+ @Test
+ public void testRSA_ECB_NoPadding_Public_UpdateThenEmptyDoFinal_Success() throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testRSA_ECB_NoPadding_Public_UpdateThenEmptyDoFinal_Success(provider);
+ }
+ }
+
+ private void testRSA_ECB_NoPadding_Public_UpdateThenEmptyDoFinal_Success(String provider) throws Exception {
+ final PublicKey pubKey = (PublicKey) getEncryptKey("RSA");
+
+ Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+
+ /*
+ * You're actually encrypting with public keys, but there is no
+ * distinction made here. It's all keyed off of what kind of key you're
+ * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+ */
+ c.init(Cipher.ENCRYPT_MODE, pubKey);
+ c.update(RSA_Vector1_Encrypt_Private);
+ byte[] encrypted = c.doFinal();
+ assertEncryptedEqualsNoPadding(provider, Cipher.ENCRYPT_MODE, RSA_2048_Vector1, encrypted);
+
+ c.init(Cipher.DECRYPT_MODE, pubKey);
+ c.update(RSA_Vector1_Encrypt_Private);
+ encrypted = c.doFinal();
+ assertEncryptedEqualsNoPadding(provider, Cipher.DECRYPT_MODE, RSA_2048_Vector1, encrypted);
+ }
+
+ @Test
+ public void testRSA_ECB_NoPadding_Public_SingleByteUpdateThenEmptyDoFinal_Success()
+ throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testRSA_ECB_NoPadding_Public_SingleByteUpdateThenEmptyDoFinal_Success(provider);
+ }
+ }
+
+ private void testRSA_ECB_NoPadding_Public_SingleByteUpdateThenEmptyDoFinal_Success(String provider)
+ throws Exception {
+ final PublicKey pubKey = (PublicKey) getEncryptKey("RSA");
+
+ Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+
+ /*
+ * You're actually encrypting with public keys, but there is no
+ * distinction made here. It's all keyed off of what kind of key you're
+ * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+ */
+ c.init(Cipher.ENCRYPT_MODE, pubKey);
+ int i;
+ for (i = 0; i < RSA_Vector1_Encrypt_Private.length / 2; i++) {
+ c.update(RSA_Vector1_Encrypt_Private, i, 1);
+ }
+ byte[] encrypted = c.doFinal(RSA_Vector1_Encrypt_Private, i, RSA_2048_Vector1.length - i);
+ assertEncryptedEqualsNoPadding(provider, Cipher.ENCRYPT_MODE, RSA_2048_Vector1, encrypted);
+
+ c.init(Cipher.DECRYPT_MODE, pubKey);
+ for (i = 0; i < RSA_Vector1_Encrypt_Private.length / 2; i++) {
+ c.update(RSA_Vector1_Encrypt_Private, i, 1);
+ }
+ encrypted = c.doFinal(RSA_Vector1_Encrypt_Private, i, RSA_2048_Vector1.length - i);
+ assertEncryptedEqualsNoPadding(provider, Cipher.DECRYPT_MODE, RSA_2048_Vector1, encrypted);
+ }
+
+ @Test
+ public void testRSA_ECB_NoPadding_Public_TooSmall_Success() throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testRSA_ECB_NoPadding_Public_TooSmall_Success(provider);
+ }
+ }
+
+ private void testRSA_ECB_NoPadding_Public_TooSmall_Success(String provider) throws Exception {
+ final PublicKey pubKey = (PublicKey) getEncryptKey("RSA");
+
+ Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+
+ /*
+ * You're actually encrypting with public keys, but there is no
+ * distinction made here. It's all keyed off of what kind of key you're
+ * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+ */
+ c.init(Cipher.ENCRYPT_MODE, pubKey);
+ byte[] encrypted = c.doFinal(TooShort_Vector);
+ assertTrue("Encrypted should match expected",
+ Arrays.equals(RSA_Vector1_ZeroPadded_Encrypted, encrypted));
+
+ c.init(Cipher.DECRYPT_MODE, pubKey);
+ encrypted = c.doFinal(TooShort_Vector);
+ assertTrue("Encrypted should match expected",
+ Arrays.equals(RSA_Vector1_ZeroPadded_Encrypted, encrypted));
+ }
+
+ @Test
+ public void testRSA_ECB_NoPadding_Private_TooSmall_Success() throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testRSA_ECB_NoPadding_Private_TooSmall_Success(provider);
+ }
+ }
+
+ private void testRSA_ECB_NoPadding_Private_TooSmall_Success(String provider) throws Exception {
+ final PrivateKey privKey = (PrivateKey) getDecryptKey("RSA");
+
+ Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+
+ /*
+ * You're actually encrypting with public keys, but there is no
+ * distinction made here. It's all keyed off of what kind of key you're
+ * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+ */
+ c.init(Cipher.ENCRYPT_MODE, privKey);
+ byte[] encrypted = c.doFinal(RSA_Vector1_ZeroPadded_Encrypted);
+ assertEncryptedEqualsNoPadding(provider, Cipher.ENCRYPT_MODE,
+ TooShort_Vector_Zero_Padded, encrypted);
+
+ c.init(Cipher.DECRYPT_MODE, privKey);
+ encrypted = c.doFinal(RSA_Vector1_ZeroPadded_Encrypted);
+ assertEncryptedEqualsNoPadding(provider, Cipher.DECRYPT_MODE,
+ TooShort_Vector_Zero_Padded, encrypted);
+ }
+
+ private static void assertEncryptedEqualsNoPadding(String provider, int mode,
+ byte[] expected, byte[] actual) {
+ if (provider.equals("BC") && mode == Cipher.DECRYPT_MODE) {
+ // BouncyCastle does us the favor of stripping leading zeroes in DECRYPT_MODE
+ int nonZeroOffset = 0;
+ for (byte b : expected) {
+ if (b != 0) {
+ break;
+ }
+ nonZeroOffset++;
+ }
+ expected = Arrays.copyOfRange(expected, nonZeroOffset, expected.length);
+ }
+ assertEquals("Encrypted should match expected",
+ Arrays.toString(expected), Arrays.toString(actual));
+ }
+
+ @Test
+ public void testRSA_ECB_NoPadding_Private_CombinedUpdateAndDoFinal_TooBig_Failure()
+ throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testRSA_ECB_NoPadding_Private_CombinedUpdateAndDoFinal_TooBig_Failure(provider);
+ }
+ }
+
+ private void testRSA_ECB_NoPadding_Private_CombinedUpdateAndDoFinal_TooBig_Failure(String provider)
+ throws Exception {
+ final PrivateKey privKey = (PrivateKey) getDecryptKey("RSA");
+
+ Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+
+ /*
+ * You're actually encrypting with public keys, but there is no
+ * distinction made here. It's all keyed off of what kind of key you're
+ * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+ */
+ c.init(Cipher.ENCRYPT_MODE, privKey);
+ c.update(RSA_Vector1_ZeroPadded_Encrypted);
+
+ try {
+ c.doFinal(RSA_Vector1_ZeroPadded_Encrypted);
+ fail("Should have error when block size is too big.");
+ } catch (IllegalBlockSizeException success) {
+ assertFalse(provider, "BC".equals(provider));
+ } catch (ArrayIndexOutOfBoundsException success) {
+ assertEquals("BC", provider);
+ }
+ }
+
+ @Test
+ public void testRSA_ECB_NoPadding_Private_UpdateInAndOutPlusDoFinal_TooBig_Failure()
+ throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testRSA_ECB_NoPadding_Private_UpdateInAndOutPlusDoFinal_TooBig_Failure(provider);
+ }
+ }
+
+ private void testRSA_ECB_NoPadding_Private_UpdateInAndOutPlusDoFinal_TooBig_Failure(String provider)
+ throws Exception {
+ final PrivateKey privKey = (PrivateKey) getDecryptKey("RSA");
+
+ Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+
+ /*
+ * You're actually encrypting with public keys, but there is no
+ * distinction made here. It's all keyed off of what kind of key you're
+ * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+ */
+ c.init(Cipher.ENCRYPT_MODE, privKey);
+
+ byte[] output = new byte[RSA_2048_Vector1.length];
+ c.update(RSA_Vector1_ZeroPadded_Encrypted, 0, RSA_Vector1_ZeroPadded_Encrypted.length,
+ output);
+
+ try {
+ c.doFinal(RSA_Vector1_ZeroPadded_Encrypted);
+ fail("Should have error when block size is too big.");
+ } catch (IllegalBlockSizeException success) {
+ assertFalse(provider, "BC".equals(provider));
+ } catch (ArrayIndexOutOfBoundsException success) {
+ assertEquals("BC", provider);
+ }
+ }
+
+ @Test
+ public void testRSA_ECB_NoPadding_Private_OnlyDoFinal_TooBig_Failure() throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testRSA_ECB_NoPadding_Private_OnlyDoFinal_TooBig_Failure(provider);
+ }
+ }
+
+ private void testRSA_ECB_NoPadding_Private_OnlyDoFinal_TooBig_Failure(String provider) throws Exception {
+ final PrivateKey privKey = (PrivateKey) getDecryptKey("RSA");
+
+ Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+
+ /*
+ * You're actually encrypting with public keys, but there is no
+ * distinction made here. It's all keyed off of what kind of key you're
+ * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+ */
+ c.init(Cipher.ENCRYPT_MODE, privKey);
+
+ byte[] tooBig_Vector = new byte[RSA_Vector1_ZeroPadded_Encrypted.length * 2];
+ System.arraycopy(RSA_Vector1_ZeroPadded_Encrypted, 0, tooBig_Vector, 0,
+ RSA_Vector1_ZeroPadded_Encrypted.length);
+ System.arraycopy(RSA_Vector1_ZeroPadded_Encrypted, 0, tooBig_Vector,
+ RSA_Vector1_ZeroPadded_Encrypted.length, RSA_Vector1_ZeroPadded_Encrypted.length);
+
+ try {
+ c.doFinal(tooBig_Vector);
+ fail("Should have error when block size is too big.");
+ } catch (IllegalBlockSizeException success) {
+ assertFalse(provider, "BC".equals(provider));
+ } catch (ArrayIndexOutOfBoundsException success) {
+ assertEquals("BC", provider);
+ }
+ }
+
+ @Test
+ public void testRSA_ECB_NoPadding_GetBlockSize_Success() throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testRSA_ECB_NoPadding_GetBlockSize_Success(provider);
+ }
+ }
+
+ private void testRSA_ECB_NoPadding_GetBlockSize_Success(String provider) throws Exception {
+ Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+ if (provider.equals("SunJCE")) {
+ assertEquals(0, c.getBlockSize());
+ } else {
+ try {
+ c.getBlockSize();
+ fail();
+ } catch (IllegalStateException expected) {
+ }
+ }
+
+ final PublicKey pubKey = (PublicKey) getEncryptKey("RSA");
+ c.init(Cipher.ENCRYPT_MODE, pubKey);
+ assertEquals(getExpectedBlockSize("RSA", Cipher.ENCRYPT_MODE, provider), c.getBlockSize());
+ }
+
+ @Test
+ public void testRSA_ECB_NoPadding_GetOutputSize_NoInit_Failure() throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testRSA_ECB_NoPadding_GetOutputSize_NoInit_Failure(provider);
+ }
+ }
+
+ private void testRSA_ECB_NoPadding_GetOutputSize_NoInit_Failure(String provider) throws Exception {
+ Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+ try {
+ c.getOutputSize(RSA_2048_Vector1.length);
+ fail("Should throw IllegalStateException if getOutputSize is called before init");
+ } catch (IllegalStateException success) {
+ }
+ }
+
+ @Test
+ public void testRSA_ECB_NoPadding_GetOutputSize_Success() throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testRSA_ECB_NoPadding_GetOutputSize_Success(provider);
+ }
+ }
+
+ private void testRSA_ECB_NoPadding_GetOutputSize_Success(String provider) throws Exception {
+ final PublicKey pubKey = (PublicKey) getEncryptKey("RSA");
+
+ Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+ c.init(Cipher.ENCRYPT_MODE, pubKey);
+
+ final int modulusInBytes = RSA_2048_modulus.bitLength() / 8;
+ assertEquals(modulusInBytes, c.getOutputSize(RSA_2048_Vector1.length));
+ assertEquals(modulusInBytes, c.getOutputSize(RSA_2048_Vector1.length * 2));
+ assertEquals(modulusInBytes, c.getOutputSize(0));
+ }
+
+ @Test
+ public void testRSA_ECB_NoPadding_GetIV_Success() throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testRSA_ECB_NoPadding_GetIV_Success(provider);
+ }
+ }
+
+ private void testRSA_ECB_NoPadding_GetIV_Success(String provider) throws Exception {
+ final PublicKey pubKey = (PublicKey) getEncryptKey("RSA");
+
+ Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+ assertNull("ECB mode has no IV and should be null", c.getIV());
+
+ c.init(Cipher.ENCRYPT_MODE, pubKey);
+
+ assertNull("ECB mode has no IV and should be null", c.getIV());
+ }
+
+ @Test
+ public void testRSA_ECB_NoPadding_GetParameters_NoneProvided_Success() throws Exception {
+ for (String provider : RSA_PROVIDERS) {
+ testRSA_ECB_NoPadding_GetParameters_NoneProvided_Success(provider);
+ }
+ }
+
+ private void testRSA_ECB_NoPadding_GetParameters_NoneProvided_Success(String provider) throws Exception {
+ Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
+ assertNull("Parameters should be null", c.getParameters());
+ }
+
+ /*
+ * Test vector generation:
+ * openssl rand -hex 16 | sed 's/\(..\)/(byte) 0x\1, /g'
+ */
+ private static final SecretKeySpec DES_112_KEY = new SecretKeySpec(new byte[] {
+ (byte) 0x6b, (byte) 0xb3, (byte) 0x85, (byte) 0x1c, (byte) 0x3d, (byte) 0x50,
+ (byte) 0xd4, (byte) 0x95, (byte) 0x39, (byte) 0x48, (byte) 0x77, (byte) 0x30,
+ (byte) 0x1a, (byte) 0xd7, (byte) 0x86, (byte) 0x57,
+ }, "DESede");
+
+ /*
+ * Test vector generation:
+ * openssl rand -hex 24 | sed 's/\(..\)/(byte) 0x\1, /g'
+ */
+ private static final SecretKeySpec DES_168_KEY = new SecretKeySpec(new byte[] {
+ (byte) 0xfe, (byte) 0xd4, (byte) 0xd7, (byte) 0xc9, (byte) 0x8a, (byte) 0x13,
+ (byte) 0x6a, (byte) 0xa8, (byte) 0x5a, (byte) 0xb8, (byte) 0x19, (byte) 0xb8,
+ (byte) 0xcf, (byte) 0x3c, (byte) 0x5f, (byte) 0xe0, (byte) 0xa2, (byte) 0xf7,
+ (byte) 0x7b, (byte) 0x65, (byte) 0x43, (byte) 0xc0, (byte) 0xc4, (byte) 0xe1,
+ }, "DESede");
+
+ /*
+ * Test vector generation:
+ * openssl rand -hex 5 | sed 's/\(..\)/(byte) 0x\1, /g'
+ */
+ private static final SecretKeySpec ARC4_40BIT_KEY = new SecretKeySpec(new byte[] {
+ (byte) 0x9c, (byte) 0xc8, (byte) 0xb9, (byte) 0x94, (byte) 0x98,
+ }, "ARC4");
+
+ /*
+ * Test vector generation:
+ * openssl rand -hex 24 | sed 's/\(..\)/(byte) 0x\1, /g'
+ */
+ private static final SecretKeySpec ARC4_128BIT_KEY = new SecretKeySpec(new byte[] {
+ (byte) 0xbc, (byte) 0x0a, (byte) 0x3c, (byte) 0xca, (byte) 0xb5, (byte) 0x42,
+ (byte) 0xfa, (byte) 0x5d, (byte) 0x86, (byte) 0x5b, (byte) 0x44, (byte) 0x87,
+ (byte) 0x83, (byte) 0xd8, (byte) 0xcb, (byte) 0xd4,
+ }, "ARC4");
+
+ /*
+ * Test vector generation:
+ * openssl rand -hex 16
+ * echo '3d4f8970b1f27537f40a39298a41555f' | sed 's/\(..\)/(byte) 0x\1, /g'
+ */
+ private static final SecretKeySpec AES_128_KEY = new SecretKeySpec(new byte[] {
+ (byte) 0x3d, (byte) 0x4f, (byte) 0x89, (byte) 0x70, (byte) 0xb1, (byte) 0xf2,
+ (byte) 0x75, (byte) 0x37, (byte) 0xf4, (byte) 0x0a, (byte) 0x39, (byte) 0x29,
+ (byte) 0x8a, (byte) 0x41, (byte) 0x55, (byte) 0x5f,
+ }, "AES");
+
+ /*
+ * Test key generation:
+ * openssl rand -hex 24
+ * echo '5a7a3d7e40b64ed996f7afa15f97fd595e27db6af428e342' | sed 's/\(..\)/(byte) 0x\1, /g'
+ */
+ private static final SecretKeySpec AES_192_KEY = new SecretKeySpec(new byte[] {
+ (byte) 0x5a, (byte) 0x7a, (byte) 0x3d, (byte) 0x7e, (byte) 0x40, (byte) 0xb6,
+ (byte) 0x4e, (byte) 0xd9, (byte) 0x96, (byte) 0xf7, (byte) 0xaf, (byte) 0xa1,
+ (byte) 0x5f, (byte) 0x97, (byte) 0xfd, (byte) 0x59, (byte) 0x5e, (byte) 0x27,
+ (byte) 0xdb, (byte) 0x6a, (byte) 0xf4, (byte) 0x28, (byte) 0xe3, (byte) 0x42,
+ }, "AES");
+
+ /*
+ * Test key generation:
+ * openssl rand -hex 32
+ * echo 'ec53c6d51d2c4973585fb0b8e51cd2e39915ff07a1837872715d6121bf861935' | sed 's/\(..\)/(byte) 0x\1, /g'
+ */
+ private static final SecretKeySpec AES_256_KEY = new SecretKeySpec(new byte[] {
+ (byte) 0xec, (byte) 0x53, (byte) 0xc6, (byte) 0xd5, (byte) 0x1d, (byte) 0x2c,
+ (byte) 0x49, (byte) 0x73, (byte) 0x58, (byte) 0x5f, (byte) 0xb0, (byte) 0xb8,
+ (byte) 0xe5, (byte) 0x1c, (byte) 0xd2, (byte) 0xe3, (byte) 0x99, (byte) 0x15,
+ (byte) 0xff, (byte) 0x07, (byte) 0xa1, (byte) 0x83, (byte) 0x78, (byte) 0x72,
+ (byte) 0x71, (byte) 0x5d, (byte) 0x61, (byte) 0x21, (byte) 0xbf, (byte) 0x86,
+ (byte) 0x19, (byte) 0x35,
+ }, "AES");
+
+ /*
+ * Test vector generation:
+ * echo -n 'Testing rocks!' | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] DES_Plaintext1 = new byte[] {
+ (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x69, (byte) 0x6E,
+ (byte) 0x67, (byte) 0x20, (byte) 0x72, (byte) 0x6F, (byte) 0x63, (byte) 0x6B,
+ (byte) 0x73, (byte) 0x21
+ };
+
+
+ /*
+ * Test vector generation: take DES_Plaintext1 and PKCS #5 pad it manually (it's not hard).
+ */
+ private static final byte[] DES_Plaintext1_PKCS5_Padded = new byte[] {
+ (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x69, (byte) 0x6E,
+ (byte) 0x67, (byte) 0x20, (byte) 0x72, (byte) 0x6F, (byte) 0x63, (byte) 0x6B,
+ (byte) 0x73, (byte) 0x21, (byte) 0x02, (byte) 0x02,
+ };
+
+ /*
+ * Test vector generation:
+ * openssl rand -hex 8 | sed 's/\(..\)/(byte) 0x\1, /g'
+ */
+ private static final byte[] DES_IV1 = new byte[] {
+ (byte) 0x5c, (byte) 0x47, (byte) 0x5e, (byte) 0x57, (byte) 0x0c, (byte) 0x46,
+ (byte) 0xcb, (byte) 0x47,
+ };
+
+ /*
+ * Test vector generation:
+ * openssl enc -des-ede-cbc -K 6bb3851c3d50d495394877301ad78657 -iv 5c475e570c46cb47 -in blah
+ * | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[]
+ DES_Plaintext1_Encrypted_With_DES_112_KEY_And_DESEDE_CBC_PKCS5PADDING_With_DES_IV1 =
+ new byte[] {
+ (byte) 0x09, (byte) 0xA5, (byte) 0x5D, (byte) 0x94, (byte) 0x94, (byte) 0xAA,
+ (byte) 0x3F, (byte) 0xC8, (byte) 0xB7, (byte) 0x73, (byte) 0x94, (byte) 0x0E,
+ (byte) 0xFC, (byte) 0xF4, (byte) 0xA5, (byte) 0x28,
+ };
+
+
+ /*
+ * Test vector generation:
+ * openssl enc -des-ede3-cbc -K fed4d7c98a136aa85ab819b8cf3c5fe0a2f77b6543c0c4e1
+ * -iv 5c475e570c46cb47 -in blah | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[]
+ DES_Plaintext1_Encrypted_With_DES_168_KEY_And_DESEDE_CBC_PKCS5PADDING_With_DES_IV1 =
+ new byte[] {
+ (byte) 0xC9, (byte) 0xF1, (byte) 0x83, (byte) 0x1F, (byte) 0x24, (byte) 0x83,
+ (byte) 0x2C, (byte) 0x7B, (byte) 0x66, (byte) 0x66, (byte) 0x99, (byte) 0x98,
+ (byte) 0x27, (byte) 0xB0, (byte) 0xED, (byte) 0x47
+ };
+
+
+ /*
+ * Test vector generation:
+ * echo -n 'Plaintext for arc4' | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] ARC4_Plaintext1 = new byte[] {
+ (byte) 0x50, (byte) 0x6C, (byte) 0x61, (byte) 0x69, (byte) 0x6E, (byte) 0x74,
+ (byte) 0x65, (byte) 0x78, (byte) 0x74, (byte) 0x20, (byte) 0x66, (byte) 0x6F,
+ (byte) 0x72, (byte) 0x20, (byte) 0x61, (byte) 0x72, (byte) 0x63, (byte) 0x34
+ };
+
+ /*
+ * Test vector generation:
+ * echo -n 'Plaintext for arc4' | openssl enc -rc4-40 -K 9cc8b99498 | recode ../x1 \
+ * | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] ARC4_Plaintext1_Encrypted_With_ARC4_40Bit_Key = new byte[] {
+ (byte) 0x63, (byte) 0xF7, (byte) 0x11, (byte) 0x90, (byte) 0x63, (byte) 0xEF,
+ (byte) 0x5E, (byte) 0xB3, (byte) 0x93, (byte) 0xB3, (byte) 0x46, (byte) 0x3F,
+ (byte) 0x1B, (byte) 0x02, (byte) 0x53, (byte) 0x9B, (byte) 0xD9, (byte) 0xE0
+ };
+
+ /*
+ * Test vector generation:
+ * echo -n 'Plaintext for arc4' | openssl enc -rc4 -K bc0a3ccab542fa5d865b448783d8cbd4 \
+ * | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] ARC4_Plaintext1_Encrypted_With_ARC4_128Bit_Key = new byte[] {
+ (byte) 0x25, (byte) 0x14, (byte) 0xA9, (byte) 0x72, (byte) 0x4D, (byte) 0xA9,
+ (byte) 0xF6, (byte) 0xA7, (byte) 0x2F, (byte) 0xB7, (byte) 0x0D, (byte) 0x60,
+ (byte) 0x09, (byte) 0xBE, (byte) 0x41, (byte) 0x9B, (byte) 0x32, (byte) 0x2B
+ };
+
+ /*
+ * Test vector creation:
+ * echo -n 'Hello, world!' | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext = new byte[] {
+ (byte) 0x48, (byte) 0x65, (byte) 0x6C, (byte) 0x6C, (byte) 0x6F, (byte) 0x2C,
+ (byte) 0x20, (byte) 0x77, (byte) 0x6F, (byte) 0x72, (byte) 0x6C, (byte) 0x64,
+ (byte) 0x21,
+ };
+
+ /*
+ * Test vector creation:
+ * openssl enc -aes-128-ecb -K 3d4f8970b1f27537f40a39298a41555f -in blah|openssl enc -aes-128-ecb -K 3d4f8970b1f27537f40a39298a41555f -nopad -d|recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded = new byte[] {
+ (byte) 0x48, (byte) 0x65, (byte) 0x6C, (byte) 0x6C, (byte) 0x6F, (byte) 0x2C,
+ (byte) 0x20, (byte) 0x77, (byte) 0x6F, (byte) 0x72, (byte) 0x6C, (byte) 0x64,
+ (byte) 0x21, (byte) 0x03, (byte) 0x03, (byte) 0x03
+ };
+
+ /*
+ * Test vector generation:
+ * openssl enc -aes-128-ecb -K 3d4f8970b1f27537f40a39298a41555f -in blah|recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted = new byte[] {
+ (byte) 0x65, (byte) 0x3E, (byte) 0x86, (byte) 0xFB, (byte) 0x05, (byte) 0x5A,
+ (byte) 0x52, (byte) 0xEA, (byte) 0xDD, (byte) 0x08, (byte) 0xE7, (byte) 0x48,
+ (byte) 0x33, (byte) 0x01, (byte) 0xFC, (byte) 0x5A,
+ };
+
+ /*
+ * Taken from BoringSSL test vectors.
+ */
+ private static final SecretKeySpec AES_128_GCM_TestVector_1_Key = new SecretKeySpec(new byte[] {
+ (byte) 0xca, (byte) 0xbd, (byte) 0xcf, (byte) 0x54, (byte) 0x1a, (byte) 0xeb,
+ (byte) 0xf9, (byte) 0x17, (byte) 0xba, (byte) 0xc0, (byte) 0x19, (byte) 0xf1,
+ (byte) 0x39, (byte) 0x25, (byte) 0xd2, (byte) 0x67,
+ }, "AES");
+
+ /*
+ * Taken from BoringSSL test vectors.
+ */
+ private static final byte[] AES_128_GCM_TestVector_1_IV = new byte[] {
+ (byte) 0x2c, (byte) 0x34, (byte) 0xc0, (byte) 0x0c, (byte) 0x42, (byte) 0xda,
+ (byte) 0xe3, (byte) 0x82, (byte) 0x27, (byte) 0x9d, (byte) 0x79, (byte) 0x74,
+ };
+
+ /*
+ * Taken from BoringSSL test vectors.
+ */
+ private static final byte[] AES_128_GCM_TestVector_1_AAD = new byte[] {
+ (byte) 0xdd, (byte) 0x10, (byte) 0xe3, (byte) 0x71, (byte) 0xb2, (byte) 0x2e,
+ (byte) 0x15, (byte) 0x67, (byte) 0x1c, (byte) 0x31, (byte) 0xaf, (byte) 0xee,
+ (byte) 0x55, (byte) 0x2b, (byte) 0xf1, (byte) 0xde, (byte) 0xa0, (byte) 0x7c,
+ (byte) 0xbb, (byte) 0xf6, (byte) 0x85, (byte) 0xe2, (byte) 0xca, (byte) 0xa0,
+ (byte) 0xe0, (byte) 0x36, (byte) 0x37, (byte) 0x16, (byte) 0xa2, (byte) 0x76,
+ (byte) 0xe1, (byte) 0x20, (byte) 0xc6, (byte) 0xc0, (byte) 0xeb, (byte) 0x4a,
+ (byte) 0xcb, (byte) 0x1a, (byte) 0x4d, (byte) 0x1b, (byte) 0xa7, (byte) 0x3f,
+ (byte) 0xde, (byte) 0x66, (byte) 0x15, (byte) 0xf7, (byte) 0x08, (byte) 0xaa,
+ (byte) 0xa4, (byte) 0x6b, (byte) 0xc7, (byte) 0x6c, (byte) 0x7f, (byte) 0xf3,
+ (byte) 0x45, (byte) 0xa4, (byte) 0xf7, (byte) 0x6b, (byte) 0xda, (byte) 0x11,
+ (byte) 0x7f, (byte) 0xe5, (byte) 0x6f, (byte) 0x0d, (byte) 0xc9, (byte) 0xb9,
+ (byte) 0x39, (byte) 0x04, (byte) 0x0d, (byte) 0xdd,
+ };
+
+ /*
+ * Taken from BoringSSL test vectors.
+ */
+ private static final byte[] AES_128_GCM_TestVector_1_Plaintext = new byte[] {
+ (byte) 0x88, (byte) 0xcc, (byte) 0x1e, (byte) 0x07, (byte) 0xdf, (byte) 0xde,
+ (byte) 0x8e, (byte) 0x08, (byte) 0x08, (byte) 0x2e, (byte) 0x67, (byte) 0x66,
+ (byte) 0xe0, (byte) 0xa8, (byte) 0x81, (byte) 0x03, (byte) 0x38, (byte) 0x47,
+ (byte) 0x42, (byte) 0xaf, (byte) 0x37, (byte) 0x8d, (byte) 0x7b, (byte) 0x6b,
+ (byte) 0x8a, (byte) 0x87, (byte) 0xfc, (byte) 0xe0, (byte) 0x36, (byte) 0xaf,
+ (byte) 0x74, (byte) 0x41, (byte) 0xc1, (byte) 0x39, (byte) 0x61, (byte) 0xc2,
+ (byte) 0x5a, (byte) 0xfe, (byte) 0xa7, (byte) 0xf6, (byte) 0xe5, (byte) 0x61,
+ (byte) 0x93, (byte) 0xf5, (byte) 0x4b, (byte) 0xee, (byte) 0x00, (byte) 0x11,
+ (byte) 0xcb, (byte) 0x78, (byte) 0x64, (byte) 0x2c, (byte) 0x3a, (byte) 0xb9,
+ (byte) 0xe6, (byte) 0xd5, (byte) 0xb2, (byte) 0xe3, (byte) 0x58, (byte) 0x33,
+ (byte) 0xec, (byte) 0x16, (byte) 0xcd, (byte) 0x35, (byte) 0x55, (byte) 0x15,
+ (byte) 0xaf, (byte) 0x1a, (byte) 0x19, (byte) 0x0f,
+ };
+
+ /*
+ * Taken from BoringSSL test vectors.
+ */
+ private static final byte[] AES_128_GCM_TestVector_1_Encrypted = new byte[] {
+ (byte) 0x04, (byte) 0x94, (byte) 0x53, (byte) 0xba, (byte) 0xf1, (byte) 0x57,
+ (byte) 0x87, (byte) 0x87, (byte) 0xd6, (byte) 0x8e, (byte) 0xd5, (byte) 0x47,
+ (byte) 0x87, (byte) 0x26, (byte) 0xc0, (byte) 0xb8, (byte) 0xa6, (byte) 0x36,
+ (byte) 0x33, (byte) 0x7a, (byte) 0x0b, (byte) 0x8a, (byte) 0x82, (byte) 0xb8,
+ (byte) 0x68, (byte) 0x36, (byte) 0xf9, (byte) 0x1c, (byte) 0xde, (byte) 0x25,
+ (byte) 0xe6, (byte) 0xe4, (byte) 0x4c, (byte) 0x34, (byte) 0x59, (byte) 0x40,
+ (byte) 0xe8, (byte) 0x19, (byte) 0xa0, (byte) 0xc5, (byte) 0x05, (byte) 0x75,
+ (byte) 0x1e, (byte) 0x60, (byte) 0x3c, (byte) 0xb8, (byte) 0xf8, (byte) 0xc4,
+ (byte) 0xfe, (byte) 0x98, (byte) 0x71, (byte) 0x91, (byte) 0x85, (byte) 0x56,
+ (byte) 0x27, (byte) 0x94, (byte) 0xa1, (byte) 0x85, (byte) 0xe5, (byte) 0xde,
+ (byte) 0xc4, (byte) 0x15, (byte) 0xc8, (byte) 0x1f, (byte) 0x2f, (byte) 0x16,
+ (byte) 0x2c, (byte) 0xdc, (byte) 0xd6, (byte) 0x50, (byte) 0xdc, (byte) 0xe7,
+ (byte) 0x19, (byte) 0x87, (byte) 0x28, (byte) 0xbf, (byte) 0xc1, (byte) 0xb5,
+ (byte) 0xf9, (byte) 0x49, (byte) 0xb9, (byte) 0xb5, (byte) 0x37, (byte) 0x41,
+ (byte) 0x99, (byte) 0xc6,
+ };
+
+ /*
+ * Test key generation:
+ * openssl rand -hex 16
+ * echo '787bdeecf05556eac5d3d865e435f6d9' | sed 's/\(..\)/(byte) 0x\1, /g'
+ */
+ private static final byte[] AES_192_CTR_NoPadding_TestVector_1_IV = new byte[] {
+ (byte) 0x78, (byte) 0x7b, (byte) 0xde, (byte) 0xec, (byte) 0xf0, (byte) 0x55,
+ (byte) 0x56, (byte) 0xea, (byte) 0xc5, (byte) 0xd3, (byte) 0xd8, (byte) 0x65,
+ (byte) 0xe4, (byte) 0x35, (byte) 0xf6, (byte) 0xd9,
+
+ };
+
+ /*
+ * Test vector generation:
+ * echo -n 'AES-192 is a silly option' | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] AES_192_CTR_NoPadding_TestVector_1_Plaintext = new byte[] {
+ (byte) 0x41, (byte) 0x45, (byte) 0x53, (byte) 0x2D, (byte) 0x31, (byte) 0x39,
+ (byte) 0x32, (byte) 0x20, (byte) 0x69, (byte) 0x73, (byte) 0x20, (byte) 0x61,
+ (byte) 0x20, (byte) 0x73, (byte) 0x69, (byte) 0x6C, (byte) 0x6C, (byte) 0x79,
+ (byte) 0x20, (byte) 0x6F, (byte) 0x70, (byte) 0x74, (byte) 0x69, (byte) 0x6F,
+ (byte) 0x6E
+ };
+
+ /*
+ * Test vector generation:
+ * echo -n 'AES-192 is a silly option' | openssl enc -aes-192-ctr -K 5a7a3d7e40b64ed996f7afa15f97fd595e27db6af428e342 -iv 787bdeecf05556eac5d3d865e435f6d9 | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] AES_192_CTR_NoPadding_TestVector_1_Ciphertext = new byte[] {
+ (byte) 0xE9, (byte) 0xC6, (byte) 0xA0, (byte) 0x40, (byte) 0xC2, (byte) 0x6A,
+ (byte) 0xB5, (byte) 0x20, (byte) 0xFE, (byte) 0x9E, (byte) 0x65, (byte) 0xB7,
+ (byte) 0x7C, (byte) 0x5E, (byte) 0xFE, (byte) 0x1F, (byte) 0xF1, (byte) 0x6F,
+ (byte) 0x20, (byte) 0xAC, (byte) 0x37, (byte) 0xE9, (byte) 0x75, (byte) 0xE3,
+ (byte) 0x52
+ };
+
+ /*
+ * Test key generation: openssl rand -hex 16 echo
+ * 'ceaa31952dfd3d0f5af4b2042ba06094' | sed 's/\(..\)/(byte) 0x\1, /g'
+ */
+ private static final byte[] AES_256_CBC_PKCS5Padding_TestVector_1_IV = new byte[] {
+ (byte) 0xce, (byte) 0xaa, (byte) 0x31, (byte) 0x95, (byte) 0x2d, (byte) 0xfd,
+ (byte) 0x3d, (byte) 0x0f, (byte) 0x5a, (byte) 0xf4, (byte) 0xb2, (byte) 0x04,
+ (byte) 0x2b, (byte) 0xa0, (byte) 0x60, (byte) 0x94,
+ };
+
+ /*
+ * Test vector generation:
+ * echo -n 'I only regret that I have but one test to write.' | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext = new byte[] {
+ (byte) 0x49, (byte) 0x20, (byte) 0x6F, (byte) 0x6E, (byte) 0x6C, (byte) 0x79,
+ (byte) 0x20, (byte) 0x72, (byte) 0x65, (byte) 0x67, (byte) 0x72, (byte) 0x65,
+ (byte) 0x74, (byte) 0x20, (byte) 0x74, (byte) 0x68, (byte) 0x61, (byte) 0x74,
+ (byte) 0x20, (byte) 0x49, (byte) 0x20, (byte) 0x68, (byte) 0x61, (byte) 0x76,
+ (byte) 0x65, (byte) 0x20, (byte) 0x62, (byte) 0x75, (byte) 0x74, (byte) 0x20,
+ (byte) 0x6F, (byte) 0x6E, (byte) 0x65, (byte) 0x20, (byte) 0x74, (byte) 0x65,
+ (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x74, (byte) 0x6F, (byte) 0x20,
+ (byte) 0x77, (byte) 0x72, (byte) 0x69, (byte) 0x74, (byte) 0x65, (byte) 0x2E
+ };
+
+ /*
+ * Test vector generation:
+ * echo -n 'I only regret that I have but one test to write.' | openssl enc -aes-256-cbc -K ec53c6d51d2c4973585fb0b8e51cd2e39915ff07a1837872715d6121bf861935 -iv ceaa31952dfd3d0f5af4b2042ba06094 | openssl enc -aes-256-cbc -K ec53c6d51d2c4973585fb0b8e51cd2e39915ff07a1837872715d6121bf861935 -iv ceaa31952dfd3d0f5af4b2042ba06094 -d -nopad | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext_Padded = new byte[] {
+ (byte) 0x49, (byte) 0x20, (byte) 0x6F, (byte) 0x6E, (byte) 0x6C, (byte) 0x79,
+ (byte) 0x20, (byte) 0x72, (byte) 0x65, (byte) 0x67, (byte) 0x72, (byte) 0x65,
+ (byte) 0x74, (byte) 0x20, (byte) 0x74, (byte) 0x68, (byte) 0x61, (byte) 0x74,
+ (byte) 0x20, (byte) 0x49, (byte) 0x20, (byte) 0x68, (byte) 0x61, (byte) 0x76,
+ (byte) 0x65, (byte) 0x20, (byte) 0x62, (byte) 0x75, (byte) 0x74, (byte) 0x20,
+ (byte) 0x6F, (byte) 0x6E, (byte) 0x65, (byte) 0x20, (byte) 0x74, (byte) 0x65,
+ (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x74, (byte) 0x6F, (byte) 0x20,
+ (byte) 0x77, (byte) 0x72, (byte) 0x69, (byte) 0x74, (byte) 0x65, (byte) 0x2E,
+ (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10,
+ (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10,
+ (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10
+ };
+
+ /*
+ * Test vector generation:
+ * echo -n 'I only regret that I have but one test to write.' | openssl enc -aes-256-cbc -K ec53c6d51d2c4973585fb0b8e51cd2e39915ff07a1837872715d6121bf861935 -iv ceaa31952dfd3d0f5af4b2042ba06094 | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] AES_256_CBC_PKCS5Padding_TestVector_1_Ciphertext = new byte[] {
+ (byte) 0x90, (byte) 0x65, (byte) 0xDD, (byte) 0xAF, (byte) 0x7A, (byte) 0xCE,
+ (byte) 0xAE, (byte) 0xBF, (byte) 0xE8, (byte) 0xF6, (byte) 0x9E, (byte) 0xDB,
+ (byte) 0xEA, (byte) 0x65, (byte) 0x28, (byte) 0xC4, (byte) 0x9A, (byte) 0x28,
+ (byte) 0xEA, (byte) 0xA3, (byte) 0x95, (byte) 0x2E, (byte) 0xFF, (byte) 0xF1,
+ (byte) 0xA0, (byte) 0xCA, (byte) 0xC2, (byte) 0xA4, (byte) 0x65, (byte) 0xCD,
+ (byte) 0xBF, (byte) 0xCE, (byte) 0x9E, (byte) 0xF1, (byte) 0x57, (byte) 0xF6,
+ (byte) 0x32, (byte) 0x2E, (byte) 0x8F, (byte) 0x93, (byte) 0x2E, (byte) 0xAE,
+ (byte) 0x41, (byte) 0x33, (byte) 0x54, (byte) 0xD0, (byte) 0xEF, (byte) 0x8C,
+ (byte) 0x52, (byte) 0x14, (byte) 0xAC, (byte) 0x2D, (byte) 0xD5, (byte) 0xA4,
+ (byte) 0xF9, (byte) 0x20, (byte) 0x77, (byte) 0x25, (byte) 0x91, (byte) 0x3F,
+ (byte) 0xD1, (byte) 0xB9, (byte) 0x00, (byte) 0x3E
+ };
+
+ private static class CipherTestParam {
+ public final String transformation;
+
+ public final AlgorithmParameterSpec spec;
+
+ public final Key encryptKey;
+
+ public final Key decryptKey;
+
+ public final byte[] aad;
+
+ public final byte[] plaintext;
+
+ public final byte[] ciphertext;
+
+ public final byte[] plaintextPadded;
+
+ public final boolean isStreamCipher;
+
+ public CipherTestParam(String transformation, AlgorithmParameterSpec spec, Key encryptKey,
+ Key decryptKey, byte[] aad, byte[] plaintext, byte[] plaintextPadded,
+ byte[] ciphertext, boolean isStreamCipher) {
+ this.transformation = transformation.toUpperCase(Locale.ROOT);
+ this.spec = spec;
+ this.encryptKey = encryptKey;
+ this.decryptKey = decryptKey;
+ this.aad = aad;
+ this.plaintext = plaintext;
+ this.plaintextPadded = plaintextPadded;
+ this.ciphertext = ciphertext;
+ this.isStreamCipher = isStreamCipher;
+ }
+
+ public CipherTestParam(String transformation, AlgorithmParameterSpec spec, Key key,
+ byte[] aad, byte[] plaintext, byte[] plaintextPadded, byte[] ciphertext,
+ boolean isStreamCipher) {
+ this(transformation, spec, key, key, aad, plaintext, plaintextPadded, ciphertext,
+ isStreamCipher);
+ }
+
+ public CipherTestParam(String transformation, AlgorithmParameterSpec spec, Key key,
+ byte[] aad, byte[] plaintext, byte[] plaintextPadded, byte[] ciphertext) {
+ this(transformation, spec, key, aad, plaintext, plaintextPadded, ciphertext,
+ false /* isStreamCipher */);
+ }
+
+ public boolean compatibleWith(String provider) {
+ // SunJCE doesn't support PKCS7Padding
+ if (provider.equals("SunJCE") && transformation.endsWith("/PKCS7PADDING")) {
+ return false;
+ }
+ if (provider.equals("BC")) {
+ return isSupportedByBC(transformation);
+ }
+ return true;
+ }
+ }
+
+ private static class OAEPCipherTestParam extends CipherTestParam {
+ public OAEPCipherTestParam(String transformation, OAEPParameterSpec spec,
+ PublicKey encryptKey, PrivateKey decryptKey, byte[] plaintext, byte[] ciphertext) {
+ super(transformation, spec, encryptKey, decryptKey, null, plaintext, plaintext, ciphertext,
+ false);
+ }
+
+ @Override
+ public boolean compatibleWith(String provider) {
+ // OAEP transformations have two digests, the "main" digest and the MGF-1 digest.
+ // BC and Conscrypt set the MGF-1 digest to the same as the main digest when it's
+ // not specified, whereas Sun's provider sets it to SHA-1. Thus, the results from
+ // the different providers won't match when there isn't an explicit MGF-1 digest set
+ // and the main digest isn't SHA-1. See b/22405492.
+ if (provider.equals("SunJCE")
+ && (spec == null)
+ && !transformation.toUpperCase(Locale.US).equals("RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING")) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ private static List<CipherTestParam> DES_CIPHER_TEST_PARAMS = new ArrayList<CipherTestParam>();
+ static {
+ DES_CIPHER_TEST_PARAMS.add(new CipherTestParam(
+ "DESede/CBC/PKCS5Padding",
+ new IvParameterSpec(DES_IV1),
+ DES_112_KEY,
+ null,
+ DES_Plaintext1,
+ DES_Plaintext1_PKCS5_Padded,
+ DES_Plaintext1_Encrypted_With_DES_112_KEY_And_DESEDE_CBC_PKCS5PADDING_With_DES_IV1
+ ) {
+ @Override
+ public boolean compatibleWith(String provider) {
+ // SunJCE doesn't support extending 112-bit keys to 168-bit keys
+ return !provider.equals("SunJCE");
+ }
+ });
+ DES_CIPHER_TEST_PARAMS.add(new CipherTestParam(
+ "DESede/CBC/PKCS5Padding",
+ new IvParameterSpec(DES_IV1),
+ DES_168_KEY,
+ null,
+ DES_Plaintext1,
+ DES_Plaintext1_PKCS5_Padded,
+ DES_Plaintext1_Encrypted_With_DES_168_KEY_And_DESEDE_CBC_PKCS5PADDING_With_DES_IV1
+ ));
+ }
+
+ private static List<CipherTestParam> ARC4_CIPHER_TEST_PARAMS = new ArrayList<CipherTestParam>();
+ static {
+ ARC4_CIPHER_TEST_PARAMS.add(new CipherTestParam(
+ "ARC4",
+ null,
+ ARC4_40BIT_KEY,
+ null, // aad
+ ARC4_Plaintext1,
+ null, // padded
+ ARC4_Plaintext1_Encrypted_With_ARC4_40Bit_Key,
+ true /*isStreamCipher */
+ ));
+ ARC4_CIPHER_TEST_PARAMS.add(new CipherTestParam(
+ "ARC4",
+ null,
+ ARC4_128BIT_KEY,
+ null, // aad
+ ARC4_Plaintext1,
+ null, // padded
+ ARC4_Plaintext1_Encrypted_With_ARC4_128Bit_Key,
+ true /*isStreamCipher */
+ ));
+ }
+
+ private static List<CipherTestParam> CIPHER_TEST_PARAMS = new ArrayList<CipherTestParam>();
+ static {
+ CIPHER_TEST_PARAMS.add(new CipherTestParam(
+ "AES/ECB/PKCS5Padding",
+ null,
+ AES_128_KEY,
+ null,
+ AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext,
+ AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded,
+ AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted));
+ // PKCS#5 is assumed to be equivalent to PKCS#7 -- same test vectors are thus used for both.
+ CIPHER_TEST_PARAMS.add(new CipherTestParam(
+ "AES/ECB/PKCS7Padding",
+ null,
+ AES_128_KEY,
+ null,
+ AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext,
+ AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded,
+ AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted));
+ CIPHER_TEST_PARAMS.add(new CipherTestParam(
+ "AES/GCM/NOPADDING",
+ new GCMParameterSpec(
+ (AES_128_GCM_TestVector_1_Encrypted.length -
+ AES_128_GCM_TestVector_1_Plaintext.length) * 8,
+ AES_128_GCM_TestVector_1_IV),
+ AES_128_GCM_TestVector_1_Key,
+ AES_128_GCM_TestVector_1_AAD,
+ AES_128_GCM_TestVector_1_Plaintext,
+ AES_128_GCM_TestVector_1_Plaintext,
+ AES_128_GCM_TestVector_1_Encrypted));
+ if (IS_UNLIMITED) {
+ CIPHER_TEST_PARAMS.add(new CipherTestParam(
+ "AES/CTR/NoPadding",
+ new IvParameterSpec(AES_192_CTR_NoPadding_TestVector_1_IV),
+ AES_192_KEY,
+ null,
+ AES_192_CTR_NoPadding_TestVector_1_Plaintext,
+ AES_192_CTR_NoPadding_TestVector_1_Plaintext,
+ AES_192_CTR_NoPadding_TestVector_1_Ciphertext));
+ CIPHER_TEST_PARAMS.add(new CipherTestParam(
+ "AES/CBC/PKCS5Padding",
+ new IvParameterSpec(AES_256_CBC_PKCS5Padding_TestVector_1_IV),
+ AES_256_KEY,
+ null,
+ AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext,
+ AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext_Padded,
+ AES_256_CBC_PKCS5Padding_TestVector_1_Ciphertext));
+ CIPHER_TEST_PARAMS.add(new CipherTestParam(
+ "AES/CBC/PKCS7Padding",
+ new IvParameterSpec(AES_256_CBC_PKCS5Padding_TestVector_1_IV),
+ AES_256_KEY,
+ null,
+ AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext,
+ AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext_Padded,
+ AES_256_CBC_PKCS5Padding_TestVector_1_Ciphertext));
+ }
+ }
+
+ private static final List<CipherTestParam> RSA_OAEP_CIPHER_TEST_PARAMS = new ArrayList<CipherTestParam>();
+ static {
+ addRsaOaepTest("SHA-1", MGF1ParameterSpec.SHA1, RSA_Vector2_OAEP_SHA1_MGF1_SHA1);
+ addRsaOaepTest("SHA-256", MGF1ParameterSpec.SHA1, RSA_Vector2_OAEP_SHA256_MGF1_SHA1);
+ addRsaOaepTest("SHA-224", MGF1ParameterSpec.SHA224, RSA_Vector2_OAEP_SHA224_MGF1_SHA224);
+ addRsaOaepTest("SHA-256", MGF1ParameterSpec.SHA256, RSA_Vector2_OAEP_SHA256_MGF1_SHA256);
+ addRsaOaepTest("SHA-384", MGF1ParameterSpec.SHA384, RSA_Vector2_OAEP_SHA384_MGF1_SHA384);
+ addRsaOaepTest("SHA-512", MGF1ParameterSpec.SHA512, RSA_Vector2_OAEP_SHA512_MGF1_SHA512);
+ addRsaOaepTest("SHA-256", MGF1ParameterSpec.SHA1, RSA_Vector2_OAEP_SHA256_MGF1_SHA1_LABEL,
+ new byte[] { 0x01, 0x02, 0x03, (byte) 0xFF, (byte) 0xA0, 0x0A });
+ addRsaOaepTest("SHA-512", MGF1ParameterSpec.SHA512, RSA_Vector2_OAEP_SHA512_MGF1_SHA512_LABEL,
+ new byte[] { 0x01, 0x02, 0x03, (byte) 0xFF, (byte) 0xA0, 0x0A });
+ }
+
+ private static void addRsaOaepTest(String digest, MGF1ParameterSpec mgf1Spec, byte[] vector) {
+ addRsaOaepTest(digest, mgf1Spec, vector, null);
+ }
+
+ private static void addRsaOaepTest(String digest, MGF1ParameterSpec mgf1Spec, byte[] vector, byte[] label) {
+ final PSource pSource;
+ if (label == null) {
+ pSource = PSource.PSpecified.DEFAULT;
+ } else {
+ pSource = new PSource.PSpecified(label);
+ }
+
+ if (mgf1Spec.getDigestAlgorithm().equals(digest) && label == null) {
+ RSA_OAEP_CIPHER_TEST_PARAMS.add(new OAEPCipherTestParam(
+ "RSA/ECB/OAEPWith" + digest + "AndMGF1Padding",
+ null,
+ (PublicKey) getEncryptKey("RSA"),
+ (PrivateKey) getDecryptKey("RSA"),
+ RSA_Vector2_Plaintext,
+ vector));
+ }
+
+ RSA_OAEP_CIPHER_TEST_PARAMS.add(new OAEPCipherTestParam(
+ "RSA/ECB/OAEPWith" + digest + "AndMGF1Padding",
+ new OAEPParameterSpec(digest, "MGF1", mgf1Spec, pSource),
+ (PublicKey) getEncryptKey("RSA"),
+ (PrivateKey) getDecryptKey("RSA"),
+ RSA_Vector2_Plaintext,
+ vector));
+
+ RSA_OAEP_CIPHER_TEST_PARAMS.add(new OAEPCipherTestParam(
+ "RSA/ECB/OAEPPadding",
+ new OAEPParameterSpec(digest, "MGF1", mgf1Spec, pSource),
+ (PublicKey) getEncryptKey("RSA"),
+ (PrivateKey) getDecryptKey("RSA"),
+ RSA_Vector2_Plaintext,
+ vector));
+ }
+
+ @Test
+ public void testCipher_Success() throws Exception {
+ for (String provider : AES_PROVIDERS) {
+ testCipher_Success(provider);
+ }
+
+ testCipher_Success_ForAllSupportingProviders_AtLeastOneProviderRequired(
+ DES_CIPHER_TEST_PARAMS);
+ testCipher_Success_ForAllSupportingProviders_AtLeastOneProviderRequired(
+ ARC4_CIPHER_TEST_PARAMS);
+ testCipher_Success_ForAllSupportingProviders_AtLeastOneProviderRequired(
+ RSA_OAEP_CIPHER_TEST_PARAMS);
+ }
+
+ /**
+ * For each test vector in the list, tests that the transformation is supported by at least one
+ * provider and that all implementations of the transformation pass the Known Answer Test (KAT)
+ * as well as other functional tests.
+ */
+ private void testCipher_Success_ForAllSupportingProviders_AtLeastOneProviderRequired(
+ List<CipherTestParam> testVectors) throws Exception {
+ ByteArrayOutputStream errBuffer = new ByteArrayOutputStream();
+ PrintStream out = new PrintStream(errBuffer);
+ for (CipherTestParam testVector : testVectors) {
+ ArrayList<Provider> providers = new ArrayList<Provider>();
+
+ Provider[] providerArray = Security.getProviders("Cipher." + testVector.transformation);
+ if (providerArray != null) {
+ Collections.addAll(providers, providerArray);
+ }
+
+ if (testVector.transformation.indexOf('/') > 0) {
+ Provider[] baseTransformProviderArray = Security.getProviders("Cipher."
+ + testVector.transformation.substring(
+ 0, testVector.transformation.indexOf('/')));
+ if (baseTransformProviderArray != null) {
+ Collections.addAll(providers, baseTransformProviderArray);
+ }
+ }
+
+ if (providers.isEmpty()) {
+ out.append("No providers offer " + testVector.transformation + "\n");
+ continue;
+ }
+
+ for (Provider provider : providers) {
+ // Do not test AndroidKeyStore's Signature. It needs an AndroidKeyStore-specific key.
+ // It's OKish not to test AndroidKeyStore's Signature here because it's tested
+ // by cts/tests/test/keystore.
+ if (provider.getName().startsWith("AndroidKeyStore")) {
+ continue;
+ }
+
+ // SunMSCAPI seems to have different opinion on what RSA should do compared to other
+ // providers. As such it fails many tests, so we will skip it for now.
+ if (provider.getName().equals("SunMSCAPI")
+ && testVector.transformation.startsWith("RSA")) {
+ continue;
+ }
+
+ try {
+ checkCipher(testVector, provider.getName());
+ } catch (Throwable e) {
+ logTestFailure(out, provider.getName(), testVector, e);
+ }
+ }
+ }
+ out.flush();
+ if (errBuffer.size() > 0) {
+ throw new Exception("Errors encountered:\n\n" + errBuffer.toString() + "\n\n");
+ }
+ }
+
+ private void testCipher_Success(String provider) throws Exception {
+ final ByteArrayOutputStream errBuffer = new ByteArrayOutputStream();
+ PrintStream out = new PrintStream(errBuffer);
+ for (CipherTestParam p : CIPHER_TEST_PARAMS) {
+ try {
+ checkCipher(p, provider);
+ } catch (Throwable e) {
+ logTestFailure(out, provider, p, e);
+ }
+ }
+ out.flush();
+ if (errBuffer.size() > 0) {
+ throw new Exception("Errors encountered:\n\n" + errBuffer.toString() + "\n\n");
+ }
+ }
+
+ private void logTestFailure(PrintStream logStream, String provider, CipherTestParam params,
+ Throwable e) {
+ logStream.append("Error encountered checking " + params.transformation);
+
+ if (params.encryptKey instanceof SecretKey) {
+ logStream.append(", keySize=" + (params.encryptKey.getEncoded().length * 8));
+ }
+
+ if (params.spec instanceof OAEPParameterSpec) {
+ OAEPParameterSpec oaepSpec = (OAEPParameterSpec) params.spec;
+ logStream.append(", OAEPSpec{digest=" + oaepSpec.getDigestAlgorithm() + ", mgfAlg="
+ + oaepSpec.getMGFAlgorithm());
+ if (oaepSpec.getMGFParameters() instanceof MGF1ParameterSpec) {
+ MGF1ParameterSpec mgf1Spec = (MGF1ParameterSpec) oaepSpec.getMGFParameters();
+ logStream.append(", mgf1Hash=" + mgf1Spec.getDigestAlgorithm());
+ }
+ logStream.append(", pSource=");
+ PSource pSource = oaepSpec.getPSource();
+ logStream.append(pSource.getAlgorithm());
+ if (pSource.getAlgorithm().equals("PSpecified")) {
+ logStream.append(":{");
+ logStream.append(Arrays.toString(((PSource.PSpecified) pSource).getValue()));
+ logStream.append('}');
+ }
+ logStream.append('}');
+ }
+
+ logStream.append(" with provider " + provider + "\n");
+ e.printStackTrace(logStream);
+ }
+
+ private void checkCipher(CipherTestParam p, String provider) throws Exception {
+ if (!p.compatibleWith(provider)) {
+ return;
+ }
+ Cipher c = Cipher.getInstance(p.transformation, provider);
+
+ c.init(Cipher.ENCRYPT_MODE, p.encryptKey, p.spec);
+
+ // This doesn't quite work on OAEPPadding unless it's the default case,
+ // because its size depends on the message digest algorithms used.
+ if (!p.transformation.endsWith("OAEPPADDING")) {
+ assertEquals(p.transformation + " getBlockSize() ENCRYPT_MODE",
+ getExpectedBlockSize(p.transformation, Cipher.ENCRYPT_MODE, provider),
+ c.getBlockSize());
+ }
+ assertTrue(p.transformation + " getOutputSize(0) ENCRYPT_MODE",
+ getExpectedOutputSize(p.transformation, Cipher.ENCRYPT_MODE, provider) <= c
+ .getOutputSize(0));
+
+ if (p.aad != null) {
+ c.updateAAD(p.aad);
+ }
+ final byte[] actualCiphertext = c.doFinal(p.plaintext);
+ if (!isRandomizedEncryption(p.transformation)) {
+ assertEquals(p.transformation + " " + provider, Arrays.toString(p.ciphertext),
+ Arrays.toString(actualCiphertext));
+ }
+
+ c = Cipher.getInstance(p.transformation, provider);
+ c.init(Cipher.ENCRYPT_MODE, p.encryptKey, p.spec);
+ if (!(p instanceof OAEPCipherTestParam) || p.spec != null) {
+ assertCorrectAlgorithmParameters(provider, p.transformation, p.spec, c.getParameters());
+ }
+
+ byte[] emptyCipherText = c.doFinal();
+ assertNotNull(emptyCipherText);
+
+ c.init(Cipher.DECRYPT_MODE, p.decryptKey, p.spec);
+
+ assertEquals(p.transformation + " getBlockSize() DECRYPT_MODE",
+ getExpectedBlockSize(p.transformation, Cipher.DECRYPT_MODE, provider),
+ c.getBlockSize());
+
+ // This doesn't quite work on OAEPPadding unless it's the default case,
+ // because its size depends on the message digest algorithms used.
+ if (!p.transformation.endsWith("OAEPPADDING")) {
+ assertTrue(p.transformation + " getOutputSize(0) DECRYPT_MODE",
+ getExpectedOutputSize(p.transformation, Cipher.DECRYPT_MODE, provider) <= c
+ .getOutputSize(0));
+ }
+
+ if (!isAEAD(p.transformation)) {
+ try {
+ c.updateAAD(new byte[8]);
+ fail("Cipher should not support AAD");
+ } catch (UnsupportedOperationException expected) {
+ } catch (IllegalStateException expected) {
+ }
+ }
+
+ try {
+ byte[] emptyPlainText = c.doFinal(emptyCipherText);
+ assertEquals(Arrays.toString(new byte[0]), Arrays.toString(emptyPlainText));
+ } catch (AEADBadTagException maybe) {
+ if (!"AndroidOpenSSL".equals(provider) || !isAEAD(p.transformation)) {
+ throw maybe;
+ }
+ } catch (BadPaddingException maybe) {
+ // BC's OAEP has a bug where it doesn't support decrypt of a zero-length plaintext
+ if (!("BC".equals(provider) && p.transformation.contains("OAEP"))) {
+ throw maybe;
+ }
+ }
+
+ // decrypt an empty ciphertext; not valid for RSA
+ if (!p.transformation.contains("OAEP")) {
+ if ((!isAEAD(p.transformation)
+ && (StandardNames.IS_RI || provider.equals("AndroidOpenSSL") ||
+ (provider.equals("BC") && p.transformation.contains("/CTR/"))))
+ || p.transformation.equals("ARC4")) {
+ assertEquals(Arrays.toString(new byte[0]),
+ Arrays.toString(c.doFinal()));
+
+ c.update(new byte[0]);
+ assertEquals(Arrays.toString(new byte[0]),
+ Arrays.toString(c.doFinal()));
+ } else if (provider.equals("BC") || isAEAD(p.transformation)) {
+ try {
+ c.doFinal();
+ fail(p.transformation + " " + provider);
+ } catch (IllegalBlockSizeException maybe) {
+ if (isAEAD(p.transformation)) {
+ throw maybe;
+ }
+ } catch (AEADBadTagException maybe) {
+ if (!isAEAD(p.transformation)) {
+ throw maybe;
+ }
+ }
+ try {
+ c.update(new byte[0]);
+ c.doFinal();
+ fail(p.transformation + " " + provider);
+ } catch (IllegalBlockSizeException maybe) {
+ if (isAEAD(p.transformation)) {
+ throw maybe;
+ }
+ } catch (AEADBadTagException maybe) {
+ if (!isAEAD(p.transformation)) {
+ throw maybe;
+ }
+ }
+ } else {
+ throw new AssertionError("Define your behavior here for " + provider);
+ }
+ }
+
+ // Cipher might be in unspecified state from failures above.
+ c.init(Cipher.DECRYPT_MODE, p.decryptKey, p.spec);
+
+ // .doFinal(input)
+ {
+ if (p.aad != null) {
+ c.updateAAD(p.aad);
+ }
+ final byte[] actualPlaintext = c.doFinal(p.ciphertext);
+ assertEquals(Arrays.toString(p.plaintext), Arrays.toString(actualPlaintext));
+ }
+
+ // .doFinal(input, offset, len, output)
+ {
+ final byte[] largerThanCiphertext = new byte[p.ciphertext.length + 5];
+ System.arraycopy(p.ciphertext, 0, largerThanCiphertext, 5, p.ciphertext.length);
+
+ if (p.aad != null) {
+ final byte[] largerThanAad = new byte[p.aad.length + 100];
+ System.arraycopy(p.aad, 0, largerThanAad, 50, p.aad.length);
+ assertTrue(p.aad.length > 1);
+ c.updateAAD(largerThanAad, 50, 1);
+ c.updateAAD(largerThanAad, 51, p.aad.length - 1);
+ }
+
+ final byte[] actualPlaintext = new byte[c.getOutputSize(p.ciphertext.length)];
+ assertEquals(p.plaintext.length,
+ c.doFinal(largerThanCiphertext, 5, p.ciphertext.length, actualPlaintext));
+ assertEquals(Arrays.toString(p.plaintext),
+ Arrays.toString(Arrays.copyOfRange(actualPlaintext, 0, p.plaintext.length)));
+ }
+
+ // .doFinal(input, offset, len, output, offset)
+ {
+ final byte[] largerThanCiphertext = new byte[p.ciphertext.length + 10];
+ System.arraycopy(p.ciphertext, 0, largerThanCiphertext, 5, p.ciphertext.length);
+
+ if (p.aad != null) {
+ final byte[] largerThanAad = new byte[p.aad.length + 2];
+ System.arraycopy(p.aad, 0, largerThanAad, 2, p.aad.length);
+ c.updateAAD(largerThanAad, 2, p.aad.length);
+ }
+
+ final byte[] actualPlaintext = new byte[c.getOutputSize(p.ciphertext.length) + 2];
+ assertEquals(p.plaintext.length,
+ c.doFinal(largerThanCiphertext, 5, p.ciphertext.length, actualPlaintext, 1));
+ assertEquals(Arrays.toString(p.plaintext),
+ Arrays.toString(Arrays.copyOfRange(actualPlaintext, 1, p.plaintext.length + 1)));
+ }
+
+ if (!p.isStreamCipher && !p.transformation.endsWith("NOPADDING")
+ && !isRandomizedEncryption(p.transformation)) {
+ Cipher cNoPad = Cipher.getInstance(
+ getCipherTransformationWithNoPadding(p.transformation), provider);
+ cNoPad.init(Cipher.DECRYPT_MODE, p.decryptKey, p.spec);
+
+ if (p.aad != null) {
+ c.updateAAD(p.aad);
+ }
+ final byte[] actualPlaintextPadded = cNoPad.doFinal(p.ciphertext);
+ assertEquals(provider + ":" + cNoPad.getAlgorithm(),
+ Arrays.toString(p.plaintextPadded), Arrays.toString(actualPlaintextPadded));
+ }
+
+ // Test wrapping a key. Every cipher should be able to wrap.
+ {
+ // Generate a small SecretKey for AES.
+ KeyGenerator kg = KeyGenerator.getInstance("AES");
+ kg.init(128);
+ SecretKey sk = kg.generateKey();
+
+ // Wrap it
+ c = Cipher.getInstance(p.transformation, provider);
+ c.init(Cipher.WRAP_MODE, p.encryptKey, p.spec);
+ byte[] cipherText = c.wrap(sk);
+
+ // Unwrap it
+ c.init(Cipher.UNWRAP_MODE, p.decryptKey, p.spec);
+ Key decryptedKey = c.unwrap(cipherText, sk.getAlgorithm(), Cipher.SECRET_KEY);
+
+ assertEquals(
+ "sk.getAlgorithm()=" + sk.getAlgorithm() + " decryptedKey.getAlgorithm()="
+ + decryptedKey.getAlgorithm() + " encryptKey.getEncoded()="
+ + Arrays.toString(sk.getEncoded()) + " decryptedKey.getEncoded()="
+ + Arrays.toString(decryptedKey.getEncoded()), sk, decryptedKey);
+ }
+ }
+
+ /**
+ * Gets the Cipher transformation with the same algorithm and mode as the provided one but
+ * which uses no padding.
+ */
+ private static String getCipherTransformationWithNoPadding(String transformation) {
+ // The transformation is assumed to be in the Algorithm/Mode/Padding format.
+ int paddingModeDelimiterIndex = transformation.lastIndexOf('/');
+ if (paddingModeDelimiterIndex == -1) {
+ fail("No padding mode delimiter: " + transformation);
+ }
+ String paddingMode = transformation.substring(paddingModeDelimiterIndex + 1);
+ if (!paddingMode.toLowerCase().endsWith("padding")) {
+ fail("No padding mode specified:" + transformation);
+ }
+ return transformation.substring(0, paddingModeDelimiterIndex) + "/NoPadding";
+ }
+
+ @Test
+ public void testCipher_updateAAD_BeforeInit_Failure() throws Exception {
+ Cipher c = Cipher.getInstance("AES/ECB/NoPadding");
+
+ try {
+ c.updateAAD((byte[]) null);
+ fail("should not be able to call updateAAD before Cipher is initialized");
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ c.updateAAD((ByteBuffer) null);
+ fail("should not be able to call updateAAD before Cipher is initialized");
+ } catch (IllegalStateException expected) {
+ }
+
+ try {
+ c.updateAAD(new byte[8]);
+ fail("should not be able to call updateAAD before Cipher is initialized");
+ } catch (IllegalStateException expected) {
+ }
+
+ try {
+ c.updateAAD(null, 0, 8);
+ fail("should not be able to call updateAAD before Cipher is initialized");
+ } catch (IllegalStateException expected) {
+ }
+
+ ByteBuffer bb = ByteBuffer.allocate(8);
+ try {
+ c.updateAAD(bb);
+ fail("should not be able to call updateAAD before Cipher is initialized");
+ } catch (IllegalStateException expected) {
+ }
+ }
+
+ @Test
+ public void testCipher_updateAAD_AfterInit_Failure() throws Exception {
+ Cipher c = Cipher.getInstance("AES/ECB/NoPadding");
+ c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(new byte[128 / 8], "AES"));
+
+ try {
+ c.updateAAD((byte[]) null);
+ fail("should not be able to call updateAAD with null input");
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ c.updateAAD((ByteBuffer) null);
+ fail("should not be able to call updateAAD with null input");
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ c.updateAAD(null, 0, 8);
+ fail("should not be able to call updateAAD with null input");
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ c.updateAAD(new byte[8], -1, 7);
+ fail("should not be able to call updateAAD with invalid offset");
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ c.updateAAD(new byte[8], 0, -1);
+ fail("should not be able to call updateAAD with negative length");
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ c.updateAAD(new byte[8], 0, 8 + 1);
+ fail("should not be able to call updateAAD with too large length");
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ c.updateAAD(new byte[8]);
+ fail("should not be able to call updateAAD on non-AEAD cipher");
+ } catch (UnsupportedOperationException expected) {
+ } catch (IllegalStateException expected) {
+ }
+ }
+
+ @Test
+ public void testCipher_ShortBlock_Failure() throws Exception {
+ for (String provider : AES_PROVIDERS) {
+ testCipher_ShortBlock_Failure(provider);
+ }
+ }
+
+ private void testCipher_ShortBlock_Failure(String provider) throws Exception {
+ final ByteArrayOutputStream errBuffer = new ByteArrayOutputStream();
+ PrintStream out = new PrintStream(errBuffer);
+ for (CipherTestParam p : CIPHER_TEST_PARAMS) {
+ if (!p.compatibleWith(provider)) {
+ continue;
+ }
+ try {
+ checkCipher_ShortBlock_Failure(p, provider);
+ } catch (Exception e) {
+ logTestFailure(out, provider, p, e);
+ }
+ }
+ out.flush();
+ if (errBuffer.size() > 0) {
+ throw new Exception("Errors encountered:\n\n" + errBuffer.toString() + "\n\n");
+ }
+ }
+
+ @Test
+ public void testCipher_DoFinal_wrapMode_Failure() throws Exception {
+ checkCipher_DoFinal_invalidMode_Failure(Cipher.WRAP_MODE);
+ }
+
+ @Test
+ public void testCipher_DoFinal_unwrapMode_Failure() throws Exception {
+ checkCipher_DoFinal_invalidMode_Failure(Cipher.UNWRAP_MODE);
+ }
+
+ /**
+ * Helper for testing that Cipher.doFinal() throws IllegalStateException when
+ * initialized in modes other than DECRYPT or ENCRYPT.
+ */
+ private static void checkCipher_DoFinal_invalidMode_Failure(int opmode) throws Exception {
+ String msg = String.format(Locale.US,
+ "doFinal() should throw IllegalStateException [mode=%d]", opmode);
+ int bs = createAesCipher(opmode).getBlockSize();
+ assertEquals(16, bs); // check test is set up correctly
+ try {
+ createAesCipher(opmode).doFinal();
+ fail(msg);
+ } catch (IllegalStateException expected) {
+ }
+
+ try {
+ createAesCipher(opmode).doFinal(new byte[0]);
+ fail(msg);
+ } catch (IllegalStateException expected) {
+ }
+
+ try {
+ createAesCipher(opmode).doFinal(new byte[2 * bs], 0, bs);
+ fail(msg);
+ } catch (IllegalStateException expected) {
+ }
+
+ try {
+ createAesCipher(opmode).doFinal(new byte[2 * bs], 0, bs, new byte[2 * bs], 0);
+ fail(msg);
+ } catch (IllegalStateException expected) {
+ }
+ }
+
+ @Test
+ public void testCipher_Update_wrapMode_Failure() throws Exception {
+ checkCipher_Update_invalidMode_Failure(Cipher.WRAP_MODE);
+ }
+
+ @Test
+ public void testCipher_Update_unwrapMode_Failure() throws Exception {
+ checkCipher_Update_invalidMode_Failure(Cipher.UNWRAP_MODE);
+ }
+
+ /**
+ * Helper for testing that Cipher.update() throws IllegalStateException when
+ * initialized in modes other than DECRYPT or ENCRYPT.
+ */
+ private static void checkCipher_Update_invalidMode_Failure(final int opmode) throws Exception {
+ String msg = "update() should throw IllegalStateException [mode=" + opmode + "]";
+ final int bs = createAesCipher(opmode).getBlockSize();
+ assertEquals(16, bs); // check test is set up correctly
+ assertIllegalStateException(msg, new Runnable() {
+ @Override
+ public void run() {
+ createAesCipher(opmode).update(new byte[0]);
+ }
+ });
+ assertIllegalStateException(msg, new Runnable() {
+ @Override
+ public void run() {
+ createAesCipher(opmode).update(new byte[2 * bs]);
+ }
+ });
+ assertIllegalStateException(msg, new Runnable() {
+ @Override
+ public void run() {
+ createAesCipher(opmode).update(
+ new byte[2 * bs] /* input */, bs /* inputOffset */, 0 /* inputLen */);
+ }
+ });
+ try {
+ createAesCipher(opmode).update(new byte[2*bs] /* input */, 0 /* inputOffset */,
+ 2 * bs /* inputLen */, new byte[2 * bs] /* output */, 0 /* outputOffset */);
+ fail(msg);
+ } catch (IllegalStateException expected) {
+ }
+ }
+
+ @Test
+ public void testCipher_Update_WithZeroLengthInput_ReturnsNull() throws Exception {
+ Cipher c = Cipher.getInstance("AES/ECB/NoPadding");
+ c.init(Cipher.ENCRYPT_MODE, AES_128_KEY);
+ assertNull(c.update(new byte[0]));
+ assertNull(c.update(new byte[c.getBlockSize() * 2], 0, 0));
+
+ // Try with non-zero offset just in case the implementation mixes up offset and inputLen
+ assertNull(c.update(new byte[c.getBlockSize() * 2], 16, 0));
+ }
+
+ @Test
+ public void testCipher_Wrap_decryptMode_Failure() throws Exception {
+ checkCipher_Wrap_invalidMode_Failure(Cipher.DECRYPT_MODE);
+ }
+
+ @Test
+ public void testCipher_Wrap_encryptMode_Failure() throws Exception {
+ checkCipher_Wrap_invalidMode_Failure(Cipher.ENCRYPT_MODE);
+ }
+
+ @Test
+ public void testCipher_Wrap_unwrapMode_Failure() throws Exception {
+ checkCipher_Wrap_invalidMode_Failure(Cipher.UNWRAP_MODE);
+ }
+
+ /**
+ * Helper for testing that Cipher.wrap() throws IllegalStateException when
+ * initialized in modes other than WRAP.
+ */
+ private static void checkCipher_Wrap_invalidMode_Failure(int opmode) throws Exception {
+ KeyGenerator kg = KeyGenerator.getInstance("AES");
+ kg.init(128);
+ SecretKey key = kg.generateKey();
+ Cipher cipher = createAesCipher(opmode);
+ try {
+ cipher.wrap(key);
+ fail("wrap() should throw IllegalStateException [mode=" + opmode + "]");
+ } catch (IllegalStateException expected) {
+ }
+ }
+
+ @Test
+ public void testCipher_Unwrap_decryptMode_Failure() throws Exception {
+ checkCipher_Unwrap_invalidMode_Failure(Cipher.DECRYPT_MODE);
+ }
+
+ @Test
+ public void testCipher_Unwrap_encryptMode_Failure() throws Exception {
+ checkCipher_Unwrap_invalidMode_Failure(Cipher.ENCRYPT_MODE);
+ }
+
+ @Test
+ public void testCipher_Unwrap_wrapMode_Failure() throws Exception {
+ checkCipher_Unwrap_invalidMode_Failure(Cipher.WRAP_MODE);
+ }
+
+ /**
+ * Helper for testing that Cipher.unwrap() throws IllegalStateException when
+ * initialized in modes other than UNWRAP.
+ */
+ private static void checkCipher_Unwrap_invalidMode_Failure(int opmode) throws Exception {
+ KeyGenerator kg = KeyGenerator.getInstance("AES");
+ kg.init(128);
+ SecretKey key = kg.generateKey();
+ Cipher cipher = createAesCipher(opmode);
+ byte[] wrappedKey = createAesCipher(Cipher.WRAP_MODE).wrap(key);
+ try {
+ cipher.unwrap(wrappedKey, key.getAlgorithm(), Cipher.PRIVATE_KEY);
+ fail("unwrap() should throw IllegalStateException [mode=" + opmode + "]");
+ } catch (IllegalStateException expected) {
+ }
+ }
+
+ private void checkCipher_ShortBlock_Failure(CipherTestParam p, String provider) throws Exception {
+ // Do not try to test ciphers with no padding already.
+ String noPaddingTransform = getCipherTransformationWithNoPadding(p.transformation);
+ if (p.transformation.equals(noPaddingTransform)) {
+ return;
+ }
+
+ Cipher c = Cipher.getInstance(
+ getCipherTransformationWithNoPadding(p.transformation), provider);
+ if (c.getBlockSize() == 0) {
+ return;
+ }
+
+ if (!p.transformation.endsWith("NOPADDING")) {
+ c.init(Cipher.ENCRYPT_MODE, p.encryptKey);
+ try {
+ c.doFinal(new byte[] { 0x01, 0x02, 0x03 });
+ fail("Should throw IllegalBlockSizeException on wrong-sized block; transform="
+ + p.transformation + " provider=" + provider);
+ } catch (IllegalBlockSizeException expected) {
+ }
+ }
+ }
+
+ @Test
+ public void testAES_ECB_PKCS5Padding_ShortBuffer_Failure() throws Exception {
+ for (String provider : AES_PROVIDERS) {
+ testAES_ECB_PKCS5Padding_ShortBuffer_Failure(provider);
+ }
+ }
+
+ private void testAES_ECB_PKCS5Padding_ShortBuffer_Failure(String provider) throws Exception {
+ Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding", provider);
+ c.init(Cipher.ENCRYPT_MODE, AES_128_KEY);
+
+ final byte[] fragmentOutput = c.update(AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext);
+ if (fragmentOutput != null) {
+ assertEquals(0, fragmentOutput.length);
+ }
+
+ // Provide null buffer.
+ {
+ try {
+ c.doFinal(null, 0);
+ fail("Should throw NullPointerException on null output buffer");
+ } catch (NullPointerException expected) {
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ // Provide short buffer.
+ {
+ final byte[] output = new byte[c.getBlockSize() - 1];
+ try {
+ c.doFinal(output, 0);
+ fail("Should throw ShortBufferException on short output buffer");
+ } catch (ShortBufferException expected) {
+ }
+ }
+
+ // Start 1 byte into output buffer.
+ {
+ final byte[] output = new byte[c.getBlockSize()];
+ try {
+ c.doFinal(output, 1);
+ fail("Should throw ShortBufferException on short output buffer");
+ } catch (ShortBufferException expected) {
+ }
+ }
+
+ // Should keep data for real output buffer
+ {
+ final byte[] output = new byte[c.getBlockSize()];
+ assertEquals(AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted.length, c.doFinal(output, 0));
+ assertTrue(Arrays.equals(AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted, output));
+ }
+ }
+
+ @Test
+ public void testAES_ECB_NoPadding_IncrementalUpdate_Success() throws Exception {
+ for (String provider : AES_PROVIDERS) {
+ testAES_ECB_NoPadding_IncrementalUpdate_Success(provider);
+ }
+ }
+
+ private void testAES_ECB_NoPadding_IncrementalUpdate_Success(String provider) throws Exception {
+ String algorithm = "AES/ECB/NoPadding";
+ if (!isSupported(algorithm, provider)) {
+ return;
+ }
+ Cipher c = Cipher.getInstance(algorithm, provider);
+ assertEquals(provider, c.getProvider().getName());
+ c.init(Cipher.ENCRYPT_MODE, AES_128_KEY);
+
+ for (int i = 0; i < AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded.length - 1; i++) {
+ final byte[] outputFragment = c.update(AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded, i, 1);
+ if (outputFragment != null) {
+ assertEquals(0, outputFragment.length);
+ }
+ }
+
+ final byte[] output = c.doFinal(AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded,
+ AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded.length - 1, 1);
+ assertNotNull(provider, output);
+ assertEquals(provider, AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded.length,
+ output.length);
+
+ assertTrue(provider, Arrays.equals(AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted, output));
+ }
+
+ private static final byte[] AES_IV_ZEROES = new byte[] {
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ };
+
+ @Test
+ public void testAES_ECB_NoPadding_IvParameters_Failure() throws Exception {
+ for (String provider : AES_PROVIDERS) {
+ testAES_ECB_NoPadding_IvParameters_Failure(provider);
+ }
+ }
+
+ private void testAES_ECB_NoPadding_IvParameters_Failure(String provider) throws Exception {
+ String algorithm = "AES/ECB/NoPadding";
+ if (!isSupported(algorithm, provider)) {
+ return;
+ }
+ Cipher c = Cipher.getInstance(algorithm, provider);
+
+ AlgorithmParameterSpec spec = new IvParameterSpec(AES_IV_ZEROES);
+ try {
+ c.init(Cipher.ENCRYPT_MODE, AES_128_KEY, spec);
+ fail("Should not accept an IV in ECB mode; provider=" + provider);
+ } catch (InvalidAlgorithmParameterException expected) {
+ }
+ }
+
+ @Test
+ public void testRC4_MultipleKeySizes() throws Exception {
+ final int SMALLEST_KEY_SIZE = 40;
+ final int LARGEST_KEY_SIZE = 1024;
+
+ /* Make an array of keys for our tests */
+ SecretKey[] keys = new SecretKey[LARGEST_KEY_SIZE - SMALLEST_KEY_SIZE];
+ {
+ KeyGenerator kg = KeyGenerator.getInstance("ARC4");
+ for (int keysize = SMALLEST_KEY_SIZE; keysize < LARGEST_KEY_SIZE; keysize++) {
+ final int index = keysize - SMALLEST_KEY_SIZE;
+ kg.init(keysize);
+ keys[index] = kg.generateKey();
+ }
+ }
+
+ /*
+ * Use this to compare the output of the first provider against
+ * subsequent providers.
+ */
+ String[] expected = new String[LARGEST_KEY_SIZE - SMALLEST_KEY_SIZE];
+
+ /* Find all providers that provide ARC4. We must have at least one! */
+ Map<String, String> filter = new HashMap<String, String>();
+ filter.put("Cipher.ARC4", "");
+ Provider[] providers = Security.getProviders(filter);
+ assertTrue("There must be security providers of Cipher.ARC4", providers.length > 0);
+
+ /* Keep track of this for later error messages */
+ String firstProvider = providers[0].getName();
+
+ for (Provider p : providers) {
+ Cipher c = Cipher.getInstance("ARC4", p);
+
+ for (int keysize = SMALLEST_KEY_SIZE; keysize < LARGEST_KEY_SIZE; keysize++) {
+ final int index = keysize - SMALLEST_KEY_SIZE;
+ final SecretKey sk = keys[index];
+
+ /*
+ * Test that encryption works. Donig this in a loop also has the
+ * benefit of testing that re-initialization works for this
+ * cipher.
+ */
+ c.init(Cipher.ENCRYPT_MODE, sk);
+ byte[] cipherText = c.doFinal(ORIGINAL_PLAIN_TEXT);
+ assertNotNull(cipherText);
+
+ /*
+ * Compare providers against eachother to make sure they're all
+ * in agreement. This helps when you add a brand new provider.
+ */
+ if (expected[index] == null) {
+ expected[index] = Arrays.toString(cipherText);
+ } else {
+ assertEquals(firstProvider + " should output the same as " + p.getName()
+ + " for key size " + keysize, expected[index],
+ Arrays.toString(cipherText));
+ }
+
+ c.init(Cipher.DECRYPT_MODE, sk);
+ byte[] actualPlaintext = c.doFinal(cipherText);
+ assertEquals("Key size: " + keysize, Arrays.toString(ORIGINAL_PLAIN_TEXT),
+ Arrays.toString(actualPlaintext));
+ }
+ }
+ }
+
+ @Test
+ public void testAES_keyConstrained() throws Exception {
+ Provider[] providers = Security.getProviders();
+ for (Provider p : providers) {
+ for (Provider.Service s : p.getServices()) {
+ if (s.getType().equals("Cipher")) {
+ if (s.getAlgorithm().startsWith("AES_128/")) {
+ Cipher c = Cipher.getInstance(s.getAlgorithm(), p);
+ assertTrue(s.getAlgorithm(), checkAES_keyConstraint(c, 128));
+ assertFalse(s.getAlgorithm(), checkAES_keyConstraint(c, 192));
+ assertFalse(s.getAlgorithm(), checkAES_keyConstraint(c, 256));
+ } else if (s.getAlgorithm().startsWith("AES_256/")) {
+ Cipher c = Cipher.getInstance(s.getAlgorithm(), p);
+ assertFalse(s.getAlgorithm(), checkAES_keyConstraint(c, 128));
+ assertFalse(s.getAlgorithm(), checkAES_keyConstraint(c, 192));
+ assertTrue(s.getAlgorithm(), checkAES_keyConstraint(c, 256));
+ }
+ }
+ }
+ }
+ }
+
+ private boolean checkAES_keyConstraint(Cipher c, int keySize) throws Exception {
+ KeyGenerator kg = KeyGenerator.getInstance(getBaseAlgorithm(c.getAlgorithm()));
+ kg.init(keySize);
+ SecretKey key = kg.generateKey();
+ try {
+ c.init(Cipher.ENCRYPT_MODE, key);
+ return true;
+ } catch (InvalidKeyException e) {
+ return false;
+ }
+ }
+
+ /*
+ * When in decrypt mode and using padding, the buffer shouldn't necessarily have room for an
+ * extra block when using padding.
+ * http://b/19186852
+ */
+ @Test
+ public void testDecryptBufferMultipleBlockSize_mustNotThrowException() throws Exception {
+ String testString = "Hello, World!";
+ byte[] testKey = "0123456789012345".getBytes(StandardCharsets.US_ASCII);
+ String testedCipher = "AES/ECB/PKCS7Padding";
+
+ Cipher encCipher = Cipher.getInstance(testedCipher);
+ encCipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(testKey, "AES"));
+ byte[] plainBuffer = testString.getBytes(StandardCharsets.US_ASCII);
+ byte[] encryptedBuffer = new byte[16];
+ int encryptedLength = encCipher.doFinal(
+ plainBuffer, 0, plainBuffer.length, encryptedBuffer);
+ assertEquals(16, encryptedLength);
+
+ Cipher cipher = Cipher.getInstance(testedCipher);
+ cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(testKey, "AES"));
+ // Must not throw exception.
+ int unencryptedBytes = cipher.doFinal(
+ encryptedBuffer, 0, encryptedBuffer.length, encryptedBuffer);
+ assertEquals(testString,
+ new String(encryptedBuffer, 0, unencryptedBytes, StandardCharsets.US_ASCII));
+ }
+
+ /**
+ * When using padding in decrypt mode, ensure that empty buffers decode to empty strings
+ * (no padding needed for the empty buffer).
+ * http://b/19186852
+ */
+ @Test
+ public void testDecryptBufferZeroSize_mustDecodeToEmptyString() throws Exception {
+ String[] androidOpenSSLCiphers = { "AES/CBC/PKCS5PADDING", "AES/CBC/PKCS7PADDING",
+ "AES/ECB/PKCS5PADDING", "AES/ECB/PKCS7PADDING", "DESEDE/CBC/PKCS5PADDING",
+ "DESEDE/CBC/PKCS7PADDING" };
+ for (String c : androidOpenSSLCiphers) {
+ Cipher cipher = Cipher.getInstance(c);
+ assertTrue(Conscrypt.isConscrypt(cipher.getProvider()));
+ if (c.contains("/CBC/")) {
+ cipher.init(Cipher.DECRYPT_MODE,
+ new SecretKeySpec("0123456789012345".getBytes(StandardCharsets.US_ASCII),
+ c.startsWith("AES/") ? "AES" : "DESEDE"),
+ new IvParameterSpec(
+ ("01234567" + (c.startsWith("AES/") ? "89012345" : ""))
+ .getBytes(StandardCharsets.US_ASCII)));
+ } else {
+ cipher.init(Cipher.DECRYPT_MODE,
+ new SecretKeySpec("0123456789012345".getBytes(StandardCharsets.US_ASCII),
+ c.startsWith("AES/") ? "AES" : "DESEDE"));
+ }
+
+ byte[] buffer = new byte[0];
+ int bytesProduced = cipher.doFinal(buffer, 0, buffer.length, buffer);
+ assertEquals("", new String(buffer, 0, bytesProduced, StandardCharsets.US_ASCII));
+ }
+ }
+
+ /**
+ * Check that RSA with OAEPPadding is supported.
+ * http://b/22208820
+ */
+ @Test
+ public void test_RSA_OAEPPadding() throws Exception {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+ keyGen.initialize(1024, SecureRandom.getInstance("SHA1PRNG"));
+ Cipher cipher = Cipher.getInstance("RSA/NONE/OAEPPadding");
+ cipher.init(Cipher.ENCRYPT_MODE, keyGen.generateKeyPair().getPublic());
+ cipher.doFinal(new byte[] {1,2,3,4});
+ }
+
+ /**
+ * Check that initializing with a GCM AlgorithmParameters produces the same result
+ * as initializing with a GCMParameterSpec.
+ */
+ @Test
+ public void test_AESGCMNoPadding_init_algParams() throws Exception {
+ SecretKeySpec key = new SecretKeySpec(new byte[16], "AES");
+ GCMParameterSpec spec = new GCMParameterSpec(96, new byte[12]);
+ AlgorithmParameters params = AlgorithmParameters.getInstance("GCM");
+ params.init(spec);
+ Cipher c1 = Cipher.getInstance("AES/GCM/NoPadding");
+ Cipher c2 = Cipher.getInstance("AES/GCM/NoPadding");
+
+ c1.init(Cipher.ENCRYPT_MODE, key, spec);
+ c2.init(Cipher.ENCRYPT_MODE, key, params);
+ // Cipher can adjust the provider based on the reponses to the init call, make sure
+ // we got the same provider for both
+ assertEquals(c1.getProvider(), c2.getProvider());
+ c1.updateAAD(new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ });
+ c2.updateAAD(new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ });
+
+ assertEquals(Arrays.toString(c1.doFinal()), Arrays.toString(c2.doFinal()));
+ }
+
+ /**
+ * http://b/27224566
+ * http://b/27994930
+ * Check that a PBKDF2WITHHMACSHA1 secret key factory works well with a
+ * PBEWITHSHAAND128BITAES-CBC-BC cipher. The former is PKCS5 and the latter is PKCS12, and so
+ * mixing them is not recommended.
+ */
+ @Test
+ public void test_PBKDF2WITHHMACSHA1_SKFactory_and_PBEAESCBC_Cipher_noIV() throws Exception {
+ Assume.assumeNotNull(Security.getProvider("BC"));
+ byte[] plaintext =
+ new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
+ byte[] ciphertext = new byte[] {92, -65, -128, 16, -102, -115, -44, 52, 16, 124, -34, -45,
+ 58, -70, -17, 127, 119, -67, 87, 91, 63, -13, -40, 9, 97, -17, -71, 97, 10, -61,
+ -19, -73};
+ SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA1");
+ PBEKeySpec pbeks = new PBEKeySpec(
+ "password".toCharArray(), "salt".getBytes(TestUtils.UTF_8), 100, 128);
+ SecretKey secretKey = skf.generateSecret(pbeks);
+
+ Cipher cipher = Cipher.getInstance("PBEWITHSHAAND128BITAES-CBC-BC");
+ PBEParameterSpec paramSpec = new PBEParameterSpec("salt".getBytes(TestUtils.UTF_8), 100);
+ assertThrows(InvalidAlgorithmParameterException.class,
+ () -> cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec));
+ }
+
+ /**
+ * http://b/27224566
+ * http://b/27994930
+ * Check that a PBKDF2WITHHMACSHA1 secret key factory works well with a
+ * PBEWITHSHAAND128BITAES-CBC-BC cipher. The former is PKCS5 and the latter is PKCS12, and so
+ * mixing them is not recommended. However, until 1.52 BouncyCastle was accepting this mixture,
+ * assuming the IV was a 0 vector. Some apps still use this functionality. This
+ * compatibility is likely to be removed in later versions of Android.
+ * TODO(27995180): consider whether we keep this compatibility. Consider whether we only allow
+ * if an IV is passed in the parameters.
+ */
+ @Test
+ public void test_PBKDF2WITHHMACSHA1_SKFactory_and_PBEAESCBC_Cipher_withIV() throws Exception {
+ Assume.assumeNotNull(Security.getProvider("BC"));
+ byte[] plaintext = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19 };
+ byte[] ciphertext = { 68, -87, 71, -6, 32, -77, 124, 3, 35, -26, 96, -16, 100, -17, 52, -32,
+ 110, 26, -117, 112, -25, -113, -58, -30, 19, -46, -21, 59, -126, -8, -70, -89 };
+ byte[] iv = new byte[] { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
+ SecretKeyFactory skf =
+ SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA1");
+ PBEKeySpec pbeks = new PBEKeySpec("password".toCharArray(),
+ "salt".getBytes(TestUtils.UTF_8),
+ 100, 128);
+ SecretKey secretKey = skf.generateSecret(pbeks);
+ Cipher cipher =
+ Cipher.getInstance("PBEWITHSHAAND128BITAES-CBC-BC");
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
+ assertEquals(Arrays.toString(ciphertext), Arrays.toString(cipher.doFinal(plaintext)));
+
+ secretKey = skf.generateSecret(pbeks);
+ cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
+ assertEquals(Arrays.toString(plaintext), Arrays.toString(cipher.doFinal(ciphertext)));
+ }
+
+ private static Cipher createAesCipher(int opmode) {
+ try {
+ final Cipher c = Cipher.getInstance("AES/ECB/NoPadding");
+ c.init(opmode, AES_128_KEY);
+ return c;
+ } catch (Exception e) {
+ fail("Unexpected Exception: " + e.getMessage());
+ return null; // unreachable
+ }
+ }
+
+ /**
+ * Asserts that running the given runnable results in an IllegalStateException
+ */
+ private static void assertIllegalStateException(String failureMessage, Runnable runnable) {
+ try {
+ runnable.run();
+ fail(failureMessage);
+ } catch (IllegalStateException expected) {
+ // expected
+ }
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/crypto/ECDHKeyAgreementTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/crypto/ECDHKeyAgreementTest.java
new file mode 100644
index 0000000..a357ecb
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/crypto/ECDHKeyAgreementTest.java
@@ -0,0 +1,555 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2013 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.
+ */
+
+package com.android.org.conscrypt.javax.crypto;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.org.conscrypt.Conscrypt;
+import com.android.org.conscrypt.TestUtils;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.interfaces.ECKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import javax.crypto.KeyAgreement;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import junit.framework.AssertionFailedError;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for all registered Elliptic Curve Diffie-Hellman {@link KeyAgreement} providers.
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class ECDHKeyAgreementTest {
+
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
+ // Two key pairs and the resulting shared secret for the Known Answer Test
+ private static final byte[] KAT_PUBLIC_KEY1_X509 = TestUtils.decodeHex(
+ "3059301306072a8648ce3d020106082a8648ce3d030107034200049fc2f71f85446b1371244491d83"
+ + "9cf97b5d27cedbb04d2c0058b59709df3a216e6b4ca1b2d622588c5a0e6968144a8965e816a600c"
+ + "05305a1da3df2bf02b41d1");
+ private static final byte[] KAT_PRIVATE_KEY1_PKCS8 = TestUtils.decodeHex(
+ "308193020100301306072a8648ce3d020106082a8648ce3d030107047930770201010420e1e683003"
+ + "c8b963a92742e5f955ce7fddc81d0c3ae9b149d6af86a0cacb2271ca00a06082a8648ce3d030107"
+ + "a144034200049fc2f71f85446b1371244491d839cf97b5d27cedbb04d2c0058b59709df3a216e6b"
+ + "4ca1b2d622588c5a0e6968144a8965e816a600c05305a1da3df2bf02b41d1");
+
+ private static final byte[] KAT_PUBLIC_KEY2_X509 = TestUtils.decodeHex(
+ "3059301306072a8648ce3d020106082a8648ce3d03010703420004358efb6d91e5bbcae21774af3f6"
+ + "d85d0848630e7e61dbeb5ac9e47036ed0f8d38c7a1d1bb249f92861c7c9153fff33f45ab5b171eb"
+ + "e8cad741125e6bb4fc6b07");
+ private static final byte[] KAT_PRIVATE_KEY2_PKCS8 = TestUtils.decodeHex(
+ "308193020100301306072a8648ce3d020106082a8648ce3d0301070479307702010104202b1810a69"
+ + "e12b74d50bf0343168f705f0104f76299855268aa526fdb31e6eec0a00a06082a8648ce3d030107"
+ + "a14403420004358efb6d91e5bbcae21774af3f6d85d0848630e7e61dbeb5ac9e47036ed0f8d38c7"
+ + "a1d1bb249f92861c7c9153fff33f45ab5b171ebe8cad741125e6bb4fc6b07");
+
+ private static final byte[] KAT_SECRET =
+ TestUtils.decodeHex("4faa0594c0e773eb26c8df2163af2443e88aab9578b9e1f324bc61e42d222783");
+
+ private static final ECPublicKey KAT_PUBLIC_KEY1;
+ private static final ECPrivateKey KAT_PRIVATE_KEY1;
+ private static final ECPublicKey KAT_PUBLIC_KEY2;
+ private static final ECPrivateKey KAT_PRIVATE_KEY2;
+ static {
+ try {
+ KAT_PUBLIC_KEY1 = getPublicKey(KAT_PUBLIC_KEY1_X509);
+ KAT_PRIVATE_KEY1 = getPrivateKey(KAT_PRIVATE_KEY1_PKCS8);
+ KAT_PUBLIC_KEY2 = getPublicKey(KAT_PUBLIC_KEY2_X509);
+ KAT_PRIVATE_KEY2 = getPrivateKey(KAT_PRIVATE_KEY2_PKCS8);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to decode KAT key pairs using default provider", e);
+ }
+ }
+
+ @BeforeClass
+ public static void setUp() {
+ TestUtils.assumeAllowsUnsignedCrypto();
+ }
+
+ /**
+ * Performs a known-answer test of the shared secret for all permutations of {@code Providers}
+ * of: first key pair, second key pair, and the {@code KeyAgreement}. This is to check that
+ * the {@code KeyAgreement} instances work with keys of all registered providers.
+ */
+ @Test
+ public void testKnownAnswer() throws Exception {
+ for (Provider keyFactoryProvider1 : getKeyFactoryProviders()) {
+ ECPrivateKey privateKey1 = getPrivateKey(KAT_PRIVATE_KEY1_PKCS8, keyFactoryProvider1);
+ ECPublicKey publicKey1 = getPublicKey(KAT_PUBLIC_KEY1_X509, keyFactoryProvider1);
+ for (Provider keyFactoryProvider2 : getKeyFactoryProviders()) {
+ ECPrivateKey privateKey2 =
+ getPrivateKey(KAT_PRIVATE_KEY2_PKCS8, keyFactoryProvider2);
+ ECPublicKey publicKey2 =
+ getPublicKey(KAT_PUBLIC_KEY2_X509, keyFactoryProvider2);
+ for (Provider keyAgreementProvider : getKeyAgreementProviders()) {
+ try {
+ testKnownAnswer(publicKey1, privateKey1, publicKey2, privateKey2,
+ keyAgreementProvider);
+ } catch (Throwable e) {
+ throw new RuntimeException(getClass().getSimpleName() + ".testKnownAnswer("
+ + keyFactoryProvider1.getName()
+ + ", " + keyFactoryProvider2.getName()
+ + ", " + keyAgreementProvider.getName() + ")",
+ e);
+ }
+ }
+ }
+ }
+ }
+
+ void testKnownAnswer(
+ ECPublicKey publicKey1, ECPrivateKey privateKey1,
+ ECPublicKey publicKey2, ECPrivateKey privateKey2,
+ Provider keyAgreementProvider) throws Exception {
+ assertTrue(Arrays.equals(
+ KAT_SECRET, generateSecret(keyAgreementProvider, privateKey1, publicKey2)));
+ assertTrue(Arrays.equals(
+ KAT_SECRET, generateSecret(keyAgreementProvider, privateKey2, publicKey1)));
+ }
+
+ @Test
+ public void testGetAlgorithm() throws Exception {
+ invokeCallingMethodForEachKeyAgreementProvider();
+ }
+
+ void testGetAlgorithm(Provider provider) throws Exception {
+ assertEquals("ECDH", getKeyAgreement(provider).getAlgorithm());
+ }
+
+ @Test
+ public void testGetProvider() throws Exception {
+ invokeCallingMethodForEachKeyAgreementProvider();
+ }
+
+ void testGetProvider(Provider provider) throws Exception {
+ assertSame(provider, getKeyAgreement(provider).getProvider());
+ }
+
+ @Test
+ public void testInit_withNullPrivateKey() throws Exception {
+ invokeCallingMethodForEachKeyAgreementProvider();
+ }
+
+ void testInit_withNullPrivateKey(Provider provider) throws Exception {
+ KeyAgreement keyAgreement = getKeyAgreement(provider);
+ try {
+ keyAgreement.init(null);
+ fail();
+ } catch (InvalidKeyException expected) {}
+ }
+
+ @Test
+ public void testInit_withUnsupportedPrivateKeyType() throws Exception {
+ invokeCallingMethodForEachKeyAgreementProvider();
+ }
+
+ void testInit_withUnsupportedPrivateKeyType(Provider provider) throws Exception {
+ KeyAgreement keyAgreement = getKeyAgreement(provider);
+ try {
+ keyAgreement.init(KAT_PUBLIC_KEY1);
+ fail();
+ } catch (InvalidKeyException expected) {}
+ }
+
+ @Test
+ public void testInit_withUnsupportedAlgorithmParameterSpec() throws Exception {
+ invokeCallingMethodForEachKeyAgreementProvider();
+ }
+
+ void testInit_withUnsupportedAlgorithmParameterSpec(Provider provider) throws Exception {
+ try {
+ getKeyAgreement(provider).init(KAT_PRIVATE_KEY1, new ECGenParameterSpec("prime256v1"));
+ fail();
+ } catch (InvalidAlgorithmParameterException expected) {}
+ }
+
+ @Test
+ public void testDoPhase_whenNotInitialized() throws Exception {
+ invokeCallingMethodForEachKeyAgreementProvider();
+ }
+
+ void testDoPhase_whenNotInitialized(Provider provider) throws Exception {
+ try {
+ getKeyAgreement(provider).doPhase(KAT_PUBLIC_KEY1, true);
+ fail();
+ } catch (IllegalStateException expected) {}
+ }
+
+ @Test
+ public void testDoPhaseReturnsNull() throws Exception {
+ invokeCallingMethodForEachKeyAgreementProvider();
+ }
+
+ void testDoPhaseReturnsNull(Provider provider) throws Exception {
+ KeyAgreement keyAgreement = getKeyAgreement(provider);
+ keyAgreement.init(KAT_PRIVATE_KEY1);
+ assertNull(keyAgreement.doPhase(KAT_PUBLIC_KEY2, true));
+ }
+
+ @Test
+ public void testDoPhase_withPhaseWhichIsNotLast() throws Exception {
+ invokeCallingMethodForEachKeyAgreementProvider();
+ }
+
+ void testDoPhase_withPhaseWhichIsNotLast(Provider provider) throws Exception {
+ KeyAgreement keyAgreement = getKeyAgreement(provider);
+ keyAgreement.init(KAT_PRIVATE_KEY1);
+ try {
+ keyAgreement.doPhase(KAT_PUBLIC_KEY2, false);
+ fail();
+ } catch (IllegalStateException expected) {}
+ }
+
+ @Test
+ public void testDoPhase_withNullKey() throws Exception {
+ invokeCallingMethodForEachKeyAgreementProvider();
+ }
+
+ void testDoPhase_withNullKey(Provider provider) throws Exception {
+ KeyAgreement keyAgreement = getKeyAgreement(provider);
+ keyAgreement.init(KAT_PRIVATE_KEY1);
+ try {
+ keyAgreement.doPhase(null, true);
+ fail();
+ } catch (InvalidKeyException expected) {}
+ }
+
+ @Test
+ public void testDoPhase_withInvalidKeyType() throws Exception {
+ invokeCallingMethodForEachKeyAgreementProvider();
+ }
+
+ void testDoPhase_withInvalidKeyType(Provider provider) throws Exception {
+ KeyAgreement keyAgreement = getKeyAgreement(provider);
+ keyAgreement.init(KAT_PRIVATE_KEY1);
+ try {
+ keyAgreement.doPhase(KAT_PRIVATE_KEY1, true);
+ fail();
+ } catch (InvalidKeyException expected) {}
+ }
+
+ @Test
+ public void testGenerateSecret_withNullOutputBuffer() throws Exception {
+ invokeCallingMethodForEachKeyAgreementProvider();
+ }
+
+ void testGenerateSecret_withNullOutputBuffer(Provider provider) throws Exception {
+ KeyAgreement keyAgreement = getKeyAgreement(provider);
+ keyAgreement.init(KAT_PRIVATE_KEY1);
+ keyAgreement.doPhase(KAT_PUBLIC_KEY2, true);
+ try {
+ keyAgreement.generateSecret(null, 0);
+ fail();
+ } catch (NullPointerException expected) {}
+ }
+
+ @Test
+ public void testGenerateSecret_withBufferOfTheRightSize() throws Exception {
+ invokeCallingMethodForEachKeyAgreementProvider();
+ }
+
+ void testGenerateSecret_withBufferOfTheRightSize(Provider provider) throws Exception {
+ KeyAgreement keyAgreement = getKeyAgreement(provider);
+ keyAgreement.init(KAT_PRIVATE_KEY1);
+ keyAgreement.doPhase(KAT_PUBLIC_KEY2, true);
+
+ byte[] buffer = new byte[KAT_SECRET.length];
+ int secretLengthBytes = keyAgreement.generateSecret(buffer, 0);
+ assertEquals(KAT_SECRET.length, secretLengthBytes);
+ assertTrue(Arrays.equals(KAT_SECRET, buffer));
+ }
+
+ @Test
+ public void testGenerateSecret_withLargerThatNeededBuffer() throws Exception {
+ invokeCallingMethodForEachKeyAgreementProvider();
+ }
+
+ void testGenerateSecret_withLargerThatNeededBuffer(Provider provider) throws Exception {
+ KeyAgreement keyAgreement = getKeyAgreement(provider);
+ keyAgreement.init(KAT_PRIVATE_KEY1);
+ keyAgreement.doPhase(KAT_PUBLIC_KEY2, true);
+
+ // Place the shared secret in the middle of the larger buffer and check that only that
+ // part of the buffer is affected.
+ byte[] buffer = new byte[KAT_SECRET.length + 2];
+ buffer[0] = (byte) 0x85; // arbitrary canary value
+ buffer[buffer.length - 1] = (byte) 0x3b; // arbitrary canary value
+ int secretLengthBytes = keyAgreement.generateSecret(buffer, 1);
+ assertEquals(KAT_SECRET.length, secretLengthBytes);
+ assertEquals((byte) 0x85, buffer[0]);
+ assertEquals((byte) 0x3b, buffer[buffer.length - 1]);
+ byte[] secret = new byte[KAT_SECRET.length];
+ System.arraycopy(buffer, 1, secret, 0, secret.length);
+ assertTrue(Arrays.equals(KAT_SECRET, secret));
+ }
+
+ @Test
+ public void testGenerateSecret_withSmallerThanNeededBuffer() throws Exception {
+ invokeCallingMethodForEachKeyAgreementProvider();
+ }
+
+ void testGenerateSecret_withSmallerThanNeededBuffer(Provider provider) throws Exception {
+ KeyAgreement keyAgreement = getKeyAgreement(provider);
+ keyAgreement.init(KAT_PRIVATE_KEY1);
+ keyAgreement.doPhase(KAT_PUBLIC_KEY2, true);
+ try {
+ // Although the buffer is big enough (1024 bytes) the shared secret should be placed
+ // at offset 1020 thus leaving only 4 bytes for the secret, which is not enough.
+ keyAgreement.generateSecret(new byte[1024], 1020);
+ fail();
+ } catch (ShortBufferException expected) {}
+ }
+
+ @Test
+ public void testGenerateSecret_withoutBuffer() throws Exception {
+ invokeCallingMethodForEachKeyAgreementProvider();
+ }
+
+ void testGenerateSecret_withoutBuffer(Provider provider) throws Exception {
+ KeyAgreement keyAgreement = getKeyAgreement(provider);
+ keyAgreement.init(KAT_PRIVATE_KEY2);
+ keyAgreement.doPhase(KAT_PUBLIC_KEY1, true);
+
+ byte[] secret = keyAgreement.generateSecret();
+ assertTrue(Arrays.equals(KAT_SECRET, secret));
+ }
+
+ @Test
+ public void testGenerateSecret_withAlgorithm() throws Exception {
+ invokeCallingMethodForEachKeyAgreementProvider();
+ }
+
+ void testGenerateSecret_withAlgorithm(Provider provider) throws Exception {
+ KeyAgreement keyAgreement = getKeyAgreement(provider);
+ keyAgreement.init(KAT_PRIVATE_KEY2);
+ keyAgreement.doPhase(KAT_PUBLIC_KEY1, true);
+
+ try {
+ SecretKey key = keyAgreement.generateSecret("AES");
+ assertEquals("AES", key.getAlgorithm());
+ // The check below will need to change if it's a hardware-backed key.
+ // We'll have to encrypt a known plaintext and check that the ciphertext is as
+ // expected.
+ assertTrue(Arrays.equals(KAT_SECRET, key.getEncoded()));
+ } catch (NoSuchAlgorithmException e) {
+ // This provider doesn't support AES, that's fine as long as it's not Conscrypt
+ assertFalse(Conscrypt.isConscrypt(provider));
+ }
+ }
+
+ @Test
+ public void testDoPhase_IncompatibleCurves_Failure() throws Exception {
+ invokeCallingMethodForEachKeyAgreementProvider();
+ }
+
+ void testDoPhase_IncompatibleCurves_Failure(Provider provider) throws Exception {
+ // The SunEC provider tries to pass a sun-only AlgorithmParameterSpec to the default
+ // AlgorithmParameters:EC when its KeyPairGenerator is initialized. Since Conscrypt
+ // is the highest-ranked provider when running our tests, its implementation of
+ // AlgorithmParameters:EC is returned, and it doesn't understand the special
+ // AlgorithmParameterSpec, so the KeyPairGenerator can't be initialized.
+ if (provider.getName().equalsIgnoreCase("SunEC")) {
+ return;
+ }
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", provider);
+ ECGenParameterSpec ecSpec256 = new ECGenParameterSpec("secp256r1");
+ keyGen.initialize(ecSpec256);
+ KeyPair keyPairA = keyGen.generateKeyPair();
+
+ ECGenParameterSpec ecSpec224 = new ECGenParameterSpec("secp224r1");
+ keyGen.initialize(ecSpec224);
+ KeyPair keyPairB = keyGen.generateKeyPair();
+
+ assertFalse(((ECKey) keyPairA.getPublic()).getParams().equals(
+ ((ECKey) keyPairB.getPublic()).getParams()));
+
+ KeyAgreement kaA = KeyAgreement.getInstance("ECDH", provider);
+ kaA.init(keyPairA.getPrivate());
+ try {
+ kaA.doPhase(keyPairB.getPublic(), true);
+ kaA.generateSecret();
+ fail("Generated secrets with mixed keys");
+ } catch (InvalidKeyException expected) {
+ }
+ }
+
+ private void invokeCallingMethodForEachKeyAgreementProvider() throws Exception {
+ StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+ String callingMethodName = null;
+ for (int i = 0; i < stackTrace.length; i++) {
+ if ("invokeCallingMethodForEachKeyAgreementProvider".equals(
+ stackTrace[i].getMethodName())) {
+ callingMethodName = stackTrace[i + 1].getMethodName();
+ }
+ }
+ if (callingMethodName == null) {
+ throw new RuntimeException("Failed to deduce calling method name from stack trace");
+ }
+
+ String invokedMethodName = callingMethodName;
+ Method method;
+ try {
+ method = getClass().getDeclaredMethod(invokedMethodName, Provider.class);
+ } catch (NoSuchMethodError e) {
+ throw new AssertionFailedError("Failed to find per-Provider test method "
+ + getClass().getSimpleName() + "." + invokedMethodName + "(Provider)");
+ }
+
+ for (Provider provider : getKeyAgreementProviders()) {
+ try {
+ method.invoke(this, provider);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(getClass().getSimpleName() + "." + invokedMethodName
+ + "(provider: " + provider.getName() + ") failed",
+ e.getCause());
+ }
+ }
+ }
+
+ private static Provider[] getKeyAgreementProviders() {
+ Provider[] providers = Security.getProviders("KeyAgreement.ECDH");
+ if (providers == null) {
+ return new Provider[0];
+ }
+
+ // Do not test AndroidKeyStore as KeyAgreement provider. It only handles Android
+ // Keystore-backed keys. It's OKish not to test AndroidKeyStore here because it's tested by
+ // cts/tests/test/keystore.
+ List<Provider> filteredProvidersList = new ArrayList<Provider>(providers.length);
+ for (Provider provider : providers) {
+ if ("AndroidKeyStore".equals(provider.getName())) {
+ continue;
+ }
+ filteredProvidersList.add(provider);
+ }
+ providers = filteredProvidersList.toArray(new Provider[filteredProvidersList.size()]);
+
+ // Sort providers by name to guarantee deterministic order in which providers are used in
+ // the tests.
+ return sortByName(providers);
+ }
+
+ private static Provider[] getKeyFactoryProviders() {
+ Provider[] providers = Security.getProviders("KeyFactory.EC");
+ if (providers == null) {
+ return new Provider[0];
+ }
+
+ // Do not test AndroidKeyStore's KeyFactory. It only handles Android Keystore-backed keys.
+ // It's OKish not to test AndroidKeyStore's KeyFactory here because it's tested by
+ // cts/tests/test/keystore.
+ List<Provider> filteredProvidersList = new ArrayList<Provider>(providers.length);
+ for (Provider provider : providers) {
+ if ("AndroidKeyStore".equals(provider.getName())) {
+ continue;
+ }
+ filteredProvidersList.add(provider);
+ }
+ providers = filteredProvidersList.toArray(new Provider[filteredProvidersList.size()]);
+
+ // Sort providers by name to guarantee deterministic order in which providers are used in
+ // the tests.
+ return sortByName(providers);
+ }
+
+ private static ECPrivateKey getPrivateKey(byte[] pkcs8EncodedKey, Provider provider)
+ throws GeneralSecurityException {
+ KeyFactory keyFactory = KeyFactory.getInstance("EC", provider);
+ return (ECPrivateKey) keyFactory.generatePrivate(new PKCS8EncodedKeySpec(pkcs8EncodedKey));
+ }
+
+ private static ECPublicKey getPublicKey(byte[] x509EncodedKey, Provider provider)
+ throws GeneralSecurityException {
+ KeyFactory keyFactory = KeyFactory.getInstance("EC", provider);
+ return (ECPublicKey) keyFactory.generatePublic(new X509EncodedKeySpec(x509EncodedKey));
+ }
+
+ private static ECPrivateKey getPrivateKey(byte[] pkcs8EncodedKey)
+ throws GeneralSecurityException {
+ KeyFactory keyFactory = KeyFactory.getInstance("EC");
+ return (ECPrivateKey) keyFactory.generatePrivate(new PKCS8EncodedKeySpec(pkcs8EncodedKey));
+ }
+
+ private static ECPublicKey getPublicKey(byte[] x509EncodedKey)
+ throws GeneralSecurityException {
+ KeyFactory keyFactory = KeyFactory.getInstance("EC");
+ return (ECPublicKey) keyFactory.generatePublic(new X509EncodedKeySpec(x509EncodedKey));
+ }
+
+ private static KeyAgreement getKeyAgreement(Provider provider) throws NoSuchAlgorithmException {
+ return KeyAgreement.getInstance("ECDH", provider);
+ }
+
+ private static byte[] generateSecret(
+ Provider keyAgreementProvider, PrivateKey privateKey, PublicKey publicKey)
+ throws GeneralSecurityException {
+ KeyAgreement keyAgreement = getKeyAgreement(keyAgreementProvider);
+ keyAgreement.init(privateKey);
+ keyAgreement.doPhase(publicKey, true);
+ return keyAgreement.generateSecret();
+ }
+
+ private static Provider[] sortByName(Provider[] providers) {
+ Arrays.sort(providers, new Comparator<Provider>() {
+ @Override
+ public int compare(Provider lhs, Provider rhs) {
+ return lhs.getName().compareTo(rhs.getName());
+ }
+ });
+ return providers;
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/crypto/KeyGeneratorTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/crypto/KeyGeneratorTest.java
new file mode 100644
index 0000000..bc35015
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/crypto/KeyGeneratorTest.java
@@ -0,0 +1,184 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.javax.crypto;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import com.android.org.conscrypt.TestUtils;
+import com.android.org.conscrypt.java.security.StandardNames;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class KeyGeneratorTest {
+ // BEGIN Android-Added: Allow access to deprecated BC algorithms.
+ // Allow access to deprecated BC algorithms in this test, so we can ensure they
+ // continue to work
+ @ClassRule
+ public static TestRule enableDeprecatedBCAlgorithmsRule =
+ EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
+ private static boolean isUnsupported(KeyGenerator kg) {
+ // Don't bother testing "Sun..." KeyGenerators or BC outside of Android
+ return kg.getProvider().getName().startsWith("Sun")
+ || (StandardNames.IS_RI && kg.getProvider().getName().equals("BC"));
+ }
+
+ @BeforeClass
+ public static void setUp() {
+ TestUtils.assumeAllowsUnsignedCrypto();
+ }
+
+ @Test
+ public void test_getInstance() throws Exception {
+ ServiceTester.test("KeyGenerator")
+ // Do not test AndroidKeyStore's KeyGenerator. It cannot be initialized without
+ // providing AndroidKeyStore-specific algorithm parameters.
+ // It's OKish not to test AndroidKeyStore's KeyGenerator here because it's tested
+ // by cts/tests/test/keystore.
+ .skipProvider("AndroidKeyStore")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider provider, String algorithm) throws Exception {
+ // KeyGenerator.getInstance(String)
+ KeyGenerator kg1 = KeyGenerator.getInstance(algorithm);
+ assertEquals(algorithm, kg1.getAlgorithm());
+ test_KeyGenerator(kg1);
+
+ // KeyGenerator.getInstance(String, Provider)
+ KeyGenerator kg2 = KeyGenerator.getInstance(algorithm, provider);
+ assertEquals(algorithm, kg2.getAlgorithm());
+ assertEquals(provider, kg2.getProvider());
+ test_KeyGenerator(kg2);
+
+ // KeyGenerator.getInstance(String, String)
+ KeyGenerator kg3 = KeyGenerator.getInstance(algorithm, provider.getName());
+ assertEquals(algorithm, kg3.getAlgorithm());
+ assertEquals(provider, kg3.getProvider());
+ test_KeyGenerator(kg3);
+ }
+ });
+ }
+
+ private static final Map<String, List<Integer>> KEY_SIZES
+ = new HashMap<String, List<Integer>>();
+ private static void putKeySize(String algorithm, int keySize) {
+ algorithm = algorithm.toUpperCase();
+ List<Integer> keySizes = KEY_SIZES.get(algorithm);
+ if (keySizes == null) {
+ keySizes = new ArrayList<Integer>();
+ KEY_SIZES.put(algorithm, keySizes);
+ }
+ keySizes.add(keySize);
+ }
+ private static List<Integer> getKeySizes(String algorithm) throws Exception {
+ algorithm = algorithm.toUpperCase();
+ List<Integer> keySizes = KEY_SIZES.get(algorithm);
+ if (keySizes == null) {
+ throw new Exception("Unknown key sizes for KeyGenerator." + algorithm);
+ }
+ return keySizes;
+ }
+ static {
+ putKeySize("AES", 128);
+ putKeySize("AES", 192);
+ putKeySize("AES", 256);
+ putKeySize("ARC4", 1024);
+ putKeySize("ARC4", 40);
+ putKeySize("ARC4", 41);
+ putKeySize("ARCFOUR", 1024);
+ putKeySize("ARCFOUR", 40);
+ putKeySize("ARCFOUR", 41);
+ putKeySize("Blowfish", 32);
+ putKeySize("Blowfish", 32+8);
+ putKeySize("Blowfish", 448);
+ putKeySize("ChaCha20", 256);
+ putKeySize("DES", 56);
+ putKeySize("DESede", 112);
+ putKeySize("DESede", 168);
+ putKeySize("RC2", 40);
+ putKeySize("RC2", 41);
+ putKeySize("RC2", 1024);
+ putKeySize("RC4", 40);
+ putKeySize("RC4", 41);
+ putKeySize("RC4", 1024);
+ putKeySize("HmacMD5", 1);
+ putKeySize("HmacMD5", 1025);
+ putKeySize("HmacSHA1", 1);
+ putKeySize("HmacSHA1", 1025);
+ putKeySize("HmacSHA224", 40);
+ putKeySize("HmacSHA224", 1025);
+ putKeySize("HmacSHA256", 40);
+ putKeySize("HmacSHA256", 1025);
+ putKeySize("HmacSHA384", 40);
+ putKeySize("HmacSHA384", 1025);
+ putKeySize("HmacSHA512", 40);
+ putKeySize("HmacSHA512", 1025);
+ }
+
+ private void test_KeyGenerator(KeyGenerator kg) throws Exception {
+ if (isUnsupported(kg)) {
+ return;
+ }
+
+ kg.init((SecureRandom) null);
+ test_SecretKey(kg, kg.generateKey());
+
+ kg.init(new SecureRandom());
+ test_SecretKey(kg, kg.generateKey());
+
+ String algorithm = kg.getAlgorithm();
+ List<Integer> keySizes = getKeySizes(algorithm);
+ for (int keySize : keySizes) {
+ kg.init(keySize);
+ test_SecretKey(kg, kg.generateKey());
+
+ kg.init(keySize, (SecureRandom) null);
+ test_SecretKey(kg, kg.generateKey());
+
+ kg.init(keySize, new SecureRandom());
+ test_SecretKey(kg, kg.generateKey());
+ }
+ }
+
+ private void test_SecretKey(KeyGenerator kg, SecretKey sk) throws Exception {
+ assertNotNull(sk);
+ assertEquals(kg.getAlgorithm().toUpperCase(), sk.getAlgorithm().toUpperCase());
+ assertNotNull(sk.getEncoded());
+ assertNotNull(sk.getFormat());
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/crypto/XDHKeyAgreementTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/crypto/XDHKeyAgreementTest.java
new file mode 100644
index 0000000..7f44a34
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/crypto/XDHKeyAgreementTest.java
@@ -0,0 +1,108 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt.javax.crypto;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import javax.crypto.KeyAgreement;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+
+/**
+ * Tests for all registered X25519 and X448 {@link KeyAgreement} providers.
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class XDHKeyAgreementTest {
+ private static final byte[] RFC_7748_X25519_OUR_PRIV_KEY = new byte[] {
+ (byte) 0x30, (byte) 0x2e, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x30, (byte) 0x05, (byte) 0x06,
+ (byte) 0x03, (byte) 0x2b, (byte) 0x65, (byte) 0x6e, (byte) 0x04, (byte) 0x22, (byte) 0x04, (byte) 0x20,
+ (byte) 0xa5, (byte) 0x46, (byte) 0xe3, (byte) 0x6b, (byte) 0xf0, (byte) 0x52, (byte) 0x7c, (byte) 0x9d,
+ (byte) 0x3b, (byte) 0x16, (byte) 0x15, (byte) 0x4b, (byte) 0x82, (byte) 0x46, (byte) 0x5e, (byte) 0xdd,
+ (byte) 0x62, (byte) 0x14, (byte) 0x4c, (byte) 0x0a, (byte) 0xc1, (byte) 0xfc, (byte) 0x5a, (byte) 0x18,
+ (byte) 0x50, (byte) 0x6a, (byte) 0x22, (byte) 0x44, (byte) 0xba, (byte) 0x44, (byte) 0x9a, (byte) 0xc4,
+ };
+
+ // Broken key for testing with JDK 11. Instead of wrapping OCTET STRING with OCTET STRING.
+ private static final byte[] RFC_7748_X25519_OUR_PRIV_KEY_BROKEN = new byte[] {
+ (byte) 0x30, (byte) 0x2c, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x30, (byte) 0x05, (byte) 0x06,
+ (byte) 0x03, (byte) 0x2b, (byte) 0x65, (byte) 0x6e, (byte) 0x04, (byte) 0x20,
+ (byte) 0xa5, (byte) 0x46, (byte) 0xe3, (byte) 0x6b, (byte) 0xf0, (byte) 0x52, (byte) 0x7c, (byte) 0x9d,
+ (byte) 0x3b, (byte) 0x16, (byte) 0x15, (byte) 0x4b, (byte) 0x82, (byte) 0x46, (byte) 0x5e, (byte) 0xdd,
+ (byte) 0x62, (byte) 0x14, (byte) 0x4c, (byte) 0x0a, (byte) 0xc1, (byte) 0xfc, (byte) 0x5a, (byte) 0x18,
+ (byte) 0x50, (byte) 0x6a, (byte) 0x22, (byte) 0x44, (byte) 0xba, (byte) 0x44, (byte) 0x9a, (byte) 0xc4,
+ };
+
+ private static final byte[] RFC_7748_X25519_THEIR_PUB_KEY = new byte[] {
+ (byte) 0x30, (byte) 0x2a, (byte) 0x30, (byte) 0x05, (byte) 0x06, (byte) 0x03, (byte) 0x2b, (byte) 0x65,
+ (byte) 0x6e, (byte) 0x03, (byte) 0x21, (byte) 0x00, (byte) 0xe6, (byte) 0xdb, (byte) 0x68, (byte) 0x67,
+ (byte) 0x58, (byte) 0x30, (byte) 0x30, (byte) 0xdb, (byte) 0x35, (byte) 0x94, (byte) 0xc1, (byte) 0xa4,
+ (byte) 0x24, (byte) 0xb1, (byte) 0x5f, (byte) 0x7c, (byte) 0x72, (byte) 0x66, (byte) 0x24, (byte) 0xec,
+ (byte) 0x26, (byte) 0xb3, (byte) 0x35, (byte) 0x3b, (byte) 0x10, (byte) 0xa9, (byte) 0x03, (byte) 0xa6,
+ (byte) 0xd0, (byte) 0xab, (byte) 0x1c, (byte) 0x4c,
+ };
+
+ private static final byte[] RFC_7748_X25519_SECRET = new byte[] {
+ (byte) 0xc3, (byte) 0xda, (byte) 0x55, (byte) 0x37, (byte) 0x9d, (byte) 0xe9, (byte) 0xc6, (byte) 0x90,
+ (byte) 0x8e, (byte) 0x94, (byte) 0xea, (byte) 0x4d, (byte) 0xf2, (byte) 0x8d, (byte) 0x08, (byte) 0x4f,
+ (byte) 0x32, (byte) 0xec, (byte) 0xcf, (byte) 0x03, (byte) 0x49, (byte) 0x1c, (byte) 0x71, (byte) 0xf7,
+ (byte) 0x54, (byte) 0xb4, (byte) 0x07, (byte) 0x55, (byte) 0x77, (byte) 0xa2, (byte) 0x85, (byte) 0x52,
+ };
+
+ private PrivateKey rfc7748X25519PrivateKey;
+ private PublicKey rfc7748X25519PublicKey;
+
+ private void setupKeys(Provider p) throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("XDH", p);
+
+ byte[] privateKey;
+ if ("SunEC".equalsIgnoreCase(p.getName())
+ && "11".equals(System.getProperty("java.specification.version"))) {
+ // SunEC in OpenJDK 11 has a bug where the format specified in RFC 8410
+ // Section 7. It uses a single OCTET STRING to represent the key instead
+ // of an OCTET STRING inside of an OCTET STRING as defined in the RFC:
+ // ("For the keys defined in this document, the private key is always an
+ // opaque byte sequence. The ASN.1 type CurvePrivateKey is defined in
+ // this document to hold the byte sequence. Thus, when encoding a
+ // OneAsymmetricKey object, the private key is wrapped in a
+ // CurvePrivateKey object and wrapped by the OCTET STRING of the
+ // "privateKey" field.")
+ privateKey = RFC_7748_X25519_OUR_PRIV_KEY_BROKEN;
+ } else {
+ privateKey = RFC_7748_X25519_OUR_PRIV_KEY;
+ }
+
+ rfc7748X25519PrivateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(privateKey));
+ rfc7748X25519PublicKey = kf.generatePublic(new X509EncodedKeySpec(RFC_7748_X25519_THEIR_PUB_KEY));
+ }
+
+ @Test
+ public void test_XDHKeyAgreement() throws Exception {
+ for (Provider p : Security.getProviders("KeyAgreement.XDH")) {
+ // Skip testing Android Keystore as it's covered by CTS tests.
+ if ("AndroidKeyStore".equals(p.getName())) {
+ continue;
+ }
+ setupKeys(p);
+
+ KeyAgreement ka = KeyAgreement.getInstance("XDH", p);
+
+ test_x25519_keyAgreement_rfc7748_kat_success(ka);
+ }
+ }
+
+ private void test_x25519_keyAgreement_rfc7748_kat_success(KeyAgreement ka) throws Exception {
+ ka.init(rfc7748X25519PrivateKey);
+ ka.doPhase(rfc7748X25519PublicKey, true);
+
+ assertArrayEquals(RFC_7748_X25519_SECRET, ka.generateSecret());
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/HttpsURLConnectionTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/HttpsURLConnectionTest.java
new file mode 100644
index 0000000..d882211
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/HttpsURLConnectionTest.java
@@ -0,0 +1,272 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2014 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.org.conscrypt.TestUtils;
+import com.android.org.conscrypt.VeryBasicHttpServer;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
+import org.junit.After;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class HttpsURLConnectionTest {
+ /**
+ * HTTPS URL which cannot be resolved and is thus safe to use in tests where network traffic
+ * should be avoided.
+ */
+ private static final String UNRESOLVABLE_HTTPS_URL = "https:///";
+ private static final String UNREACHABLE_IP = "10.255.255.1";
+
+ private final ExecutorService executor = Executors.newSingleThreadExecutor();
+ private final VeryBasicHttpServer server = new VeryBasicHttpServer();
+
+ public HttpsURLConnectionTest() throws IOException {}
+
+ @After
+ public void after() {
+ executor.shutdownNow();
+ }
+
+ @Test
+ public void testDefaultHostnameVerifierNotNull() {
+ assertNotNull(HttpsURLConnection.getDefaultHostnameVerifier());
+ }
+
+ @Test
+ public void testDefaultHostnameVerifierUsedForNewConnectionsByDefault() throws IOException {
+ HostnameVerifier originalHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
+ HttpsURLConnection connection =
+ (HttpsURLConnection) new URL(UNRESOLVABLE_HTTPS_URL).openConnection();
+ try {
+ assertSame(originalHostnameVerifier, connection.getHostnameVerifier());
+ } finally {
+ connection.disconnect();
+ }
+
+ HostnameVerifier anotherVerifier = new FakeHostnameVerifier();
+ try {
+ HttpsURLConnection.setDefaultHostnameVerifier(anotherVerifier);
+ connection = (HttpsURLConnection) new URL(UNRESOLVABLE_HTTPS_URL).openConnection();
+ try {
+ assertSame(anotherVerifier, connection.getHostnameVerifier());
+ } finally {
+ connection.disconnect();
+ }
+
+ HttpsURLConnection.setDefaultHostnameVerifier(originalHostnameVerifier);
+ connection = (HttpsURLConnection) new URL(UNRESOLVABLE_HTTPS_URL).openConnection();
+ try {
+ assertSame(originalHostnameVerifier, connection.getHostnameVerifier());
+ } finally {
+ connection.disconnect();
+ }
+ } finally {
+ HttpsURLConnection.setDefaultHostnameVerifier(originalHostnameVerifier);
+ }
+ }
+
+ @Test
+ public void testDefaultSSLSocketFactoryNotNull() {
+ SSLSocketFactory factory = HttpsURLConnection.getDefaultSSLSocketFactory();
+ assertNotNull(factory);
+ assertTrue(factory.getClass().getCanonicalName().contains("conscrypt"));
+ }
+
+ @Test
+ public void failedUrlConnect() throws Exception {
+ VeryBasicHttpServer.Op op = server.opBuilder().build();
+
+ Future<Void> future = executor.submit(server.run(op));
+
+ HttpsURLConnection connection = server.tlsConnection("/file");
+ int response = connection.getResponseCode();
+ assertEquals(404, response);
+
+ future.get(2000, TimeUnit.MILLISECONDS);
+ }
+
+ @Test
+ public void successfulUrlConnect() throws Exception {
+ VeryBasicHttpServer.Op op = server.opBuilder().content("/file", "Hello\nWorld\n").build();
+ Future<Void> future = executor.submit(server.run(op));
+
+ HttpsURLConnection connection = server.tlsConnection("/file");
+ int response = connection.getResponseCode();
+ assertEquals(200, response);
+
+ future.get(2000, TimeUnit.MILLISECONDS);
+ }
+
+ @Test
+ public void urlReadTimeout() throws Exception {
+ TestUtils.assumeEngineSocket();
+ VeryBasicHttpServer.Op op =
+ server.opBuilder().postAcceptDelay(5000).closeBeforeRead().build();
+ Future<Void> future = executor.submit(server.run(op));
+
+ HttpsURLConnection connection = server.tlsConnection("/file");
+ connection.setConnectTimeout(0);
+ connection.setReadTimeout(1000);
+
+ try {
+ connection.getInputStream();
+ fail("Connection succeeded unexpectedly");
+ } catch (SocketException e) {
+ if (e.getMessage().contains("reset")) {
+ fail("HttpsURLConnection's Read timeout failed, got: " + e.getMessage());
+ } else {
+ fail("Unexpected SocketException");
+ }
+ } catch (SocketTimeoutException expected) {
+ // Expected
+ }
+
+ future.get(6000, TimeUnit.MILLISECONDS);
+ }
+
+ @Test
+ public void urlConnectTimeout() throws Exception {
+ int timeoutMillis = 1000;
+ URL url = new URL("https", UNREACHABLE_IP, 443, "/file");
+ HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
+ connection.setConnectTimeout(timeoutMillis);
+ connection.setReadTimeout(0);
+
+ Future<Void> future = executor.submit(() -> {
+ try {
+ connection.getResponseCode();
+ fail("Unexpected connection to unroutable address");
+ } catch (SocketTimeoutException e) {
+ // Expected
+ }
+ return null;
+ });
+ try {
+ future.get(2 * timeoutMillis, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ fail("HttpsURLConnection connection timeout failed.");
+ }
+ }
+
+ @Test
+ public void testDefaultSSLSocketFactoryUsedForNewConnectionsByDefault() throws IOException {
+ SSLSocketFactory originalFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
+ HttpsURLConnection connection =
+ (HttpsURLConnection) new URL(UNRESOLVABLE_HTTPS_URL).openConnection();
+ try {
+ assertSame(originalFactory, connection.getSSLSocketFactory());
+ } finally {
+ connection.disconnect();
+ }
+
+ SSLSocketFactory anotherFactory = new FakeSSLSocketFactory();
+ try {
+ HttpsURLConnection.setDefaultSSLSocketFactory(anotherFactory);
+ connection = (HttpsURLConnection) new URL(UNRESOLVABLE_HTTPS_URL).openConnection();
+ try {
+ assertSame(anotherFactory, connection.getSSLSocketFactory());
+ } finally {
+ connection.disconnect();
+ }
+
+ HttpsURLConnection.setDefaultSSLSocketFactory(originalFactory);
+ connection = (HttpsURLConnection) new URL(UNRESOLVABLE_HTTPS_URL).openConnection();
+ try {
+ assertSame(originalFactory, connection.getSSLSocketFactory());
+ } finally {
+ connection.disconnect();
+ }
+ } finally {
+ HttpsURLConnection.setDefaultSSLSocketFactory(originalFactory);
+ }
+ }
+
+ private static final class FakeHostnameVerifier implements HostnameVerifier {
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ return true;
+ }
+ }
+
+ private static final class FakeSSLSocketFactory extends SSLSocketFactory {
+ FakeSSLSocketFactory() {}
+
+ @Override
+ public String[] getDefaultCipherSuites() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Socket createSocket(Socket s, String host, int port, boolean autoClose) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Socket createSocket(
+ InetAddress address, int port, InetAddress localAddress, int localPort) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Socket createSocket(InetAddress host, int port) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Socket createSocket(String host, int port, InetAddress localHost, int localPort) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Socket createSocket(String host, int port) {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyManagerFactoryTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyManagerFactoryTest.java
new file mode 100644
index 0000000..3f5bd36
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyManagerFactoryTest.java
@@ -0,0 +1,523 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStore.PasswordProtection;
+import java.security.KeyStore.PrivateKeyEntry;
+import java.security.KeyStoreException;
+import java.security.KeyStoreSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Enumeration;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.KeyStoreBuilderParameters;
+import javax.net.ssl.ManagerFactoryParameters;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.X509KeyManager;
+import com.android.org.conscrypt.KeyManagerFactoryImpl;
+import com.android.org.conscrypt.TestUtils;
+import com.android.org.conscrypt.java.security.StandardNames;
+import com.android.org.conscrypt.java.security.TestKeyStore;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class KeyManagerFactoryTest {
+ private TestKeyStore testKeyStore;
+
+ @Before
+ public void setUp() throws Exception {
+ // note the rare usage of DSA keys here in addition to RSA
+ String[] keyAlgorithms = StandardNames.IS_RI
+ ? new String[] { "RSA", "DSA", "EC", "EC_RSA" }
+ : new String[] { "RSA", "DH_RSA", "DSA", "DH_DSA", "EC", "EC_RSA" };
+ testKeyStore = new TestKeyStore.Builder()
+ .keyAlgorithms(keyAlgorithms)
+ .aliasPrefix("rsa-dsa-ec-dh")
+ .build();
+ }
+
+ private TestKeyStore getTestKeyStore() throws Exception {
+ return testKeyStore;
+ }
+
+ @Test
+ public void test_KeyManagerFactory_getDefaultAlgorithm() throws Exception {
+ String algorithm = KeyManagerFactory.getDefaultAlgorithm();
+ assertEquals(StandardNames.KEY_MANAGER_FACTORY_DEFAULT, algorithm);
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
+ test_KeyManagerFactory(kmf);
+ }
+
+ private static class UselessManagerFactoryParameters implements ManagerFactoryParameters {}
+
+ private static boolean supportsManagerFactoryParameters(String algorithm) {
+ // Only the "New" one supports ManagerFactoryParameters
+ return algorithm.equals("NewSunX509");
+ }
+
+ private static String[] keyTypes(String algorithm) {
+ // Although the "New" one supports ManagerFactoryParameters,
+ // it can't handle nulls in the key types array.
+ return (algorithm.equals("NewSunX509") ? KEY_TYPES_WITH_EMPTY
+ : KEY_TYPES_WITH_EMPTY_AND_NULL);
+ }
+
+ private void test_KeyManagerFactory(KeyManagerFactory kmf) throws Exception {
+ assertNotNull(kmf);
+ assertNotNull(kmf.getAlgorithm());
+ assertNotNull(kmf.getProvider());
+
+ // before init
+ try {
+ kmf.getKeyManagers();
+ fail();
+ } catch (IllegalStateException expected) {
+ // Ignore
+ }
+
+ // init with null ManagerFactoryParameters
+ try {
+ kmf.init(null);
+ fail();
+ } catch (InvalidAlgorithmParameterException expected) {
+ // Ignore
+ }
+
+ // init with useless ManagerFactoryParameters
+ try {
+ kmf.init(new UselessManagerFactoryParameters());
+ fail();
+ } catch (InvalidAlgorithmParameterException expected) {
+ // Ignore
+ }
+
+ // init with KeyStoreBuilderParameters ManagerFactoryParameters
+ PasswordProtection pp = new PasswordProtection(getTestKeyStore().storePassword);
+ KeyStore.Builder builder = KeyStore.Builder.newInstance(getTestKeyStore().keyStore, pp);
+ KeyStoreBuilderParameters ksbp = new KeyStoreBuilderParameters(builder);
+ if (supportsManagerFactoryParameters(kmf.getAlgorithm())) {
+ kmf.init(ksbp);
+ test_KeyManagerFactory_getKeyManagers(kmf, false);
+ } else {
+ try {
+ kmf.init(ksbp);
+ fail();
+ } catch (InvalidAlgorithmParameterException expected) {
+ // Ignore
+ }
+ }
+
+ // init with null for default behavior
+ kmf.init(null, null);
+ test_KeyManagerFactory_getKeyManagers(kmf, true);
+
+ // init with specific key store and password
+ kmf.init(getTestKeyStore().keyStore, getTestKeyStore().storePassword);
+ test_KeyManagerFactory_getKeyManagers(kmf, false);
+ }
+
+ private void test_KeyManagerFactory_getKeyManagers(KeyManagerFactory kmf, boolean empty)
+ throws Exception {
+ KeyManager[] keyManagers = kmf.getKeyManagers();
+ assertNotNull(keyManagers);
+ assertTrue(keyManagers.length > 0);
+ for (KeyManager keyManager : keyManagers) {
+ assertNotNull(keyManager);
+ if (keyManager instanceof X509KeyManager) {
+ test_X509KeyManager((X509KeyManager) keyManager, empty, kmf.getAlgorithm());
+ }
+ }
+ }
+
+ private static final String[] KEY_TYPES_ONLY =
+ StandardNames.KEY_TYPES.toArray(new String[StandardNames.KEY_TYPES.size()]);
+ private static final String[] KEY_TYPES_WITH_EMPTY = new String[KEY_TYPES_ONLY.length + 1];
+ private static final String[] KEY_TYPES_WITH_EMPTY_AND_NULL =
+ new String[KEY_TYPES_ONLY.length + 2];
+ static {
+ System.arraycopy(KEY_TYPES_ONLY, 0, KEY_TYPES_WITH_EMPTY, 0, KEY_TYPES_ONLY.length);
+ KEY_TYPES_WITH_EMPTY[KEY_TYPES_WITH_EMPTY.length - 1] = "";
+
+ System.arraycopy(KEY_TYPES_WITH_EMPTY, 0, KEY_TYPES_WITH_EMPTY_AND_NULL, 0,
+ KEY_TYPES_WITH_EMPTY.length);
+ // extra null at end requires no initialization
+ }
+
+ private void test_X509KeyManager(X509KeyManager km, boolean empty, String algorithm)
+ throws Exception {
+ String[] keyTypes = keyTypes(algorithm);
+ for (String keyType : keyTypes) {
+ String[] aliases = km.getClientAliases(keyType, null);
+ if (empty || keyType == null || keyType.isEmpty()) {
+ assertNull(keyType, aliases);
+ continue;
+ }
+ assertNotNull(keyType, aliases);
+ for (String alias : aliases) {
+ test_X509KeyManager_alias(km, alias, keyType, false, empty);
+ }
+ }
+ for (String keyType : keyTypes) {
+ String[] aliases = km.getServerAliases(keyType, null);
+ if (empty || keyType == null || keyType.isEmpty()) {
+ assertNull(keyType, aliases);
+ continue;
+ }
+ assertNotNull(keyType, aliases);
+ for (String alias : aliases) {
+ test_X509KeyManager_alias(km, alias, keyType, false, empty);
+ }
+ }
+
+ String[][] rotatedTypes = rotate(nonEmpty(keyTypes));
+ for (String[] keyList : rotatedTypes) {
+ String alias = km.chooseClientAlias(keyList, null, null);
+ test_X509KeyManager_alias(km, alias, null, true, empty);
+ }
+
+ for (String keyType : keyTypes) {
+ String[] array = new String[] {keyType};
+ String alias = km.chooseClientAlias(array, null, null);
+ test_X509KeyManager_alias(km, alias, keyType, false, empty);
+ }
+ for (String keyType : keyTypes) {
+ String alias = km.chooseServerAlias(keyType, null, null);
+ test_X509KeyManager_alias(km, alias, keyType, false, empty);
+ }
+ if (km instanceof X509ExtendedKeyManager) {
+ test_X509ExtendedKeyManager((X509ExtendedKeyManager) km, empty, algorithm);
+ }
+ }
+
+ private void test_X509ExtendedKeyManager(
+ X509ExtendedKeyManager km, boolean empty, String algorithm) throws Exception {
+ String[] keyTypes = keyTypes(algorithm);
+ String[][] rotatedTypes = rotate(nonEmpty(keyTypes));
+ for (String[] keyList : rotatedTypes) {
+ String alias = km.chooseEngineClientAlias(keyList, null, null);
+ test_X509KeyManager_alias(km, alias, null, true, empty);
+ }
+
+ for (String keyType : keyTypes) {
+ String[] array = new String[] {keyType};
+ String alias = km.chooseEngineClientAlias(array, null, null);
+ test_X509KeyManager_alias(km, alias, keyType, false, empty);
+ }
+ for (String keyType : keyTypes) {
+ String alias = km.chooseEngineServerAlias(keyType, null, null);
+ test_X509KeyManager_alias(km, alias, keyType, false, empty);
+ }
+ }
+
+ // Filters null or empty values from a String array and returns a new array with the results.
+ private static String[] nonEmpty(String[] input) {
+ String[] nonEmpty = new String[input.length];
+ int size = 0;
+ for (String keyType : input) {
+ if (keyType != null && !keyType.isEmpty()) {
+ nonEmpty[size++] = keyType;
+ }
+ }
+ return Arrays.copyOfRange(nonEmpty, 0, size);
+ }
+
+ // Generates an array of arrays of all the rotational permutations of its input.
+ private static String[][] rotate(String[] input) {
+ int size = input.length;
+ String[][] result = new String[size][size];
+ for (int i = 0; i < size; i++) {
+ for (int j = 0; j < size; j++) {
+ result[i][j] = input[(i + j) % size];
+ }
+ }
+ return result;
+ }
+
+ private void test_X509KeyManager_alias(X509KeyManager km, String alias, String keyType,
+ boolean many, boolean empty) throws Exception {
+ if (empty || (!many && (keyType == null || keyType.isEmpty()))) {
+ assertNull(keyType, alias);
+ assertNull(keyType, km.getCertificateChain(alias));
+ assertNull(keyType, km.getPrivateKey(alias));
+ return;
+ }
+ assertNotNull(alias);
+ X509Certificate[] certificateChain = km.getCertificateChain(alias);
+ PrivateKey privateKey = km.getPrivateKey(alias);
+
+ String keyAlgName = privateKey.getAlgorithm();
+
+ X509Certificate certificate = certificateChain[0];
+ assertEquals(keyType, keyAlgName, certificate.getPublicKey().getAlgorithm());
+
+ String sigAlgName = certificate.getSigAlgName();
+
+ PrivateKeyEntry privateKeyEntry = getTestKeyStore().getPrivateKey(keyAlgName, sigAlgName);
+
+ assertEquals(keyType, Arrays.asList(privateKeyEntry.getCertificateChain()),
+ Arrays.<Certificate>asList(certificateChain));
+ assertEquals(keyType, privateKeyEntry.getPrivateKey(), privateKey);
+
+ if (keyType != null) {
+ assertEquals(TestKeyStore.keyAlgorithm(keyType), keyAlgName);
+
+ // Skip this when we're given only "DH" or "EC" instead of "DH_DSA",
+ // "EC_RSA", etc. since we don't know what the expected
+ // algorithm was.
+ if (!keyType.equals("DH") && !keyType.equals("EC")) {
+ assertTrue("SigAlg: " + sigAlgName + ", KeyType: " + keyType,
+ sigAlgName.contains(TestKeyStore.signatureAlgorithm(keyType)));
+ }
+ }
+ }
+
+ @Test
+ public void test_KeyManagerFactory_getInstance() throws Exception {
+ ServiceTester.test("KeyManagerFactory")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider provider, String algorithm) throws Exception {
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
+ assertEquals(algorithm, kmf.getAlgorithm());
+ test_KeyManagerFactory(kmf);
+
+ kmf = KeyManagerFactory.getInstance(algorithm, provider);
+ assertEquals(algorithm, kmf.getAlgorithm());
+ assertEquals(provider, kmf.getProvider());
+ test_KeyManagerFactory(kmf);
+
+ kmf = KeyManagerFactory.getInstance(algorithm, provider.getName());
+ assertEquals(algorithm, kmf.getAlgorithm());
+ assertEquals(provider, kmf.getProvider());
+ test_KeyManagerFactory(kmf);
+ }
+ });
+ }
+
+ // The Conscrypt provider on OpenJDK doesn't provide the KeyManagerFactory, but we want
+ // to test it on OpenJDK anyway
+ @Test
+ public void test_KeyManagerFactory_Conscrypt() throws Exception {
+ KeyManagerFactory kmf = new KeyManagerFactory(new KeyManagerFactoryImpl(),
+ TestUtils.getConscryptProvider(), KeyManagerFactory.getDefaultAlgorithm()) { };
+ test_KeyManagerFactory(kmf);
+
+ // Test that using a KeyStore that doesn't implement getEntry(), like Android Keystore
+ // doesn't, still produces a functional KeyManager.
+ kmf.init(new NoGetEntryKeyStore(getTestKeyStore().keyStore),
+ getTestKeyStore().storePassword);
+ test_KeyManagerFactory_getKeyManagers(kmf, false);
+ }
+
+ private static class NoGetEntryKeyStore extends KeyStore {
+ public NoGetEntryKeyStore(KeyStore keyStore) throws Exception {
+ super(new NoGetEntryKeyStoreSpi(keyStore), keyStore.getProvider(), keyStore.getType());
+ load(null, null);
+ }
+ }
+
+ // Android Keystore's KeyStore doesn't support getEntry(), so we replicate that here
+ // for testing by throwing UnsupportedOperationException and passing everything else through
+ // to a working implementation.
+ private static class NoGetEntryKeyStoreSpi extends KeyStoreSpi {
+
+ private final KeyStore keyStore;
+
+ public NoGetEntryKeyStoreSpi(KeyStore keyStore) {
+ this.keyStore = keyStore;
+ }
+
+ @Override
+ public KeyStore.Entry engineGetEntry(String alias, KeyStore.ProtectionParameter protParam) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Key engineGetKey(String s, char[] chars)
+ throws NoSuchAlgorithmException, UnrecoverableKeyException {
+ try {
+ return keyStore.getKey(s, chars);
+ } catch (KeyStoreException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public Certificate[] engineGetCertificateChain(String s) {
+ try {
+ return keyStore.getCertificateChain(s);
+ } catch (KeyStoreException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public Certificate engineGetCertificate(String s) {
+ try {
+ return keyStore.getCertificate(s);
+ } catch (KeyStoreException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public Date engineGetCreationDate(String s) {
+ try {
+ return keyStore.getCreationDate(s);
+ } catch (KeyStoreException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public void engineSetKeyEntry(String s, Key key, char[] chars, Certificate[] certificates)
+ throws KeyStoreException {
+ try {
+ keyStore.setKeyEntry(s, key, chars, certificates);
+ } catch (KeyStoreException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public void engineSetKeyEntry(String s, byte[] bytes, Certificate[] certificates)
+ throws KeyStoreException {
+ try {
+ keyStore.setKeyEntry(s, bytes, certificates);
+ } catch (KeyStoreException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public void engineSetCertificateEntry(String s, Certificate certificate)
+ throws KeyStoreException {
+ try {
+ keyStore.setCertificateEntry(s, certificate);
+ } catch (KeyStoreException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public void engineDeleteEntry(String s) throws KeyStoreException {
+ try {
+ keyStore.deleteEntry(s);
+ } catch (KeyStoreException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public Enumeration<String> engineAliases() {
+ try {
+ return keyStore.aliases();
+ } catch (KeyStoreException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public boolean engineContainsAlias(String s) {
+ try {
+ return keyStore.containsAlias(s);
+ } catch (KeyStoreException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public int engineSize() {
+ try {
+ return keyStore.size();
+ } catch (KeyStoreException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public boolean engineIsKeyEntry(String s) {
+ try {
+ return keyStore.isKeyEntry(s);
+ } catch (KeyStoreException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public boolean engineIsCertificateEntry(String s) {
+ try {
+ return keyStore.isCertificateEntry(s);
+ } catch (KeyStoreException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public String engineGetCertificateAlias(Certificate certificate) {
+ try {
+ return keyStore.getCertificateAlias(certificate);
+ } catch (KeyStoreException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public void engineStore(OutputStream outputStream, char[] chars)
+ throws IOException, NoSuchAlgorithmException, CertificateException {
+ try {
+ keyStore.store(outputStream, chars);
+ } catch (KeyStoreException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public void engineLoad(InputStream inputStream, char[] chars)
+ throws IOException, NoSuchAlgorithmException, CertificateException {
+ // Do nothing, the keystore is already loaded
+ }
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyStoreBuilderParametersTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyStoreBuilderParametersTest.java
new file mode 100644
index 0000000..ff34e5b
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyStoreBuilderParametersTest.java
@@ -0,0 +1,118 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+
+import java.security.KeyStore;
+import java.security.KeyStore.PasswordProtection;
+import java.util.Arrays;
+import java.util.List;
+import javax.net.ssl.KeyStoreBuilderParameters;
+import com.android.org.conscrypt.java.security.TestKeyStore;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class KeyStoreBuilderParametersTest {
+
+ private static void assumeObjectsAvailable() {
+ boolean available = false;
+ try {
+ Class.forName("java.util.Objects");
+ available = true;
+ } catch (ClassNotFoundException ignore) {
+ // Ignored
+ }
+ Assume.assumeTrue("Skipping test: Objects unavailable", available);
+ }
+
+ @Test
+ public void test_init_Builder_null() {
+ // KeyStoreBuilderParameters' constructor didn't check for null until
+ // Objects.requireNonNull was added
+ assumeObjectsAvailable();
+ try {
+ new KeyStoreBuilderParameters((KeyStore.Builder) null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ @Test
+ public void test_init_Builder() {
+ TestKeyStore testKeyStore = TestKeyStore.getClient();
+ KeyStore.Builder builder = KeyStore.Builder.newInstance(
+ testKeyStore.keyStore, new PasswordProtection(testKeyStore.storePassword));
+ KeyStoreBuilderParameters ksbp = new KeyStoreBuilderParameters(builder);
+ assertNotNull(ksbp);
+ assertNotNull(ksbp.getParameters());
+ assertEquals(1, ksbp.getParameters().size());
+ assertSame(builder, ksbp.getParameters().get(0));
+ }
+
+ @Test
+ public void test_init_List_null() {
+ try {
+ new KeyStoreBuilderParameters((List<KeyStore.Builder>) null);
+ fail();
+ } catch (NullPointerException expected) {
+ // Ignored.
+ }
+ }
+
+ @Test
+ public void test_init_List() {
+ TestKeyStore testKeyStore1 = TestKeyStore.getClient();
+ TestKeyStore testKeyStore2 = TestKeyStore.getServer();
+ KeyStore.Builder builder1 = KeyStore.Builder.newInstance(
+ testKeyStore1.keyStore, new PasswordProtection(testKeyStore1.storePassword));
+ KeyStore.Builder builder2 = KeyStore.Builder.newInstance(
+ testKeyStore2.keyStore, new PasswordProtection(testKeyStore2.storePassword));
+
+ List<KeyStore.Builder> list = Arrays.asList(builder1, builder2);
+ KeyStoreBuilderParameters ksbp = new KeyStoreBuilderParameters(list);
+ assertNotNull(ksbp);
+ assertNotNull(ksbp.getParameters());
+ assertNotSame(list, ksbp.getParameters());
+ assertEquals(2, ksbp.getParameters().size());
+ assertSame(builder1, ksbp.getParameters().get(0));
+ assertSame(builder2, ksbp.getParameters().get(1));
+
+ // confirm result is not modifiable
+ try {
+ ksbp.getParameters().set(0, builder2);
+ fail();
+ } catch (UnsupportedOperationException expected) {
+ // Ignored.
+ }
+
+ // confirm result is a copy of original
+ list.set(0, builder2);
+ assertSame(builder1, ksbp.getParameters().get(0));
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SNIHostNameTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SNIHostNameTest.java
new file mode 100644
index 0000000..48e8eee
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SNIHostNameTest.java
@@ -0,0 +1,53 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2016 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.StandardConstants;
+import com.android.org.conscrypt.TestUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class SNIHostNameTest {
+ @Test
+ public void test_byteArray_Constructor() throws Exception {
+ TestUtils.assumeSNIHostnameAvailable();
+
+ // From draft-josefsson-idn-test-vectors-00 section 5.2
+ byte[] idnEncoded = new byte[] {
+ (byte) 0xE4, (byte) 0xBB, (byte) 0x96, (byte) 0xE4, (byte) 0xBB, (byte) 0xAC,
+ (byte) 0xE4, (byte) 0xB8, (byte) 0xBA, (byte) 0xE4, (byte) 0xBB, (byte) 0x80,
+ (byte) 0xE4, (byte) 0xB9, (byte) 0x88, (byte) 0xE4, (byte) 0xB8, (byte) 0x8D,
+ (byte) 0xE8, (byte) 0xAF, (byte) 0xB4, (byte) 0xE4, (byte) 0xB8, (byte) 0xAD,
+ (byte) 0xE6, (byte) 0x96, (byte) 0x87,
+ };
+
+ SNIHostName hostName = new SNIHostName(idnEncoded);
+ assertEquals("xn--ihqwcrb4cv8a8dqg056pqjye", hostName.getAsciiName());
+ assertEquals(StandardConstants.SNI_HOST_NAME, hostName.getType());
+ assertEquals(Arrays.toString(idnEncoded), Arrays.toString(hostName.getEncoded()));
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLContextTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLContextTest.java
new file mode 100644
index 0000000..5f382d1
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLContextTest.java
@@ -0,0 +1,758 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static com.android.org.conscrypt.TestUtils.isWindows;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.org.conscrypt.TestUtils;
+import com.android.org.conscrypt.java.security.StandardNames;
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+import java.security.Security;
+import java.security.UnrecoverableKeyException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import javax.net.ServerSocketFactory;
+import javax.net.SocketFactory;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.KeyManagerFactorySpi;
+import javax.net.ssl.ManagerFactoryParameters;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.TrustManagerFactorySpi;
+import javax.net.ssl.X509KeyManager;
+import junit.framework.AssertionFailedError;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class SSLContextTest {
+
+ @Test
+ public void test_SSLContext_getDefault() throws Exception {
+ SSLContext sslContext = SSLContext.getDefault();
+ assertNotNull(sslContext);
+ try {
+ sslContext.init(null, null, null);
+ fail();
+ } catch (KeyManagementException expected) {
+ // Ignored.
+ }
+ }
+
+ @Test
+ public void test_SSLContext_setDefault() throws Exception {
+ try {
+ SSLContext.setDefault(null);
+ fail();
+ } catch (NullPointerException expected) {
+ // Ignored.
+ }
+
+ SSLContext defaultContext = SSLContext.getDefault();
+ for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) {
+ SSLContext oldContext = SSLContext.getDefault();
+ assertNotNull(oldContext);
+ SSLContext newContext = SSLContext.getInstance(protocol);
+ assertNotNull(newContext);
+ assertNotSame(oldContext, newContext);
+ SSLContext.setDefault(newContext);
+ assertSame(newContext, SSLContext.getDefault());
+ }
+ SSLContext.setDefault(defaultContext);
+ }
+
+ @Test
+ public void test_SSLContext_defaultConfiguration() throws Exception {
+ SSLConfigurationAsserts.assertSSLContextDefaultConfiguration(SSLContext.getDefault());
+
+ for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS_WITH_DEFAULT_CONFIG) {
+ SSLContext sslContext = SSLContext.getInstance(protocol);
+ if (!protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) {
+ sslContext.init(null, null, null);
+ }
+ SSLConfigurationAsserts.assertSSLContextDefaultConfiguration(sslContext);
+ }
+ }
+
+ @Test
+ public void test_SSLContext_pskOnlyConfiguration_defaultProviderOnly() throws Exception {
+ // Test the scenario where only a PSKKeyManager is provided and no TrustManagers are
+ // provided.
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(new KeyManager[] { PSKKeyManagerProxy.getConscryptPSKKeyManager(
+ new PSKKeyManagerProxy())},
+ new TrustManager[0], null);
+ List<String> expectedCipherSuites =
+ new ArrayList<String>(StandardNames.CIPHER_SUITES_TLS13);
+ expectedCipherSuites.addAll(StandardNames.CIPHER_SUITES_DEFAULT_PSK);
+ expectedCipherSuites.add(StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION);
+ assertEnabledCipherSuites(expectedCipherSuites, sslContext);
+ }
+
+ @Test
+ public void test_SSLContext_x509AndPskConfiguration_defaultProviderOnly() throws Exception {
+ // Test the scenario where an X509TrustManager and PSKKeyManager are provided.
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(new KeyManager[] {PSKKeyManagerProxy.getConscryptPSKKeyManager(
+ new PSKKeyManagerProxy())},
+ null, // Use default trust managers, one of which is an X.509 one.
+ null);
+ // The TLS 1.3 cipher suites appear before the PSK ones, so we need to dedup them
+ Set<String> expectedCipherSuiteSet = new LinkedHashSet<String>();
+ expectedCipherSuiteSet.addAll(StandardNames.CIPHER_SUITES_TLS13);
+ expectedCipherSuiteSet.addAll(StandardNames.CIPHER_SUITES_DEFAULT_PSK);
+ expectedCipherSuiteSet.addAll(StandardNames.CIPHER_SUITES_DEFAULT);
+ List<String> expectedCipherSuites = new ArrayList<String>(expectedCipherSuiteSet);
+ assertEnabledCipherSuites(expectedCipherSuites, sslContext);
+
+ // Test the scenario where an X509KeyManager and PSKKeyManager are provided.
+ sslContext = SSLContext.getInstance("TLS");
+ // Just an arbitrary X509KeyManager -- it won't be invoked in this test.
+ X509KeyManager x509KeyManager = new RandomPrivateKeyX509ExtendedKeyManager(null);
+ sslContext.init(
+ new KeyManager[] {x509KeyManager,
+ PSKKeyManagerProxy.getConscryptPSKKeyManager(new PSKKeyManagerProxy())},
+ new TrustManager[0], null);
+ assertEnabledCipherSuites(expectedCipherSuites, sslContext);
+ }
+
+ @Test
+ public void test_SSLContext_emptyConfiguration_defaultProviderOnly() throws Exception {
+ // Test the scenario where neither X.509 nor PSK KeyManagers or TrustManagers are provided.
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(new KeyManager[0], new TrustManager[0], null);
+ // No TLS 1.2 cipher suites should be enabled, since neither PSK nor X.509 key exchange
+ // can be done. The TLS 1.3 cipher suites should be there, since key exchange isn't
+ // part of the cipher suite in 1.3.
+ List<String> expected = new ArrayList<String>(StandardNames.CIPHER_SUITES_TLS13);
+ expected.add(StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION);
+ assertEnabledCipherSuites(expected, sslContext);
+ }
+
+ @Test
+ public void test_SSLContext_init_correctProtocolVersionsEnabled() throws Exception {
+ for (String tlsVersion : StandardNames.SSL_CONTEXT_PROTOCOLS) {
+ // Don't test the "Default" instance.
+ if (StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT.equals(tlsVersion)) {
+ continue;
+ }
+
+ SSLContext context = SSLContext.getInstance(tlsVersion);
+ context.init(null, null, null);
+
+ StandardNames.assertSSLContextEnabledProtocols(
+ tlsVersion, ((SSLSocket) context.getSocketFactory().createSocket())
+ .getEnabledProtocols());
+ StandardNames.assertSSLContextEnabledProtocols(tlsVersion,
+ ((SSLServerSocket) context.getServerSocketFactory().createServerSocket())
+ .getEnabledProtocols());
+ StandardNames.assertSSLContextEnabledProtocols(
+ tlsVersion, context.getDefaultSSLParameters().getProtocols());
+ StandardNames.assertSSLContextEnabledProtocols(
+ tlsVersion, context.createSSLEngine().getEnabledProtocols());
+ }
+ }
+
+ private static void assertEnabledCipherSuites(
+ List<String> expectedCipherSuites, SSLContext sslContext) throws Exception {
+ TestUtils.assumeSetEndpointIdentificationAlgorithmAvailable();
+ assertContentsInOrder(
+ expectedCipherSuites, sslContext.createSSLEngine().getEnabledCipherSuites());
+ assertContentsInOrder(expectedCipherSuites,
+ sslContext.createSSLEngine().getSSLParameters().getCipherSuites());
+ assertContentsInOrder(
+ expectedCipherSuites, sslContext.getSocketFactory().getDefaultCipherSuites());
+ assertContentsInOrder(
+ expectedCipherSuites, sslContext.getServerSocketFactory().getDefaultCipherSuites());
+
+ SSLSocket sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket();
+ try {
+ assertContentsInOrder(expectedCipherSuites, sslSocket.getEnabledCipherSuites());
+ assertContentsInOrder(
+ expectedCipherSuites, sslSocket.getSSLParameters().getCipherSuites());
+ } finally {
+ try {
+ sslSocket.close();
+ } catch (IOException ignored) {
+ }
+ }
+
+ SSLServerSocket sslServerSocket =
+ (SSLServerSocket) sslContext.getServerSocketFactory().createServerSocket();
+ try {
+ assertContentsInOrder(expectedCipherSuites, sslServerSocket.getEnabledCipherSuites());
+ } finally {
+ try {
+ sslSocket.close();
+ } catch (IOException ignored) {
+ }
+ }
+ }
+
+ @Test
+ public void test_SSLContext_getInstance() throws Exception {
+ try {
+ SSLContext.getInstance(null);
+ fail();
+ } catch (NullPointerException expected) {
+ // Ignored.
+ }
+ for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) {
+ assertNotNull(SSLContext.getInstance(protocol));
+ assertNotSame(SSLContext.getInstance(protocol), SSLContext.getInstance(protocol));
+ }
+
+ try {
+ SSLContext.getInstance(null, (String) null);
+ fail();
+ } catch (Exception expected) {
+ if (javaVersion() >= 9) {
+ assertTrue("Expected NullPointerException on Java 9, was "
+ + expected.getClass().getName(),
+ expected instanceof NullPointerException);
+ } else {
+ assertTrue(
+ "Expected IllegalArgumentException, was " + expected.getClass().getName(),
+ expected instanceof IllegalArgumentException);
+ }
+ }
+ try {
+ SSLContext.getInstance(null, "");
+ fail();
+ } catch (Exception expected) {
+ if (javaVersion() >= 9) {
+ assertTrue("Expected NullPointerException on Java 9, was "
+ + expected.getClass().getName(),
+ expected instanceof NullPointerException);
+ } else {
+ assertTrue(
+ "Expected IllegalArgumentException, was " + expected.getClass().getName(),
+ expected instanceof IllegalArgumentException);
+ }
+ }
+ for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) {
+ try {
+ SSLContext.getInstance(protocol, (String) null);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ }
+ try {
+ SSLContext.getInstance(null, StandardNames.JSSE_PROVIDER_NAME);
+ fail();
+ } catch (NullPointerException expected) {
+ // Ignored.
+ }
+ }
+
+ @Test
+ public void test_SSLContext_getProtocol() throws Exception {
+ for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) {
+ String protocolName = SSLContext.getInstance(protocol).getProtocol();
+ assertNotNull(protocolName);
+ assertTrue(protocol.startsWith(protocolName));
+ }
+ }
+
+ @Test
+ public void test_SSLContext_getProvider() throws Exception {
+ Provider provider = SSLContext.getDefault().getProvider();
+ assertNotNull(provider);
+ assertEquals(StandardNames.JSSE_PROVIDER_NAME, provider.getName());
+ }
+
+ @Test
+ public void test_SSLContext_init_Default() throws Exception {
+ // Assert that initializing a default SSLContext fails because it's supposed to be
+ // initialized already.
+ SSLContext sslContext = SSLContext.getInstance(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT);
+ try {
+ sslContext.init(null, null, null);
+ fail();
+ } catch (KeyManagementException expected) {
+ // Ignored.
+ }
+ try {
+ sslContext.init(new KeyManager[0], new TrustManager[0], null);
+ fail();
+ } catch (KeyManagementException expected) {
+ // Ignored.
+ }
+ try {
+ sslContext.init(new KeyManager[] {new KeyManager(){}},
+ new TrustManager[] {new TrustManager(){}}, null);
+ fail();
+ } catch (KeyManagementException expected) {
+ // Ignored.
+ }
+ }
+
+ @Test
+ public void test_SSLContext_init_withNullManagerArrays() throws Exception {
+ // Assert that SSLContext.init works fine even when provided with null arrays of
+ // KeyManagers and TrustManagers.
+ // The contract of SSLContext.init is that it will for default X.509 KeyManager and
+ // TrustManager from the highest priority KeyManagerFactory and TrustManagerFactory.
+ for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) {
+ if (protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) {
+ // Default SSLContext is provided in an already initialized state
+ continue;
+ }
+ SSLContext sslContext = SSLContext.getInstance(protocol);
+ sslContext.init(null, null, null);
+ }
+ }
+
+ @Test
+ public void test_SSLContext_init_withEmptyManagerArrays() throws Exception {
+ // Assert that SSLContext.init works fine even when provided with empty arrays of
+ // KeyManagers and TrustManagers.
+ // The contract of SSLContext.init is that it will not look for default X.509 KeyManager and
+ // TrustManager.
+ // This test thus installs a Provider of KeyManagerFactory and TrustManagerFactory whose
+ // factories throw exceptions which will make this test fail if the factories are used.
+ Provider provider = new ThrowExceptionKeyAndTrustManagerFactoryProvider();
+ invokeWithHighestPrioritySecurityProvider(provider, new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ assertEquals(ThrowExceptionKeyAndTrustManagerFactoryProvider.class,
+ TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
+ .getProvider()
+ .getClass());
+ assertEquals(ThrowExceptionKeyAndTrustManagerFactoryProvider.class,
+ KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
+ .getProvider()
+ .getClass());
+
+ KeyManager[] keyManagers = new KeyManager[0];
+ TrustManager[] trustManagers = new TrustManager[0];
+ for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) {
+ if (protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) {
+ // Default SSLContext is provided in an already initialized state
+ continue;
+ }
+ SSLContext sslContext = SSLContext.getInstance(protocol);
+ sslContext.init(keyManagers, trustManagers, null);
+ }
+
+ return null;
+ }
+ });
+ }
+
+ @Test
+ public void test_SSLContext_init_withoutX509() throws Exception {
+ // Assert that SSLContext.init works fine even when provided with KeyManagers and
+ // TrustManagers which don't include the X.509 ones.
+ // The contract of SSLContext.init is that it will not look for default X.509 KeyManager and
+ // TrustManager.
+ // This test thus installs a Provider of KeyManagerFactory and TrustManagerFactory whose
+ // factories throw exceptions which will make this test fail if the factories are used.
+ Provider provider = new ThrowExceptionKeyAndTrustManagerFactoryProvider();
+ invokeWithHighestPrioritySecurityProvider(provider, new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ assertEquals(ThrowExceptionKeyAndTrustManagerFactoryProvider.class,
+ TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
+ .getProvider()
+ .getClass());
+ assertEquals(ThrowExceptionKeyAndTrustManagerFactoryProvider.class,
+ KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
+ .getProvider()
+ .getClass());
+
+ KeyManager[] keyManagers = new KeyManager[]{new KeyManager() {
+ }};
+ TrustManager[] trustManagers = new TrustManager[]{new TrustManager() {
+ }};
+ for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) {
+ if (protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) {
+ // Default SSLContext is provided in an already initialized state
+ continue;
+ }
+ SSLContext sslContext = SSLContext.getInstance(protocol);
+ sslContext.init(keyManagers, trustManagers, null);
+ }
+
+ return null;
+ }
+ });
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class ThrowExceptionKeyAndTrustManagerFactoryProvider extends Provider {
+ public ThrowExceptionKeyAndTrustManagerFactoryProvider() {
+ super("ThrowExceptionKeyAndTrustManagerProvider", 1.0,
+ "SSLContextTest fake KeyManagerFactory and TrustManagerFactory provider");
+
+ put("TrustManagerFactory." + TrustManagerFactory.getDefaultAlgorithm(),
+ ThrowExceptionTrustManagagerFactorySpi.class.getName());
+ put("TrustManagerFactory.PKIX", ThrowExceptionTrustManagagerFactorySpi.class.getName());
+
+ put("KeyManagerFactory." + KeyManagerFactory.getDefaultAlgorithm(),
+ ThrowExceptionKeyManagagerFactorySpi.class.getName());
+ put("KeyManagerFactory.PKIX", ThrowExceptionKeyManagagerFactorySpi.class.getName());
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class ThrowExceptionTrustManagagerFactorySpi extends TrustManagerFactorySpi {
+ @Override
+ protected void engineInit(KeyStore ks) throws KeyStoreException {
+ fail();
+ }
+
+ @Override
+ protected void engineInit(ManagerFactoryParameters spec)
+ throws InvalidAlgorithmParameterException {
+ fail();
+ }
+
+ @Override
+ protected TrustManager[] engineGetTrustManagers() {
+ throw new AssertionFailedError();
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class ThrowExceptionKeyManagagerFactorySpi extends KeyManagerFactorySpi {
+ @Override
+ protected void engineInit(KeyStore ks, char[] password)
+ throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+ fail();
+ }
+
+ @Override
+ protected void engineInit(ManagerFactoryParameters spec)
+ throws InvalidAlgorithmParameterException {
+ fail();
+ }
+
+ @Override
+ protected KeyManager[] engineGetKeyManagers() {
+ throw new AssertionFailedError();
+ }
+ }
+
+ /**
+ * Installs the specified security provider as the highest provider, invokes the provided
+ * {@link Callable}, and removes the provider.
+ *
+ * @return result returned by the {@code callable}.
+ */
+ private static <T> T invokeWithHighestPrioritySecurityProvider(
+ Provider provider, Callable<T> callable) throws Exception {
+ int providerPosition = -1;
+ try {
+ providerPosition = Security.insertProviderAt(provider, 1);
+ assertEquals(1, providerPosition);
+ return callable.call();
+ } finally {
+ if (providerPosition != -1) {
+ Security.removeProvider(provider.getName());
+ }
+ }
+ }
+
+ @Test
+ public void test_SSLContext_getSocketFactory() throws Exception {
+ for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) {
+ if (protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) {
+ SSLContext.getInstance(protocol).getSocketFactory();
+ } else {
+ try {
+ SSLContext.getInstance(protocol).getSocketFactory();
+ fail();
+ } catch (IllegalStateException expected) {
+ // Ignored.
+ }
+ }
+
+ SSLContext sslContext = SSLContext.getInstance(protocol);
+ if (!protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) {
+ sslContext.init(null, null, null);
+ }
+ SocketFactory sf = sslContext.getSocketFactory();
+ assertNotNull(sf);
+ assertTrue(SSLSocketFactory.class.isAssignableFrom(sf.getClass()));
+ }
+ }
+
+ @Test
+ public void test_SSLContext_getServerSocketFactory() throws Exception {
+ for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) {
+ if (protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) {
+ SSLContext.getInstance(protocol).getServerSocketFactory();
+ } else {
+ try {
+ SSLContext.getInstance(protocol).getServerSocketFactory();
+ fail();
+ } catch (IllegalStateException expected) {
+ // Ignored.
+ }
+ }
+
+ SSLContext sslContext = SSLContext.getInstance(protocol);
+ if (!protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) {
+ sslContext.init(null, null, null);
+ }
+ ServerSocketFactory ssf = sslContext.getServerSocketFactory();
+ assertNotNull(ssf);
+ assertTrue(SSLServerSocketFactory.class.isAssignableFrom(ssf.getClass()));
+ }
+ }
+
+ @Test
+ public void test_SSLContext_createSSLEngine() throws Exception {
+ for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) {
+ if (protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) {
+ SSLContext.getInstance(protocol).createSSLEngine();
+ } else {
+ try {
+ SSLContext.getInstance(protocol).createSSLEngine();
+ fail();
+ } catch (IllegalStateException expected) {
+ // Ignored.
+ }
+ }
+
+ if (protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) {
+ SSLContext.getInstance(protocol).createSSLEngine(null, -1);
+ } else {
+ try {
+ SSLContext.getInstance(protocol).createSSLEngine(null, -1);
+ fail();
+ } catch (IllegalStateException expected) {
+ // Ignored.
+ }
+ }
+
+ {
+ SSLContext sslContext = SSLContext.getInstance(protocol);
+ if (!protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) {
+ sslContext.init(null, null, null);
+ }
+ SSLEngine se = sslContext.createSSLEngine();
+ assertNotNull(se);
+ }
+
+ {
+ SSLContext sslContext = SSLContext.getInstance(protocol);
+ if (!protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) {
+ sslContext.init(null, null, null);
+ }
+ SSLEngine se = sslContext.createSSLEngine(null, -1);
+ assertNotNull(se);
+ }
+ }
+ }
+
+ @Test
+ public void test_SSLContext_getServerSessionContext() throws Exception {
+ for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) {
+ SSLContext sslContext = SSLContext.getInstance(protocol);
+ SSLSessionContext sessionContext = sslContext.getServerSessionContext();
+ assertNotNull(sessionContext);
+
+ if (protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) {
+ assertSame(
+ SSLContext.getInstance(protocol).getServerSessionContext(), sessionContext);
+ } else {
+ assertNotSame(
+ SSLContext.getInstance(protocol).getServerSessionContext(), sessionContext);
+ }
+ }
+ }
+
+ @Test
+ public void test_SSLContext_getClientSessionContext() throws Exception {
+ for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) {
+ SSLContext sslContext = SSLContext.getInstance(protocol);
+ SSLSessionContext sessionContext = sslContext.getClientSessionContext();
+ assertNotNull(sessionContext);
+
+ if (protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) {
+ assertSame(
+ SSLContext.getInstance(protocol).getClientSessionContext(), sessionContext);
+ } else {
+ assertNotSame(
+ SSLContext.getInstance(protocol).getClientSessionContext(), sessionContext);
+ }
+ }
+ }
+
+ @Test
+ public void test_SSLContextTest_TestSSLContext_create() {
+ TestSSLContext testContext = TestSSLContext.create();
+ assertNotNull(testContext);
+ assertNotNull(testContext.clientKeyStore);
+ assertNull(testContext.clientStorePassword);
+ assertNotNull(testContext.serverKeyStore);
+ assertNotNull(testContext.clientKeyManagers);
+ assertNotNull(testContext.serverKeyManagers);
+ if (testContext.clientKeyManagers.length == 0) {
+ fail("No client KeyManagers");
+ }
+ if (testContext.serverKeyManagers.length == 0) {
+ fail("No server KeyManagers");
+ }
+ assertNotNull(testContext.clientKeyManagers[0]);
+ assertNotNull(testContext.serverKeyManagers[0]);
+ assertNotNull(testContext.clientTrustManager);
+ assertNotNull(testContext.serverTrustManager);
+ assertNotNull(testContext.clientContext);
+ assertNotNull(testContext.serverContext);
+ assertNotNull(testContext.serverSocket);
+ assertNotNull(testContext.host);
+ assertTrue(testContext.port != 0);
+ testContext.close();
+ }
+
+ @Test
+ public void test_SSLContext_SSLv3Unsupported() throws Exception {
+ // Find the default provider for TLS and verify that it does NOT support SSLv3.
+ Provider defaultTlsProvider = null;
+ for (String protocol : new String[] {"SSLContext.TLSv1.2", "SSLContext.TLSv1"}) {
+ for (Provider p : Security.getProviders()) {
+ if (p.get(protocol) != null) {
+ defaultTlsProvider = p;
+ break;
+ }
+ }
+ }
+ assertNotNull(defaultTlsProvider);
+ Provider finalDefaultTlsProvider = defaultTlsProvider;
+ assertThrows(NoSuchAlgorithmException.class,
+ () -> SSLContext.getInstance("SSLv3", finalDefaultTlsProvider));
+ }
+
+ private static void assertContentsInOrder(List<String> expected, String... actual) {
+ List<String> actualList = Arrays.asList(actual);
+ if (expected.size() != actual.length) {
+ fail("Unexpected length. Expected len <" + expected.size() + ">, actual len <"
+ + actual.length + ">, expected <" + expected + ">, actual <" + actualList
+ + ">");
+ }
+
+ if (isWindows()) {
+ // TODO(prbprbprb): CpuFeatures.isAESHardwareAccelerated is not reliable on windows
+ Collections.sort(actualList);
+ Collections.sort(expected);
+ }
+
+ if (!expected.equals(actualList)) {
+ fail("Unexpected element(s). Expected <" + expected + ">, actual <" + actualList + ">");
+ }
+ }
+
+ private static boolean isAndroid() {
+ boolean android;
+ try {
+ Class.forName("android.app.Application", false, getSystemClassLoader());
+ android = true;
+ } catch (Throwable ignored) {
+ // Failed to load the class uniquely available in Android.
+ android = false;
+ }
+ return android;
+ }
+
+ private static int javaVersion() {
+ final int majorVersion;
+
+ if (isAndroid()) {
+ majorVersion = 6;
+ } else {
+ majorVersion = majorVersionFromJavaSpecificationVersion();
+ }
+
+ return majorVersion;
+ }
+
+ private static int majorVersionFromJavaSpecificationVersion() {
+ return majorVersion(System.getProperty("java.specification.version", "1.6"));
+ }
+
+ private static int majorVersion(final String javaSpecVersion) {
+ final String[] components = javaSpecVersion.split("\\.", -1);
+ final int[] version = new int[components.length];
+ for (int i = 0; i < components.length; i++) {
+ version[i] = Integer.parseInt(components[i]);
+ }
+
+ if (version[0] == 1) {
+ assertTrue(version[1] >= 6);
+ return version[1];
+ } else {
+ return version[0];
+ }
+ }
+
+ private static ClassLoader getSystemClassLoader() {
+ if (System.getSecurityManager() == null) {
+ return ClassLoader.getSystemClassLoader();
+ } else {
+ return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+ @Override
+ public ClassLoader run() {
+ return ClassLoader.getSystemClassLoader();
+ }
+ });
+ }
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineTest.java
new file mode 100644
index 0000000..f3b5148
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineTest.java
@@ -0,0 +1,1132 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static com.android.org.conscrypt.TestUtils.UTF_8;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.org.conscrypt.TestUtils;
+import com.android.org.conscrypt.TestUtils.BufferType;
+import com.android.org.conscrypt.java.security.StandardNames;
+import com.android.org.conscrypt.java.security.TestKeyStore;
+import java.io.IOException;
+import java.net.Socket;
+import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLEngineResult.Status;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.X509ExtendedTrustManager;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class SSLEngineTest {
+ @Test
+ public void test_SSLEngine_defaultConfiguration() throws Exception {
+ SSLConfigurationAsserts.assertSSLEngineDefaultConfiguration(
+ TestSSLContext.create().clientContext.createSSLEngine());
+ }
+
+ @Test
+ public void test_SSLEngine_getSupportedCipherSuites_returnsCopies() throws Exception {
+ TestSSLContext c = TestSSLContext.create();
+ SSLEngine e = c.clientContext.createSSLEngine();
+ assertNotSame(e.getSupportedCipherSuites(), e.getSupportedCipherSuites());
+ c.close();
+ }
+
+ @Test
+ public void test_SSLEngine_getSupportedCipherSuites_connect() throws Exception {
+ // note the rare usage of non-RSA keys
+ TestKeyStore testKeyStore = new TestKeyStore.Builder()
+ .keyAlgorithms("RSA", "DSA", "EC", "EC_RSA")
+ .aliasPrefix("rsa-dsa-ec")
+ .ca(true)
+ .build();
+ test_SSLEngine_getSupportedCipherSuites_connect(testKeyStore, false);
+ test_SSLEngine_getSupportedCipherSuites_connect(testKeyStore, true);
+ }
+
+ // http://b/18554122
+ @Test
+ public void test_SSLEngine_underflowsOnEmptyBuffersDuringHandshake() throws Exception {
+ final SSLEngine sslEngine = SSLContext.getDefault().createSSLEngine();
+ sslEngine.setUseClientMode(false);
+ ByteBuffer input = ByteBuffer.allocate(1024);
+ input.flip();
+ ByteBuffer output = ByteBuffer.allocate(1024);
+ sslEngine.beginHandshake();
+ assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP, sslEngine.getHandshakeStatus());
+ SSLEngineResult result = sslEngine.unwrap(input, output);
+ assertEquals(SSLEngineResult.Status.BUFFER_UNDERFLOW, result.getStatus());
+ assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP, result.getHandshakeStatus());
+ }
+
+ // http://b/18554122
+ @Test
+ public void test_SSLEngine_underflowsOnEmptyBuffersAfterHandshake() throws Exception {
+ // Note that create performs the handshake.
+ final TestSSLEnginePair engines = TestSSLEnginePair.create();
+ ByteBuffer input = ByteBuffer.allocate(1024);
+ input.flip();
+ ByteBuffer output = ByteBuffer.allocate(1024);
+ assertEquals(SSLEngineResult.Status.BUFFER_UNDERFLOW,
+ engines.client.unwrap(input, output).getStatus());
+ }
+
+ @Test
+ public void test_SSLEngine_wrap_overflowOnEmptyOutputBuffer() throws Exception {
+ TestSSLEnginePair pair = TestSSLEnginePair.create();
+ ByteBuffer input = ByteBuffer.allocate(10);
+ ByteBuffer output = ByteBuffer.allocate(1024);
+ output.flip();
+ assertEquals(Status.BUFFER_OVERFLOW, pair.client.wrap(input, output).getStatus());
+ }
+
+ @Test
+ public void test_SSLEngine_unwrap_overflowOnEmptyOutputBuffer() throws Exception {
+ TestSSLEnginePair pair = TestSSLEnginePair.create();
+ ByteBuffer input = ByteBuffer.allocate(10);
+ ByteBuffer wrapped = ByteBuffer.allocate(1024);
+ assertEquals(Status.OK, pair.client.wrap(input, wrapped).getStatus());
+ wrapped.flip();
+ ByteBuffer output = ByteBuffer.allocate(1024);
+ output.flip();
+ assertEquals(Status.BUFFER_OVERFLOW, pair.server.unwrap(wrapped, output).getStatus());
+ }
+
+ private void test_SSLEngine_getSupportedCipherSuites_connect(
+ TestKeyStore testKeyStore, boolean secureRenegotiation) throws Exception {
+ KeyManager pskKeyManager =
+ PSKKeyManagerProxy.getConscryptPSKKeyManager(new PSKKeyManagerProxy() {
+ @Override
+ protected SecretKey getKey(
+ String identityHint, String identity, SSLEngine engine) {
+ return new SecretKeySpec("Just an arbitrary key".getBytes(UTF_8), "RAW");
+ }
+ });
+ TestSSLContext c = TestSSLContext.newBuilder()
+ .client(testKeyStore)
+ .server(testKeyStore)
+ .clientProtocol("TLSv1.2")
+ .serverProtocol("TLSv1.2")
+ .additionalClientKeyManagers(new KeyManager[] {pskKeyManager})
+ .additionalServerKeyManagers(new KeyManager[] {pskKeyManager})
+ .build();
+
+ // Create a TestSSLContext where the KeyManager returns wrong (randomly generated) private
+ // keys, matching the algorithm and parameters of the correct keys.
+ // I couldn't find a more elegant way to achieve this other than temporarily replacing the
+ // first X509ExtendedKeyManager element of TestKeyStore.keyManagers while invoking
+ // TestSSLContext.create.
+ TestSSLContext cWithWrongPrivateKeys;
+ {
+ // Create a RandomPrivateKeyX509ExtendedKeyManager based on the first
+ // X509ExtendedKeyManager in c.serverKeyManagers.
+ KeyManager randomPrivateKeyX509ExtendedKeyManager = null;
+ for (KeyManager keyManager : c.serverKeyManagers) {
+ if (keyManager instanceof X509ExtendedKeyManager) {
+ randomPrivateKeyX509ExtendedKeyManager =
+ new RandomPrivateKeyX509ExtendedKeyManager(
+ (X509ExtendedKeyManager) keyManager);
+ break;
+ }
+ }
+ if (randomPrivateKeyX509ExtendedKeyManager == null) {
+ fail("No X509ExtendedKeyManager in c.serverKeyManagers");
+ }
+
+ // Find the first X509ExtendedKeyManager in testKeyStore.keyManagers
+ int replaceIndex = -1;
+ for (int i = 0; i < testKeyStore.keyManagers.length; i++) {
+ KeyManager keyManager = testKeyStore.keyManagers[i];
+ if (keyManager instanceof X509ExtendedKeyManager) {
+ replaceIndex = i;
+ break;
+ }
+ }
+ if (replaceIndex == -1) {
+ fail("No X509ExtendedKeyManager in testKeyStore.keyManagers");
+ }
+
+ // Temporarily substitute the RandomPrivateKeyX509ExtendedKeyManager in place of the
+ // original X509ExtendedKeyManager.
+ KeyManager originalKeyManager = testKeyStore.keyManagers[replaceIndex];
+ testKeyStore.keyManagers[replaceIndex] = randomPrivateKeyX509ExtendedKeyManager;
+ cWithWrongPrivateKeys = TestSSLContext.create(testKeyStore, testKeyStore);
+ testKeyStore.keyManagers[replaceIndex] = originalKeyManager;
+ }
+
+ // To catch all the errors.
+ StringBuilder error = new StringBuilder();
+
+ String[] cipherSuites = c.clientContext.createSSLEngine().getSupportedCipherSuites();
+ for (String cipherSuite : cipherSuites) {
+ try {
+ // Skip cipher suites that are obsoleted.
+ if (StandardNames.IS_RI && "TLSv1.2".equals(c.clientContext.getProtocol())
+ && StandardNames.CIPHER_SUITES_OBSOLETE_TLS12.contains(cipherSuite)) {
+ continue;
+ }
+ /*
+ * Signaling Cipher Suite Values (SCSV) cannot be used on their own, but instead in
+ * conjunction with other cipher suites.
+ */
+ if (cipherSuite.equals(StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION)
+ || cipherSuite.equals(StandardNames.CIPHER_SUITE_FALLBACK)) {
+ continue;
+ }
+ /*
+ * This test uses TLS 1.2, and the TLS 1.3 cipher suites aren't customizable
+ * anyway.
+ */
+ if (StandardNames.CIPHER_SUITES_TLS13.contains(cipherSuite)) {
+ continue;
+ }
+
+ final String[] cipherSuiteArray = (secureRenegotiation
+ ? new String[] {cipherSuite,
+ StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION}
+ : new String[] {cipherSuite});
+
+ // Check that handshake succeeds.
+ TestSSLEnginePair pair = null;
+ try {
+ pair = TestSSLEnginePair.create(c, new TestSSLEnginePair.Hooks() {
+ @Override
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+ client.setEnabledCipherSuites(cipherSuiteArray);
+ server.setEnabledCipherSuites(cipherSuiteArray);
+ }
+ });
+ assertConnected(pair);
+
+ boolean needsRecordSplit = "TLS".equalsIgnoreCase(c.clientContext.getProtocol())
+ && cipherSuite.contains("_CBC_");
+
+ assertSendsCorrectly("This is the client. Hello!".getBytes(UTF_8), pair.client,
+ pair.server, needsRecordSplit);
+ assertSendsCorrectly("This is the server. Hi!".getBytes(UTF_8), pair.server,
+ pair.client, needsRecordSplit);
+ } finally {
+ if (pair != null) {
+ pair.close();
+ }
+ }
+
+ // Check that handshake fails when the server does not possess the private key
+ // corresponding to the server's certificate. This is achieved by using SSLContext
+ // cWithWrongPrivateKeys whose KeyManager returns wrong private keys that match
+ // the algorithm (and parameters) of the correct keys.
+ boolean serverAuthenticatedUsingPublicKey = true;
+ if (cipherSuite.contains("_anon_")) {
+ serverAuthenticatedUsingPublicKey = false;
+ } else if (cipherSuite.startsWith("TLS_PSK_")
+ || cipherSuite.startsWith("TLS_ECDHE_PSK_")) {
+ serverAuthenticatedUsingPublicKey = false;
+ }
+ if (serverAuthenticatedUsingPublicKey) {
+ TestSSLEnginePair p = null;
+ try {
+ p = TestSSLEnginePair.create(
+ cWithWrongPrivateKeys, new TestSSLEnginePair.Hooks() {
+ @Override
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+ client.setEnabledCipherSuites(cipherSuiteArray);
+ server.setEnabledCipherSuites(cipherSuiteArray);
+ }
+ });
+ assertNotConnected(p);
+ } catch (IOException expected) {
+ // Ignored.
+ } finally {
+ if (p != null) {
+ p.close();
+ }
+ }
+ }
+ } catch (Exception e) {
+ String message = ("Problem trying to connect cipher suite " + cipherSuite);
+ System.out.println(message);
+ e.printStackTrace();
+ error.append(message);
+ error.append('\n');
+ }
+ }
+ c.close();
+
+ if (error.length() > 0) {
+ throw new Exception("One or more problems in "
+ + "test_SSLEngine_getSupportedCipherSuites_connect:\n" + error);
+ }
+ }
+
+ private static void assertSendsCorrectly(final byte[] sourceBytes, SSLEngine source,
+ SSLEngine dest, boolean needsRecordSplit) throws SSLException {
+ ByteBuffer sourceOut = ByteBuffer.wrap(sourceBytes);
+ SSLSession sourceSession = source.getSession();
+ ByteBuffer sourceToDest = ByteBuffer.allocate(sourceSession.getPacketBufferSize());
+ SSLEngineResult sourceOutRes = source.wrap(sourceOut, sourceToDest);
+ sourceToDest.flip();
+
+ String sourceCipherSuite = source.getSession().getCipherSuite();
+ assertEquals(sourceCipherSuite, sourceBytes.length, sourceOutRes.bytesConsumed());
+ assertEquals(sourceCipherSuite, HandshakeStatus.NOT_HANDSHAKING,
+ sourceOutRes.getHandshakeStatus());
+
+ SSLSession destSession = dest.getSession();
+ ByteBuffer destIn = ByteBuffer.allocate(destSession.getApplicationBufferSize());
+
+ int numUnwrapCalls = 0;
+ while (destIn.position() != sourceOut.limit()) {
+ SSLEngineResult destRes = dest.unwrap(sourceToDest, destIn);
+ assertEquals(sourceCipherSuite, HandshakeStatus.NOT_HANDSHAKING,
+ destRes.getHandshakeStatus());
+ if (needsRecordSplit && numUnwrapCalls == 0) {
+ assertEquals(sourceCipherSuite, 1, destRes.bytesProduced());
+ }
+ numUnwrapCalls++;
+ }
+
+ destIn.flip();
+ byte[] actual = new byte[destIn.remaining()];
+ destIn.get(actual);
+ assertEquals(sourceCipherSuite, Arrays.toString(sourceBytes), Arrays.toString(actual));
+
+ if (needsRecordSplit) {
+ assertEquals(sourceCipherSuite, 2, numUnwrapCalls);
+ } else {
+ assertEquals(sourceCipherSuite, 1, numUnwrapCalls);
+ assertSendsCorrectlyWhenSplit(sourceBytes, source, dest);
+ }
+ }
+
+ private static void assertSendsCorrectlyWhenSplit(final byte[] sourceBytes, SSLEngine source,
+ SSLEngine dest) throws SSLException {
+ // Split the input into three to test the version that accepts ByteBuffer[]. Three
+ // is chosen somewhat arbitrarily as a number larger than the minimum of 2 but small
+ // enough that it's not unwieldy.
+ ByteBuffer[] sourceBufs = new ByteBuffer[3];
+ int sourceLen = sourceBytes.length;
+ sourceBufs[0] = ByteBuffer.wrap(sourceBytes, 0, sourceLen / 3);
+ sourceBufs[1] = ByteBuffer.wrap(sourceBytes, sourceLen / 3, sourceLen / 3);
+ sourceBufs[2] = ByteBuffer.wrap(
+ sourceBytes, 2 * (sourceLen / 3), sourceLen - 2 * (sourceLen / 3));
+ SSLSession sourceSession = source.getSession();
+ ByteBuffer sourceToDest = ByteBuffer.allocate(sourceSession.getPacketBufferSize());
+ SSLEngineResult sourceOutRes = source.wrap(sourceBufs, sourceToDest);
+ sourceToDest.flip();
+ String sourceCipherSuite = source.getSession().getCipherSuite();
+ assertEquals(sourceCipherSuite, sourceBytes.length, sourceOutRes.bytesConsumed());
+ assertEquals(sourceCipherSuite, HandshakeStatus.NOT_HANDSHAKING,
+ sourceOutRes.getHandshakeStatus());
+ SSLSession destSession = dest.getSession();
+ ByteBuffer destIn = ByteBuffer.allocate(destSession.getApplicationBufferSize());
+ while (destIn.position() != sourceBytes.length) {
+ SSLEngineResult destRes = dest.unwrap(sourceToDest, destIn);
+ assertEquals(sourceCipherSuite, HandshakeStatus.NOT_HANDSHAKING,
+ destRes.getHandshakeStatus());
+ }
+ destIn.flip();
+ byte[] actual = new byte[destIn.remaining()];
+ destIn.get(actual);
+ assertEquals(sourceCipherSuite, Arrays.toString(sourceBytes), Arrays.toString(actual));
+ }
+
+ @Test
+ public void test_SSLEngine_getEnabledCipherSuites_returnsCopies() throws Exception {
+ TestSSLContext c = TestSSLContext.create();
+ SSLEngine e = c.clientContext.createSSLEngine();
+ assertNotSame(e.getEnabledCipherSuites(), e.getEnabledCipherSuites());
+ c.close();
+ }
+
+ @Test
+ public void test_SSLEngine_setEnabledCipherSuites_storesCopy() throws Exception {
+ TestSSLContext c = TestSSLContext.create();
+ SSLEngine e = c.clientContext.createSSLEngine();
+ String[] array = new String[] {e.getEnabledCipherSuites()[0]};
+ String originalFirstElement = array[0];
+ e.setEnabledCipherSuites(array);
+ array[0] = "Modified after having been set";
+ assertEquals(originalFirstElement, e.getEnabledCipherSuites()[0]);
+ }
+
+ @Test
+ public void test_SSLEngine_setEnabledCipherSuites_TLS12() throws Exception {
+ SSLContext context = SSLContext.getInstance("TLSv1.2");
+ context.init(null, null, null);
+ SSLEngine e = context.createSSLEngine();
+
+ try {
+ e.setEnabledCipherSuites(null);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ try {
+ e.setEnabledCipherSuites(new String[1]);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ try {
+ e.setEnabledCipherSuites(new String[] {"Bogus"});
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+
+ e.setEnabledCipherSuites(new String[0]);
+ e.setEnabledCipherSuites(e.getEnabledCipherSuites());
+ e.setEnabledCipherSuites(e.getSupportedCipherSuites());
+
+ // Check that setEnabledCipherSuites affects getEnabledCipherSuites
+ String[] cipherSuites = new String[] {
+ TestUtils.pickArbitraryNonTls13Suite(e.getSupportedCipherSuites())
+ };
+ e.setEnabledCipherSuites(cipherSuites);
+ assertEquals(Arrays.asList(cipherSuites), Arrays.asList(e.getEnabledCipherSuites()));
+ }
+
+ @Test
+ public void test_SSLEngine_setEnabledCipherSuites_TLS13() throws Exception {
+ SSLContext context = SSLContext.getInstance("TLSv1.3");
+ context.init(null, null, null);
+ SSLEngine e = context.createSSLEngine();
+ // The TLS 1.3 cipher suites should be enabled by default
+ assertTrue(new HashSet<String>(Arrays.asList(e.getEnabledCipherSuites()))
+ .containsAll(StandardNames.CIPHER_SUITES_TLS13));
+ // Disabling them should be ignored
+ e.setEnabledCipherSuites(new String[0]);
+ assertTrue(new HashSet<String>(Arrays.asList(e.getEnabledCipherSuites()))
+ .containsAll(StandardNames.CIPHER_SUITES_TLS13));
+
+ e.setEnabledCipherSuites(new String[] {
+ TestUtils.pickArbitraryNonTls13Suite(e.getSupportedCipherSuites())
+ });
+ assertTrue(new HashSet<String>(Arrays.asList(e.getEnabledCipherSuites()))
+ .containsAll(StandardNames.CIPHER_SUITES_TLS13));
+
+ // Disabling TLS 1.3 should disable the 1.3 cipher suites
+ e.setEnabledProtocols(new String[] { "TLSv1.2" });
+ assertFalse(new HashSet<String>(Arrays.asList(e.getEnabledCipherSuites()))
+ .containsAll(StandardNames.CIPHER_SUITES_TLS13));
+ }
+
+ @Test
+ public void test_SSLEngine_getSupportedProtocols_returnsCopies() throws Exception {
+ TestSSLContext c = TestSSLContext.create();
+ SSLEngine e = c.clientContext.createSSLEngine();
+ assertNotSame(e.getSupportedProtocols(), e.getSupportedProtocols());
+ c.close();
+ }
+
+ @Test
+ public void test_SSLEngine_getEnabledProtocols_returnsCopies() throws Exception {
+ TestSSLContext c = TestSSLContext.create();
+ SSLEngine e = c.clientContext.createSSLEngine();
+ assertNotSame(e.getEnabledProtocols(), e.getEnabledProtocols());
+ c.close();
+ }
+
+ @Test
+ public void test_SSLEngine_setEnabledProtocols_storesCopy() throws Exception {
+ TestSSLContext c = TestSSLContext.create();
+ SSLEngine e = c.clientContext.createSSLEngine();
+ String[] array = new String[] {e.getEnabledProtocols()[0]};
+ String originalFirstElement = array[0];
+ e.setEnabledProtocols(array);
+ array[0] = "Modified after having been set";
+ assertEquals(originalFirstElement, e.getEnabledProtocols()[0]);
+ }
+
+ @Test
+ public void test_SSLEngine_setEnabledProtocols() throws Exception {
+ TestSSLContext c = TestSSLContext.create();
+ SSLEngine e = c.clientContext.createSSLEngine();
+
+ try {
+ e.setEnabledProtocols(null);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ try {
+ e.setEnabledProtocols(new String[1]);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ try {
+ e.setEnabledProtocols(new String[] {"Bogus"});
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ e.setEnabledProtocols(new String[0]);
+ e.setEnabledProtocols(e.getEnabledProtocols());
+ e.setEnabledProtocols(e.getSupportedProtocols());
+
+ // Check that setEnabledProtocols affects getEnabledProtocols
+ for (String protocol : e.getSupportedProtocols()) {
+ if ("SSLv2Hello".equals(protocol)) {
+ try {
+ e.setEnabledProtocols(new String[] {protocol});
+ fail("Should fail when SSLv2Hello is set by itself");
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ } else {
+ String[] protocols = new String[] {protocol};
+ e.setEnabledProtocols(protocols);
+ assertEquals(Arrays.deepToString(protocols),
+ Arrays.deepToString(e.getEnabledProtocols()));
+ }
+ }
+
+ c.close();
+ }
+
+ @Test
+ public void test_SSLEngine_getSession() throws Exception {
+ TestSSLContext c = TestSSLContext.create();
+ SSLEngine e = c.clientContext.createSSLEngine();
+ SSLSession session = e.getSession();
+ assertNotNull(session);
+ assertFalse(session.isValid());
+ c.close();
+ }
+
+ // http://b/37078438
+ @Test
+ public void test_SSLEngine_beginHandshake_redundantCalls() throws Exception {
+ TestSSLContext c = TestSSLContext.create();
+ SSLEngine client = c.clientContext.createSSLEngine(c.host.getHostName(), c.port);
+ client.setUseClientMode(true);
+ client.beginHandshake();
+ client.beginHandshake(); // This call should be ignored
+ c.close();
+ }
+
+ @Test
+ public void test_SSLEngine_getHandshakeSession_duringHandshake_client() throws Exception {
+ // We can't reference the actual context we're using, since we need to pass
+ // the test trust manager in to construct it, so create reference objects that
+ // we can test against.
+ final TestSSLContext referenceContext = TestSSLContext.create();
+ final SSLEngine referenceEngine = referenceContext.clientContext.createSSLEngine();
+
+ final AtomicInteger checkServerTrustedWasCalled = new AtomicInteger(0);
+ TestSSLContext c = TestSSLContext.newBuilder()
+ .clientTrustManager(new X509ExtendedTrustManager() {
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s,
+ Socket socket) throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s,
+ Socket socket) throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s,
+ SSLEngine sslEngine) throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s,
+ SSLEngine sslEngine) throws CertificateException {
+ try {
+ SSLSession session = sslEngine.getHandshakeSession();
+ assertNotNull(session);
+ // By the point of the handshake where we're validating certificates,
+ // the hostname is known and the cipher suite should be agreed
+ assertEquals(referenceContext.host.getHostName(), session.getPeerHost());
+ String sessionSuite = session.getCipherSuite();
+ List<String> enabledSuites =
+ Arrays.asList(referenceEngine.getEnabledCipherSuites());
+ String message = "Handshake session has invalid cipher suite: "
+ + (sessionSuite == null ? "(null)" : sessionSuite);
+ assertTrue(message, enabledSuites.contains(sessionSuite));
+
+ checkServerTrustedWasCalled.incrementAndGet();
+ } catch (Exception e) {
+ throw new CertificateException("Something broke", e);
+ }
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s)
+ throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s)
+ throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[0];
+ }
+ }).build();
+ TestSSLEnginePair pair = TestSSLEnginePair.create(c);
+ pair.close();
+ assertEquals(1, checkServerTrustedWasCalled.get());
+ }
+
+ @Test
+ public void test_SSLEngine_getHandshakeSession_duringHandshake_server() throws Exception {
+ // We can't reference the actual context we're using, since we need to pass
+ // the test trust manager in to construct it, so create reference objects that
+ // we can test against.
+ final TestSSLContext referenceContext = TestSSLContext.create();
+ final SSLEngine referenceEngine = referenceContext.clientContext.createSSLEngine();
+
+ final AtomicInteger checkClientTrustedWasCalled = new AtomicInteger(0);
+ TestSSLContext c = TestSSLContext.newBuilder()
+ .client(TestKeyStore.getClientCertificate())
+ .serverTrustManager(new X509ExtendedTrustManager() {
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s,
+ Socket socket) throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s,
+ Socket socket) throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s,
+ SSLEngine sslEngine) throws CertificateException {
+ try {
+ SSLSession session = sslEngine.getHandshakeSession();
+ assertNotNull(session);
+ // By the point of the handshake where we're validating client certificates,
+ // the cipher suite should be agreed and the server's own certificates
+ // should have been delivered
+
+ // The negotiated cipher suite should be one of the enabled ones, but
+ // BoringSSL may have reordered them based on things like hardware support,
+ // so we don't know which one may have been negotiated.
+ String sessionSuite = session.getCipherSuite();
+ List<String> enabledSuites =
+ Arrays.asList(referenceEngine.getEnabledCipherSuites());
+ String message = "Handshake session has invalid cipher suite: "
+ + (sessionSuite == null ? "(null)" : sessionSuite);
+ assertTrue(message, enabledSuites.contains(sessionSuite));
+
+ assertNotNull(session.getLocalCertificates());
+ assertEquals("CN=localhost",
+ ((X509Certificate) session.getLocalCertificates()[0])
+ .getSubjectDN().getName());
+ assertEquals("CN=Test Intermediate Certificate Authority",
+ ((X509Certificate) session.getLocalCertificates()[0])
+ .getIssuerDN().getName());
+ checkClientTrustedWasCalled.incrementAndGet();
+ } catch (Exception e) {
+ throw new CertificateException("Something broke", e);
+ }
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s,
+ SSLEngine sslEngine) throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s)
+ throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s)
+ throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return referenceContext.serverTrustManager.getAcceptedIssuers();
+ }
+ }).build();
+ TestSSLEnginePair pair = TestSSLEnginePair.create(c, new TestSSLEnginePair.Hooks() {
+ @Override
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+ server.setNeedClientAuth(true);
+ }
+ });
+ pair.close();
+ assertEquals(1, checkClientTrustedWasCalled.get());
+ }
+
+ @Test
+ public void test_SSLEngine_getUseClientMode() throws Exception {
+ TestSSLContext c = TestSSLContext.create();
+ assertFalse(c.clientContext.createSSLEngine().getUseClientMode());
+ assertFalse(c.clientContext.createSSLEngine(null, -1).getUseClientMode());
+ c.close();
+ }
+
+ @Test
+ public void test_SSLEngine_setUseClientMode() throws Exception {
+ boolean[] finished;
+ TestSSLEnginePair p;
+
+ // client is client, server is server
+ finished = new boolean[2];
+ p = test_SSLEngine_setUseClientMode(true, false, finished);
+ assertConnected(p);
+ assertTrue(finished[0]);
+ assertTrue(finished[1]);
+ p.close();
+
+ // client is server, server is client
+ finished = new boolean[2];
+ p = test_SSLEngine_setUseClientMode(false, true, finished);
+ assertConnected(p);
+ assertTrue(finished[0]);
+ assertTrue(finished[1]);
+ p.close();
+
+ // both are client
+ /*
+ * Our implementation throws an SSLHandshakeException, but RI just
+ * stalls forever
+ */
+ p = null;
+ try {
+ p = test_SSLEngine_setUseClientMode(true, true, null);
+ assertNotConnected(p);
+ } catch (SSLHandshakeException maybeExpected) {
+ // Ignored.
+ } finally {
+ if (p != null) {
+ p.close();
+ }
+ }
+
+ p = test_SSLEngine_setUseClientMode(false, false, null);
+ // both are server
+ assertNotConnected(p);
+ p.close();
+ }
+
+ @Test
+ public void test_SSLEngine_setUseClientMode_afterHandshake() throws Exception {
+ // can't set after handshake
+ TestSSLEnginePair pair = TestSSLEnginePair.create();
+ try {
+ pair.server.setUseClientMode(false);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ try {
+ pair.client.setUseClientMode(false);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ pair.close();
+ }
+
+ private TestSSLEnginePair test_SSLEngine_setUseClientMode(final boolean clientClientMode,
+ final boolean serverClientMode, final boolean[] finished) throws Exception {
+ TestSSLContext c;
+ if (!clientClientMode && serverClientMode) {
+ c = TestSSLContext.create(/* client= */ TestKeyStore.getServer(),
+ /* server= */ TestKeyStore.getClient());
+ } else {
+ c = TestSSLContext.create();
+ }
+
+ return TestSSLEnginePair.create(c, new TestSSLEnginePair.Hooks() {
+ @Override
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+ client.setUseClientMode(clientClientMode);
+ server.setUseClientMode(serverClientMode);
+ }
+ }, finished);
+ }
+
+ @Test
+ public void test_SSLEngine_getEnableSessionCreation() throws Exception {
+ TestSSLContext c = TestSSLContext.create();
+ SSLEngine e = c.clientContext.createSSLEngine();
+ assertTrue(e.getEnableSessionCreation());
+ c.close();
+ TestSSLEnginePair.close(new SSLEngine[] {e});
+ }
+
+ @Test
+ public void test_SSLEngine_setEnableSessionCreation_server() throws Exception {
+ TestSSLEnginePair p = null;
+ try {
+ p = TestSSLEnginePair.create(new TestSSLEnginePair.Hooks() {
+ @Override
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+ server.setEnableSessionCreation(false);
+ }
+ });
+ assertNotConnected(p);
+ } catch (SSLException maybeExpected) {
+ // Ignored.
+ } finally {
+ if (p != null) {
+ p.close();
+ }
+ }
+ }
+
+ @Test
+ public void test_SSLEngine_setEnableSessionCreation_client() throws Exception {
+ TestSSLEnginePair p = null;
+ try {
+ p = TestSSLEnginePair.create(new TestSSLEnginePair.Hooks() {
+ @Override
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+ client.setEnableSessionCreation(false);
+ }
+ });
+ fail();
+ } catch (SSLException expected) {
+ // Ignored.
+ } finally {
+ if (p != null) {
+ p.close();
+ }
+ }
+ }
+
+ @Test
+ public void test_SSLEngine_getSSLParameters() throws Exception {
+ TestSSLContext c = TestSSLContext.create();
+ SSLEngine e = c.clientContext.createSSLEngine();
+
+ SSLParameters p = e.getSSLParameters();
+ assertNotNull(p);
+
+ String[] cipherSuites = p.getCipherSuites();
+ assertNotSame(cipherSuites, e.getEnabledCipherSuites());
+ assertEquals(Arrays.asList(cipherSuites), Arrays.asList(e.getEnabledCipherSuites()));
+
+ String[] protocols = p.getProtocols();
+ assertNotSame(protocols, e.getEnabledProtocols());
+ assertEquals(Arrays.asList(protocols), Arrays.asList(e.getEnabledProtocols()));
+
+ assertEquals(p.getWantClientAuth(), e.getWantClientAuth());
+ assertEquals(p.getNeedClientAuth(), e.getNeedClientAuth());
+
+ c.close();
+ }
+
+ @Test
+ public void test_SSLEngine_setSSLParameters() throws Exception {
+ TestSSLContext c = TestSSLContext.create();
+ SSLEngine e = c.clientContext.createSSLEngine();
+ String[] defaultCipherSuites = e.getEnabledCipherSuites();
+ String[] defaultProtocols = e.getEnabledProtocols();
+ String[] supportedCipherSuites = e.getSupportedCipherSuites();
+ String[] supportedProtocols = e.getSupportedProtocols();
+
+ {
+ SSLParameters p = new SSLParameters();
+ e.setSSLParameters(p);
+ assertEquals(
+ Arrays.asList(defaultCipherSuites), Arrays.asList(e.getEnabledCipherSuites()));
+ assertEquals(Arrays.asList(defaultProtocols), Arrays.asList(e.getEnabledProtocols()));
+ }
+
+ {
+ SSLParameters p = new SSLParameters(supportedCipherSuites, supportedProtocols);
+ e.setSSLParameters(p);
+ assertEquals(Arrays.asList(supportedCipherSuites),
+ Arrays.asList(e.getEnabledCipherSuites()));
+ assertEquals(Arrays.asList(supportedProtocols), Arrays.asList(e.getEnabledProtocols()));
+ }
+ {
+ SSLParameters p = new SSLParameters();
+
+ p.setNeedClientAuth(true);
+ assertFalse(e.getNeedClientAuth());
+ assertFalse(e.getWantClientAuth());
+ e.setSSLParameters(p);
+ assertTrue(e.getNeedClientAuth());
+ assertFalse(e.getWantClientAuth());
+
+ p.setWantClientAuth(true);
+ assertTrue(e.getNeedClientAuth());
+ assertFalse(e.getWantClientAuth());
+ e.setSSLParameters(p);
+ assertFalse(e.getNeedClientAuth());
+ assertTrue(e.getWantClientAuth());
+
+ p.setWantClientAuth(false);
+ assertFalse(e.getNeedClientAuth());
+ assertTrue(e.getWantClientAuth());
+ e.setSSLParameters(p);
+ assertFalse(e.getNeedClientAuth());
+ assertFalse(e.getWantClientAuth());
+ }
+ c.close();
+ }
+
+ @Test
+ public void wrapPreconditions() throws Exception {
+ ByteBuffer buffer = ByteBuffer.allocate(10);
+ ByteBuffer[] buffers = new ByteBuffer[] {buffer, buffer, buffer};
+ ByteBuffer[] badBuffers = new ByteBuffer[] {buffer, buffer, null, buffer};
+
+ // Client/server mode not set => IllegalStateException
+ try {
+ newUnconnectedEngine().wrap(buffer, buffer);
+ fail();
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+
+ try {
+ newUnconnectedEngine().wrap(buffers, buffer);
+ fail();
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+
+ try {
+ newUnconnectedEngine().wrap(buffers, 0, 1, buffer);
+ fail();
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+
+ // Read-only destination => ReadOnlyBufferException
+ try {
+ newConnectedEngine().wrap(buffer, buffer.asReadOnlyBuffer());
+ fail();
+ } catch (ReadOnlyBufferException e) {
+ // Expected
+ }
+
+ try {
+ newConnectedEngine().wrap(buffers, buffer.asReadOnlyBuffer());
+ fail();
+ } catch (ReadOnlyBufferException e) {
+ // Expected
+ }
+
+ try {
+ newConnectedEngine().wrap(buffers, 0, 1, buffer.asReadOnlyBuffer());
+ fail();
+ } catch (ReadOnlyBufferException e) {
+ // Expected
+ }
+
+ // Null destination => IllegalArgumentException
+ try {
+ newConnectedEngine().wrap(buffer, null);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ try {
+ newConnectedEngine().wrap(buffers, null);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ try {
+ newConnectedEngine().wrap(buffers, 0, 1, null);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ // Null source => IllegalArgumentException
+ try {
+ newConnectedEngine().wrap((ByteBuffer) null, buffer);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ try {
+ newConnectedEngine().wrap((ByteBuffer[]) null, buffer);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ try {
+ newConnectedEngine().wrap(null, 0, 1, buffer);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ // Null entries in buffer array => IllegalArgumentException
+ try {
+ newConnectedEngine().wrap(badBuffers, buffer);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ try {
+ newConnectedEngine().wrap(badBuffers, 0, badBuffers.length, buffer);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ // Bad offset or length => IndexOutOfBoundsException
+ try {
+ newConnectedEngine().wrap(buffers, 0, 7, buffer);
+ fail();
+ } catch (IndexOutOfBoundsException e) {
+ // Expected
+ }
+ }
+
+ @Test
+ public void bufferArrayOffsets() throws Exception {
+ TestSSLEnginePair pair = TestSSLEnginePair.create();
+ ByteBuffer tlsBuffer = ByteBuffer.allocate(600);
+ int bufferSize = 100;
+
+ for (BufferType bufferType : BufferType.values()) {
+ ByteBuffer[] sourceBuffers = bufferType.newRandomBuffers(
+ bufferSize, bufferSize, bufferSize, bufferSize, bufferSize);
+ for (int offset = 0; offset < sourceBuffers.length; offset++) {
+ for (int length = 1; length < sourceBuffers.length - offset; length++) {
+ // Reset source buffers
+ for (ByteBuffer buffer : sourceBuffers) {
+ if (buffer.remaining() == 0) {
+ buffer.flip();
+ }
+ assertEquals(bufferSize, buffer.remaining());
+ }
+ // Make an array copy of what we expect to send
+ byte[] sourceBytes = copyDataFromBuffers(sourceBuffers, offset, length);
+ byte[] destinationBytes = new byte[sourceBytes.length];
+ ByteBuffer destination = ByteBuffer.wrap(destinationBytes);
+ // Send and compare
+ tlsBuffer.clear();
+ pair.client.wrap(sourceBuffers, offset, length, tlsBuffer);
+ tlsBuffer.flip();
+ pair.server.unwrap(tlsBuffer, destination);
+ assertArrayEquals(sourceBytes, destinationBytes);
+ }
+ }
+ }
+ }
+
+ private byte[] copyDataFromBuffers(ByteBuffer[] buffers, int offset, int length) {
+ // NB avoids using Arrays.copyOfRange() to prevent any common bugs with
+ // ConscryptEngine.wrap().
+ int size = 0;
+ for (int i = offset; i < offset + length; i++) {
+ size += buffers[i].remaining();
+ }
+ byte[] data = new byte[size];
+ int dataOffset = 0;
+ for (int i = offset; i < offset + length; i++) {
+ ByteBuffer buffer = buffers[i];
+ int remaining = buffer.remaining();
+ buffer.get(data, dataOffset, remaining);
+ buffer.flip();
+ dataOffset += remaining;
+ }
+ return data;
+ }
+
+ private SSLEngine newUnconnectedEngine() {
+ TestSSLContext context = TestSSLContext.create();
+ return context.clientContext.createSSLEngine();
+ }
+
+ private SSLEngine newConnectedEngine() throws Exception {
+ TestSSLEnginePair pair = TestSSLEnginePair.create();
+ assertConnected(pair);
+ return pair.client;
+ }
+
+ private void assertConnected(TestSSLEnginePair e) {
+ assertConnected(e.client, e.server);
+ }
+
+ private void assertNotConnected(TestSSLEnginePair e) {
+ assertNotConnected(e.client, e.server);
+ }
+
+ private void assertConnected(SSLEngine a, SSLEngine b) {
+ assertTrue(connected(a, b));
+ }
+
+ private void assertNotConnected(SSLEngine a, SSLEngine b) {
+ assertFalse(connected(a, b));
+ }
+
+ private boolean connected(SSLEngine a, SSLEngine b) {
+ return (a.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING
+ && b.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING
+ && a.getSession() != null && b.getSession() != null && !a.isInboundDone()
+ && !b.isInboundDone() && !a.isOutboundDone() && !b.isOutboundDone());
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineVersionCompatibilityTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineVersionCompatibilityTest.java
new file mode 100644
index 0000000..24621c5
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineVersionCompatibilityTest.java
@@ -0,0 +1,954 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static com.android.org.conscrypt.TestUtils.UTF_8;
+import static com.android.org.conscrypt.TestUtils.assumeJava8;
+import static java.util.Collections.singleton;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.org.conscrypt.Conscrypt;
+import com.android.org.conscrypt.TestUtils;
+import com.android.org.conscrypt.java.security.TestKeyStore;
+import com.android.org.conscrypt.testing.FailingSniMatcher;
+import com.android.org.conscrypt.tlswire.TlsTester;
+import com.android.org.conscrypt.tlswire.handshake.AlpnHelloExtension;
+import com.android.org.conscrypt.tlswire.handshake.ClientHello;
+import com.android.org.conscrypt.tlswire.handshake.HandshakeMessage;
+import com.android.org.conscrypt.tlswire.handshake.HelloExtension;
+import com.android.org.conscrypt.tlswire.handshake.ServerNameHelloExtension;
+import com.android.org.conscrypt.tlswire.record.TlsProtocols;
+import com.android.org.conscrypt.tlswire.record.TlsRecord;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.nio.ByteBuffer;
+import java.security.Principal;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Random;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import javax.net.ssl.ExtendedSSLSession;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIMatcher;
+import javax.net.ssl.SNIServerName;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLEngineResult.Status;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.X509TrustManager;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/**
+ * Tests for SSLSocket classes that ensure the TLS 1.2 and TLS 1.3 implementations
+ * are compatible.
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(Parameterized.class)
+public class SSLEngineVersionCompatibilityTest {
+
+ @Parameterized.Parameters(name = "{index}: {0} client, {1} server")
+ public static Iterable<Object[]> data() {
+ // We can't support TLS 1.3 without our own trust manager (which requires
+ // X509ExtendedTrustManager), so only test TLS 1.2 if it's not available.
+ if (TestUtils.isClassAvailable("javax.net.ssl.X509ExtendedTrustManager")) {
+ return Arrays.asList(new Object[][] {
+ { "TLSv1.2", "TLSv1.2" },
+ { "TLSv1.2", "TLSv1.3" },
+ { "TLSv1.3", "TLSv1.2" },
+ { "TLSv1.3", "TLSv1.3" },
+ });
+ } else {
+ return Arrays.asList(new Object[][]{{ "TLSv1.2", "TLSv1.2"}});
+ }
+ }
+
+ private final String clientVersion;
+ private final String serverVersion;
+
+ public SSLEngineVersionCompatibilityTest(String clientVersion, String serverVersion) {
+ this.clientVersion = clientVersion;
+ this.serverVersion = serverVersion;
+ }
+
+ private static void assertSendsCorrectly(final byte[] sourceBytes, SSLEngine source,
+ SSLEngine dest, boolean needsRecordSplit) throws SSLException {
+ ByteBuffer sourceOut = ByteBuffer.wrap(sourceBytes);
+ SSLSession sourceSession = source.getSession();
+ ByteBuffer sourceToDest = ByteBuffer.allocate(sourceSession.getPacketBufferSize());
+ SSLEngineResult sourceOutRes = source.wrap(sourceOut, sourceToDest);
+ sourceToDest.flip();
+
+ String sourceCipherSuite = source.getSession().getCipherSuite();
+ assertEquals(sourceCipherSuite, sourceBytes.length, sourceOutRes.bytesConsumed());
+ assertEquals(sourceCipherSuite, HandshakeStatus.NOT_HANDSHAKING,
+ sourceOutRes.getHandshakeStatus());
+
+ SSLSession destSession = dest.getSession();
+ ByteBuffer destIn = ByteBuffer.allocate(destSession.getApplicationBufferSize());
+
+ int numUnwrapCalls = 0;
+ while (destIn.position() != sourceOut.limit()) {
+ SSLEngineResult destRes = dest.unwrap(sourceToDest, destIn);
+ assertEquals(sourceCipherSuite, HandshakeStatus.NOT_HANDSHAKING,
+ destRes.getHandshakeStatus());
+ if (needsRecordSplit && numUnwrapCalls == 0) {
+ assertEquals(sourceCipherSuite, 1, destRes.bytesProduced());
+ }
+ numUnwrapCalls++;
+ }
+
+ destIn.flip();
+ byte[] actual = new byte[destIn.remaining()];
+ destIn.get(actual);
+ assertEquals(sourceCipherSuite, Arrays.toString(sourceBytes), Arrays.toString(actual));
+
+ if (needsRecordSplit) {
+ assertEquals(sourceCipherSuite, 2, numUnwrapCalls);
+ } else {
+ assertEquals(sourceCipherSuite, 1, numUnwrapCalls);
+ assertSendsCorrectlyWhenSplit(sourceBytes, source, dest);
+ }
+ }
+
+ private static void assertSendsCorrectlyWhenSplit(final byte[] sourceBytes, SSLEngine source,
+ SSLEngine dest) throws SSLException {
+ // Split the input into three to test the version that accepts ByteBuffer[]. Three
+ // is chosen somewhat arbitrarily as a number larger than the minimum of 2 but small
+ // enough that it's not unwieldy.
+ ByteBuffer[] sourceBufs = new ByteBuffer[3];
+ int sourceLen = sourceBytes.length;
+ sourceBufs[0] = ByteBuffer.wrap(sourceBytes, 0, sourceLen / 3);
+ sourceBufs[1] = ByteBuffer.wrap(sourceBytes, sourceLen / 3, sourceLen / 3);
+ sourceBufs[2] = ByteBuffer.wrap(
+ sourceBytes, 2 * (sourceLen / 3), sourceLen - 2 * (sourceLen / 3));
+ SSLSession sourceSession = source.getSession();
+ ByteBuffer sourceToDest = ByteBuffer.allocate(sourceSession.getPacketBufferSize());
+ SSLEngineResult sourceOutRes = source.wrap(sourceBufs, sourceToDest);
+ sourceToDest.flip();
+ String sourceCipherSuite = source.getSession().getCipherSuite();
+ assertEquals(sourceCipherSuite, sourceBytes.length, sourceOutRes.bytesConsumed());
+ assertEquals(sourceCipherSuite, HandshakeStatus.NOT_HANDSHAKING,
+ sourceOutRes.getHandshakeStatus());
+ SSLSession destSession = dest.getSession();
+ ByteBuffer destIn = ByteBuffer.allocate(destSession.getApplicationBufferSize());
+ while (destIn.position() != sourceBytes.length) {
+ SSLEngineResult destRes = dest.unwrap(sourceToDest, destIn);
+ assertEquals(sourceCipherSuite, HandshakeStatus.NOT_HANDSHAKING,
+ destRes.getHandshakeStatus());
+ }
+ destIn.flip();
+ byte[] actual = new byte[destIn.remaining()];
+ destIn.get(actual);
+ assertEquals(sourceCipherSuite, Arrays.toString(sourceBytes), Arrays.toString(actual));
+ }
+
+ @Test
+ public void test_SSLEngine_beginHandshake() throws Exception {
+ TestSSLContext c = TestSSLContext.newBuilder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion).build();
+
+ try {
+ c.clientContext.createSSLEngine().beginHandshake();
+ fail();
+ } catch (IllegalStateException expected) {
+ // Ignored.
+ }
+ c.close();
+
+ TestSSLEnginePair p = TestSSLEnginePair.create();
+ assertConnected(p);
+ p.close();
+ }
+
+ @Test
+ public void test_SSLEngine_beginHandshake_noKeyStore() throws Exception {
+ SSLContext clientContext = SSLContext.getInstance(clientVersion);
+ clientContext.init(null, null, null);
+ SSLContext serverContext = SSLContext.getInstance(serverVersion);
+ serverContext.init(null, null, null);
+ TestSSLContext c = TestSSLContext.newBuilder()
+ .useDefaults(false)
+ .clientContext(clientContext)
+ .serverContext(serverContext).build();
+ SSLEngine[] p = null;
+ try {
+ // TODO Fix KnownFailure AlertException "NO SERVER CERTIFICATE FOUND"
+ // ServerHandshakeImpl.selectSuite should not select a suite without a required cert
+ p = TestSSLEnginePair.connect(c, null);
+ fail();
+ } catch (SSLHandshakeException expected) {
+ // Ignored.
+ } finally {
+ if (p != null) {
+ TestSSLEnginePair.close(p);
+ }
+ }
+ c.close();
+ }
+
+ @Test
+ public void test_SSLEngine_beginHandshake_noClientCertificate() throws Exception {
+ TestSSLContext c = TestSSLContext.newBuilder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion).build();
+ SSLEngine[] engines = TestSSLEnginePair.connect(c, null);
+ assertConnected(engines[0], engines[1]);
+ c.close();
+ TestSSLEnginePair.close(engines);
+ }
+
+ @Test
+ public void test_SSLEngine_clientAuth() throws Exception {
+ TestSSLContext c = TestSSLContext.newBuilder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion).build();
+ SSLEngine e = c.clientContext.createSSLEngine();
+
+ assertFalse(e.getWantClientAuth());
+ assertFalse(e.getNeedClientAuth());
+
+ // confirm turning one on by itself
+ e.setWantClientAuth(true);
+ assertTrue(e.getWantClientAuth());
+ assertFalse(e.getNeedClientAuth());
+
+ // confirm turning setting on toggles the other
+ e.setNeedClientAuth(true);
+ assertFalse(e.getWantClientAuth());
+ assertTrue(e.getNeedClientAuth());
+
+ // confirm toggling back
+ e.setWantClientAuth(true);
+ assertTrue(e.getWantClientAuth());
+ assertFalse(e.getNeedClientAuth());
+
+ // TODO Fix KnownFailure "init - invalid private key"
+ TestSSLContext clientAuthContext = new TestSSLContext.Builder()
+ .client(TestKeyStore.getClientCertificate())
+ .server(TestKeyStore.getServer())
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion).build();
+ TestSSLEnginePair p =
+ TestSSLEnginePair.create(clientAuthContext, new TestSSLEnginePair.Hooks() {
+ @Override
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+ server.setWantClientAuth(true);
+ }
+ });
+ assertConnected(p);
+ assertNotNull(p.client.getSession().getLocalCertificates());
+ TestKeyStore.assertChainLength(p.client.getSession().getLocalCertificates());
+ TestSSLContext.assertClientCertificateChain(
+ clientAuthContext.clientTrustManager, p.client.getSession().getLocalCertificates());
+ clientAuthContext.close();
+ c.close();
+ p.close();
+ }
+
+ /**
+ * http://code.google.com/p/android/issues/detail?id=31903
+ * This test case directly tests the fix for the issue.
+ */
+ @Test
+ public void test_SSLEngine_clientAuthWantedNoClientCert() throws Exception {
+ TestSSLContext clientAuthContext = new TestSSLContext.Builder()
+ .client(TestKeyStore.getClient())
+ .server(TestKeyStore.getServer())
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion).build();
+ TestSSLEnginePair p =
+ TestSSLEnginePair.create(clientAuthContext, new TestSSLEnginePair.Hooks() {
+ @Override
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+ server.setWantClientAuth(true);
+ }
+ });
+ assertConnected(p);
+ clientAuthContext.close();
+ p.close();
+ }
+
+ /**
+ * http://code.google.com/p/android/issues/detail?id=31903
+ * This test case verifies that if the server requires a client cert
+ * (setNeedClientAuth) but the client does not provide one SSL connection
+ * establishment will fail
+ */
+ @Test
+ public void test_SSLEngine_clientAuthNeededNoClientCert() throws Exception {
+ TestSSLContext clientAuthContext = new TestSSLContext.Builder()
+ .client(TestKeyStore.getClient())
+ .server(TestKeyStore.getServer())
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion).build();
+ TestSSLEnginePair p = null;
+ try {
+ p = TestSSLEnginePair.create(clientAuthContext, new TestSSLEnginePair.Hooks() {
+ @Override
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+ server.setNeedClientAuth(true);
+ }
+ });
+ fail();
+ } catch (SSLException expected) {
+ // Ignored.
+ } finally {
+ clientAuthContext.close();
+ if (p != null) {
+ p.close();
+ }
+ }
+ }
+
+ @Test
+ public void test_SSLEngine_endpointVerification_Success() throws Exception {
+ TestUtils.assumeSetEndpointIdentificationAlgorithmAvailable();
+ // The default hostname verifier on OpenJDK just rejects all hostnames,
+ // which is not helpful, so replace with a basic functional one.
+ HostnameVerifier oldDefault = HttpsURLConnection.getDefaultHostnameVerifier();
+ HttpsURLConnection.setDefaultHostnameVerifier(new TestHostnameVerifier());
+ try {
+ TestSSLContext c = TestSSLContext.newBuilder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion).build();
+ TestSSLEnginePair p = TestSSLEnginePair.create(c, new TestSSLEnginePair.Hooks() {
+ @Override
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+ SSLParameters p = client.getSSLParameters();
+ p.setEndpointIdentificationAlgorithm("HTTPS");
+ client.setSSLParameters(p);
+ }
+ });
+ assertConnected(p);
+ c.close();
+ } finally {
+ HttpsURLConnection.setDefaultHostnameVerifier(oldDefault);
+ }
+ }
+
+ @Test
+ public void test_TestSSLEnginePair_create() throws Exception {
+ TestSSLEnginePair test = TestSSLEnginePair.create(
+ TestSSLContext.newBuilder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion).build());
+ assertNotNull(test.c);
+ assertNotNull(test.server);
+ assertNotNull(test.client);
+ assertConnected(test);
+ test.close();
+ }
+
+ private final int NUM_STRESS_ITERATIONS = 1000;
+
+ @Test
+ public void test_SSLEngine_Multiple_Thread_Success() throws Exception {
+ final TestSSLEnginePair pair = TestSSLEnginePair.create(
+ TestSSLContext.newBuilder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion).build());
+ try {
+ assertConnected(pair);
+
+ final CountDownLatch startUpSync = new CountDownLatch(2);
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ Future<Void> client = executor.submit(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ startUpSync.countDown();
+
+ for (int i = 0; i < NUM_STRESS_ITERATIONS; i++) {
+ assertSendsCorrectly("This is the client. Hello!".getBytes(UTF_8),
+ pair.client, pair.server, false);
+ }
+
+ return null;
+ }
+ });
+ Future<Void> server = executor.submit(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ startUpSync.countDown();
+
+ for (int i = 0; i < NUM_STRESS_ITERATIONS; i++) {
+ assertSendsCorrectly("This is the server. Hi!".getBytes(UTF_8), pair.server,
+ pair.client, false);
+ }
+
+ return null;
+ }
+ });
+ executor.shutdown();
+ client.get();
+ server.get();
+ } finally {
+ pair.close();
+ }
+ }
+
+ @Test
+ public void test_SSLEngine_CloseOutbound() throws Exception {
+ final TestSSLEnginePair pair = TestSSLEnginePair.create(
+ TestSSLContext.newBuilder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion).build());
+ try {
+ assertConnected(pair);
+
+ // Closing the outbound direction should cause a close_notify to be sent
+ pair.client.closeOutbound();
+ ByteBuffer clientOut = ByteBuffer
+ .allocate(pair.client.getSession().getPacketBufferSize());
+ SSLEngineResult res = pair.client.wrap(ByteBuffer.wrap(new byte[0]), clientOut);
+ assertEquals(Status.CLOSED, res.getStatus());
+ assertEquals(HandshakeStatus.NOT_HANDSHAKING, res.getHandshakeStatus());
+ assertTrue(res.bytesProduced() > 0);
+
+ // Read the close_notify in the server
+ clientOut.flip();
+ ByteBuffer serverIn = ByteBuffer
+ .allocate(pair.server.getSession().getApplicationBufferSize());
+ res = pair.server.unwrap(clientOut, serverIn);
+ assertEquals(Status.CLOSED, res.getStatus());
+ assertEquals(HandshakeStatus.NEED_WRAP, res.getHandshakeStatus());
+
+ // Reading the close_notify should cause a close_notify to be sent back
+ ByteBuffer serverOut = ByteBuffer
+ .allocate(pair.server.getSession().getPacketBufferSize());
+ res = pair.server.wrap(ByteBuffer.wrap(new byte[0]), serverOut);
+ assertEquals(Status.CLOSED, res.getStatus());
+ assertEquals(HandshakeStatus.NOT_HANDSHAKING, res.getHandshakeStatus());
+ assertTrue(res.bytesProduced() > 0);
+
+ // Read the close_notify in the client
+ serverOut.flip();
+ ByteBuffer clientIn = ByteBuffer
+ .allocate(pair.client.getSession().getApplicationBufferSize());
+ res = pair.client.unwrap(serverOut, clientIn);
+ assertEquals(Status.CLOSED, res.getStatus());
+ assertEquals(HandshakeStatus.NOT_HANDSHAKING, res.getHandshakeStatus());
+
+ // Both sides have received close_notify messages, so both peers should have
+ // registered that they're finished
+ assertTrue(pair.client.isInboundDone() && pair.client.isOutboundDone());
+ assertTrue(pair.server.isInboundDone() && pair.server.isOutboundDone());
+ } finally {
+ pair.close();
+ }
+ }
+
+ @Test
+ public void test_SSLEngine_Closed() throws Exception {
+ final TestSSLEnginePair pair = TestSSLEnginePair.create(
+ TestSSLContext.newBuilder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion).build());
+ pair.close();
+ ByteBuffer out = ByteBuffer.allocate(pair.client.getSession().getPacketBufferSize());
+ SSLEngineResult res = pair.client.wrap(ByteBuffer.wrap(new byte[] { 0x01 }), out);
+ assertEquals(Status.CLOSED, res.getStatus());
+ // The engine should have a close_notify alert pending, so it should ignore the
+ // proffered data and push the alert into out
+ assertEquals(0, res.bytesConsumed());
+ assertNotEquals(0, res.bytesProduced());
+
+ res = pair.client.unwrap(ByteBuffer.wrap(new byte[] { 0x01} ), out);
+ assertEquals(Status.CLOSED, res.getStatus());
+ assertEquals(0, res.bytesConsumed());
+ assertEquals(0, res.bytesProduced());
+ }
+
+ @Test
+ public void test_SSLEngine_ClientHello_record_size() throws Exception {
+ // This test checks the size of ClientHello of the default SSLEngine. TLS/SSL handshakes
+ // with older/unpatched F5/BIG-IP appliances are known to stall and time out when
+ // the fragment containing ClientHello is between 256 and 511 (inclusive) bytes long.
+ SSLContext context = SSLContext.getInstance(clientVersion);
+ context.init(null, null, null);
+ SSLEngine e = context.createSSLEngine();
+ e.setUseClientMode(true);
+
+ // Enable SNI extension on the engine (this is typically enabled by default)
+ // to increase the size of ClientHello.
+ Conscrypt.setHostname(e, "sslenginetest.androidcts.google.com");
+
+ // Enable Session Tickets extension on the engine (this is typically enabled
+ // by default) to increase the size of ClientHello.
+ Conscrypt.setUseSessionTickets(e, true);
+
+ TlsRecord firstReceivedTlsRecord = TlsTester.parseRecord(getFirstChunk(e));
+
+ assertEquals("TLS record type", TlsProtocols.HANDSHAKE, firstReceivedTlsRecord.type);
+ HandshakeMessage handshakeMessage = HandshakeMessage.read(
+ new DataInputStream(new ByteArrayInputStream(firstReceivedTlsRecord.fragment)));
+ assertEquals(
+ "HandshakeMessage type", HandshakeMessage.TYPE_CLIENT_HELLO, handshakeMessage.type);
+
+ int fragmentLength = firstReceivedTlsRecord.fragment.length;
+ if ((fragmentLength >= 256) && (fragmentLength <= 511)) {
+ fail("Fragment containing ClientHello is of dangerous length: " + fragmentLength
+ + " bytes");
+ }
+ }
+
+ @Test
+ public void test_SSLEngine_ClientHello_SNI() throws Exception {
+ SSLContext context = SSLContext.getInstance(clientVersion);
+ context.init(null, null, null);
+ SSLEngine e = context.createSSLEngine();
+ e.setUseClientMode(true);
+
+ Conscrypt.setHostname(e, "sslenginetest.androidcts.google.com");
+
+ ClientHello clientHello = TlsTester.parseClientHello(getFirstChunk(e));
+ ServerNameHelloExtension sniExtension =
+ (ServerNameHelloExtension) clientHello.findExtensionByType(
+ HelloExtension.TYPE_SERVER_NAME);
+
+ assertNotNull(sniExtension);
+ assertEquals(Arrays.asList("sslenginetest.androidcts.google.com"), sniExtension.hostnames);
+ }
+
+ @Test
+ public void test_SSLEngine_ClientHello_ALPN() throws Exception {
+ String[] protocolList = new String[] { "h2", "http/1.1" };
+
+ SSLContext context = SSLContext.getInstance(clientVersion);
+ context.init(null, null, null);
+ SSLEngine e = context.createSSLEngine();
+ e.setUseClientMode(true);
+
+ Conscrypt.setApplicationProtocols(e, protocolList);
+
+ ClientHello clientHello = TlsTester.parseClientHello(getFirstChunk(e));
+ AlpnHelloExtension alpnExtension =
+ (AlpnHelloExtension) clientHello.findExtensionByType(
+ HelloExtension.TYPE_APPLICATION_LAYER_PROTOCOL_NEGOTIATION);
+ assertNotNull(alpnExtension);
+ assertEquals(Arrays.asList(protocolList), alpnExtension.protocols);
+ }
+
+ private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);
+
+ private static byte[] getFirstChunk(SSLEngine e) throws SSLException {
+ ByteBuffer out = ByteBuffer.allocate(64 * 1024);
+
+ e.wrap(EMPTY_BUFFER, out);
+ out.flip();
+ byte[] data = new byte[out.limit()];
+ out.get(data);
+
+ return data;
+ }
+
+ @Test
+ public void test_SSLEngine_TlsUnique() throws Exception {
+ // tls_unique isn't supported in TLS 1.3
+ assumeTlsV1_2Connection();
+ TestSSLEnginePair pair = TestSSLEnginePair.create(
+ TestSSLContext.newBuilder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion).build(),
+ new TestSSLEnginePair.Hooks() {
+ @Override
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+ assertNull(Conscrypt.getTlsUnique(client));
+ assertNull(Conscrypt.getTlsUnique(server));
+ }
+ });
+ try {
+ assertConnected(pair);
+
+ byte[] clientTlsUnique = Conscrypt.getTlsUnique(pair.client);
+ byte[] serverTlsUnique = Conscrypt.getTlsUnique(pair.server);
+ assertNotNull(clientTlsUnique);
+ assertNotNull(serverTlsUnique);
+ assertArrayEquals(clientTlsUnique, serverTlsUnique);
+ } finally {
+ pair.close();
+ }
+ }
+
+ @Test
+ public void test_SSLEngine_EKM() throws Exception {
+ TestSSLEnginePair pair = TestSSLEnginePair.create(
+ TestSSLContext.newBuilder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion).build(),
+ new TestSSLEnginePair.Hooks() {
+ @Override
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+ try {
+ assertNull(Conscrypt.exportKeyingMaterial(client, "FOO", null, 20));
+ assertNull(Conscrypt.exportKeyingMaterial(server, "FOO", null, 20));
+ } catch (SSLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ try {
+ assertConnected(pair);
+
+ byte[] clientEkm = Conscrypt.exportKeyingMaterial(pair.client, "FOO", null, 20);
+ byte[] serverEkm = Conscrypt.exportKeyingMaterial(pair.server, "FOO", null, 20);
+ assertNotNull(clientEkm);
+ assertNotNull(serverEkm);
+ assertEquals(20, clientEkm.length);
+ assertEquals(20, serverEkm.length);
+ assertArrayEquals(clientEkm, serverEkm);
+
+ byte[] clientContextEkm = Conscrypt.exportKeyingMaterial(
+ pair.client, "FOO", new byte[0], 20);
+ byte[] serverContextEkm = Conscrypt.exportKeyingMaterial(
+ pair.server, "FOO", new byte[0], 20);
+ assertNotNull(clientContextEkm);
+ assertNotNull(serverContextEkm);
+ assertEquals(20, clientContextEkm.length);
+ assertEquals(20, serverContextEkm.length);
+ assertArrayEquals(clientContextEkm, serverContextEkm);
+
+ // In TLS 1.2, an empty context and a null context are different (RFC 5705, section 4),
+ // but in TLS 1.3 they are the same (RFC 8446, section 7.5).
+ if ("TLSv1.2".equals(negotiatedVersion())) {
+ assertFalse(Arrays.equals(clientEkm, clientContextEkm));
+ } else {
+ assertTrue(Arrays.equals(clientEkm, clientContextEkm));
+ }
+ } finally {
+ pair.close();
+ }
+ }
+
+ // Test whether an exception thrown from within the TrustManager properly flows immediately
+ // to the caller and doesn't get caught and held by the SSLEngine. This was previously
+ // the behavior of Conscrypt, see https://github.com/google/conscrypt/issues/577.
+ @Test
+ public void test_SSLEngine_Exception() throws Exception {
+ final TestSSLContext referenceContext = TestSSLContext.create();
+ class ThrowingTrustManager implements X509TrustManager {
+ public boolean threw = false;
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s)
+ throws CertificateException {
+ }
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s)
+ throws CertificateException {
+ threw = true;
+ throw new CertificateException("Nope!");
+ }
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return referenceContext.clientTrustManager.getAcceptedIssuers();
+ }
+ }
+ ThrowingTrustManager trustManager = new ThrowingTrustManager();
+ final TestSSLContext c = TestSSLContext.newBuilder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .clientTrustManager(trustManager).build();
+
+ // The following code is taken from TestSSLEnginePair.connect()
+ SSLSession session = c.clientContext.createSSLEngine().getSession();
+
+ int packetBufferSize = session.getPacketBufferSize();
+ ByteBuffer clientToServer = ByteBuffer.allocate(packetBufferSize);
+ ByteBuffer serverToClient = ByteBuffer.allocate(packetBufferSize);
+
+ int applicationBufferSize = session.getApplicationBufferSize();
+ ByteBuffer scratch = ByteBuffer.allocate(applicationBufferSize);
+
+ SSLEngine client = c.clientContext.createSSLEngine(c.host.getHostName(), c.port);
+ SSLEngine server = c.serverContext.createSSLEngine();
+ client.setUseClientMode(true);
+ server.setUseClientMode(false);
+ client.beginHandshake();
+ server.beginHandshake();
+
+ try {
+ while (true) {
+ boolean clientDone = client.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING;
+ boolean serverDone = server.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING;
+ if (clientDone && serverDone) {
+ break;
+ }
+
+ boolean progress = TestSSLEnginePair.handshakeStep(client,
+ clientToServer,
+ serverToClient,
+ scratch,
+ new boolean[1]);
+ progress |= TestSSLEnginePair.handshakeStep(server,
+ serverToClient,
+ clientToServer,
+ scratch,
+ new boolean[1]);
+ assertFalse(trustManager.threw);
+ if (!progress) {
+ break;
+ }
+ }
+ fail();
+ } catch (SSLHandshakeException expected) {
+ assertTrue(expected.getCause() instanceof CertificateException);
+ }
+ assertTrue(trustManager.threw);
+ }
+
+ @Test
+ public void sniHandlerFailureResultsInHandshakeError() throws Exception {
+ assumeJava8();
+
+ try {
+ TestSSLEnginePair.create(TestSSLContext.newBuilder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build(),
+ new TestSSLEnginePair.Hooks() {
+ @Override
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+ Conscrypt.setHostname(client, "any.host");
+
+ SSLParameters sslParameters = server.getSSLParameters();
+ sslParameters.setSNIMatchers(singleton(FailingSniMatcher.create()));
+ server.setSSLParameters(sslParameters);
+ }
+ });
+ fail();
+ } catch (SSLHandshakeException e) {
+ assertEquals("SNI match failed: any.host", e.getMessage());
+ }
+ }
+
+ @Test
+ public void sniHandlerIsCalledAfterHandshakeAndBeforeServerCert() throws Exception {
+ assumeJava8();
+
+ final String host = "sni.con-scry.pt";
+
+ final AtomicReference<String> serverHost = new AtomicReference<>();
+ final AtomicBoolean serverAliasCalled = new AtomicBoolean(false);
+
+ TestSSLEnginePair pair = TestSSLEnginePair.create(
+ TestSSLContext.newBuilder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .server(addServerCertListener(new Runnable() {
+ @Override
+ public void run() {
+ assertEquals("cert is loaded after sni", host, serverHost.get());
+ serverAliasCalled.set(true);
+ }
+ }))
+ .build(),
+ new TestSSLEnginePair.Hooks() {
+ @Override
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+ Conscrypt.setHostname(client, host);
+
+ SSLParameters sslParameters = server.getSSLParameters();
+ sslParameters.setSNIMatchers(
+ Collections.<SNIMatcher>singleton(new SNIMatcher(0) {
+ @Override
+ public boolean matches(SNIServerName sniServerName) {
+ String host = ((SNIHostName) sniServerName).getAsciiName();
+ serverHost.set(host);
+ return true;
+ }
+ }));
+ server.setSSLParameters(sslParameters);
+ }
+ });
+
+ ExtendedSSLSession session = (ExtendedSSLSession) pair.server.getSession();
+ assertEquals(Collections.singletonList(new SNIHostName(host)),
+ session.getRequestedServerNames());
+ assertEquals(host, serverHost.get());
+ assertTrue(serverAliasCalled.get());
+ }
+
+ // Splits a ByteArray into an array of ByteBuffers each no bigger than the specified size.
+ private ByteBuffer[] splitDataIntoBuffers(byte[] sourceData, int size) {
+ int nbuf = ((sourceData.length - 1) / size) + 1;
+ ByteBuffer[] buffers = new ByteBuffer[nbuf];
+ int buffer = 0;
+ for (int offset = 0; offset < sourceData.length; offset += size, buffer++) {
+ buffers[buffer] = ByteBuffer.allocate(size);
+ int remaining = sourceData.length - offset;
+ buffers[buffer].put(sourceData, offset, Math.min(remaining, size));
+ buffers[buffer].flip();
+ }
+ return buffers;
+ }
+
+ // Sends dataSize bytes of application data, split into an array of ByteBuffers
+ // of size bufferSize and verifies it arrives intact. If offset is non-zero then
+ // additional invalid buffers will be added to the start and end of the buffer array
+ // in order to test the offset and length arguments of wrap().
+ private void sendAppDataInMultipleBuffers(
+ SSLEngine src, SSLEngine dst, int dataSize, int bufferSize) throws SSLException {
+ // Generate random data and split into multiple.
+ byte[] sourceData = new byte[dataSize];
+ Random random = new Random(System.currentTimeMillis());
+ random.nextBytes(sourceData);
+ ByteBuffer[] sourceBuffers = splitDataIntoBuffers(sourceData, bufferSize);
+ int length = sourceBuffers.length;
+
+ // Ensure there is no pending outbound data or encrypted data and handshaking is complete.
+ ByteBuffer tlsBuffer = ByteBuffer.allocateDirect(src.getSession().getPacketBufferSize());
+ SSLEngineResult result = src.wrap(EMPTY_BUFFER, tlsBuffer);
+ assertEquals(Status.OK, result.getStatus());
+ assertEquals(HandshakeStatus.NOT_HANDSHAKING, result.getHandshakeStatus());
+ assertEquals(0, result.bytesConsumed());
+ assertEquals(0, result.bytesProduced());
+
+ // Ensure there is no pending inbound data
+ result = dst.unwrap(EMPTY_BUFFER, tlsBuffer);
+ assertEquals(Status.BUFFER_UNDERFLOW, result.getStatus());
+ assertEquals(0, result.bytesConsumed());
+ assertEquals(0, result.bytesProduced());
+
+ // Send the data. wrap() should consume as many source buffers as needed but
+ // never generate more than one full packet buffer of TLS data, and so unwrap()
+ // should only be needed once per loop iteration.
+ int consumed = 0, produced = 0;
+ ByteBuffer destBuffer = ByteBuffer.allocate(dataSize);
+ while (consumed < dataSize) {
+ String message =
+ String.format("sendData: dataSize=%d, bufSize=%d", dataSize, bufferSize);
+
+ tlsBuffer.clear();
+ result = src.wrap(sourceBuffers, 0, length, tlsBuffer);
+ assertEquals(message, Status.OK, result.getStatus());
+ consumed += result.bytesConsumed();
+
+ tlsBuffer.flip();
+ result = dst.unwrap(tlsBuffer, destBuffer);
+ assertEquals(message, Status.OK, result.getStatus());
+ produced += result.bytesProduced();
+ }
+ assertEquals(dataSize, consumed);
+ assertEquals(dataSize, produced);
+
+ // Compare source and destination data.
+ destBuffer.flip();
+ // destBuffer is non-direct so will always have a backing array
+ assertArrayEquals(sourceData, destBuffer.array());
+ }
+
+ /**
+ * Tests the multiple {@link ByteBuffer} cases of {@code wrap())} by sending blocks of
+ * application data split into arrays of ByteBuffers of different sizes.
+ *
+ * The main intention is to check that regardless of how the data is structured in
+ * buffers, each call to wrap() always generates a single TLS record that is smaller
+ * than the maximum allowed size, see https://github.com/google/conscrypt/issues/929
+ */
+ @Test
+ public void multipleBuffersOfDifferentSizes() throws Exception {
+ TestSSLEnginePair pair = TestSSLEnginePair.create();
+ SSLSession session = pair.client.getSession();
+ int appBufSize = session.getApplicationBufferSize();
+
+ int[] dataSizes = new int[] {12, 512, 555, 1500, 8192, appBufSize, 5 * appBufSize};
+ int[] bufferSizes = new int[] {
+ 53, 512, 8192, appBufSize, appBufSize - 53, appBufSize + 53, 5 * appBufSize};
+ for (int dataSize : dataSizes) {
+ for (int bufSize : bufferSizes) {
+ sendAppDataInMultipleBuffers(pair.client, pair.server, dataSize, bufSize);
+ sendAppDataInMultipleBuffers(pair.server, pair.client, dataSize, bufSize);
+ sendAppDataInMultipleBuffers(pair.client, pair.server, dataSize, bufSize);
+ sendAppDataInMultipleBuffers(pair.server, pair.client, dataSize, bufSize);
+ }
+ }
+ }
+
+ private TestKeyStore addServerCertListener(final Runnable callback) {
+ TestKeyStore store = TestKeyStore.getServer().copy();
+ X509ExtendedKeyManager tm = new ForwardingX509ExtendedKeyManager(
+ (X509ExtendedKeyManager) store.keyManagers[0]) {
+ @Override
+ public String chooseEngineServerAlias(
+ String keyType, Principal[] issuers, SSLEngine engine) {
+ callback.run();
+ return super.chooseEngineServerAlias(keyType, issuers, engine);
+ }
+ };
+ store.keyManagers[0] = tm;
+ return store;
+ }
+
+ private void assertConnected(TestSSLEnginePair e) {
+ assertConnected(e.client, e.server);
+ }
+
+ private void assertConnected(SSLEngine a, SSLEngine b) {
+ assertTrue(connected(a, b));
+ }
+
+ private boolean connected(SSLEngine a, SSLEngine b) {
+ return (a.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING
+ && b.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING
+ && a.getSession() != null && b.getSession() != null && !a.isInboundDone()
+ && !b.isInboundDone() && !a.isOutboundDone() && !b.isOutboundDone());
+ }
+
+ // Assumes that the negotiated connection will be TLS 1.2
+ private void assumeTlsV1_2Connection() {
+ assumeTrue("TLSv1.2".equals(negotiatedVersion()));
+ }
+
+ /**
+ * Returns the version that a connection between {@code clientVersion} and
+ * {@code serverVersion} should produce.
+ */
+ private String negotiatedVersion() {
+ if (clientVersion.equals("TLSv1.3") && serverVersion.equals("TLSv1.3")) {
+ return "TLSv1.3";
+ } else {
+ return "TLSv1.2";
+ }
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLParametersTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLParametersTest.java
new file mode 100644
index 0000000..93cb054
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLParametersTest.java
@@ -0,0 +1,241 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIMatcher;
+import javax.net.ssl.SNIServerName;
+import javax.net.ssl.SSLParameters;
+import com.android.org.conscrypt.TestUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class SSLParametersTest {
+ @Test
+ public void test_SSLParameters_emptyConstructor() {
+ SSLParameters p = new SSLParameters();
+ assertNull(p.getCipherSuites());
+ assertNull(p.getProtocols());
+ assertFalse(p.getWantClientAuth());
+ assertFalse(p.getNeedClientAuth());
+ }
+
+ @Test
+ public void test_SSLParameters_cipherSuitesConstructor() {
+ String[] cipherSuites = new String[] {"foo", null, "bar"};
+ SSLParameters p = new SSLParameters(cipherSuites);
+ assertNotNull(p.getCipherSuites());
+ assertNotSame(cipherSuites, p.getCipherSuites());
+ assertEquals(Arrays.asList(cipherSuites), Arrays.asList(p.getCipherSuites()));
+ assertNull(p.getProtocols());
+ assertFalse(p.getWantClientAuth());
+ assertFalse(p.getNeedClientAuth());
+ }
+
+ @Test
+ public void test_SSLParameters_cpherSuitesProtocolsConstructor() {
+ String[] cipherSuites = new String[] {"foo", null, "bar"};
+ String[] protocols = new String[] {"baz", null, "qux"};
+ SSLParameters p = new SSLParameters(cipherSuites, protocols);
+ assertNotNull(p.getCipherSuites());
+ assertNotNull(p.getProtocols());
+ assertNotSame(cipherSuites, p.getCipherSuites());
+ assertNotSame(protocols, p.getProtocols());
+ assertEquals(Arrays.asList(cipherSuites), Arrays.asList(p.getCipherSuites()));
+ assertEquals(Arrays.asList(protocols), Arrays.asList(p.getProtocols()));
+ assertFalse(p.getWantClientAuth());
+ assertFalse(p.getNeedClientAuth());
+ }
+
+ @Test
+ public void test_SSLParameters_CipherSuites() {
+ SSLParameters p = new SSLParameters();
+ assertNull(p.getCipherSuites());
+
+ // confirm clone on input
+ String[] cipherSuites = new String[] {"fnord"};
+ String[] copy = cipherSuites.clone();
+ p.setCipherSuites(copy);
+ copy[0] = null;
+ assertEquals(Arrays.asList(cipherSuites), Arrays.asList(p.getCipherSuites()));
+
+ // confirm clone on output
+ assertNotSame(p.getCipherSuites(), p.getCipherSuites());
+ }
+
+ @Test
+ public void test_SSLParameters_Protocols() {
+ SSLParameters p = new SSLParameters();
+ assertNull(p.getProtocols());
+
+ // confirm clone on input
+ String[] protocols = new String[] {"fnord"};
+ String[] copy = protocols.clone();
+ p.setProtocols(copy);
+ copy[0] = null;
+ assertEquals(Arrays.asList(protocols), Arrays.asList(p.getProtocols()));
+
+ // confirm clone on output
+ assertNotSame(p.getProtocols(), p.getProtocols());
+ }
+
+ @Test
+ public void test_SSLParameters_ClientAuth() {
+ SSLParameters p = new SSLParameters();
+ assertFalse(p.getWantClientAuth());
+ assertFalse(p.getNeedClientAuth());
+
+ // confirm turning one on by itself
+ p.setWantClientAuth(true);
+ assertTrue(p.getWantClientAuth());
+ assertFalse(p.getNeedClientAuth());
+
+ // confirm turning setting on toggles the other
+ p.setNeedClientAuth(true);
+ assertFalse(p.getWantClientAuth());
+ assertTrue(p.getNeedClientAuth());
+
+ // confirm toggling back
+ p.setWantClientAuth(true);
+ assertTrue(p.getWantClientAuth());
+ assertFalse(p.getNeedClientAuth());
+ }
+
+ @Test
+ public void test_SSLParameters_setServerNames_duplicatedNameThrows() throws Exception {
+ TestUtils.assumeSNIHostnameAvailable();
+
+ SSLParameters p = new SSLParameters();
+ ArrayList<SNIServerName> dupeNames = new ArrayList<SNIServerName>();
+ dupeNames.add(new SNIHostName("www.example.com"));
+ dupeNames.add(new SNIHostName("www.example.com"));
+ try {
+ p.setServerNames(dupeNames);
+ fail("Should throw IllegalArgumentException when names are duplicated");
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ }
+
+ @Test
+ public void test_SSLParameters_setServerNames_setNull_getNull() throws Exception {
+ TestUtils.assumeSNIHostnameAvailable();
+ SSLParameters p = new SSLParameters();
+ p.setServerNames(
+ Collections.singletonList((SNIServerName) new SNIHostName("www.example.com")));
+ assertNotNull(p.getServerNames());
+ p.setServerNames(null);
+ assertNull(p.getServerNames());
+ }
+
+ @Test
+ public void test_SSLParameters_setServerNames_setEmpty_getEmpty() throws Exception {
+ TestUtils.assumeSNIHostnameAvailable();
+ SSLParameters p = new SSLParameters();
+ p.setServerNames(new ArrayList<SNIServerName>());
+ Collection<SNIServerName> actual = p.getServerNames();
+ assertNotNull(actual);
+ assertEquals(0, actual.size());
+ }
+
+ @Test
+ public void test_SSLParameters_getServerNames_unmodifiable() throws Exception {
+ TestUtils.assumeSNIHostnameAvailable();
+ SSLParameters p = new SSLParameters();
+ p.setServerNames(
+ Collections.singletonList((SNIServerName) new SNIHostName("www.example.com")));
+ Collection<SNIServerName> actual = p.getServerNames();
+ try {
+ actual.add(new SNIHostName("www.foo.com"));
+ fail("Should not allow modifications to the list");
+ } catch (UnsupportedOperationException expected) {
+ // Ignored.
+ }
+ }
+
+ @Test
+ public void test_SSLParameters_setSNIMatchers_duplicatedNameThrows() throws Exception {
+ TestUtils.assumeSNIHostnameAvailable();
+ SSLParameters p = new SSLParameters();
+ ArrayList<SNIMatcher> dupeMatchers = new ArrayList<SNIMatcher>();
+ dupeMatchers.add(SNIHostName.createSNIMatcher("www\\.example\\.com"));
+ dupeMatchers.add(SNIHostName.createSNIMatcher("www\\.example\\.com"));
+ try {
+ p.setSNIMatchers(dupeMatchers);
+ fail("Should throw IllegalArgumentException when matchers are duplicated");
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ }
+
+ @Test
+ public void test_SSLParameters_setSNIMatchers_setNull_getNull() throws Exception {
+ TestUtils.assumeSNIHostnameAvailable();
+ SSLParameters p = new SSLParameters();
+ p.setSNIMatchers(
+ Collections.singletonList(SNIHostName.createSNIMatcher("www\\.example\\.com")));
+ assertNotNull(p.getSNIMatchers());
+ p.setSNIMatchers(null);
+ assertNull(p.getSNIMatchers());
+ }
+
+ @Test
+ public void test_SSLParameters_setSNIMatchers_setEmpty_getEmpty() throws Exception {
+ TestUtils.assumeSNIHostnameAvailable();
+ SSLParameters p = new SSLParameters();
+ p.setSNIMatchers(
+ Collections.singletonList(SNIHostName.createSNIMatcher("www\\.example\\.com")));
+ assertEquals(1, p.getSNIMatchers().size());
+ p.setSNIMatchers(Collections.<SNIMatcher>emptyList());
+ Collection<SNIMatcher> actual = p.getSNIMatchers();
+ assertNotNull(actual);
+ assertEquals(0, actual.size());
+ }
+
+ @Test
+ public void test_SSLParameters_getSNIMatchers_unmodifiable() throws Exception {
+ TestUtils.assumeSNIHostnameAvailable();
+ SSLParameters p = new SSLParameters();
+ p.setSNIMatchers(
+ Collections.singletonList(SNIHostName.createSNIMatcher("www\\.example\\.com")));
+ Collection<SNIMatcher> actual = p.getSNIMatchers();
+ try {
+ actual.add(SNIHostName.createSNIMatcher("www\\.google\\.com"));
+ fail("Should not allow modification of list");
+ } catch (UnsupportedOperationException expected) {
+ // Ignored.
+ }
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLServerSocketFactoryTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLServerSocketFactoryTest.java
new file mode 100644
index 0000000..debf19c
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLServerSocketFactoryTest.java
@@ -0,0 +1,36 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2013 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import javax.net.ssl.SSLServerSocketFactory;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class SSLServerSocketFactoryTest {
+
+ @Test
+ public void testDefaultConfiguration() throws Exception {
+ SSLConfigurationAsserts.assertSSLServerSocketFactoryDefaultConfiguration(
+ (SSLServerSocketFactory) SSLServerSocketFactory.getDefault());
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLServerSocketTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLServerSocketTest.java
new file mode 100644
index 0000000..55244a9
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLServerSocketTest.java
@@ -0,0 +1,131 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2013 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import com.android.org.conscrypt.TestUtils;
+import com.android.org.conscrypt.java.security.StandardNames;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class SSLServerSocketTest {
+
+ @Test
+ public void testDefaultConfiguration() throws Exception {
+ SSLConfigurationAsserts.assertSSLServerSocketDefaultConfiguration(
+ (SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket());
+ }
+
+ @Test
+ public void testSetEnabledCipherSuitesAffectsGetter_TLS12() throws Exception {
+ SSLContext context = SSLContext.getInstance("TLSv1.2");
+ context.init(null, null, null);
+ SSLServerSocket socket =
+ (SSLServerSocket) context.getServerSocketFactory().createServerSocket();
+ String[] cipherSuites = new String[] {
+ TestUtils.pickArbitraryNonTls13Suite(socket.getSupportedCipherSuites())
+ };
+ socket.setEnabledCipherSuites(cipherSuites);
+ assertEquals(Arrays.asList(cipherSuites), Arrays.asList(socket.getEnabledCipherSuites()));
+ }
+
+ @Test
+ public void testSetEnabledCipherSuitesAffectsGetter_TLS13() throws Exception {
+ SSLServerSocket socket =
+ (SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket();
+ String[] cipherSuites = new String[] {
+ TestUtils.pickArbitraryNonTls13Suite(socket.getSupportedCipherSuites())
+ };
+ socket.setEnabledCipherSuites(cipherSuites);
+ List<String> expected = new ArrayList<String>(StandardNames.CIPHER_SUITES_TLS13);
+ expected.addAll(Arrays.asList(cipherSuites));
+ assertEquals(expected, Arrays.asList(socket.getEnabledCipherSuites()));
+ }
+
+ @Test
+ public void testSetEnabledCipherSuitesStoresCopy() throws Exception {
+ SSLServerSocket socket =
+ (SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket();
+ String[] array = new String[] {socket.getEnabledCipherSuites()[0]};
+ String originalFirstElement = array[0];
+ socket.setEnabledCipherSuites(array);
+ array[0] = "Modified after having been set";
+ assertEquals(originalFirstElement, socket.getEnabledCipherSuites()[0]);
+ }
+
+ @Test
+ public void testSetEnabledProtocolsAffectsGetter() throws Exception {
+ SSLServerSocket socket =
+ (SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket();
+ String[] protocols = new String[] {socket.getSupportedProtocols()[0]};
+ socket.setEnabledProtocols(protocols);
+ assertEquals(Arrays.asList(protocols), Arrays.asList(socket.getEnabledProtocols()));
+ }
+
+ @Test
+ public void testSetEnabledProtocolsStoresCopy() throws Exception {
+ SSLServerSocket socket =
+ (SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket();
+ String[] array = new String[] {socket.getEnabledProtocols()[0]};
+ String originalFirstElement = array[0];
+ socket.setEnabledProtocols(array);
+ array[0] = "Modified after having been set";
+ assertEquals(originalFirstElement, socket.getEnabledProtocols()[0]);
+ }
+
+ @Test
+ public void test_SSLSocket_setEnabledCipherSuites_TLS13() throws Exception {
+ SSLContext context = SSLContext.getInstance("TLSv1.3");
+ context.init(null, null, null);
+ SSLServerSocketFactory sf = context.getServerSocketFactory();
+ SSLServerSocket ssl = (SSLServerSocket) sf.createServerSocket();
+ // The TLS 1.3 cipher suites should be enabled by default
+ assertTrue(new HashSet<String>(Arrays.asList(ssl.getEnabledCipherSuites()))
+ .containsAll(StandardNames.CIPHER_SUITES_TLS13));
+ // Disabling them should be ignored
+ ssl.setEnabledCipherSuites(new String[0]);
+ assertTrue(new HashSet<String>(Arrays.asList(ssl.getEnabledCipherSuites()))
+ .containsAll(StandardNames.CIPHER_SUITES_TLS13));
+
+ ssl.setEnabledCipherSuites(new String[] {
+ TestUtils.pickArbitraryNonTls13Suite(ssl.getSupportedCipherSuites())
+ });
+ assertTrue(new HashSet<String>(Arrays.asList(ssl.getEnabledCipherSuites()))
+ .containsAll(StandardNames.CIPHER_SUITES_TLS13));
+
+ // Disabling TLS 1.3 should disable 1.3 cipher suites
+ ssl.setEnabledProtocols(new String[] { "TLSv1.2" });
+ assertFalse(new HashSet<String>(Arrays.asList(ssl.getEnabledCipherSuites()))
+ .containsAll(StandardNames.CIPHER_SUITES_TLS13));
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSessionContextTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSessionContextTest.java
new file mode 100644
index 0000000..19a6bee
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSessionContextTest.java
@@ -0,0 +1,420 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static com.android.org.conscrypt.Conscrypt.isConscrypt;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.SSLSocket;
+import com.android.org.conscrypt.TestUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(Parameterized.class)
+public class SSLSessionContextTest {
+
+ @Parameterized.Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ // We can't support TLS 1.3 without our own trust manager (which requires
+ // X509ExtendedTrustManager), so only test TLS 1.2 if it's not available.
+ if (TestUtils.isClassAvailable("javax.net.ssl.X509ExtendedTrustManager")) {
+ return Arrays.asList("TLSv1.2", "TLSv1.3");
+ } else {
+ return Arrays.asList("TLSv1.2");
+ }
+ }
+
+ private final String protocol;
+
+ public SSLSessionContextTest(String protocol) {
+ this.protocol = protocol;
+ }
+
+ private TestSSLContext newTestContext() {
+ return TestSSLContext.newBuilder()
+ .clientProtocol(protocol).serverProtocol(protocol).build();
+ }
+
+ private boolean isTls13() {
+ return "TLSv1.3".equals(protocol);
+ }
+
+ @Test
+ @SuppressWarnings("JdkObsolete") // Public API SSLSessionContext.getIds() uses Enumeration
+ public void test_SSLSessionContext_getIds() {
+ TestSSLContext c = newTestContext();
+ assertSSLSessionContextSize(0, c);
+ c.close();
+
+ TestSSLSocketPair s = TestSSLSocketPair.create(newTestContext()).connect();
+ if (isTls13()) {
+ assertSSLSessionContextSizeAtLeast(1, s.c);
+ } else {
+ assertSSLSessionContextSize(1, s.c);
+ }
+ Enumeration<byte[]> clientIds = s.c.clientContext.getClientSessionContext().getIds();
+ Enumeration<byte[]> serverIds = s.c.serverContext.getServerSessionContext().getIds();
+ byte[] clientId = clientIds.nextElement();
+ assertEquals(32, clientId.length);
+ if (TestSSLContext.sslServerSocketSupportsSessionTickets()) {
+ assertFalse(serverIds.hasMoreElements());
+ } else {
+ byte[] serverId = serverIds.nextElement();
+ assertEquals(32, serverId.length);
+ assertTrue(Arrays.equals(clientId, serverId));
+ }
+ s.close();
+ }
+
+ @Test
+ @SuppressWarnings("JdkObsolete") // Public API SSLSessionContext.getIds() uses Enumeration
+ public void test_SSLSessionContext_getSession() {
+ TestSSLContext c = newTestContext();
+ try {
+ c.clientContext.getClientSessionContext().getSession(null);
+ fail();
+ } catch (NullPointerException expected) {
+ // Ignored.
+ }
+ assertNull(c.clientContext.getClientSessionContext().getSession(new byte[0]));
+ assertNull(c.clientContext.getClientSessionContext().getSession(new byte[1]));
+ try {
+ c.serverContext.getServerSessionContext().getSession(null);
+ fail();
+ } catch (NullPointerException expected) {
+ // Ignored.
+ }
+ assertNull(c.serverContext.getServerSessionContext().getSession(new byte[0]));
+ assertNull(c.serverContext.getServerSessionContext().getSession(new byte[1]));
+ c.close();
+
+ TestSSLSocketPair s = TestSSLSocketPair.create(newTestContext()).connect();
+ SSLSessionContext client = s.c.clientContext.getClientSessionContext();
+ SSLSessionContext server = s.c.serverContext.getServerSessionContext();
+ byte[] clientId = client.getIds().nextElement();
+ assertNotNull(client.getSession(clientId));
+ assertTrue(Arrays.equals(clientId, client.getSession(clientId).getId()));
+ if (TestSSLContext.sslServerSocketSupportsSessionTickets()) {
+ assertFalse(server.getIds().hasMoreElements());
+ } else {
+ byte[] serverId = server.getIds().nextElement();
+ assertNotNull(server.getSession(serverId));
+ assertTrue(Arrays.equals(serverId, server.getSession(serverId).getId()));
+ }
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSessionContext_getSessionCacheSize() {
+ TestSSLContext c = newTestContext();
+ int expectedClientSessionCacheSize = expectedClientSslSessionCacheSize(c);
+ int expectedServerSessionCacheSize = expectedServerSslSessionCacheSize(c);
+ assertEquals(expectedClientSessionCacheSize,
+ c.clientContext.getClientSessionContext().getSessionCacheSize());
+ assertEquals(expectedServerSessionCacheSize,
+ c.serverContext.getServerSessionContext().getSessionCacheSize());
+ c.close();
+
+ TestSSLSocketPair s = TestSSLSocketPair.create(newTestContext()).connect();
+ assertEquals(expectedClientSessionCacheSize,
+ s.c.clientContext.getClientSessionContext().getSessionCacheSize());
+ assertEquals(expectedServerSessionCacheSize,
+ s.c.serverContext.getServerSessionContext().getSessionCacheSize());
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSessionContext_setSessionCacheSize_noConnect() {
+ TestSSLContext c = newTestContext();
+ int expectedClientSessionCacheSize = expectedClientSslSessionCacheSize(c);
+ int expectedServerSessionCacheSize = expectedServerSslSessionCacheSize(c);
+ assertNoConnectSetSessionCacheSizeBehavior(
+ expectedClientSessionCacheSize, c.clientContext.getClientSessionContext());
+ assertNoConnectSetSessionCacheSizeBehavior(
+ expectedServerSessionCacheSize, c.serverContext.getServerSessionContext());
+ c.close();
+ }
+
+ private static void assertNoConnectSetSessionCacheSizeBehavior(
+ int expectedDefault, SSLSessionContext s) {
+ try {
+ s.setSessionCacheSize(-1);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ assertEquals(expectedDefault, s.getSessionCacheSize());
+ s.setSessionCacheSize(1);
+ assertEquals(1, s.getSessionCacheSize());
+ }
+
+ @Test
+ public void test_SSLSessionContext_setSessionCacheSize_oneConnect() {
+ TestSSLSocketPair s = TestSSLSocketPair.create(newTestContext()).connect();
+ int expectedClientSessionCacheSize = expectedClientSslSessionCacheSize(s.c);
+ int expectedServerSessionCacheSize = expectedServerSslSessionCacheSize(s.c);
+ SSLSessionContext client = s.c.clientContext.getClientSessionContext();
+ SSLSessionContext server = s.c.serverContext.getServerSessionContext();
+ assertEquals(expectedClientSessionCacheSize, client.getSessionCacheSize());
+ assertEquals(expectedServerSessionCacheSize, server.getSessionCacheSize());
+ if (isTls13()) {
+ assertSSLSessionContextSizeAtLeast(1, s.c);
+ } else {
+ assertSSLSessionContextSize(1, s.c);
+ }
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSessionContext_setSessionCacheSize_dynamic() throws Exception {
+ TestSSLContext c = newTestContext();
+ SSLSessionContext client = c.clientContext.getClientSessionContext();
+ SSLSessionContext server = c.serverContext.getServerSessionContext();
+
+ String[] supportedCipherSuites = c.serverSocket.getSupportedCipherSuites();
+ c.serverSocket.setEnabledCipherSuites(supportedCipherSuites);
+ Deque<String> uniqueCipherSuites =
+ new ArrayDeque<String>(Arrays.asList(supportedCipherSuites));
+ // only use RSA cipher suites which will work with our TrustProvider
+ Iterator<String> i = uniqueCipherSuites.iterator();
+ while (i.hasNext()) {
+ String cipherSuite = i.next();
+
+ // Certificate key length too long for export ciphers
+ if (cipherSuite.startsWith("SSL_RSA_EXPORT_")) {
+ i.remove();
+ continue;
+ }
+
+ if (cipherSuite.startsWith("SSL_RSA_")) {
+ continue;
+ }
+ if (cipherSuite.startsWith("TLS_RSA_")) {
+ continue;
+ }
+ if (cipherSuite.startsWith("TLS_DHE_RSA_")) {
+ continue;
+ }
+ if (cipherSuite.startsWith("SSL_DHE_RSA_")) {
+ continue;
+ }
+ i.remove();
+ }
+
+ /*
+ * having more than 3 uniqueCipherSuites is a test
+ * requirement, not a requirement of the interface or
+ * implementation. It simply allows us to make sure that we
+ * will not get a cached session ID since we'll have to
+ * renegotiate a new session due to the new cipher suite
+ * requirement. even this test only really needs three if it
+ * reused the unique cipher suites every time it resets the
+ * session cache.
+ */
+ assertTrue(uniqueCipherSuites.size() >= 3);
+ String cipherSuite1 = uniqueCipherSuites.pop();
+ String cipherSuite2 = uniqueCipherSuites.pop();
+ String cipherSuite3 = uniqueCipherSuites.pop();
+
+ List<SSLSocket[]> toClose = new ArrayList<SSLSocket[]>();
+ toClose.add(
+ TestSSLSocketPair.create(c).connect(new String[] {cipherSuite1}, null).sockets());
+ if (isTls13()) {
+ assertSSLSessionContextSizeAtLeast(1, c);
+ } else {
+ assertSSLSessionContextSize(1, c);
+ }
+ toClose.add(
+ TestSSLSocketPair.create(c).connect(new String[] {cipherSuite2}, null).sockets());
+ if (isTls13()) {
+ assertSSLSessionContextSizeAtLeast(2, c);
+ } else {
+ assertSSLSessionContextSize(2, c);
+ }
+ toClose.add(
+ TestSSLSocketPair.create(c).connect(new String[] {cipherSuite3}, null).sockets());
+ if (isTls13()) {
+ assertSSLSessionContextSizeAtLeast(3, c);
+ } else {
+ assertSSLSessionContextSize(3, c);
+ }
+
+ client.setSessionCacheSize(1);
+ server.setSessionCacheSize(1);
+ assertEquals(1, client.getSessionCacheSize());
+ assertEquals(1, server.getSessionCacheSize());
+ assertSSLSessionContextSize(1, c);
+ toClose.add(
+ TestSSLSocketPair.create(c).connect(new String[] {cipherSuite1}, null).sockets());
+ assertSSLSessionContextSize(1, c);
+
+ client.setSessionCacheSize(2);
+ server.setSessionCacheSize(2);
+ toClose.add(
+ TestSSLSocketPair.create(c).connect(new String[] {cipherSuite2}, null).sockets());
+ assertSSLSessionContextSize(2, c);
+ toClose.add(
+ TestSSLSocketPair.create(c).connect(new String[] {cipherSuite3}, null).sockets());
+ assertSSLSessionContextSize(2, c);
+
+ for (SSLSocket[] pair : toClose) {
+ for (SSLSocket s : pair) {
+ s.close();
+ }
+ }
+ c.close();
+ }
+
+ @Test
+ public void test_SSLSessionContext_getSessionTimeout() {
+ TestSSLContext c = newTestContext();
+ int expectedCacheTimeout = expectedSslSessionCacheTimeout(c);
+ assertEquals(expectedCacheTimeout,
+ c.clientContext.getClientSessionContext().getSessionTimeout());
+ assertEquals(expectedCacheTimeout,
+ c.serverContext.getServerSessionContext().getSessionTimeout());
+ c.close();
+
+ TestSSLSocketPair s = TestSSLSocketPair.create(newTestContext()).connect();
+ assertEquals(expectedCacheTimeout,
+ s.c.clientContext.getClientSessionContext().getSessionTimeout());
+ assertEquals(expectedCacheTimeout,
+ s.c.serverContext.getServerSessionContext().getSessionTimeout());
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSessionContext_setSessionTimeout() throws Exception {
+ TestSSLContext c = newTestContext();
+ int expectedCacheTimeout = expectedSslSessionCacheTimeout(c);
+ assertEquals(expectedCacheTimeout,
+ c.clientContext.getClientSessionContext().getSessionTimeout());
+ assertEquals(expectedCacheTimeout,
+ c.serverContext.getServerSessionContext().getSessionTimeout());
+ c.clientContext.getClientSessionContext().setSessionTimeout(0);
+ c.serverContext.getServerSessionContext().setSessionTimeout(0);
+ assertEquals(0, c.clientContext.getClientSessionContext().getSessionTimeout());
+ assertEquals(0, c.serverContext.getServerSessionContext().getSessionTimeout());
+
+ try {
+ c.clientContext.getClientSessionContext().setSessionTimeout(-1);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ try {
+ c.serverContext.getServerSessionContext().setSessionTimeout(-1);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ c.close();
+
+ TestSSLSocketPair s = TestSSLSocketPair.create(newTestContext()).connect();
+ if (isTls13()) {
+ assertSSLSessionContextSizeAtLeast(1, s.c);
+ } else {
+ assertSSLSessionContextSize(1, s.c);
+ }
+ Thread.sleep(1000);
+ s.c.clientContext.getClientSessionContext().setSessionTimeout(1);
+ s.c.serverContext.getServerSessionContext().setSessionTimeout(1);
+ assertSSLSessionContextSize(0, s.c);
+ s.close();
+ }
+
+ private static void assertSSLSessionContextSize(int expected, TestSSLContext c) {
+ assertSSLSessionContextSize(expected, c.clientContext.getClientSessionContext(),
+ c.serverContext.getServerSessionContext());
+ assertSSLSessionContextSize(0, c.serverContext.getClientSessionContext(),
+ c.clientContext.getServerSessionContext());
+ }
+
+ private static void assertSSLSessionContextSize(
+ int expected, SSLSessionContext client, SSLSessionContext server) {
+ assertSSLSessionContextSize(expected, client, false);
+ assertSSLSessionContextSize(expected, server, true);
+ }
+
+ private static void assertSSLSessionContextSize(
+ int expected, SSLSessionContext s, boolean server) {
+ if (server && TestSSLContext.sslServerSocketSupportsSessionTickets()) {
+ assertEquals(0, numSessions(s));
+ } else {
+ assertEquals(expected, numSessions(s));
+ }
+ }
+
+ private static void assertSSLSessionContextSizeAtLeast(int expected, TestSSLContext c) {
+ assertSSLSessionContextSizeAtLeast(expected, c.clientContext.getClientSessionContext(),
+ c.serverContext.getServerSessionContext());
+ assertSSLSessionContextSizeAtLeast(0, c.serverContext.getClientSessionContext(),
+ c.clientContext.getServerSessionContext());
+ }
+
+ private static void assertSSLSessionContextSizeAtLeast(
+ int expected, SSLSessionContext client, SSLSessionContext server) {
+ assertSSLSessionContextSizeAtLeast(expected, client, false);
+ assertSSLSessionContextSizeAtLeast(expected, server, true);
+ }
+
+ private static void assertSSLSessionContextSizeAtLeast(
+ int expected, SSLSessionContext s, boolean server) {
+ if (server && TestSSLContext.sslServerSocketSupportsSessionTickets()) {
+ assertEquals(0, numSessions(s));
+ } else {
+ assertTrue("numSessions: " + numSessions(s) + ", expected at least: " + expected,
+ numSessions(s) >= expected);
+ }
+ }
+
+ private int expectedClientSslSessionCacheSize(TestSSLContext c) {
+ return isConscrypt(c.clientContext.getProvider()) ? 10 : 0;
+ }
+
+ private int expectedServerSslSessionCacheSize(TestSSLContext c) {
+ return isConscrypt(c.serverContext.getProvider()) ? 100 : 0;
+ }
+
+ private int expectedSslSessionCacheTimeout(TestSSLContext c) {
+ return isConscrypt(c.serverContext.getProvider()) ? 8 * 3600 : 24 * 3600;
+ }
+
+ private static int numSessions(SSLSessionContext s) {
+ return Collections.list(s.getIds()).size();
+ }
+
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSessionTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSessionTest.java
new file mode 100644
index 0000000..f80dea4
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSessionTest.java
@@ -0,0 +1,541 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.util.Arrays;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionBindingEvent;
+import javax.net.ssl.SSLSessionBindingListener;
+import javax.net.ssl.SSLSocket;
+import com.android.org.conscrypt.TestUtils;
+import com.android.org.conscrypt.java.security.StandardNames;
+import com.android.org.conscrypt.java.security.TestKeyStore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class SSLSessionTest {
+ @Test
+ public void test_SSLSocket_TestSSLSessions_create() {
+ TestSSLSessions s = TestSSLSessions.create();
+ assertNotNull(s.invalid);
+ assertFalse(s.invalid.isValid());
+ assertTrue(s.server.isValid());
+ assertTrue(s.client.isValid());
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_getApplicationBufferSize() {
+ TestSSLSessions s = TestSSLSessions.create();
+ assertTrue(s.invalid.getApplicationBufferSize() > 0);
+ assertTrue(s.server.getApplicationBufferSize() > 0);
+ assertTrue(s.client.getApplicationBufferSize() > 0);
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_getCipherSuite() {
+ TestSSLSessions s = TestSSLSessions.create();
+ assertNotNull(s.invalid.getCipherSuite());
+ assertEquals(StandardNames.CIPHER_SUITE_INVALID, s.invalid.getCipherSuite());
+ assertNotNull(s.server.getCipherSuite());
+ assertNotNull(s.client.getCipherSuite());
+ assertEquals(s.server.getCipherSuite(), s.client.getCipherSuite());
+ StandardNames.assertValidCipherSuites(new String[] {s.server.getCipherSuite()});
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_getCreationTime() {
+ // We use OpenSSL, which only returns times accurate to the nearest second.
+ // NativeCrypto just multiplies by 1000, which looks like truncation, which
+ // would make it appear as if the OpenSSL side of things was created before
+ // we called it.
+ long t0 = System.currentTimeMillis() / 1000;
+ TestSSLSessions s = TestSSLSessions.create();
+ long t1 = System.currentTimeMillis() / 1000;
+
+ assertTrue(s.invalid.getCreationTime() > 0);
+
+ long sTime = s.server.getCreationTime() / 1000;
+ assertTrue(sTime + " >= " + t0, sTime >= t0);
+ assertTrue(sTime + " <= " + t1, sTime <= t1);
+
+ long cTime = s.client.getCreationTime() / 1000;
+ assertTrue(cTime + " >= " + t0, cTime >= t0);
+ assertTrue(cTime + " <= " + t1, cTime <= t1);
+
+ s.close();
+ }
+
+ // TLS 1.2 and TLS 1.3 sessions are philosophically different: In TLS 1.3, sessions for
+ // resumption are sent outside the handshake, are generally single-use, and there can be
+ // multiple cached at any time, whereas in TLS 1.2 the session caching info is sent as part of
+ // the handshake and effectively enhances the current session. So in TLS 1.3, the current
+ // session has no ID (and cannot be resumed), whereas in TLS 1.2, the current session gets
+ // an ID and can be used for session resumption.
+
+ @Test
+ public void test_SSLSession_getId_TLS12() {
+ TestSSLSessions s = TestSSLSessions.create(TestSSLContext.newBuilder()
+ .clientProtocol("TLSv1.2").serverProtocol("TLSv1.2").build());
+ assertNotNull(s.invalid.getId());
+ assertNotNull(s.server.getId());
+ assertNotNull(s.client.getId());
+ assertEquals(0, s.invalid.getId().length);
+ if (TestSSLContext.sslServerSocketSupportsSessionTickets()) {
+ assertEquals(0, s.server.getId().length);
+ } else {
+ assertEquals(32, s.server.getId().length);
+ assertTrue(Arrays.equals(s.server.getId(), s.client.getId()));
+ }
+ assertEquals(32, s.client.getId().length);
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_getId_TLS13() {
+ TestSSLSessions s = TestSSLSessions.create(TestSSLContext.newBuilder()
+ .clientProtocol("TLSv1.3").serverProtocol("TLSv1.3").build());
+ assertNotNull(s.invalid.getId());
+ assertNotNull(s.server.getId());
+ assertNotNull(s.client.getId());
+ assertEquals(0, s.invalid.getId().length);
+ assertEquals(0, s.server.getId().length);
+ assertEquals(0, s.client.getId().length);
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_getLastAccessedTime() {
+ TestSSLSessions s = TestSSLSessions.create();
+ assertTrue(s.invalid.getLastAccessedTime() > 0);
+ assertTrue(s.server.getLastAccessedTime() > 0);
+ assertTrue(s.client.getLastAccessedTime() > 0);
+ assertTrue("s.server.getLastAccessedTime()=" + s.server.getLastAccessedTime() + " "
+ + "s.client.getLastAccessedTime()=" + s.client.getLastAccessedTime(),
+ Math.abs(s.server.getLastAccessedTime() - s.client.getLastAccessedTime())
+ <= 1000);
+ assertTrue(s.server.getLastAccessedTime() >= s.server.getCreationTime());
+ assertTrue(s.client.getLastAccessedTime() >= s.client.getCreationTime());
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_getLocalCertificates() throws Exception {
+ TestSSLSessions s = TestSSLSessions.create();
+ assertNull(s.invalid.getLocalCertificates());
+ assertNull(s.client.getLocalCertificates());
+ assertNotNull(s.server.getLocalCertificates());
+ TestKeyStore.assertChainLength(s.server.getLocalCertificates());
+ TestSSLContext.assertServerCertificateChain(
+ s.s.c.serverTrustManager, s.server.getLocalCertificates());
+ TestSSLContext.assertCertificateInKeyStore(
+ s.server.getLocalCertificates()[0], s.s.c.serverKeyStore);
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_getLocalPrincipal() throws Exception {
+ TestSSLSessions s = TestSSLSessions.create();
+ assertNull(s.invalid.getLocalPrincipal());
+ assertNull(s.client.getLocalPrincipal());
+ assertNotNull(s.server.getLocalPrincipal());
+ assertNotNull(s.server.getLocalPrincipal().getName());
+ TestSSLContext.assertCertificateInKeyStore(
+ s.server.getLocalPrincipal(), s.s.c.serverKeyStore);
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_getPacketBufferSize() {
+ TestSSLSessions s = TestSSLSessions.create();
+ assertTrue(s.invalid.getPacketBufferSize() > 0);
+ assertTrue(s.server.getPacketBufferSize() > 0);
+ assertTrue(s.client.getPacketBufferSize() > 0);
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_getPeerCertificateChain() throws Exception {
+ TestSSLSessions s = TestSSLSessions.create();
+ try {
+ s.invalid.getPeerCertificateChain();
+ fail();
+ } catch (SSLPeerUnverifiedException expected) {
+ // Ignored.
+ } catch (UnsupportedOperationException e) {
+ if (!StandardNames.IS_15_OR_UP) {
+ fail("Should only throw UnsupportedOperationException on OpenJDK 15 or up");
+ }
+ }
+ assertNotNull(s.client.getPeerCertificates());
+ TestKeyStore.assertChainLength(s.client.getPeerCertificates());
+ try {
+ assertNull(s.server.getPeerCertificateChain());
+ fail();
+ } catch (SSLPeerUnverifiedException expected) {
+ // Ignored.
+ } catch (UnsupportedOperationException e) {
+ if (!StandardNames.IS_15_OR_UP) {
+ fail("Should only throw UnsupportedOperationException on OpenJDK 15 or up");
+ }
+ }
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_getPeerCertificates() throws Exception {
+ TestSSLSessions s = TestSSLSessions.create();
+ try {
+ s.invalid.getPeerCertificates();
+ fail();
+ } catch (SSLPeerUnverifiedException expected) {
+ // Ignored.
+ }
+ assertNotNull(s.client.getPeerCertificates());
+ TestKeyStore.assertChainLength(s.client.getPeerCertificates());
+ TestSSLContext.assertServerCertificateChain(
+ s.s.c.serverTrustManager, s.client.getPeerCertificates());
+ TestSSLContext.assertCertificateInKeyStore(
+ s.client.getPeerCertificates()[0], s.s.c.serverKeyStore);
+ try {
+ s.server.getPeerCertificates();
+ fail();
+ } catch (SSLPeerUnverifiedException expected) {
+ // Ignored.
+ }
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_getPeerCertificates_resumption() throws Exception {
+ TestSSLContext context = TestSSLContext.create();
+
+ // Ensure that the session is reused to the best of our ability
+ context.clientContext.getClientSessionContext().setSessionTimeout(1000000);
+ context.clientContext.getClientSessionContext().setSessionCacheSize(0);
+
+ SSLSocket client = (SSLSocket) context.clientContext.getSocketFactory().createSocket(
+ context.host, context.port);
+ SSLSocket server = (SSLSocket) context.serverSocket.accept();
+ connect(client, server);
+
+ assertNotNull(client.getSession().getPeerCertificates());
+
+ client.close();
+ server.close();
+
+ client = (SSLSocket) context.clientContext.getSocketFactory().createSocket(
+ context.host, context.port);
+ server = (SSLSocket) context.serverSocket.accept();
+ connect(client, server);
+
+ assertNotNull(client.getSession().getPeerCertificates());
+
+ client.close();
+ server.close();
+ context.close();
+ }
+
+ private static void connect(final SSLSocket client, final SSLSocket server)
+ throws InterruptedException, ExecutionException {
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ Future<Void> s = executor.submit(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ server.startHandshake();
+ return null;
+ }
+ });
+ Future<Void> c = executor.submit(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ client.startHandshake();
+ return null;
+ }
+ });
+ executor.shutdown();
+ s.get();
+ c.get();
+ }
+
+ @Test
+ public void test_SSLSession_getPeerHost() {
+ TestSSLSessions s = TestSSLSessions.create();
+ assertNull(s.invalid.getPeerHost());
+ assertNotNull(s.server.getPeerHost());
+ assertNotNull(s.client.getPeerHost());
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_getPeerPort() {
+ TestSSLSessions s = TestSSLSessions.create();
+ assertEquals(-1, s.invalid.getPeerPort());
+ assertTrue(s.server.getPeerPort() > 0);
+ assertEquals(s.s.c.port, s.client.getPeerPort());
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_getPeerPrincipal() throws Exception {
+ TestSSLSessions s = TestSSLSessions.create();
+ try {
+ s.invalid.getPeerPrincipal();
+ fail();
+ } catch (SSLPeerUnverifiedException expected) {
+ // Ignored.
+ }
+ try {
+ s.server.getPeerPrincipal();
+ fail();
+ } catch (SSLPeerUnverifiedException expected) {
+ // Ignored.
+ }
+ assertNotNull(s.client.getPeerPrincipal());
+ assertNotNull(s.client.getPeerPrincipal().getName());
+ TestSSLContext.assertCertificateInKeyStore(
+ s.client.getPeerPrincipal(), s.s.c.serverKeyStore);
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_getProtocol() {
+ TestSSLSessions s = TestSSLSessions.create();
+ assertNotNull(s.invalid.getProtocol());
+ assertEquals("NONE", s.invalid.getProtocol());
+ assertNotNull(s.server.getProtocol());
+ assertNotNull(s.client.getProtocol());
+ assertEquals(s.server.getProtocol(), s.client.getProtocol());
+ assertTrue(StandardNames.SSL_SOCKET_PROTOCOLS.contains(s.server.getProtocol()));
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_getSessionContext() {
+ TestSSLSessions s = TestSSLSessions.create();
+ assertNull(s.invalid.getSessionContext());
+ assertNotNull(s.server.getSessionContext());
+ assertNotNull(s.client.getSessionContext());
+ assertEquals(s.s.c.serverContext.getServerSessionContext(), s.server.getSessionContext());
+ assertEquals(s.s.c.clientContext.getClientSessionContext(), s.client.getSessionContext());
+ assertNotSame(s.server.getSessionContext(), s.client.getSessionContext());
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_getValue() {
+ TestSSLSessions s = TestSSLSessions.create();
+ try {
+ s.invalid.getValue(null);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ assertNull(s.invalid.getValue("BOGUS"));
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_getValueNames() {
+ TestSSLSessions s = TestSSLSessions.create();
+ assertNotNull(s.invalid.getValueNames());
+ assertEquals(0, s.invalid.getValueNames().length);
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_invalidate() {
+ TestSSLSessions s = TestSSLSessions.create();
+
+ assertFalse(s.invalid.isValid());
+ s.invalid.invalidate();
+ assertFalse(s.invalid.isValid());
+ assertNull(s.invalid.getSessionContext());
+
+ assertTrue(s.server.isValid());
+ s.server.invalidate();
+ assertFalse(s.server.isValid());
+ assertNull(s.server.getSessionContext());
+
+ assertTrue(s.client.isValid());
+ s.client.invalidate();
+ assertFalse(s.client.isValid());
+ assertNull(s.client.getSessionContext());
+
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_isValid() {
+ TestSSLSessions s = TestSSLSessions.create();
+ assertFalse(s.invalid.isValid());
+ assertTrue(s.server.isValid());
+ assertTrue(s.client.isValid());
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_putValue() {
+ TestSSLSessions s = TestSSLSessions.create();
+ String key = "KEY";
+ String value = "VALUE";
+ assertNull(s.invalid.getValue(key));
+ assertEquals(0, s.invalid.getValueNames().length);
+ s.invalid.putValue(key, value);
+ assertSame(value, s.invalid.getValue(key));
+ assertEquals(1, s.invalid.getValueNames().length);
+ assertEquals(key, s.invalid.getValueNames()[0]);
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_removeValue() {
+ TestSSLSessions s = TestSSLSessions.create();
+ String key = "KEY";
+ String value = "VALUE";
+ s.invalid.putValue(key, value);
+ assertEquals(1, s.invalid.getValueNames().length);
+ assertEquals(key, s.invalid.getValueNames()[0]);
+ s.invalid.removeValue(key);
+ assertNull(s.invalid.getValue(key));
+ assertEquals(0, s.invalid.getValueNames().length);
+ s.close();
+ }
+
+ @Test
+ public void test_SSLSession_BindingListener() {
+ final TestSSLSessions s = TestSSLSessions.create();
+ final String key = "KEY";
+ final boolean[] bound = new boolean[] { false };
+ final Object value = new SSLSessionBindingListener() {
+ @Override
+ public void valueBound(SSLSessionBindingEvent e) {
+ assertEquals(s.client, e.getSession());
+ assertEquals(key, e.getName());
+ assertFalse(bound[0]);
+ bound[0] = true;
+ }
+
+ @Override
+ public void valueUnbound(SSLSessionBindingEvent e) {
+ assertEquals(s.client, e.getSession());
+ assertEquals(key, e.getName());
+ assertTrue(bound[0]);
+ bound[0] = false;
+ }
+ };
+ s.client.putValue(key, value);
+ assertSame(value, s.client.getValue(key));
+ assertTrue(bound[0]);
+ s.client.removeValue(key);
+ assertFalse(bound[0]);
+ }
+
+ @Test
+ public void test_SSLSession_valueIndependence() {
+ // Multiple sessions should have independent value stores
+ for (int i = 0; i < 2; i++) {
+ TestSSLSessions s = TestSSLSessions.create();
+ String key = "KEY";
+ String value = "VALUE";
+ assertNull(s.invalid.getValue(key));
+ assertEquals(0, s.invalid.getValueNames().length);
+ s.invalid.putValue(key, value);
+ assertSame(value, s.invalid.getValue(key));
+ assertEquals(1, s.invalid.getValueNames().length);
+ assertEquals(key, s.invalid.getValueNames()[0]);
+ s.close();
+ }
+ }
+
+ private static String alterOriginalHostName(InetAddress inetAddress, String originalHostName)
+ throws Exception {
+ Method getHolder = InetAddress.class.getDeclaredMethod("holder");
+ getHolder.setAccessible(true);
+
+ Field originalHostNameField = Class.forName("java.net.InetAddress$InetAddressHolder")
+ .getDeclaredField("originalHostName");
+ originalHostNameField.setAccessible(true);
+
+ Object holder = getHolder.invoke(inetAddress);
+ String oldValue = (String)originalHostNameField.get(holder);
+ originalHostNameField.set(holder, originalHostName);
+ return oldValue;
+ }
+
+ // http://b/35942385
+ @Test
+ public void test_SSLSession_getPeerHostFromInetAddress() throws Exception {
+ TestUtils.assumeAndroid();
+ InetAddress inetAddress = TestUtils.getLoopbackAddress();
+ String oldOriginalHostName = alterOriginalHostName(inetAddress, "foobar");
+ try {
+ final TestSSLContext c = TestSSLContext.create();
+ final SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(
+ TestUtils.getLoopbackAddress(), c.port);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Future<Void> future = executor.submit(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ server.startHandshake();
+ return null;
+ }
+ });
+ executor.shutdown();
+ client.startHandshake();
+
+ SSLSession sslSession = client.getSession();
+ assertEquals("foobar", sslSession.getPeerHost());
+
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ } finally {
+ // Restore the original value (InetAddress objects are cached).
+ alterOriginalHostName(inetAddress, oldOriginalHostName);
+ }
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketFactoryTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketFactoryTest.java
new file mode 100644
index 0000000..d13c039
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketFactoryTest.java
@@ -0,0 +1,97 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import javax.net.ServerSocketFactory;
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class SSLSocketFactoryTest {
+
+ @Test
+ public void test_SSLSocketFactory_getDefault() {
+ SocketFactory sf = SSLSocketFactory.getDefault();
+ assertNotNull(sf);
+ assertTrue(SSLSocketFactory.class.isAssignableFrom(sf.getClass()));
+ }
+
+ @Test
+ public void test_SSLSocketFactory_defaultConfiguration() throws Exception {
+ SSLConfigurationAsserts.assertSSLSocketFactoryDefaultConfiguration(
+ (SSLSocketFactory) SSLSocketFactory.getDefault());
+ }
+
+ @Test
+ public void test_SSLSocketFactory_getDefaultCipherSuitesReturnsCopies() {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ assertNotSame(sf.getDefaultCipherSuites(), sf.getDefaultCipherSuites());
+ }
+
+ @Test
+ public void test_SSLSocketFactory_getSupportedCipherSuitesReturnsCopies() {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ assertNotSame(sf.getSupportedCipherSuites(), sf.getSupportedCipherSuites());
+ }
+
+ @Test
+ public void test_SSLSocketFactory_createSocket() throws Exception {
+ try {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ sf.createSocket(null, null, -1, false);
+ fail();
+ } catch (NullPointerException expected) {
+ // Ignored.
+ }
+
+ try {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ sf.createSocket(new Socket(), null, -1, false);
+ fail();
+ } catch (SocketException expected) {
+ // Ignored.
+ }
+
+ ServerSocket ss = ServerSocketFactory.getDefault().createServerSocket(0);
+ InetSocketAddress sa = (InetSocketAddress) ss.getLocalSocketAddress();
+ InetAddress host = sa.getAddress();
+ int port = sa.getPort();
+ Socket s = new Socket(host, port);
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ Socket ssl = sf.createSocket(s, null, -1, false);
+ assertNotNull(ssl);
+ assertTrue(SSLSocket.class.isAssignableFrom(ssl.getClass()));
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketTest.java
new file mode 100644
index 0000000..7940ee9
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketTest.java
@@ -0,0 +1,1109 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import com.android.org.conscrypt.TestUtils;
+import com.android.org.conscrypt.java.security.StandardNames;
+import com.android.org.conscrypt.java.security.TestKeyStore;
+import com.android.org.conscrypt.tlswire.TlsTester;
+import com.android.org.conscrypt.tlswire.handshake.CipherSuite;
+import com.android.org.conscrypt.tlswire.handshake.ClientHello;
+import com.android.org.conscrypt.tlswire.handshake.CompressionMethod;
+import com.android.org.conscrypt.tlswire.handshake.EllipticCurve;
+import com.android.org.conscrypt.tlswire.handshake.EllipticCurvesHelloExtension;
+import com.android.org.conscrypt.tlswire.handshake.HelloExtension;
+import com.android.org.conscrypt.tlswire.util.TlsProtocolVersion;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLProtocolException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.X509ExtendedTrustManager;
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.net.DelegatingSSLSocketFactory;
+import tests.util.ForEachRunner;
+import tests.util.Pair;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class SSLSocketTest {
+ private final ThreadGroup threadGroup = new ThreadGroup("SSLSocketTest");
+ private final ExecutorService executor =
+ Executors.newCachedThreadPool(t -> new Thread(threadGroup, t));
+
+ @After
+ public void teardown() throws InterruptedException {
+ executor.shutdownNow();
+ assertTrue(executor.awaitTermination(5, TimeUnit.SECONDS));
+ }
+
+ @Test
+ public void test_SSLSocket_defaultConfiguration() throws Exception {
+ SSLConfigurationAsserts.assertSSLSocketDefaultConfiguration(
+ (SSLSocket) SSLSocketFactory.getDefault().createSocket());
+ }
+
+ @Test
+ public void test_SSLSocket_getSupportedCipherSuites_returnsCopies() throws Exception {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ try (SSLSocket ssl = (SSLSocket) sf.createSocket()) {
+ assertNotSame(ssl.getSupportedCipherSuites(), ssl.getSupportedCipherSuites());
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_getSupportedCipherSuites_connect() throws Exception {
+ // note the rare usage of non-RSA keys
+ TestKeyStore testKeyStore = new TestKeyStore.Builder()
+ .keyAlgorithms("RSA", "DSA", "EC", "EC_RSA")
+ .aliasPrefix("rsa-dsa-ec")
+ .ca(true)
+ .build();
+ StringBuilder error = new StringBuilder();
+ test_SSLSocket_getSupportedCipherSuites_connect(testKeyStore, error);
+ if (error.length() > 0) {
+ throw new Exception("One or more problems in "
+ + "test_SSLSocket_getSupportedCipherSuites_connect:\n" + error);
+ }
+ }
+
+ private void test_SSLSocket_getSupportedCipherSuites_connect(
+ TestKeyStore testKeyStore, StringBuilder error) {
+ String clientToServerString = "this is sent from the client to the server...";
+ String serverToClientString = "... and this from the server to the client";
+ byte[] clientToServer = clientToServerString.getBytes(UTF_8);
+ byte[] serverToClient = serverToClientString.getBytes(UTF_8);
+ KeyManager pskKeyManager =
+ PSKKeyManagerProxy.getConscryptPSKKeyManager(new PSKKeyManagerProxy() {
+ @Override
+ protected SecretKey getKey(
+ String identityHint, String identity, Socket socket) {
+ return newKey();
+ }
+
+ @Override
+ protected SecretKey getKey(
+ String identityHint, String identity, SSLEngine engine) {
+ return newKey();
+ }
+
+ private SecretKey newKey() {
+ return new SecretKeySpec("Just an arbitrary key".getBytes(UTF_8), "RAW");
+ }
+ });
+ TestSSLContext c = TestSSLContext.newBuilder()
+ .client(testKeyStore)
+ .server(testKeyStore)
+ .clientProtocol("TLSv1.2")
+ .serverProtocol("TLSv1.2")
+ .additionalClientKeyManagers(new KeyManager[] {pskKeyManager})
+ .additionalServerKeyManagers(new KeyManager[] {pskKeyManager})
+ .build();
+ String[] cipherSuites = c.clientContext.getSocketFactory().getSupportedCipherSuites();
+ for (String cipherSuite : cipherSuites) {
+ try {
+ /*
+ * TLS_EMPTY_RENEGOTIATION_INFO_SCSV cannot be used on
+ * its own, but instead in conjunction with other
+ * cipher suites.
+ */
+ if (cipherSuite.equals(StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION)) {
+ continue;
+ }
+ /*
+ * Similarly with the TLS_FALLBACK_SCSV suite, it is not
+ * a selectable suite, but is used in conjunction with
+ * other cipher suites.
+ */
+ if (cipherSuite.equals(StandardNames.CIPHER_SUITE_FALLBACK)) {
+ continue;
+ }
+ /*
+ * This test uses TLS 1.2, and the TLS 1.3 cipher suites aren't customizable
+ * anyway.
+ */
+ if (StandardNames.CIPHER_SUITES_TLS13.contains(cipherSuite)) {
+ continue;
+ }
+ String[] clientCipherSuiteArray =
+ new String[] {cipherSuite, StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION};
+ TestSSLSocketPair socketPair = TestSSLSocketPair.create(c).connect(
+ clientCipherSuiteArray, clientCipherSuiteArray);
+ SSLSocket server = socketPair.server;
+ SSLSocket client = socketPair.client;
+ // Check that the client can read the message sent by the server
+ server.getOutputStream().write(serverToClient);
+ byte[] clientFromServer = new byte[serverToClient.length];
+ readFully(client.getInputStream(), clientFromServer);
+ assertEquals(serverToClientString, new String(clientFromServer, UTF_8));
+ // Check that the server can read the message sent by the client
+ client.getOutputStream().write(clientToServer);
+ byte[] serverFromClient = new byte[clientToServer.length];
+ readFully(server.getInputStream(), serverFromClient);
+ assertEquals(clientToServerString, new String(serverFromClient, UTF_8));
+ // Check that the server and the client cannot read anything else
+ // (reads should time out)
+ server.setSoTimeout(10);
+ assertThrows(IOException.class, () -> server.getInputStream().read());
+ client.setSoTimeout(10);
+ assertThrows(IOException.class, () -> client.getInputStream().read());
+ client.close();
+ server.close();
+ } catch (Exception maybeExpected) {
+ String message = ("Problem trying to connect cipher suite " + cipherSuite);
+ System.out.println(message);
+ maybeExpected.printStackTrace();
+ error.append(message);
+ error.append('\n');
+ }
+ }
+ c.close();
+ }
+
+ @Test
+ public void test_SSLSocket_getInputStream_available() throws Exception {
+ TestSSLSocketPair pair = TestSSLSocketPair.create().connect();
+
+ pair.client.getOutputStream().write(new byte[] { 1, 2, 3, 4 });
+ // We read a single byte first because it's okay if available() returns zero
+ // before we've checked the network to see if any packets are available to
+ // be decrypted, but we should show available bytes once we've decrypted a packet
+ assertEquals(1, pair.server.getInputStream().read());
+ assertTrue(pair.server.getInputStream().available() > 0);
+ assertEquals(3, pair.server.getInputStream().read(new byte[4]));
+ assertEquals(0, pair.server.getInputStream().available());
+
+ pair.server.getOutputStream().write(new byte[] { 1, 2, 3, 4 });
+ // We read a single byte first because it's okay if available() returns zero
+ // before we've checked the network to see if any packets are available to
+ // be decrypted, but we should show available bytes once we've decrypted a packet
+ assertEquals(1, pair.client.getInputStream().read());
+ assertTrue(pair.client.getInputStream().available() > 0);
+ assertEquals(3, pair.client.getInputStream().read(new byte[4]));
+ assertEquals(0, pair.client.getInputStream().available());
+ }
+
+ @Test
+ public void test_SSLSocket_InputStream_read() throws Exception {
+ // Regression test for https://github.com/google/conscrypt/issues/738
+ // Ensure values returned from InputStream.read() are unsigned.
+ TestSSLSocketPair pair = TestSSLSocketPair.create().connect();
+
+ for (int i = 0; i < 256; i++) {
+ pair.client.getOutputStream().write(i);
+ assertEquals(i, pair.server.getInputStream().read());
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_getEnabledCipherSuites_returnsCopies() throws Exception {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ try (SSLSocket ssl = (SSLSocket) sf.createSocket()) {
+ assertNotSame(ssl.getEnabledCipherSuites(), ssl.getEnabledCipherSuites());
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_setEnabledCipherSuites_storesCopy() throws Exception {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ try (SSLSocket ssl = (SSLSocket) sf.createSocket()) {
+ String[] array = new String[] {ssl.getEnabledCipherSuites()[0]};
+ String originalFirstElement = array[0];
+ ssl.setEnabledCipherSuites(array);
+ array[0] = "Modified after having been set";
+ assertEquals(originalFirstElement, ssl.getEnabledCipherSuites()[0]);
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_setEnabledCipherSuites_TLS12() throws Exception {
+ SSLContext context = SSLContext.getInstance("TLSv1.2");
+ context.init(null, null, null);
+ try (SSLSocket ssl = (SSLSocket) context.getSocketFactory().createSocket()) {
+ assertThrows(IllegalArgumentException.class, () -> ssl.setEnabledCipherSuites(null));
+ assertThrows(IllegalArgumentException.class,
+ () -> ssl.setEnabledCipherSuites(new String[1]));
+ assertThrows(IllegalArgumentException.class,
+ () -> ssl.setEnabledCipherSuites(new String[] {"Bogus"}));
+ ssl.setEnabledCipherSuites(new String[0]);
+ ssl.setEnabledCipherSuites(ssl.getEnabledCipherSuites());
+ ssl.setEnabledCipherSuites(ssl.getSupportedCipherSuites());
+ // Check that setEnabledCipherSuites affects getEnabledCipherSuites
+ String[] cipherSuites = new String[] {
+ TestUtils.pickArbitraryNonTls13Suite(ssl.getSupportedCipherSuites())};
+ ssl.setEnabledCipherSuites(cipherSuites);
+ assertEquals(Arrays.asList(cipherSuites), Arrays.asList(ssl.getEnabledCipherSuites()));
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_setEnabledCipherSuites_TLS13() throws Exception {
+ SSLContext context = SSLContext.getInstance("TLSv1.3");
+ context.init(null, null, null);
+ SSLSocketFactory sf = context.getSocketFactory();
+ try (SSLSocket ssl = (SSLSocket) sf.createSocket()) {
+ // The TLS 1.3 cipher suites should be enabled by default
+ assertTrue(new HashSet<>(Arrays.asList(ssl.getEnabledCipherSuites()))
+ .containsAll(StandardNames.CIPHER_SUITES_TLS13));
+ // Disabling them should be ignored
+ ssl.setEnabledCipherSuites(new String[0]);
+ assertTrue(new HashSet<>(Arrays.asList(ssl.getEnabledCipherSuites()))
+ .containsAll(StandardNames.CIPHER_SUITES_TLS13));
+
+ ssl.setEnabledCipherSuites(new String[] {
+ TestUtils.pickArbitraryNonTls13Suite(ssl.getSupportedCipherSuites())});
+ assertTrue(new HashSet<>(Arrays.asList(ssl.getEnabledCipherSuites()))
+ .containsAll(StandardNames.CIPHER_SUITES_TLS13));
+
+ // Disabling TLS 1.3 should disable 1.3 cipher suites
+ ssl.setEnabledProtocols(new String[] {"TLSv1.2"});
+ assertFalse(new HashSet<>(Arrays.asList(ssl.getEnabledCipherSuites()))
+ .containsAll(StandardNames.CIPHER_SUITES_TLS13));
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_getSupportedProtocols_returnsCopies() throws Exception {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ try (SSLSocket ssl = (SSLSocket) sf.createSocket()) {
+ assertNotSame(ssl.getSupportedProtocols(), ssl.getSupportedProtocols());
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_getEnabledProtocols_returnsCopies() throws Exception {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ try (SSLSocket ssl = (SSLSocket) sf.createSocket()) {
+ assertNotSame(ssl.getEnabledProtocols(), ssl.getEnabledProtocols());
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_setEnabledProtocols_storesCopy() throws Exception {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ try (SSLSocket ssl = (SSLSocket) sf.createSocket()) {
+ String[] array = new String[] {ssl.getEnabledProtocols()[0]};
+ String originalFirstElement = array[0];
+ ssl.setEnabledProtocols(array);
+ array[0] = "Modified after having been set";
+ assertEquals(originalFirstElement, ssl.getEnabledProtocols()[0]);
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_setEnabledProtocols() throws Exception {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ try (SSLSocket ssl = (SSLSocket) sf.createSocket()) {
+ assertThrows(IllegalArgumentException.class, () -> ssl.setEnabledProtocols(null));
+ assertThrows(
+ IllegalArgumentException.class, () -> ssl.setEnabledProtocols(new String[1]));
+ assertThrows(IllegalArgumentException.class,
+ () -> ssl.setEnabledProtocols(new String[] {"Bogus"}));
+ ssl.setEnabledProtocols(new String[0]);
+ ssl.setEnabledProtocols(ssl.getEnabledProtocols());
+ ssl.setEnabledProtocols(ssl.getSupportedProtocols());
+ // Check that setEnabledProtocols affects getEnabledProtocols
+ for (String protocol : ssl.getSupportedProtocols()) {
+ if ("SSLv2Hello".equals(protocol)) {
+ // Should fail when SSLv2Hello is set by itself
+ assertThrows(IllegalArgumentException.class,
+ () -> ssl.setEnabledProtocols(new String[] {protocol}));
+ } else {
+ String[] protocols = new String[] {protocol};
+ ssl.setEnabledProtocols(protocols);
+ assertEquals(Arrays.deepToString(protocols),
+ Arrays.deepToString(ssl.getEnabledProtocols()));
+ }
+ }
+ }
+ }
+
+ /**
+ * Tests that when the client has a hole in their supported protocol list, the
+ * lower span of contiguous protocols is used in practice.
+ */
+ @Test
+ public void test_SSLSocket_noncontiguousProtocols_useLower() throws Exception {
+ TestSSLContext c = TestSSLContext.create();
+ SSLContext clientContext = c.clientContext;
+ // Can't test fallback without at least 3 protocol versions enabled.
+ TestUtils.assumeTlsV11Enabled(clientContext);
+ SSLSocket client = (SSLSocket)
+ clientContext.getSocketFactory().createSocket(c.host, c.port);
+ client.setEnabledProtocols(new String[] {"TLSv1.3", "TLSv1.1"});
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ server.setEnabledProtocols(new String[] {"TLSv1.3", "TLSv1.2", "TLSv1.1"});
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Future<Void> future = executor.submit(() -> {
+ server.startHandshake();
+ return null;
+ });
+ executor.shutdown();
+ client.startHandshake();
+
+ assertEquals("TLSv1.1", client.getSession().getProtocol());
+
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ }
+
+ /**
+ * Tests that protocol negotiation succeeds when the highest-supported protocol
+ * for both client and server isn't supported by the other.
+ */
+ @Test
+ public void test_SSLSocket_noncontiguousProtocols_canNegotiate() throws Exception {
+ TestSSLContext c = TestSSLContext.create();
+ SSLContext clientContext = c.clientContext;
+ // Can't test fallback without at least 3 protocol versions enabled.
+ TestUtils.assumeTlsV11Enabled(clientContext);
+ SSLSocket client = (SSLSocket)
+ clientContext.getSocketFactory().createSocket(c.host, c.port);
+ client.setEnabledProtocols(new String[] {"TLSv1.3", "TLSv1.1"});
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ server.setEnabledProtocols(new String[] {"TLSv1.2", "TLSv1.1"});
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Future<Void> future = executor.submit(() -> {
+ server.startHandshake();
+ return null;
+ });
+ executor.shutdown();
+ client.startHandshake();
+
+ assertEquals("TLSv1.1", client.getSession().getProtocol());
+
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ }
+
+ @Test
+ public void test_SSLSocket_getSession() throws Exception {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ try (SSLSocket ssl = (SSLSocket) sf.createSocket()) {
+ SSLSession session = ssl.getSession();
+ assertNotNull(session);
+ assertFalse(session.isValid());
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_getHandshakeSession_unconnected() throws Exception {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ try (SSLSocket socket = (SSLSocket) sf.createSocket()) {
+ SSLSession session = socket.getHandshakeSession();
+ assertNull(session);
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_getHandshakeSession_duringHandshake_client() throws Exception {
+ // We can't reference the actual context we're using, since we need to pass
+ // the test trust manager in to construct it, so create reference objects that
+ // we can test against.
+ final TestSSLContext referenceContext = TestSSLContext.create();
+ final SSLSocket referenceClientSocket =
+ (SSLSocket) referenceContext.clientContext.getSocketFactory().createSocket();
+
+ final AtomicInteger checkServerTrustedWasCalled = new AtomicInteger(0);
+ TestSSLContext c = TestSSLContext.newBuilder()
+ .clientTrustManager(new X509ExtendedTrustManager() {
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s,
+ Socket socket) throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s,
+ Socket socket) throws CertificateException {
+ try {
+ SSLSocket sslSocket = (SSLSocket) socket;
+ SSLSession session = sslSocket.getHandshakeSession();
+ assertNotNull(session);
+ // By the point of the handshake where we're validating certificates,
+ // the hostname is known and the cipher suite should be agreed
+ assertEquals(referenceContext.host.getHostName(), session.getPeerHost());
+ String sessionSuite = session.getCipherSuite();
+ List<String> enabledSuites =
+ Arrays.asList(referenceClientSocket.getEnabledCipherSuites());
+ String message = "Handshake session has invalid cipher suite: "
+ + (sessionSuite == null ? "(null)" : sessionSuite);
+ assertTrue(message, enabledSuites.contains(sessionSuite));
+
+ checkServerTrustedWasCalled.incrementAndGet();
+ } catch (Exception e) {
+ throw new CertificateException("Something broke", e);
+ }
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s,
+ SSLEngine sslEngine) throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s,
+ SSLEngine sslEngine) throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s)
+ throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s)
+ throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[0];
+ }
+ }).build();
+ SSLContext clientContext = c.clientContext;
+ SSLSocket client = (SSLSocket)
+ clientContext.getSocketFactory().createSocket(c.host, c.port);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Future<Void> future = executor.submit(() -> {
+ server.startHandshake();
+ return null;
+ });
+ executor.shutdown();
+ client.startHandshake();
+
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ assertEquals(1, checkServerTrustedWasCalled.get());
+ }
+
+ @Test
+ public void test_SSLSocket_getHandshakeSession_duringHandshake_server() throws Exception {
+ // We can't reference the actual context we're using, since we need to pass
+ // the test trust manager in to construct it, so create reference objects that
+ // we can test against.
+ final TestSSLContext referenceContext = TestSSLContext.create();
+ final SSLSocket referenceClientSocket =
+ (SSLSocket) referenceContext.clientContext.getSocketFactory().createSocket();
+
+ final AtomicInteger checkClientTrustedWasCalled = new AtomicInteger(0);
+ TestSSLContext c = TestSSLContext.newBuilder()
+ .client(TestKeyStore.getClientCertificate())
+ .serverTrustManager(new X509ExtendedTrustManager() {
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s,
+ Socket socket) throws CertificateException {
+ try {
+ SSLSocket sslSocket = (SSLSocket) socket;
+ SSLSession session = sslSocket.getHandshakeSession();
+ assertNotNull(session);
+ // By the point of the handshake where we're validating client certificates,
+ // the cipher suite should be agreed and the server's own certificates
+ // should have been delivered
+
+ // The negotiated cipher suite should be one of the enabled ones, but
+ // BoringSSL may have reordered them based on things like hardware support,
+ // so we don't know which one may have been negotiated.
+ String sessionSuite = session.getCipherSuite();
+ List<String> enabledSuites =
+ Arrays.asList(referenceClientSocket.getEnabledCipherSuites());
+ String message = "Handshake session has invalid cipher suite: "
+ + (sessionSuite == null ? "(null)" : sessionSuite);
+ assertTrue(message, enabledSuites.contains(sessionSuite));
+
+ assertNotNull(session.getLocalCertificates());
+ assertEquals("CN=localhost",
+ ((X509Certificate) session.getLocalCertificates()[0])
+ .getSubjectDN().getName());
+ assertEquals("CN=Test Intermediate Certificate Authority",
+ ((X509Certificate) session.getLocalCertificates()[0])
+ .getIssuerDN().getName());
+ checkClientTrustedWasCalled.incrementAndGet();
+ } catch (Exception e) {
+ throw new CertificateException("Something broke", e);
+ }
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s,
+ Socket socket) throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s,
+ SSLEngine sslEngine) throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s,
+ SSLEngine sslEngine) throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s)
+ throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s)
+ throws CertificateException {
+ throw new CertificateException("Shouldn't be called");
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return referenceContext.serverTrustManager.getAcceptedIssuers();
+ }
+ }).build();
+ SSLContext clientContext = c.clientContext;
+ SSLSocket client = (SSLSocket)
+ clientContext.getSocketFactory().createSocket(c.host, c.port);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Future<Void> future = executor.submit(() -> {
+ server.setNeedClientAuth(true);
+ server.startHandshake();
+ return null;
+ });
+ executor.shutdown();
+ client.startHandshake();
+
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ assertEquals(1, checkClientTrustedWasCalled.get());
+ }
+
+ @Test
+ public void test_SSLSocket_setUseClientMode_afterHandshake() {
+ // can't set after handshake
+ TestSSLSocketPair pair = TestSSLSocketPair.create().connect();
+ assertThrows(IllegalArgumentException.class, () -> pair.server.setUseClientMode(true));
+ assertThrows(IllegalArgumentException.class, () -> pair.client.setUseClientMode(false));
+ }
+
+ @Test
+ public void test_SSLSocket_untrustedServer() throws Exception {
+ TestSSLContext c =
+ TestSSLContext.create(TestKeyStore.getClientCA2(), TestKeyStore.getServer());
+ SSLSocket client =
+ (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host, c.port);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ Future<Void> future = runAsync(() -> {
+ assertThrows(SSLHandshakeException.class, server::startHandshake);
+ return null;
+ });
+ SSLHandshakeException expected =
+ assertThrows(SSLHandshakeException.class, client::startHandshake);
+ assertTrue(expected.getCause() instanceof CertificateException);
+
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ }
+
+ @Test
+ public void test_SSLSocket_getSSLParameters() throws Exception {
+ TestUtils.assumeSetEndpointIdentificationAlgorithmAvailable();
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ try (SSLSocket ssl = (SSLSocket) sf.createSocket()) {
+ SSLParameters p = ssl.getSSLParameters();
+ assertNotNull(p);
+ String[] cipherSuites = p.getCipherSuites();
+ assertNotSame(cipherSuites, ssl.getEnabledCipherSuites());
+ assertEquals(Arrays.asList(cipherSuites), Arrays.asList(ssl.getEnabledCipherSuites()));
+ String[] protocols = p.getProtocols();
+ assertNotSame(protocols, ssl.getEnabledProtocols());
+ assertEquals(Arrays.asList(protocols), Arrays.asList(ssl.getEnabledProtocols()));
+ assertEquals(p.getWantClientAuth(), ssl.getWantClientAuth());
+ assertEquals(p.getNeedClientAuth(), ssl.getNeedClientAuth());
+ assertNull(p.getEndpointIdentificationAlgorithm());
+ p.setEndpointIdentificationAlgorithm(null);
+ assertNull(p.getEndpointIdentificationAlgorithm());
+ p.setEndpointIdentificationAlgorithm("HTTPS");
+ assertEquals("HTTPS", p.getEndpointIdentificationAlgorithm());
+ p.setEndpointIdentificationAlgorithm("FOO");
+ assertEquals("FOO", p.getEndpointIdentificationAlgorithm());
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_setSSLParameters() throws Exception {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ try (SSLSocket ssl = (SSLSocket) sf.createSocket()) {
+ String[] defaultCipherSuites = ssl.getEnabledCipherSuites();
+ String[] defaultProtocols = ssl.getEnabledProtocols();
+ String[] supportedCipherSuites = ssl.getSupportedCipherSuites();
+ String[] supportedProtocols = ssl.getSupportedProtocols();
+ {
+ SSLParameters p = new SSLParameters();
+ ssl.setSSLParameters(p);
+ assertEquals(Arrays.asList(defaultCipherSuites),
+ Arrays.asList(ssl.getEnabledCipherSuites()));
+ assertEquals(
+ Arrays.asList(defaultProtocols), Arrays.asList(ssl.getEnabledProtocols()));
+ }
+ {
+ SSLParameters p = new SSLParameters(supportedCipherSuites, supportedProtocols);
+ ssl.setSSLParameters(p);
+ assertEquals(Arrays.asList(supportedCipherSuites),
+ Arrays.asList(ssl.getEnabledCipherSuites()));
+ assertEquals(Arrays.asList(supportedProtocols),
+ Arrays.asList(ssl.getEnabledProtocols()));
+ }
+ {
+ SSLParameters p = new SSLParameters();
+ p.setNeedClientAuth(true);
+ assertFalse(ssl.getNeedClientAuth());
+ assertFalse(ssl.getWantClientAuth());
+ ssl.setSSLParameters(p);
+ assertTrue(ssl.getNeedClientAuth());
+ assertFalse(ssl.getWantClientAuth());
+ p.setWantClientAuth(true);
+ assertTrue(ssl.getNeedClientAuth());
+ assertFalse(ssl.getWantClientAuth());
+ ssl.setSSLParameters(p);
+ assertFalse(ssl.getNeedClientAuth());
+ assertTrue(ssl.getWantClientAuth());
+ p.setWantClientAuth(false);
+ assertFalse(ssl.getNeedClientAuth());
+ assertTrue(ssl.getWantClientAuth());
+ ssl.setSSLParameters(p);
+ assertFalse(ssl.getNeedClientAuth());
+ assertFalse(ssl.getWantClientAuth());
+ }
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_setSoTimeout_basic() throws Exception {
+ try (ServerSocket listening = new ServerSocket(0)) {
+ Socket underlying = new Socket(listening.getInetAddress(), listening.getLocalPort());
+ assertEquals(0, underlying.getSoTimeout());
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ Socket wrapping = sf.createSocket(underlying, null, -1, false);
+ assertEquals(0, wrapping.getSoTimeout());
+ // setting wrapper sets underlying and ...
+ int expectedTimeoutMillis =
+ 1000; // 10 was too small because it was affected by rounding
+ wrapping.setSoTimeout(expectedTimeoutMillis);
+ // The kernel can round the requested value based on the HZ setting. We allow up to
+ // 10ms.
+ assertTrue(Math.abs(expectedTimeoutMillis - wrapping.getSoTimeout()) <= 10);
+ assertTrue(Math.abs(expectedTimeoutMillis - underlying.getSoTimeout()) <= 10);
+ // ... getting wrapper inspects underlying
+ underlying.setSoTimeout(0);
+ assertEquals(0, wrapping.getSoTimeout());
+ assertEquals(0, underlying.getSoTimeout());
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_setSoTimeout_wrapper() throws Exception {
+ ServerSocket listening = new ServerSocket(0);
+ // setSoTimeout applies to read, not connect, so connect first
+ Socket underlying = new Socket(listening.getInetAddress(), listening.getLocalPort());
+ Socket server = listening.accept();
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ Socket clientWrapping = sf.createSocket(underlying, null, -1, false);
+ underlying.setSoTimeout(1);
+ assertThrows(SocketTimeoutException.class, () -> clientWrapping.getInputStream().read());
+ clientWrapping.close();
+ server.close();
+ underlying.close();
+ listening.close();
+ }
+
+ @Test
+ public void test_TestSSLSocketPair_create() {
+ TestSSLSocketPair test = TestSSLSocketPair.create().connect();
+ assertNotNull(test.c);
+ assertNotNull(test.server);
+ assertNotNull(test.client);
+ assertTrue(test.server.isConnected());
+ assertTrue(test.client.isConnected());
+ assertFalse(test.server.isClosed());
+ assertFalse(test.client.isClosed());
+ assertNotNull(test.server.getSession());
+ assertNotNull(test.client.getSession());
+ assertTrue(test.server.getSession().isValid());
+ assertTrue(test.client.getSession().isValid());
+ test.close();
+ }
+
+ @Test
+ public void test_SSLSocket_ClientHello_cipherSuites() throws Exception {
+ ForEachRunner.runNamed(sslSocketFactory -> {
+ ClientHello clientHello =
+ TlsTester.captureTlsHandshakeClientHello(executor, sslSocketFactory);
+ final String[] cipherSuites;
+ // RFC 5746 allows you to send an empty "renegotiation_info" extension *or*
+ // a special signaling cipher suite. The TLS API has no way to check or
+ // indicate that a certain TLS extension should be used.
+ HelloExtension renegotiationInfoExtension =
+ clientHello.findExtensionByType(HelloExtension.TYPE_RENEGOTIATION_INFO);
+ if (renegotiationInfoExtension != null && renegotiationInfoExtension.data.length == 1
+ && renegotiationInfoExtension.data[0] == 0) {
+ cipherSuites = new String[clientHello.cipherSuites.size() + 1];
+ cipherSuites[clientHello.cipherSuites.size()] =
+ StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION;
+ } else {
+ cipherSuites = new String[clientHello.cipherSuites.size()];
+ }
+ for (int i = 0; i < clientHello.cipherSuites.size(); i++) {
+ CipherSuite cipherSuite = clientHello.cipherSuites.get(i);
+ cipherSuites[i] = cipherSuite.getAndroidName();
+ }
+ StandardNames.assertDefaultCipherSuites(cipherSuites);
+ }, getSSLSocketFactoriesToTest());
+ }
+
+ @Test
+ public void test_SSLSocket_ClientHello_supportedCurves() throws Exception {
+ ForEachRunner.runNamed(sslSocketFactory -> {
+ ClientHello clientHello =
+ TlsTester.captureTlsHandshakeClientHello(executor, sslSocketFactory);
+ EllipticCurvesHelloExtension ecExtension =
+ (EllipticCurvesHelloExtension) clientHello.findExtensionByType(
+ HelloExtension.TYPE_ELLIPTIC_CURVES);
+ final String[] supportedCurves;
+ if (ecExtension == null) {
+ supportedCurves = new String[0];
+ } else {
+ assertTrue(ecExtension.wellFormed);
+ supportedCurves = new String[ecExtension.supported.size()];
+ for (int i = 0; i < ecExtension.supported.size(); i++) {
+ EllipticCurve curve = ecExtension.supported.get(i);
+ supportedCurves[i] = curve.toString();
+ }
+ }
+ StandardNames.assertDefaultEllipticCurves(supportedCurves);
+ }, getSSLSocketFactoriesToTest());
+ }
+
+ @Test
+ public void test_SSLSocket_ClientHello_clientProtocolVersion() throws Exception {
+ ForEachRunner.runNamed(sslSocketFactory -> {
+ ClientHello clientHello =
+ TlsTester.captureTlsHandshakeClientHello(executor, sslSocketFactory);
+ assertEquals(TlsProtocolVersion.TLSv1_2, clientHello.clientVersion);
+ }, getSSLSocketFactoriesToTest());
+ }
+
+ @Test
+ public void test_SSLSocket_ClientHello_compressionMethods() throws Exception {
+ ForEachRunner.runNamed(sslSocketFactory -> {
+ ClientHello clientHello =
+ TlsTester.captureTlsHandshakeClientHello(executor, sslSocketFactory);
+ assertEquals(Collections.singletonList(CompressionMethod.NULL),
+ clientHello.compressionMethods);
+ }, getSSLSocketFactoriesToTest());
+ }
+
+ private List<Pair<String, SSLSocketFactory>> getSSLSocketFactoriesToTest()
+ throws NoSuchAlgorithmException, KeyManagementException {
+ List<Pair<String, SSLSocketFactory>> result = new ArrayList<>();
+ result.add(Pair.of("default", (SSLSocketFactory) SSLSocketFactory.getDefault()));
+ for (String sslContextProtocol : StandardNames.SSL_CONTEXT_PROTOCOLS_WITH_DEFAULT_CONFIG) {
+ SSLContext sslContext = SSLContext.getInstance(sslContextProtocol);
+ if (StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT.equals(sslContextProtocol)) {
+ continue;
+ }
+ sslContext.init(null, null, null);
+ result.add(Pair.of("SSLContext(\"" + sslContext.getProtocol() + "\")",
+ sslContext.getSocketFactory()));
+ }
+ return result;
+ }
+
+ @Test
+ public void test_SSLSocket_sendsTlsFallbackScsv_Fallback_Success() throws Exception {
+ TestSSLContext context = TestSSLContext.create();
+ final SSLSocket client = (SSLSocket) context.clientContext.getSocketFactory().createSocket(
+ context.host, context.port);
+ final SSLSocket server = (SSLSocket) context.serverSocket.accept();
+ final String[] serverCipherSuites = server.getEnabledCipherSuites();
+ final String[] clientCipherSuites = new String[serverCipherSuites.length + 1];
+ System.arraycopy(serverCipherSuites, 0, clientCipherSuites, 0, serverCipherSuites.length);
+ clientCipherSuites[serverCipherSuites.length] = StandardNames.CIPHER_SUITE_FALLBACK;
+ Future<Void> s = runAsync(() -> {
+ server.setEnabledProtocols(new String[] {"TLSv1.2"});
+ server.setEnabledCipherSuites(serverCipherSuites);
+ server.startHandshake();
+ return null;
+ });
+ Future<Void> c = runAsync(() -> {
+ client.setEnabledProtocols(new String[] {"TLSv1.2"});
+ client.setEnabledCipherSuites(clientCipherSuites);
+ client.startHandshake();
+ return null;
+ });
+ s.get();
+ c.get();
+ client.close();
+ server.close();
+ context.close();
+ }
+
+ // Confirms that communication without the TLS_FALLBACK_SCSV cipher works as it always did.
+ @Test
+ public void test_SSLSocket_sendsNoTlsFallbackScsv_Fallback_Success() throws Exception {
+ TestSSLContext context = TestSSLContext.create();
+ // TLS_FALLBACK_SCSV is only applicable to TLS <= 1.2
+ TestUtils.assumeTlsV11Enabled(context.clientContext);
+ final SSLSocket client = (SSLSocket) context.clientContext.getSocketFactory().createSocket(
+ context.host, context.port);
+ final SSLSocket server = (SSLSocket) context.serverSocket.accept();
+ // Confirm absence of TLS_FALLBACK_SCSV.
+ assertFalse(Arrays.asList(client.getEnabledCipherSuites())
+ .contains(StandardNames.CIPHER_SUITE_FALLBACK));
+ Future<Void> s = runAsync(() -> {
+ server.setEnabledProtocols(new String[] {"TLSv1.2", "TLSv1.1"});
+ server.startHandshake();
+ return null;
+ });
+ Future<Void> c = runAsync(() -> {
+ client.setEnabledProtocols(new String[] {"TLSv1.1"});
+ client.startHandshake();
+ return null;
+ });
+ s.get();
+ c.get();
+ client.close();
+ server.close();
+ context.close();
+ }
+
+ private static void assertInappropriateFallbackIsCause(Throwable cause) {
+ assertTrue(cause.getMessage(),
+ cause.getMessage().contains("inappropriate fallback")
+ || cause.getMessage().contains("INAPPROPRIATE_FALLBACK"));
+ }
+
+ @Test
+ public void test_SSLSocket_sendsTlsFallbackScsv_InappropriateFallback_Failure()
+ throws Exception {
+ TestSSLContext context = TestSSLContext.create();
+ // TLS_FALLBACK_SCSV is only applicable to TLS <= 1.2
+ TestUtils.assumeTlsV11Enabled(context.clientContext);
+ final SSLSocket client = (SSLSocket) context.clientContext.getSocketFactory().createSocket(
+ context.host, context.port);
+ final SSLSocket server = (SSLSocket) context.serverSocket.accept();
+ final String[] serverCipherSuites = server.getEnabledCipherSuites();
+ // Add TLS_FALLBACK_SCSV
+ final String[] clientCipherSuites = new String[serverCipherSuites.length + 1];
+ System.arraycopy(serverCipherSuites, 0, clientCipherSuites, 0, serverCipherSuites.length);
+ clientCipherSuites[serverCipherSuites.length] = StandardNames.CIPHER_SUITE_FALLBACK;
+ Future<Void> s = runAsync(() -> {
+ server.setEnabledProtocols(new String[] {"TLSv1.2", "TLSv1.1"});
+ server.setEnabledCipherSuites(serverCipherSuites);
+ SSLHandshakeException expected =
+ assertThrows(SSLHandshakeException.class, server::startHandshake);
+ Throwable cause = expected.getCause();
+ assertEquals(SSLProtocolException.class, cause.getClass());
+ assertInappropriateFallbackIsCause(cause);
+ return null;
+ });
+ Future<Void> c = runAsync(() -> {
+ client.setEnabledProtocols(new String[] {"TLSv1.1"});
+ client.setEnabledCipherSuites(clientCipherSuites);
+ SSLHandshakeException expected =
+ assertThrows(SSLHandshakeException.class, client::startHandshake);
+ Throwable cause = expected.getCause();
+ assertEquals(SSLProtocolException.class, cause.getClass());
+ assertInappropriateFallbackIsCause(cause);
+ return null;
+ });
+ s.get();
+ c.get();
+ client.close();
+ server.close();
+ context.close();
+ }
+
+ @Test
+ public void test_SSLSocket_tlsFallback_byVersion() throws Exception {
+ String[] supportedProtocols =
+ SSLContext.getDefault().getDefaultSSLParameters().getProtocols();
+ for (final String protocol : supportedProtocols) {
+ SSLSocketFactory factory = new DelegatingSSLSocketFactory(
+ (SSLSocketFactory) SSLSocketFactory.getDefault()) {
+ @Override protected SSLSocket configureSocket(SSLSocket socket) {
+ socket.setEnabledProtocols(new String[] {protocol});
+ String[] enabled = socket.getEnabledCipherSuites();
+ String[] cipherSuites = new String[socket.getEnabledCipherSuites().length + 1];
+ System.arraycopy(enabled, 0, cipherSuites, 0, enabled.length);
+ cipherSuites[cipherSuites.length - 1] = StandardNames.CIPHER_SUITE_FALLBACK;
+ socket.setEnabledCipherSuites(cipherSuites);
+ return socket;
+ }
+ };
+ ClientHello clientHello = TlsTester.captureTlsHandshakeClientHello(executor, factory);
+ if (protocol.equals("TLSv1.2") || protocol.equals("TLSv1.3")) {
+ assertFalse(clientHello.cipherSuites.contains(CipherSuite.valueOf("TLS_FALLBACK_SCSV")));
+ } else {
+ assertTrue(clientHello.cipherSuites.contains(CipherSuite.valueOf("TLS_FALLBACK_SCSV")));
+ }
+ }
+ }
+
+ @Test
+ public void handshakeListenersRunExactlyOnce() {
+ AtomicInteger count = new AtomicInteger(0);
+ TestSSLSocketPair pair = TestSSLSocketPair.create();
+ pair.client.addHandshakeCompletedListener(event -> count.addAndGet(1));
+ pair.client.addHandshakeCompletedListener(event -> count.addAndGet(2));
+ pair.client.addHandshakeCompletedListener(event -> count.addAndGet(4));
+ pair.connect();
+ assertEquals(1 + 2 + 4, count.get());
+ }
+
+ @Test
+ public void closeFromHandshakeListener() throws Exception {
+ TestUtils.assumeEngineSocket();
+
+ TestSSLSocketPair pair = TestSSLSocketPair.create();
+ pair.client.addHandshakeCompletedListener(event -> socketClose(pair.client));
+ Future<Void> serverFuture = runAsync((Callable<Void>) () -> {
+ pair.server.startHandshake();
+ return null;
+ });
+ pair.client.startHandshake();
+ assertThrows(SocketException.class, pair.client::getInputStream);
+ serverFuture.get();
+ InputStream istream = pair.server.getInputStream();
+ assertEquals(-1, istream.read());
+ }
+
+ @Test
+ public void writeFromHandshakeListener() throws Exception {
+ TestUtils.assumeEngineSocket();
+
+ byte[] ping = "ping".getBytes(UTF_8);
+ byte[] pong = "pong".getBytes(UTF_8);
+ TestSSLSocketPair pair = TestSSLSocketPair.create();
+ pair.client.addHandshakeCompletedListener(event -> socketWrite(pair.client, ping));
+ pair.server.addHandshakeCompletedListener(event -> socketWrite(pair.server, pong));
+ Future<Void> serverFuture = runAsync(() -> {
+ pair.server.startHandshake();
+ return null;
+ });
+ byte[] buffer = new byte[4];
+ InputStream clientStream = pair.client.getInputStream();
+ assertEquals(4, clientStream.read(buffer));
+ assertArrayEquals(pong, buffer);
+
+ serverFuture.get();
+ InputStream serverStream = pair.server.getInputStream();
+ assertEquals(4, serverStream.read(buffer));
+ assertArrayEquals(ping, buffer);
+ }
+
+ private void socketClose(Socket socket) {
+ try {
+ socket.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void socketWrite(Socket socket, byte[] data) {
+ try {
+ socket.getOutputStream().write(data);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private <T> Future<T> runAsync(Callable<T> callable) {
+ return executor.submit(callable);
+ }
+
+ private static void readFully(InputStream in, byte[] dst) throws IOException {
+ int offset = 0;
+ int byteCount = dst.length;
+ while (byteCount > 0) {
+ int bytesRead = in.read(dst, offset, byteCount);
+ if (bytesRead < 0) {
+ throw new EOFException();
+ }
+ offset += bytesRead;
+ byteCount -= bytesRead;
+ }
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java
new file mode 100644
index 0000000..847b20a
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java
@@ -0,0 +1,2231 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static com.android.org.conscrypt.TestUtils.UTF_8;
+import static com.android.org.conscrypt.TestUtils.isLinux;
+import static com.android.org.conscrypt.TestUtils.isOsx;
+import static com.android.org.conscrypt.TestUtils.isWindows;
+import static com.android.org.conscrypt.TestUtils.osName;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.org.conscrypt.Conscrypt;
+import com.android.org.conscrypt.TestUtils;
+import com.android.org.conscrypt.java.security.StandardNames;
+import com.android.org.conscrypt.java.security.TestKeyStore;
+import com.android.org.conscrypt.testing.OpaqueProvider;
+import com.android.org.conscrypt.tlswire.TlsTester;
+import com.android.org.conscrypt.tlswire.handshake.AlpnHelloExtension;
+import com.android.org.conscrypt.tlswire.handshake.ClientHello;
+import com.android.org.conscrypt.tlswire.handshake.HandshakeMessage;
+import com.android.org.conscrypt.tlswire.handshake.HelloExtension;
+import com.android.org.conscrypt.tlswire.handshake.ServerNameHelloExtension;
+import com.android.org.conscrypt.tlswire.record.TlsProtocols;
+import com.android.org.conscrypt.tlswire.record.TlsRecord;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.lang.reflect.Method;
+import java.net.ConnectException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ServerSocketFactory;
+import javax.net.SocketFactory;
+import javax.net.ssl.ExtendedSSLSession;
+import javax.net.ssl.HandshakeCompletedEvent;
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIServerName;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.StandardConstants;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import tests.net.DelegatingSSLSocketFactory;
+import tests.util.ForEachRunner;
+import tests.util.Pair;
+
+/**
+ * Tests for SSLSocket classes that ensure the TLS 1.2 and TLS 1.3 implementations
+ * are compatible.
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(Parameterized.class)
+public class SSLSocketVersionCompatibilityTest {
+
+ @Parameterized.Parameters(name = "{index}: {0} client, {1} server")
+ public static Iterable<Object[]> data() {
+ return Arrays.asList(new Object[][] {
+ {"TLSv1.2", "TLSv1.2"},
+ {"TLSv1.2", "TLSv1.3"},
+ {"TLSv1.3", "TLSv1.2"},
+ {"TLSv1.3", "TLSv1.3"},
+ });
+ }
+
+ private final String clientVersion;
+ private final String serverVersion;
+ private ExecutorService executor;
+ private ThreadGroup threadGroup;
+
+ public SSLSocketVersionCompatibilityTest(String clientVersion, String serverVersion) {
+ this.clientVersion = clientVersion;
+ this.serverVersion = serverVersion;
+ }
+
+ @Before
+ public void setup() {
+ threadGroup = new ThreadGroup("SSLSocketVersionedTest");
+ executor = Executors.newCachedThreadPool(new ThreadFactory() {
+ @Override
+ public Thread newThread(Runnable r) {
+ return new Thread(threadGroup, r);
+ }
+ });
+ }
+
+ @After
+ public void teardown() throws InterruptedException {
+ executor.shutdownNow();
+ executor.awaitTermination(5, TimeUnit.SECONDS);
+ }
+
+ @Test
+ public void test_SSLSocket_startHandshake() throws Exception {
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion).build();
+ SSLSocket client =
+ (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host, c.port);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ Future<Void> future = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ server.startHandshake();
+ assertNotNull(server.getSession());
+ assertNull(server.getHandshakeSession());
+ try {
+ server.getSession().getPeerCertificates();
+ fail();
+ } catch (SSLPeerUnverifiedException expected) {
+ // Ignored.
+ }
+ Certificate[] localCertificates = server.getSession().getLocalCertificates();
+ assertNotNull(localCertificates);
+ TestKeyStore.assertChainLength(localCertificates);
+ assertNotNull(localCertificates[0]);
+ TestSSLContext
+ .assertServerCertificateChain(c.serverTrustManager, localCertificates);
+ TestSSLContext.assertCertificateInKeyStore(localCertificates[0], c.serverKeyStore);
+ return null;
+ }
+ });
+ client.startHandshake();
+ assertNotNull(client.getSession());
+ assertNull(client.getSession().getLocalCertificates());
+ Certificate[] peerCertificates = client.getSession().getPeerCertificates();
+ assertNotNull(peerCertificates);
+ TestKeyStore.assertChainLength(peerCertificates);
+ assertNotNull(peerCertificates[0]);
+ TestSSLContext.assertServerCertificateChain(c.clientTrustManager, peerCertificates);
+ TestSSLContext.assertCertificateInKeyStore(peerCertificates[0], c.serverKeyStore);
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ }
+ private static final class SSLServerSessionIdCallable implements Callable<byte[]> {
+ private final SSLSocket server;
+ private SSLServerSessionIdCallable(SSLSocket server) {
+ this.server = server;
+ }
+ @Override
+ public byte[] call() throws Exception {
+ server.startHandshake();
+ assertNotNull(server.getSession());
+ assertNotNull(server.getSession().getId());
+ return server.getSession().getId();
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_confirmSessionReuse() throws Exception {
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ final SSLSocket client1 = (SSLSocket) c.clientContext.getSocketFactory().createSocket(
+ c.host.getHostName(), c.port);
+ final SSLSocket server1 = (SSLSocket) c.serverSocket.accept();
+ final Future<byte[]> future1 = runAsync(new SSLServerSessionIdCallable(server1));
+ client1.startHandshake();
+ assertNotNull(client1.getSession());
+ assertNotNull(client1.getSession().getId());
+ final byte[] clientSessionId1 = client1.getSession().getId();
+ final byte[] serverSessionId1 = future1.get();
+ assertTrue(Arrays.equals(clientSessionId1, serverSessionId1));
+ client1.close();
+ server1.close();
+ final SSLSocket client2 = (SSLSocket) c.clientContext.getSocketFactory().createSocket(
+ c.host.getHostName(), c.port);
+ final SSLSocket server2 = (SSLSocket) c.serverSocket.accept();
+ final Future<byte[]> future2 = runAsync(new SSLServerSessionIdCallable(server2));
+ client2.startHandshake();
+ assertNotNull(client2.getSession());
+ assertNotNull(client2.getSession().getId());
+ final byte[] clientSessionId2 = client2.getSession().getId();
+ final byte[] serverSessionId2 = future2.get();
+ assertTrue(Arrays.equals(clientSessionId2, serverSessionId2));
+ client2.close();
+ server2.close();
+ assertTrue(Arrays.equals(clientSessionId1, clientSessionId2));
+ c.close();
+ }
+
+ @Test
+ public void test_SSLSocket_NoEnabledCipherSuites_Failure() throws Exception {
+ TestSSLContext c = TestSSLContext.newBuilder()
+ .useDefaults(false)
+ .clientContext(defaultInit(SSLContext.getInstance(clientVersion)))
+ .serverContext(defaultInit(SSLContext.getInstance(serverVersion)))
+ .build();
+ SSLSocket client =
+ (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host, c.port);
+ client.setEnabledCipherSuites(new String[0]);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ Future<Void> future = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ try {
+ server.startHandshake();
+ fail();
+ } catch (SSLHandshakeException expected) {
+ // Ignored.
+ }
+ return null;
+ }
+ });
+ try {
+ client.startHandshake();
+ fail();
+ } catch (SSLHandshakeException expected) {
+ // Ignored.
+ }
+ future.get();
+ server.close();
+ client.close();
+ c.close();
+ }
+
+ @Test
+ public void test_SSLSocket_startHandshake_noKeyStore() throws Exception {
+ TestSSLContext c = TestSSLContext.newBuilder()
+ .useDefaults(false)
+ .clientContext(defaultInit(SSLContext.getInstance(clientVersion)))
+ .serverContext(defaultInit(SSLContext.getInstance(serverVersion)))
+ .build();
+ SSLSocket client =
+ (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host, c.port);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ Future<Void> future = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ try {
+ server.startHandshake();
+ fail();
+ } catch (SSLHandshakeException expected) {
+ // Ignored.
+ }
+ return null;
+ }
+ });
+ try {
+ client.startHandshake();
+ fail();
+ } catch (SSLHandshakeException expected) {
+ // Ignored.
+ }
+ future.get();
+ server.close();
+ client.close();
+ c.close();
+ }
+
+ @Test
+ public void test_SSLSocket_startHandshake_noClientCertificate() throws Exception {
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ SSLContext clientContext = c.clientContext;
+ SSLSocket client =
+ (SSLSocket) clientContext.getSocketFactory().createSocket(c.host, c.port);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ Future<Void> future = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ server.startHandshake();
+ return null;
+ }
+ });
+ client.startHandshake();
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ }
+
+ @Test
+ public void test_SSLSocket_HandshakeCompletedListener() throws Exception {
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ final SSLSocket client =
+ (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host, c.port);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ Future<Void> future = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ server.startHandshake();
+ return null;
+ }
+ });
+ final boolean[] handshakeCompletedListenerCalled = new boolean[1];
+ client.addHandshakeCompletedListener(new HandshakeCompletedListener() {
+ @Override
+ public void handshakeCompleted(HandshakeCompletedEvent event) {
+ SSLSocket socket = null;
+ try {
+ SSLSession session = event.getSession();
+ String cipherSuite = event.getCipherSuite();
+ Certificate[] localCertificates = event.getLocalCertificates();
+ Certificate[] peerCertificates = event.getPeerCertificates();
+ javax.security.cert.X509Certificate[] peerCertificateChain =
+ event.getPeerCertificateChain();
+ Principal peerPrincipal = event.getPeerPrincipal();
+ Principal localPrincipal = event.getLocalPrincipal();
+ socket = event.getSocket();
+ assertNotNull(session);
+ byte[] id = session.getId();
+ assertNotNull(id);
+ if (negotiatedVersion().equals("TLSv1.2")) {
+ // Session ticket delivery happens inside the handshake in TLS 1.2,
+ // but outside it for TLS 1.3.
+ assertEquals(32, id.length);
+ assertNotNull(c.clientContext.getClientSessionContext().getSession(id));
+ } else {
+ assertEquals(0, id.length);
+ }
+ assertNotNull(cipherSuite);
+ assertTrue(Arrays.asList(client.getEnabledCipherSuites())
+ .contains(cipherSuite));
+ assertTrue(Arrays.asList(c.serverSocket.getEnabledCipherSuites())
+ .contains(cipherSuite));
+
+ assertNull(localCertificates);
+ assertNotNull(peerCertificates);
+ TestKeyStore.assertChainLength(peerCertificates);
+ assertNotNull(peerCertificates[0]);
+ TestSSLContext
+ .assertServerCertificateChain(c.clientTrustManager, peerCertificates);
+ TestSSLContext
+ .assertCertificateInKeyStore(peerCertificates[0], c.serverKeyStore);
+ assertNotNull(peerCertificateChain);
+ TestKeyStore.assertChainLength(peerCertificateChain);
+ assertNotNull(peerCertificateChain[0]);
+ TestSSLContext.assertCertificateInKeyStore(
+ peerCertificateChain[0].getSubjectDN(), c.serverKeyStore);
+ assertNotNull(peerPrincipal);
+ TestSSLContext.assertCertificateInKeyStore(peerPrincipal, c.serverKeyStore);
+ assertNull(localPrincipal);
+ assertNotNull(socket);
+ assertSame(client, socket);
+ assertNull(socket.getHandshakeSession());
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ } finally {
+ synchronized (handshakeCompletedListenerCalled) {
+ handshakeCompletedListenerCalled[0] = true;
+ handshakeCompletedListenerCalled.notify();
+ }
+ handshakeCompletedListenerCalled[0] = true;
+ if (socket != null) {
+ socket.removeHandshakeCompletedListener(this);
+ }
+ }
+ }
+ });
+ client.startHandshake();
+ future.get();
+ if (negotiatedVersion().equals("TLSv1.2")) {
+ assertNotNull(
+ c.serverContext.getServerSessionContext()
+ .getSession(client.getSession().getId()));
+ }
+ synchronized (handshakeCompletedListenerCalled) {
+ while (!handshakeCompletedListenerCalled[0]) {
+ handshakeCompletedListenerCalled.wait();
+ }
+ }
+ client.close();
+ server.close();
+ c.close();
+ }
+ private static final class TestUncaughtExceptionHandler implements UncaughtExceptionHandler {
+ Throwable actualException;
+ @Override
+ public void uncaughtException(Thread thread, Throwable ex) {
+ assertNull(actualException);
+ actualException = ex;
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_HandshakeCompletedListener_RuntimeException() throws Exception {
+ final Thread self = Thread.currentThread();
+ final UncaughtExceptionHandler original = self.getUncaughtExceptionHandler();
+ final RuntimeException expectedException = new RuntimeException("expected");
+ final TestUncaughtExceptionHandler test = new TestUncaughtExceptionHandler();
+ self.setUncaughtExceptionHandler(test);
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ final SSLSocket client =
+ (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host, c.port);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ Future<Void> future = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ server.startHandshake();
+ return null;
+ }
+ });
+ client.addHandshakeCompletedListener(new HandshakeCompletedListener() {
+ @Override
+ public void handshakeCompleted(HandshakeCompletedEvent event) {
+ throw expectedException;
+ }
+ });
+ client.startHandshake();
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ assertSame(expectedException, test.actualException);
+ self.setUncaughtExceptionHandler(original);
+ }
+
+ @Test
+ public void test_SSLSocket_getUseClientMode() throws Exception {
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ SSLSocket client =
+ (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host, c.port);
+ SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ assertTrue(client.getUseClientMode());
+ assertFalse(server.getUseClientMode());
+ client.close();
+ server.close();
+ c.close();
+ }
+
+ @Test
+ public void testClientMode_normal() throws Exception {
+ // Client is client and server is server.
+ test_SSLSocket_setUseClientMode(true, false);
+ }
+
+ @Test(expected = SSLHandshakeException.class)
+ public void testClientMode_reverse() throws Exception {
+ // Client is server and server is client.
+ test_SSLSocket_setUseClientMode(false, true);
+ }
+
+ @Test(expected = SSLHandshakeException.class)
+ public void testClientMode_bothClient() throws Exception {
+ test_SSLSocket_setUseClientMode(true, true);
+ }
+
+ @Test
+ public void testClientMode_bothServer() throws Exception {
+ try {
+ test_SSLSocket_setUseClientMode(false, false);
+ fail();
+ } catch (SocketTimeoutException expected) {
+ // Ignore
+ } catch (SSLHandshakeException expected) {
+ // Depending on the timing of the socket closures, this can happen as well.
+ assertTrue("Unexpected handshake error: " + expected.getMessage(),
+ expected.getMessage().toLowerCase().contains("connection closed"));
+ }
+ }
+
+ private void test_SSLSocket_setUseClientMode(
+ final boolean clientClientMode, final boolean serverClientMode) throws Exception {
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ SSLSocket client =
+ (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host, c.port);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ Future<IOException> future = runAsync(new Callable<IOException>() {
+ @Override
+ public IOException call() throws Exception {
+ try {
+ if (!serverClientMode) {
+ server.setSoTimeout(1000);
+ }
+ server.setUseClientMode(serverClientMode);
+ server.startHandshake();
+ return null;
+ } catch (SSLHandshakeException e) {
+ return e;
+ } catch (SocketTimeoutException e) {
+ return e;
+ }
+ }
+ });
+ if (!clientClientMode) {
+ client.setSoTimeout(1000);
+ }
+ client.setUseClientMode(clientClientMode);
+ client.startHandshake();
+ IOException ioe = future.get();
+ if (ioe != null) {
+ throw ioe;
+ }
+ client.close();
+ server.close();
+ c.close();
+ }
+
+ @Test
+ public void test_SSLSocket_clientAuth() throws Exception {
+ TestSSLContext c = new TestSSLContext.Builder()
+ .client(TestKeyStore.getClientCertificate())
+ .server(TestKeyStore.getServer())
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ SSLSocket client =
+ (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host, c.port);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ Future<Void> future = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ assertFalse(server.getWantClientAuth());
+ assertFalse(server.getNeedClientAuth());
+ // confirm turning one on by itself
+ server.setWantClientAuth(true);
+ assertTrue(server.getWantClientAuth());
+ assertFalse(server.getNeedClientAuth());
+ // confirm turning setting on toggles the other
+ server.setNeedClientAuth(true);
+ assertFalse(server.getWantClientAuth());
+ assertTrue(server.getNeedClientAuth());
+ // confirm toggling back
+ server.setWantClientAuth(true);
+ assertTrue(server.getWantClientAuth());
+ assertFalse(server.getNeedClientAuth());
+ server.startHandshake();
+ return null;
+ }
+ });
+ client.startHandshake();
+ assertNotNull(client.getSession().getLocalCertificates());
+ TestKeyStore.assertChainLength(client.getSession().getLocalCertificates());
+ TestSSLContext.assertClientCertificateChain(
+ c.clientTrustManager, client.getSession().getLocalCertificates());
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ }
+
+ @Test
+ public void test_SSLSocket_clientAuth_bogusAlias() throws Exception {
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ SSLContext clientContext = SSLContext.getInstance(clientVersion);
+ X509ExtendedKeyManager keyManager = new X509ExtendedKeyManager() {
+ @Override
+ public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
+ return "bogus";
+ }
+ @Override
+ public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
+ throw new AssertionError();
+ }
+ @Override
+ public X509Certificate[] getCertificateChain(String alias) {
+ // return null for "bogus" alias
+ return null;
+ }
+ @Override
+ public String[] getClientAliases(String keyType, Principal[] issuers) {
+ throw new AssertionError();
+ }
+ @Override
+ public String[] getServerAliases(String keyType, Principal[] issuers) {
+ throw new AssertionError();
+ }
+ @Override
+ public String chooseEngineClientAlias(
+ String[] keyType, Principal[] issuers, SSLEngine engine) {
+ throw new AssertionError();
+ }
+ @Override
+ public String chooseEngineServerAlias(
+ String keyType, Principal[] issuers, SSLEngine engine) {
+ throw new AssertionError();
+ }
+ @Override
+ public PrivateKey getPrivateKey(String alias) {
+ // return null for "bogus" alias
+ return null;
+ }
+ };
+ clientContext.init(
+ new KeyManager[] {keyManager}, new TrustManager[] {c.clientTrustManager}, null);
+ SSLSocket client =
+ (SSLSocket) clientContext.getSocketFactory().createSocket(c.host, c.port);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ Future<Void> future = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ try {
+ server.setNeedClientAuth(true);
+ server.startHandshake();
+ fail();
+ } catch (SSLHandshakeException expected) {
+ // Ignored.
+ }
+ return null;
+ }
+ });
+ try {
+ client.startHandshake();
+ // In TLS 1.3, the alert will only show up once we try to use the connection, since
+ // the client finishes the handshake without feedback from the server
+ client.getInputStream().read();
+ fail();
+ } catch (SSLException expected) {
+ // before we would get a NullPointerException from passing
+ // due to the null PrivateKey return by the X509KeyManager.
+ }
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ }
+
+ @Test
+ public void test_SSLSocket_clientAuth_OpaqueKey_RSA() throws Exception {
+ run_SSLSocket_clientAuth_OpaqueKey(TestKeyStore.getClientCertificate());
+ }
+
+ @Test
+ public void test_SSLSocket_clientAuth_OpaqueKey_EC_RSA() throws Exception {
+ run_SSLSocket_clientAuth_OpaqueKey(TestKeyStore.getClientEcRsaCertificate());
+ }
+
+ @Test
+ public void test_SSLSocket_clientAuth_OpaqueKey_EC_EC() throws Exception {
+ run_SSLSocket_clientAuth_OpaqueKey(TestKeyStore.getClientEcEcCertificate());
+ }
+ private void run_SSLSocket_clientAuth_OpaqueKey(TestKeyStore keyStore) throws Exception {
+ // OpaqueProvider will not be allowed to operate if the VM we're running on
+ // requires Oracle signatures for provider jars, since we don't sign the test jar.
+ TestUtils.assumeAllowsUnsignedCrypto();
+ try {
+ Security.insertProviderAt(new OpaqueProvider(), 1);
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .client(keyStore)
+ .server(TestKeyStore.getServer())
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ SSLContext clientContext = SSLContext.getInstance("TLS");
+ final X509KeyManager delegateKeyManager = (X509KeyManager) c.clientKeyManagers[0];
+ X509ExtendedKeyManager keyManager = new X509ExtendedKeyManager() {
+ @Override
+ public String chooseClientAlias(
+ String[] keyType, Principal[] issuers, Socket socket) {
+ return delegateKeyManager.chooseClientAlias(keyType, issuers, socket);
+ }
+ @Override
+ public String chooseServerAlias(
+ String keyType, Principal[] issuers, Socket socket) {
+ return delegateKeyManager.chooseServerAlias(keyType, issuers, socket);
+ }
+ @Override
+ public X509Certificate[] getCertificateChain(String alias) {
+ return delegateKeyManager.getCertificateChain(alias);
+ }
+ @Override
+ public String[] getClientAliases(String keyType, Principal[] issuers) {
+ return delegateKeyManager.getClientAliases(keyType, issuers);
+ }
+ @Override
+ public String[] getServerAliases(String keyType, Principal[] issuers) {
+ return delegateKeyManager.getServerAliases(keyType, issuers);
+ }
+ @Override
+ public PrivateKey getPrivateKey(String alias) {
+ PrivateKey privKey = delegateKeyManager.getPrivateKey(alias);
+ return OpaqueProvider.wrapKey(privKey);
+ }
+ @Override
+ public String chooseEngineClientAlias(
+ String[] keyType, Principal[] issuers, SSLEngine engine) {
+ throw new AssertionError();
+ }
+ @Override
+ public String chooseEngineServerAlias(
+ String keyType, Principal[] issuers, SSLEngine engine) {
+ throw new AssertionError();
+ }
+ };
+ clientContext.init(
+ new KeyManager[] {keyManager}, new TrustManager[] {c.clientTrustManager}, null);
+ SSLSocket client =
+ (SSLSocket) clientContext.getSocketFactory().createSocket(c.host, c.port);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ Future<Void> future = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ server.setNeedClientAuth(true);
+ server.startHandshake();
+ return null;
+ }
+ });
+ client.startHandshake();
+ assertNotNull(client.getSession().getLocalCertificates());
+ TestKeyStore.assertChainLength(client.getSession().getLocalCertificates());
+ TestSSLContext.assertClientCertificateChain(
+ c.clientTrustManager, client.getSession().getLocalCertificates());
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ } finally {
+ Security.removeProvider(OpaqueProvider.NAME);
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_TrustManagerRuntimeException() throws Exception {
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ SSLContext clientContext = SSLContext.getInstance("TLS");
+ X509TrustManager trustManager = new X509TrustManager() {
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ throw new AssertionError();
+ }
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ throw new RuntimeException(); // throw a RuntimeException from custom TrustManager
+ }
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ throw new AssertionError();
+ }
+ };
+ clientContext.init(null, new TrustManager[] {trustManager}, null);
+ SSLSocket client =
+ (SSLSocket) clientContext.getSocketFactory().createSocket(c.host, c.port);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ Future<Void> future = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ try {
+ server.startHandshake();
+ fail();
+ } catch (SSLHandshakeException expected) {
+ // Ignored.
+ }
+ return null;
+ }
+ });
+ try {
+ client.startHandshake();
+ fail();
+ } catch (SSLHandshakeException expected) {
+ // before we would get a RuntimeException from checkServerTrusted.
+ }
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ }
+
+ @Test
+ public void test_SSLSocket_getEnableSessionCreation() throws Exception {
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ SSLSocket client =
+ (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host, c.port);
+ SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ assertTrue(client.getEnableSessionCreation());
+ assertTrue(server.getEnableSessionCreation());
+ client.close();
+ server.close();
+ c.close();
+ }
+
+ @Test
+ public void test_SSLSocket_setEnableSessionCreation_server() throws Exception {
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ SSLSocket client =
+ (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host, c.port);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ Future<Void> future = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ server.setEnableSessionCreation(false);
+ try {
+ server.startHandshake();
+ fail();
+ } catch (SSLException expected) {
+ // Ignored.
+ }
+ return null;
+ }
+ });
+ try {
+ client.startHandshake();
+ fail();
+ } catch (SSLException expected) {
+ // Ignored.
+ }
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ }
+
+ @Test
+ public void test_SSLSocket_setEnableSessionCreation_client() throws Exception {
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ SSLSocket client =
+ (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host, c.port);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ Future<Void> future = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ try {
+ server.startHandshake();
+ fail();
+ } catch (SSLException expected) {
+ // Ignored.
+ }
+ return null;
+ }
+ });
+ client.setEnableSessionCreation(false);
+ try {
+ client.startHandshake();
+ fail();
+ } catch (SSLException expected) {
+ // Ignored.
+ }
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ }
+
+ @Test
+ public void test_SSLSocket_close() throws Exception {
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ TestSSLSocketPair pair = TestSSLSocketPair.create(c).connect();
+ SSLSocket server = pair.server;
+ SSLSocket client = pair.client;
+ assertFalse(server.isClosed());
+ assertFalse(client.isClosed());
+ InputStream input = client.getInputStream();
+ OutputStream output = client.getOutputStream();
+ server.close();
+ client.close();
+ assertTrue(server.isClosed());
+ assertTrue(client.isClosed());
+ // close after close is okay...
+ server.close();
+ client.close();
+ // ...so are a lot of other operations...
+ HandshakeCompletedListener l = new HandshakeCompletedListener() {
+ @Override
+ public void handshakeCompleted(HandshakeCompletedEvent e) {
+ }
+ };
+ client.addHandshakeCompletedListener(l);
+ assertNotNull(client.getEnabledCipherSuites());
+ assertNotNull(client.getEnabledProtocols());
+ client.getEnableSessionCreation();
+ client.getNeedClientAuth();
+ assertNotNull(client.getSession());
+ assertNotNull(client.getSSLParameters());
+ assertNotNull(client.getSupportedProtocols());
+ client.getUseClientMode();
+ client.getWantClientAuth();
+ client.removeHandshakeCompletedListener(l);
+ client.setEnabledCipherSuites(new String[0]);
+ client.setEnabledProtocols(new String[0]);
+ client.setEnableSessionCreation(false);
+ client.setNeedClientAuth(false);
+ client.setSSLParameters(client.getSSLParameters());
+ client.setWantClientAuth(false);
+ // ...but some operations are expected to give SocketException...
+ try {
+ client.startHandshake();
+ fail();
+ } catch (SocketException expected) {
+ // Ignored.
+ }
+ try {
+ client.getInputStream();
+ fail();
+ } catch (SocketException expected) {
+ // Ignored.
+ }
+ try {
+ client.getOutputStream();
+ fail();
+ } catch (SocketException expected) {
+ // Ignored.
+ }
+ try {
+ @SuppressWarnings("unused")
+ int value = input.read();
+ fail();
+ } catch (SocketException expected) {
+ // Ignored.
+ }
+ try {
+ @SuppressWarnings("unused")
+ int bytesRead = input.read(null, -1, -1);
+ fail();
+ } catch (NullPointerException expected) {
+ // Ignored.
+ } catch (SocketException expected) {
+ // Ignored.
+ }
+ try {
+ output.write(-1);
+ fail();
+ } catch (SocketException expected) {
+ // Ignored.
+ }
+ try {
+ output.write(null, -1, -1);
+ fail();
+ } catch (NullPointerException expected) {
+ // Ignored.
+ } catch (SocketException expected) {
+ // Ignored.
+ }
+ // ... and one gives IllegalArgumentException
+ try {
+ client.setUseClientMode(false);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ pair.close();
+ }
+
+ @Test
+ public void test_SSLSocket_ShutdownInput() throws Exception {
+ // Fdsocket throws SslException rather than returning EOF after input shutdown
+ // on Windows, but we won't be fixing it as that implementation is already deprecated.
+ assumeFalse("Skipping shutdownInput() test on Windows", isWindows());
+
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ byte[] buffer = new byte[1];
+ TestSSLSocketPair pair = TestSSLSocketPair.create(c).connect();
+ SSLSocket server = pair.server;
+ SSLSocket client = pair.client;
+ assertFalse(server.isClosed());
+ assertFalse(client.isClosed());
+ InputStream input = client.getInputStream();
+ client.shutdownInput();
+ assertFalse(client.isClosed());
+ assertFalse(server.isClosed());
+ // Shutdown after shutdown is not OK
+ SocketException exception = assertThrows(SocketException.class, client::shutdownInput);
+ assertTrue(exception.getMessage().contains("already shutdown"));
+
+ // The following operations should succeed, same as after close()
+ HandshakeCompletedListener listener = e -> {};
+ client.addHandshakeCompletedListener(listener);
+ assertNotNull(client.getEnabledCipherSuites());
+ assertNotNull(client.getEnabledProtocols());
+ client.getEnableSessionCreation();
+ client.getNeedClientAuth();
+ assertNotNull(client.getSession());
+ assertNotNull(client.getSSLParameters());
+ assertNotNull(client.getSupportedProtocols());
+ client.getUseClientMode();
+ client.getWantClientAuth();
+ client.removeHandshakeCompletedListener(listener);
+ client.setEnabledCipherSuites(new String[0]);
+ client.setEnabledProtocols(new String[0]);
+ client.setEnableSessionCreation(false);
+ client.setNeedClientAuth(false);
+ client.setSSLParameters(client.getSSLParameters());
+ client.setWantClientAuth(false);
+
+ // The following operations should succeed, unlike after close()
+ client.startHandshake();
+ client.getInputStream();
+ client.getOutputStream();
+ assertEquals(-1, input.read());
+ assertEquals(-1, input.read(buffer));
+ assertEquals(0, input.available());
+
+ pair.close();
+ }
+
+ @Test
+ public void test_SSLSocket_ShutdownOutput() throws Exception {
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ byte[] buffer = new byte[1];
+ TestSSLSocketPair pair = TestSSLSocketPair.create(c).connect();
+ SSLSocket server = pair.server;
+ SSLSocket client = pair.client;
+ assertFalse(server.isClosed());
+ assertFalse(client.isClosed());
+ OutputStream output = client.getOutputStream();
+ client.shutdownOutput();
+ assertFalse(client.isClosed());
+ assertFalse(server.isClosed());
+ // Shutdown after shutdown is not OK
+ SocketException exception = assertThrows(SocketException.class, client::shutdownOutput);
+ assertTrue(exception.getMessage().contains("already shutdown"));
+
+ // The following operations should succeed, same as after close()
+ HandshakeCompletedListener listener = e -> {};
+ client.addHandshakeCompletedListener(listener);
+ assertNotNull(client.getEnabledCipherSuites());
+ assertNotNull(client.getEnabledProtocols());
+ client.getEnableSessionCreation();
+ client.getNeedClientAuth();
+ assertNotNull(client.getSession());
+ assertNotNull(client.getSSLParameters());
+ assertNotNull(client.getSupportedProtocols());
+ client.getUseClientMode();
+ client.getWantClientAuth();
+ client.removeHandshakeCompletedListener(listener);
+ client.setEnabledCipherSuites(new String[0]);
+ client.setEnabledProtocols(new String[0]);
+ client.setEnableSessionCreation(false);
+ client.setNeedClientAuth(false);
+ client.setSSLParameters(client.getSSLParameters());
+ client.setWantClientAuth(false);
+
+ // The following operations should succeed, unlike after close()
+ client.startHandshake();
+ client.getInputStream();
+ client.getOutputStream();
+
+ // Any output should fail
+ try {
+ output.write(buffer);
+ fail();
+ } catch (SocketException | SSLException expected) {
+ // Expected.
+ // SocketException is correct but the old fd-based implementation
+ // throws SSLException, and it's not worth changing it at this late stage.
+ }
+ pair.close();
+ }
+
+ /**
+ * b/3350645 Test to confirm that an SSLSocket.close() performing
+ * an SSL_shutdown does not throw an IOException if the peer
+ * socket has been closed.
+ */
+ @Test
+ public void test_SSLSocket_shutdownCloseOnClosedPeer() throws Exception {
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ final Socket underlying = new Socket(c.host, c.port);
+ final SSLSocket wrapping = (SSLSocket) c.clientContext.getSocketFactory().createSocket(
+ underlying, c.host.getHostName(), c.port, false);
+ Future<Void> clientFuture = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ wrapping.startHandshake();
+ wrapping.getOutputStream().write(42);
+ // close the underlying socket,
+ // so that no SSL shutdown is sent
+ underlying.close();
+ wrapping.close();
+ return null;
+ }
+ });
+ SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ server.startHandshake();
+ @SuppressWarnings("unused")
+ int value = server.getInputStream().read();
+ // wait for thread to finish so we know client is closed.
+ clientFuture.get();
+ // close should cause an SSL_shutdown which will fail
+ // because the peer has closed, but it shouldn't throw.
+ server.close();
+ }
+
+ @Test
+ public void test_SSLSocket_endpointIdentification_Success() throws Exception {
+ TestUtils.assumeSetEndpointIdentificationAlgorithmAvailable();
+ // The default hostname verifier on OpenJDK just rejects all hostnames,
+ // which is not helpful, so replace with a basic functional one.
+ HostnameVerifier oldDefault = HttpsURLConnection.getDefaultHostnameVerifier();
+ HttpsURLConnection.setDefaultHostnameVerifier(new TestHostnameVerifier());
+ try {
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket();
+ SSLParameters p = client.getSSLParameters();
+ p.setEndpointIdentificationAlgorithm("HTTPS");
+ client.setSSLParameters(p);
+ client.connect(new InetSocketAddress(c.host, c.port));
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ Future<Void> future = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ server.startHandshake();
+ assertNotNull(server.getSession());
+ try {
+ server.getSession().getPeerCertificates();
+ fail();
+ } catch (SSLPeerUnverifiedException expected) {
+ // Ignored.
+ }
+ Certificate[] localCertificates = server.getSession().getLocalCertificates();
+ assertNotNull(localCertificates);
+ TestKeyStore.assertChainLength(localCertificates);
+ assertNotNull(localCertificates[0]);
+ TestSSLContext
+ .assertCertificateInKeyStore(localCertificates[0], c.serverKeyStore);
+ return null;
+ }
+ });
+ client.startHandshake();
+ assertNotNull(client.getSession());
+ assertNull(client.getSession().getLocalCertificates());
+ Certificate[] peerCertificates = client.getSession().getPeerCertificates();
+ assertNotNull(peerCertificates);
+ TestKeyStore.assertChainLength(peerCertificates);
+ assertNotNull(peerCertificates[0]);
+ TestSSLContext.assertCertificateInKeyStore(peerCertificates[0], c.serverKeyStore);
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ } finally {
+ HttpsURLConnection.setDefaultHostnameVerifier(oldDefault);
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_endpointIdentification_Failure() throws Exception {
+ TestUtils.assumeSetEndpointIdentificationAlgorithmAvailable();
+ // The default hostname verifier on OpenJDK just rejects all hostnames,
+ // which is not helpful, so replace with a basic functional one.
+ HostnameVerifier oldDefault = HttpsURLConnection.getDefaultHostnameVerifier();
+ HttpsURLConnection.setDefaultHostnameVerifier(new TestHostnameVerifier());
+ try {
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket();
+ SSLParameters p = client.getSSLParameters();
+ p.setEndpointIdentificationAlgorithm("HTTPS");
+ client.setSSLParameters(p);
+ client.connect(c.getLoopbackAsHostname("unmatched.example.com", c.port));
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ Future<Void> future = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ try {
+ server.startHandshake();
+ fail("Should receive SSLHandshakeException as server");
+ } catch (SSLHandshakeException expected) {
+ // Ignored.
+ }
+ return null;
+ }
+ });
+ try {
+ client.startHandshake();
+ fail("Should throw when hostname does not match expected");
+ } catch (SSLHandshakeException expected) {
+ // Ignored.
+ } finally {
+ try {
+ future.get();
+ } finally {
+ client.close();
+ server.close();
+ c.close();
+ }
+ }
+ } finally {
+ HttpsURLConnection.setDefaultHostnameVerifier(oldDefault);
+ }
+ }
+
+ @Test(expected = SocketTimeoutException.class)
+ public void test_SSLSocket_setSoWriteTimeout() throws Exception {
+ // Only run this test on Linux since it relies on non-posix methods.
+ assumeTrue("Test only runs on Linux. Current OS: " + osName(), isLinux());
+
+ // In jb-mr2 it was found that we need to also set SO_RCVBUF
+ // to a minimal size or the write would not block.
+ final int receiveBufferSize = 128;
+ TestSSLContext c = TestSSLContext.newBuilder()
+ .serverReceiveBufferSize(receiveBufferSize)
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+
+ final SSLSocket client =
+ (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host, c.port);
+
+ // Try to make the client SO_SNDBUF size as small as possible
+ // (it can default to 512k or even megabytes). Note that
+ // socket(7) says that the kernel will double the request to
+ // leave room for its own book keeping and that the minimal
+ // value will be 2048. Also note that tcp(7) says the value
+ // needs to be set before connect(2).
+ int sendBufferSize = 1024;
+ client.setSendBufferSize(sendBufferSize);
+ sendBufferSize = client.getSendBufferSize();
+
+ // Start the handshake.
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ Future<Void> future = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ client.startHandshake();
+ return null;
+ }
+ });
+ server.startHandshake();
+
+ assertTrue(isConscryptSocket(client));
+ // The concrete class that Conscrypt returns has methods on it that have no
+ // equivalent on the public API (like setSoWriteTimeout), so users have
+ // previously used reflection to access those otherwise-inaccessible methods
+ // on that class. The concrete class used to be named OpenSSLSocketImpl, so
+ // check that OpenSSLSocketImpl is still in the class hierarchy so applications
+ // that rely on getting that class back still work.
+ Class<?> superClass = client.getClass();
+ do {
+ superClass = superClass.getSuperclass();
+ } while (superClass != Object.class && !superClass.getName().endsWith("OpenSSLSocketImpl"));
+ assertEquals("OpenSSLSocketImpl", superClass.getSimpleName());
+
+
+ try {
+ setWriteTimeout(client, 1);
+
+ // Add extra space to the write to exceed the send buffer
+ // size and cause the write to block.
+ final int extra = 1;
+ client.getOutputStream().write(new byte[sendBufferSize + extra]);
+ } finally {
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_reusedNpnSocket() throws Exception {
+ byte[] npnProtocols = new byte[] {
+ 8, 'h', 't', 't', 'p', '/', '1', '.', '1'
+ };
+
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket();
+
+ assertTrue(isConscryptSocket(client));
+ Class<?> actualClass = client.getClass();
+ Method setNpnProtocols = actualClass.getMethod("setNpnProtocols", byte[].class);
+
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+
+ // First connection with NPN set on client and server
+ {
+ setNpnProtocols.invoke(client, npnProtocols);
+ client.connect(new InetSocketAddress(c.host, c.port));
+
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ assertTrue(isConscryptSocket(server));
+ setNpnProtocols.invoke(server, npnProtocols);
+
+ Future<Void> future = executor.submit(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ server.startHandshake();
+ return null;
+ }
+ });
+ client.startHandshake();
+
+ future.get();
+ client.close();
+ server.close();
+ }
+
+ // Second connection with client NPN already set on the SSL context, but
+ // without server NPN set.
+ {
+ SSLServerSocket serverSocket = (SSLServerSocket) c.serverContext
+ .getServerSocketFactory().createServerSocket(0);
+ InetAddress host = InetAddress.getLocalHost();
+ int port = serverSocket.getLocalPort();
+
+ client = (SSLSocket) c.clientContext.getSocketFactory().createSocket();
+ client.connect(new InetSocketAddress(host, port));
+
+ final SSLSocket server = (SSLSocket) serverSocket.accept();
+
+ Future<Void> future = executor.submit(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ server.startHandshake();
+ return null;
+ }
+ });
+ client.startHandshake();
+
+ future.get();
+ client.close();
+ server.close();
+ serverSocket.close();
+ }
+
+ c.close();
+ }
+
+ // TODO(nmittler): Conscrypt socket read may return -1 instead of SocketException.
+ @Test
+ public void test_SSLSocket_interrupt_readUnderlyingAndCloseUnderlying() throws Exception {
+ test_SSLSocket_interrupt_case(true, true);
+ }
+
+ // TODO(nmittler): Conscrypt socket read may return -1 instead of SocketException.
+ @Test
+ public void test_SSLSocket_interrupt_readUnderlyingAndCloseWrapper() throws Exception {
+ test_SSLSocket_interrupt_case(true, false);
+ }
+
+ // TODO(nmittler): FD socket gets stuck in read on Windows and OSX.
+ @Test
+ public void test_SSLSocket_interrupt_readWrapperAndCloseUnderlying() throws Exception {
+ test_SSLSocket_interrupt_case(false, true);
+ }
+
+ // TODO(nmittler): Conscrypt socket read may return -1 instead of SocketException.
+ @Test
+ public void test_SSLSocket_interrupt_readWrapperAndCloseWrapper() throws Exception {
+ test_SSLSocket_interrupt_case(false, false);
+ }
+
+ private void test_SSLSocket_interrupt_case(boolean readUnderlying, boolean closeUnderlying)
+ throws Exception {
+ final int readingTimeoutMillis = 5000;
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ final Socket underlying = new Socket(c.host, c.port);
+ final SSLSocket clientWrapping =
+ (SSLSocket) c.clientContext.getSocketFactory().createSocket(
+ underlying, c.host.getHostName(), c.port, true);
+
+ if (isConscryptFdSocket(clientWrapping) && !readUnderlying && closeUnderlying) {
+ // TODO(nmittler): FD socket gets stuck in the read on Windows and OSX.
+ assumeFalse("Skipping interrupt test on Windows", isWindows());
+ assumeFalse("Skipping interrupt test on OSX", isOsx());
+ }
+
+ SSLSocket server = (SSLSocket) c.serverSocket.accept();
+
+ // Start the handshake.
+ Future<Integer> handshakeFuture = runAsync(new Callable<Integer>() {
+ @Override
+ public Integer call() throws Exception {
+ clientWrapping.startHandshake();
+ return clientWrapping.getInputStream().read();
+ }
+ });
+ server.startHandshake();
+ // TLS 1.3 sends some post-handshake management messages, so send a single byte through
+ // to process through those messages.
+ server.getOutputStream().write(42);
+ assertEquals(42, handshakeFuture.get().intValue());
+
+ final Socket toRead = readUnderlying ? underlying : clientWrapping;
+ final Socket toClose = closeUnderlying ? underlying : clientWrapping;
+
+ // Schedule the socket to be closed in 1 second.
+ Future<Void> future = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ Thread.sleep(1000);
+ toClose.close();
+ return null;
+ }
+ });
+
+ // Read from the socket.
+ try {
+ toRead.setSoTimeout(readingTimeoutMillis);
+ int read = toRead.getInputStream().read();
+ // In the case of reading the wrapper and closing the underlying socket,
+ // there is a race condition between the reading thread being woken and
+ // reading the socket again and the closing thread marking the file descriptor
+ // as invalid. If the latter happens first, a SocketException is thrown,
+ // but if the former happens first it just looks like the peer closed the
+ // connection and a -1 return is acceptable.
+ if (read != -1 || readUnderlying || !closeUnderlying) {
+ fail();
+ }
+ } catch (SocketTimeoutException e) {
+ throw e;
+ } catch (IOException expected) {
+ // Expected
+ }
+
+ future.get();
+ server.close();
+ underlying.close();
+ server.close();
+ }
+
+ /**
+ * b/7014266 Test to confirm that an SSLSocket.close() on one
+ * thread will interrupt another thread blocked reading on the same
+ * socket.
+ */
+ // TODO(nmittler): Interrupts do not work with the engine-based socket.
+ @Test
+ public void test_SSLSocket_interrupt_read_withoutAutoClose() throws Exception {
+ final int readingTimeoutMillis = 5000;
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ final Socket underlying = new Socket(c.host, c.port);
+ final SSLSocket wrapping = (SSLSocket) c.clientContext.getSocketFactory().createSocket(
+ underlying, c.host.getHostName(), c.port, false);
+
+ // TODO(nmittler): Interrupts do not work with the engine-based socket.
+ assumeFalse(isConscryptEngineSocket(wrapping));
+
+ Future<Void> clientFuture = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ wrapping.startHandshake();
+ try {
+ wrapping.setSoTimeout(readingTimeoutMillis);
+ wrapping.getInputStream().read();
+ fail();
+ } catch (SocketException expected) {
+ // Conscrypt throws an exception complaining that the socket is closed
+ // if it's interrupted by a close() in the middle of a read()
+ assertTrue(expected.getMessage().contains("closed"));
+ }
+ return null;
+ }
+ });
+ SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ server.startHandshake();
+
+ // Wait for the client to at least be in the "read" method before calling close()
+ Thread[] threads = new Thread[1];
+ threadGroup.enumerate(threads);
+ if (threads[0] != null) {
+ boolean clientInRead = false;
+ while (!clientInRead) {
+ StackTraceElement[] elements = threads[0].getStackTrace();
+ for (StackTraceElement element : elements) {
+ if ("read".equals(element.getMethodName())) {
+ // The client might be executing "read" but still not have reached the
+ // point in which it's blocked reading. This is causing flakiness
+ // (b/24367646). Delaying for a fraction of the timeout.
+ Thread.sleep(1000);
+ clientInRead = true;
+ break;
+ }
+ }
+ }
+ }
+
+ wrapping.close();
+
+ clientFuture.get();
+ server.close();
+ }
+
+ /**
+ * Test to confirm that an SSLSocket.close() on one
+ * thread will interrupt another thread blocked writing on the same
+ * socket.
+ *
+ * Currently disabled: If the victim thread is not actually blocked in a write
+ * call then ConscryptEngineSocket can corrupt the output due to unsynchronized
+ * concurrent access to the socket's output stream and cause flakes: b/161347005
+ * TODO(prb): Re-enable after underlying bug resolved
+ *
+ * See also b/147323301 where close() triggered an infinite loop instead.
+ */
+ @Test
+ @Ignore
+ public void test_SSLSocket_interrupt_write_withAutoclose() throws Exception {
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ final Socket underlying = new Socket(c.host, c.port);
+ final SSLSocket wrapping = (SSLSocket) c.clientContext.getSocketFactory().createSocket(
+ underlying, c.host.getHostName(), c.port, true);
+ final byte[] data = new byte[1024 * 64];
+
+ // TODO(b/161347005): Re-enable once engine-based socket interruption works correctly.
+ assumeFalse(isConscryptEngineSocket(wrapping));
+ Future<Void> clientFuture = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ wrapping.startHandshake();
+ try {
+ for (int i = 0; i < 64; i++) {
+ wrapping.getOutputStream().write(data);
+ }
+ // Failure here means that no exception was thrown, so the data buffer is
+ // probably too small.
+ fail();
+ } catch (SocketException expected) {
+ assertTrue(expected.getMessage().contains("closed"));
+ }
+ return null;
+ }
+ });
+ SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ server.startHandshake();
+
+ // Read one byte so that both ends are in a fully connected state and data has
+ // started to flow, and then close the socket from this thread.
+ int unused = server.getInputStream().read();
+ wrapping.close();
+
+ clientFuture.get();
+ server.close();
+ }
+
+ @Test
+ public void test_SSLSocket_ClientHello_record_size() throws Exception {
+ // This test checks the size of ClientHello of the default SSLSocket. TLS/SSL handshakes
+ // with older/unpatched F5/BIG-IP appliances are known to stall and time out when
+ // the fragment containing ClientHello is between 256 and 511 (inclusive) bytes long.
+ SSLContext sslContext = SSLContext.getInstance(clientVersion);
+ sslContext.init(null, null, null);
+ SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+ sslSocketFactory = new DelegatingSSLSocketFactory(sslSocketFactory) {
+ @Override
+ protected SSLSocket configureSocket(SSLSocket socket) {
+ // Enable SNI extension on the socket (this is typically enabled by default)
+ // to increase the size of ClientHello.
+ setHostname(socket);
+
+ // Enable Session Tickets extension on the socket (this is typically enabled
+ // by default) to increase the size of ClientHello.
+ enableSessionTickets(socket);
+ return socket;
+ }
+ };
+ TlsRecord firstReceivedTlsRecord = TlsTester.captureTlsHandshakeFirstTlsRecord(executor, sslSocketFactory);
+ assertEquals("TLS record type", TlsProtocols.HANDSHAKE, firstReceivedTlsRecord.type);
+ HandshakeMessage handshakeMessage = HandshakeMessage.read(
+ new DataInputStream(new ByteArrayInputStream(firstReceivedTlsRecord.fragment)));
+ assertEquals(
+ "HandshakeMessage type", HandshakeMessage.TYPE_CLIENT_HELLO, handshakeMessage.type);
+ int fragmentLength = firstReceivedTlsRecord.fragment.length;
+ if ((fragmentLength >= 256) && (fragmentLength <= 511)) {
+ fail("Fragment containing ClientHello is of dangerous length: " + fragmentLength
+ + " bytes");
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_ClientHello_SNI() throws Exception {
+ ForEachRunner.runNamed(new ForEachRunner.Callback<SSLSocketFactory>() {
+ @Override
+ public void run(SSLSocketFactory sslSocketFactory) throws Exception {
+ ClientHello clientHello = TlsTester
+ .captureTlsHandshakeClientHello(executor, sslSocketFactory);
+ ServerNameHelloExtension sniExtension =
+ (ServerNameHelloExtension) clientHello.findExtensionByType(
+ HelloExtension.TYPE_SERVER_NAME);
+ assertNotNull(sniExtension);
+ assertEquals(
+ Collections.singletonList("localhost.localdomain"), sniExtension.hostnames);
+ }
+ }, getSSLSocketFactoriesToTest());
+ }
+
+ @Test
+ public void test_SSLSocket_ClientHello_ALPN() throws Exception {
+ final String[] protocolList = new String[] { "h2", "http/1.1" };
+
+ ForEachRunner.runNamed(new ForEachRunner.Callback<SSLSocketFactory>() {
+ @Override
+ public void run(SSLSocketFactory sslSocketFactory) throws Exception {
+ ClientHello clientHello = TlsTester.captureTlsHandshakeClientHello(executor,
+ new DelegatingSSLSocketFactory(sslSocketFactory) {
+ @Override public SSLSocket configureSocket(SSLSocket socket) {
+ Conscrypt.setApplicationProtocols(socket, protocolList);
+ return socket;
+ }
+ });
+ AlpnHelloExtension alpnExtension =
+ (AlpnHelloExtension) clientHello.findExtensionByType(
+ HelloExtension.TYPE_APPLICATION_LAYER_PROTOCOL_NEGOTIATION);
+ assertNotNull(alpnExtension);
+ assertEquals(Arrays.asList(protocolList), alpnExtension.protocols);
+ }
+ }, getSSLSocketFactoriesToTest());
+ }
+
+ private List<Pair<String, SSLSocketFactory>> getSSLSocketFactoriesToTest()
+ throws NoSuchAlgorithmException, KeyManagementException {
+ List<Pair<String, SSLSocketFactory>> result =
+ new ArrayList<Pair<String, SSLSocketFactory>>();
+ result.add(Pair.of("default", (SSLSocketFactory) SSLSocketFactory.getDefault()));
+ for (String sslContextProtocol : StandardNames.SSL_CONTEXT_PROTOCOLS) {
+ SSLContext sslContext = SSLContext.getInstance(sslContextProtocol);
+ if (StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT.equals(sslContextProtocol)) {
+ continue;
+ }
+ sslContext.init(null, null, null);
+ result.add(Pair.of("SSLContext(\"" + sslContext.getProtocol() + "\")",
+ sslContext.getSocketFactory()));
+ }
+ return result;
+ }
+
+ // http://b/18428603
+ @Test
+ public void test_SSLSocket_getPortWithSNI() throws Exception {
+ TestSSLContext context = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ SSLSocket client =
+ (SSLSocket) context.clientContext.getSocketFactory().createSocket();
+ try {
+ client.connect(new InetSocketAddress(context.host, context.port));
+ setHostname(client);
+ assertTrue(client.getPort() > 0);
+ } finally {
+ client.close();
+ context.close();
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_SNIHostName() throws Exception {
+ TestUtils.assumeSNIHostnameAvailable();
+ final TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ final SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket();
+ SSLParameters clientParams = client.getSSLParameters();
+ clientParams.setServerNames(
+ Collections.singletonList((SNIServerName) new SNIHostName("www.example.com")));
+ client.setSSLParameters(clientParams);
+ SSLParameters serverParams = c.serverSocket.getSSLParameters();
+ serverParams.setSNIMatchers(
+ Collections.singletonList(SNIHostName.createSNIMatcher("www\\.example\\.com")));
+ c.serverSocket.setSSLParameters(serverParams);
+ client.connect(new InetSocketAddress(c.host, c.port));
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ @SuppressWarnings("unused")
+ Future<?> future = runAsync(new Callable<Object>() {
+ @Override
+ public Object call() throws Exception {
+ client.startHandshake();
+ return null;
+ }
+ });
+ server.startHandshake();
+ SSLSession serverSession = server.getSession();
+ assertTrue(serverSession instanceof ExtendedSSLSession);
+ ExtendedSSLSession extendedServerSession = (ExtendedSSLSession) serverSession;
+ List<SNIServerName> requestedNames = extendedServerSession.getRequestedServerNames();
+ assertNotNull(requestedNames);
+ assertEquals(1, requestedNames.size());
+ SNIServerName serverName = requestedNames.get(0);
+ assertEquals(StandardConstants.SNI_HOST_NAME, serverName.getType());
+ assertTrue(serverName instanceof SNIHostName);
+ SNIHostName serverHostName = (SNIHostName) serverName;
+ assertEquals("www.example.com", serverHostName.getAsciiName());
+ }
+
+ @Test
+ public void test_SSLSocket_ClientGetsAlertDuringHandshake_HasGoodExceptionMessage()
+ throws Exception {
+ TestSSLContext context = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ final ServerSocket listener = ServerSocketFactory.getDefault().createServerSocket(0);
+ final SSLSocket client = (SSLSocket) context.clientContext.getSocketFactory().createSocket(
+ context.host, listener.getLocalPort());
+ final Socket server = listener.accept();
+ Future<Void> c = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ try {
+ client.startHandshake();
+ fail("Should receive handshake exception");
+ } catch (SSLHandshakeException expected) {
+ assertFalse(expected.getMessage().contains("SSL_ERROR_ZERO_RETURN"));
+ assertFalse(expected.getMessage().contains("You should never see this."));
+ }
+ return null;
+ }
+ });
+ Future<Void> s = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ // Wait until the client sends something.
+ byte[] scratch = new byte[8192];
+ @SuppressWarnings("unused")
+ int bytesRead = server.getInputStream().read(scratch);
+ // Write a bogus TLS alert:
+ // TLSv1.2 Record Layer: Alert (Level: Warning, Description: Protocol Version)
+ server.getOutputStream()
+ .write(new byte[]{0x15, 0x03, 0x03, 0x00, 0x02, 0x01, 0x46});
+ // TLSv1.2 Record Layer: Alert (Level: Warning, Description: Close Notify)
+ server.getOutputStream()
+ .write(new byte[]{0x15, 0x03, 0x03, 0x00, 0x02, 0x01, 0x00});
+ return null;
+ }
+ });
+ c.get(5, TimeUnit.SECONDS);
+ s.get(5, TimeUnit.SECONDS);
+ client.close();
+ server.close();
+ listener.close();
+ context.close();
+ }
+
+ @Test
+ public void test_SSLSocket_ServerGetsAlertDuringHandshake_HasGoodExceptionMessage()
+ throws Exception {
+ TestSSLContext context = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ final Socket client = SocketFactory.getDefault().createSocket(context.host, context.port);
+ final SSLSocket server = (SSLSocket) context.serverSocket.accept();
+ Future<Void> s = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ try {
+ server.startHandshake();
+ fail("Should receive handshake exception");
+ } catch (SSLHandshakeException expected) {
+ assertFalse(expected.getMessage().contains("SSL_ERROR_ZERO_RETURN"));
+ assertFalse(expected.getMessage().contains("You should never see this."));
+ }
+ return null;
+ }
+ });
+ Future<Void> c = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ // Send bogus ClientHello:
+ // TLSv1.2 Record Layer: Handshake Protocol: Client Hello
+ client.getOutputStream().write(new byte[]{
+ (byte) 0x16, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0xb9,
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0xb5, (byte) 0x03,
+ (byte) 0x03, (byte) 0x5a, (byte) 0x31, (byte) 0xba, (byte) 0x44,
+ (byte) 0x24, (byte) 0xfd, (byte) 0xf0, (byte) 0x56, (byte) 0x46,
+ (byte) 0xea, (byte) 0xee, (byte) 0x1c, (byte) 0x62, (byte) 0x8f,
+ (byte) 0x18, (byte) 0x04, (byte) 0xbd, (byte) 0x1c, (byte) 0xbc,
+ (byte) 0xbf, (byte) 0x6d, (byte) 0x84, (byte) 0x12, (byte) 0xe9,
+ (byte) 0x94, (byte) 0xf5, (byte) 0x1c, (byte) 0x15, (byte) 0x3e,
+ (byte) 0x79, (byte) 0x01, (byte) 0xe2, (byte) 0x00, (byte) 0x00,
+ (byte) 0x28, (byte) 0xc0, (byte) 0x2b, (byte) 0xc0, (byte) 0x2c,
+ (byte) 0xc0, (byte) 0x2f, (byte) 0xc0, (byte) 0x30, (byte) 0x00,
+ (byte) 0x9e, (byte) 0x00, (byte) 0x9f, (byte) 0xc0, (byte) 0x09,
+ (byte) 0xc0, (byte) 0x0a, (byte) 0xc0, (byte) 0x13, (byte) 0xc0,
+ (byte) 0x14, (byte) 0x00, (byte) 0x33, (byte) 0x00, (byte) 0x39,
+ (byte) 0xc0, (byte) 0x07, (byte) 0xc0, (byte) 0x11, (byte) 0x00,
+ (byte) 0x9c, (byte) 0x00, (byte) 0x9d, (byte) 0x00, (byte) 0x2f,
+ (byte) 0x00, (byte) 0x35, (byte) 0x00, (byte) 0x05, (byte) 0x00,
+ (byte) 0xff, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x64,
+ (byte) 0x00, (byte) 0x0b, (byte) 0x00, (byte) 0x04, (byte) 0x03,
+ (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x00, (byte) 0x0a,
+ (byte) 0x00, (byte) 0x34, (byte) 0x00, (byte) 0x32, (byte) 0x00,
+ (byte) 0x0e, (byte) 0x00, (byte) 0x0d, (byte) 0x00, (byte) 0x19,
+ (byte) 0x00, (byte) 0x0b, (byte) 0x00, (byte) 0x0c, (byte) 0x00,
+ (byte) 0x18, (byte) 0x00, (byte) 0x09, (byte) 0x00, (byte) 0x0a,
+ (byte) 0x00, (byte) 0x16, (byte) 0x00, (byte) 0x17, (byte) 0x00,
+ (byte) 0x08, (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x07,
+ (byte) 0x00, (byte) 0x14, (byte) 0x00, (byte) 0x15, (byte) 0x00,
+ (byte) 0x04, (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x12,
+ (byte) 0x00, (byte) 0x13, (byte) 0x00, (byte) 0x01, (byte) 0x00,
+ (byte) 0x02, (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x0f,
+ (byte) 0x00, (byte) 0x10, (byte) 0x00, (byte) 0x11, (byte) 0x00,
+ (byte) 0x0d, (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x1e,
+ (byte) 0x06, (byte) 0x01, (byte) 0x06, (byte) 0x02, (byte) 0x06,
+ (byte) 0x03, (byte) 0x05, (byte) 0x01, (byte) 0x05, (byte) 0x02,
+ (byte) 0x05, (byte) 0x03, (byte) 0x04, (byte) 0x01, (byte) 0x04,
+ (byte) 0x02, (byte) 0x04, (byte) 0x03, (byte) 0x03, (byte) 0x01,
+ (byte) 0x03, (byte) 0x02, (byte) 0x03, (byte) 0x03, (byte) 0x02,
+ (byte) 0x01, (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x03,
+ });
+ // Wait until the server sends something.
+ byte[] scratch = new byte[8192];
+ @SuppressWarnings("unused")
+ int bytesRead = client.getInputStream().read(scratch);
+ // Write a bogus TLS alert:
+ // TLSv1.2 Record Layer: Alert (Level: Warning, Description:
+ // Protocol Version)
+ client.getOutputStream()
+ .write(new byte[]{0x15, 0x03, 0x03, 0x00, 0x02, 0x01, 0x46});
+ // TLSv1.2 Record Layer: Alert (Level: Warning, Description:
+ // Close Notify)
+ client.getOutputStream()
+ .write(new byte[]{0x15, 0x03, 0x03, 0x00, 0x02, 0x01, 0x00});
+ return null;
+ }
+ });
+ c.get(5, TimeUnit.SECONDS);
+ s.get(5, TimeUnit.SECONDS);
+ client.close();
+ server.close();
+ context.close();
+ }
+
+ @Test
+ public void test_SSLSocket_SSLv3Unsupported() throws Exception {
+ TestSSLContext context = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ final SSLSocket client =
+ (SSLSocket) context.clientContext.getSocketFactory().createSocket();
+ // For app compatibility, SSLv3 is stripped out when setting only.
+ client.setEnabledProtocols(new String[] {"SSLv3"});
+ assertEquals(0, client.getEnabledProtocols().length);
+ try {
+ client.setEnabledProtocols(new String[] {"SSL"});
+ fail("SSLSocket should not support SSL protocol");
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ }
+
+ // Under some circumstances, the file descriptor socket may get finalized but still
+ // be reused by the JDK's built-in HTTP connection reuse code. Ensure that a
+ // SocketException is thrown if that happens.
+ @Test
+ public void test_SSLSocket_finalizeThrowsProperException() throws Exception {
+ TestSSLContext context = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ TestSSLSocketPair test = TestSSLSocketPair.create(context).connect();
+ try {
+ if (isConscryptFdSocket(test.client)) {
+ // The finalize method might be declared on a superclass rather than this
+ // class.
+ Method method = null;
+ Class<?> clazz = test.client.getClass();
+ while (clazz != null) {
+ try {
+ method = clazz.getDeclaredMethod("finalize");
+ break;
+ } catch (NoSuchMethodException e) {
+ // Try the superclass
+ }
+ clazz = clazz.getSuperclass();
+ }
+ assertNotNull(method);
+ method.setAccessible(true);
+ method.invoke(test.client);
+ try {
+ test.client.getOutputStream().write(new byte[] { 0x01 });
+ fail("The socket shouldn't work after being finalized");
+ } catch (SocketException expected) {
+ // Expected
+ }
+ }
+ } finally {
+ test.close();
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_TlsUnique() throws Exception {
+ // tls_unique isn't supported in TLS 1.3
+ assumeTlsV1_2Connection();
+ TestSSLContext context = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ TestSSLSocketPair pair = TestSSLSocketPair.create(context);
+ try {
+ assertNull(Conscrypt.getTlsUnique(pair.client));
+ assertNull(Conscrypt.getTlsUnique(pair.server));
+
+ pair.connect();
+
+ byte[] clientTlsUnique = Conscrypt.getTlsUnique(pair.client);
+ byte[] serverTlsUnique = Conscrypt.getTlsUnique(pair.server);
+ assertNotNull(clientTlsUnique);
+ assertNotNull(serverTlsUnique);
+ assertArrayEquals(clientTlsUnique, serverTlsUnique);
+ } finally {
+ pair.close();
+ }
+ }
+
+ // Tests that all cipher suites have a 12-byte tls-unique channel binding value. If this
+ // test fails, that means some cipher suite has been added that uses a customized verify_data
+ // length and we need to update MAX_TLS_UNIQUE_LENGTH in native_crypto.cc to account for that.
+ @Test
+ public void test_SSLSocket_TlsUniqueLength() throws Exception {
+ // tls_unique isn't supported in TLS 1.3
+ assumeTlsV1_2Connection();
+ // note the rare usage of non-RSA keys
+ TestKeyStore testKeyStore = new TestKeyStore.Builder()
+ .keyAlgorithms("RSA", "DSA", "EC", "EC_RSA")
+ .aliasPrefix("rsa-dsa-ec")
+ .ca(true)
+ .build();
+ KeyManager pskKeyManager =
+ PSKKeyManagerProxy.getConscryptPSKKeyManager(new PSKKeyManagerProxy() {
+ @Override
+ protected SecretKey getKey(
+ String identityHint, String identity, Socket socket) {
+ return newKey();
+ }
+
+ @Override
+ protected SecretKey getKey(
+ String identityHint, String identity, SSLEngine engine) {
+ return newKey();
+ }
+
+ private SecretKey newKey() {
+ return new SecretKeySpec("Just an arbitrary key".getBytes(UTF_8), "RAW");
+ }
+ });
+ TestSSLContext c = TestSSLContext.newBuilder()
+ .client(testKeyStore)
+ .server(testKeyStore)
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .additionalClientKeyManagers(new KeyManager[] {pskKeyManager})
+ .additionalServerKeyManagers(new KeyManager[] {pskKeyManager})
+ .build();
+ for (String cipherSuite : c.clientContext.getSocketFactory().getSupportedCipherSuites()) {
+ if (cipherSuite.equals(StandardNames.CIPHER_SUITE_FALLBACK)
+ || cipherSuite.equals(StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION)) {
+ continue;
+ }
+ /*
+ * tls_unique only works on 1.2, so skip TLS 1.3 cipher suites.
+ */
+ if (StandardNames.CIPHER_SUITES_TLS13.contains(cipherSuite)) {
+ continue;
+ }
+ TestSSLSocketPair pair = TestSSLSocketPair.create(c);
+ try {
+ String[] cipherSuites =
+ new String[] {cipherSuite, StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION};
+ pair.connect(cipherSuites, cipherSuites);
+
+ assertEquals(cipherSuite, pair.client.getSession().getCipherSuite());
+
+ byte[] clientTlsUnique = Conscrypt.getTlsUnique(pair.client);
+ byte[] serverTlsUnique = Conscrypt.getTlsUnique(pair.server);
+ assertNotNull(clientTlsUnique);
+ assertNotNull(serverTlsUnique);
+ assertArrayEquals(clientTlsUnique, serverTlsUnique);
+ assertEquals(12, clientTlsUnique.length);
+ } catch (Exception e) {
+ throw new AssertionError("Cipher suite is " + cipherSuite, e);
+ } finally {
+ pair.client.close();
+ pair.server.close();
+ }
+ }
+ }
+
+ @Test
+ public void test_SSLSocket_EKM() throws Exception {
+ TestSSLContext context = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ TestSSLSocketPair pair = TestSSLSocketPair.create(context);
+ try {
+ // No EKM values available before handshaking
+ assertNull(Conscrypt.exportKeyingMaterial(pair.client, "FOO", null, 20));
+ assertNull(Conscrypt.exportKeyingMaterial(pair.server, "FOO", null, 20));
+
+ pair.connect();
+
+ byte[] clientEkm = Conscrypt.exportKeyingMaterial(pair.client, "FOO", null, 20);
+ byte[] serverEkm = Conscrypt.exportKeyingMaterial(pair.server, "FOO", null, 20);
+ assertNotNull(clientEkm);
+ assertNotNull(serverEkm);
+ assertEquals(20, clientEkm.length);
+ assertEquals(20, serverEkm.length);
+ assertArrayEquals(clientEkm, serverEkm);
+
+ byte[] clientContextEkm = Conscrypt.exportKeyingMaterial(
+ pair.client, "FOO", new byte[0], 20);
+ byte[] serverContextEkm = Conscrypt.exportKeyingMaterial(
+ pair.server, "FOO", new byte[0], 20);
+ assertNotNull(clientContextEkm);
+ assertNotNull(serverContextEkm);
+ assertEquals(20, clientContextEkm.length);
+ assertEquals(20, serverContextEkm.length);
+ assertArrayEquals(clientContextEkm, serverContextEkm);
+
+ // In TLS 1.2, an empty context and a null context are different (RFC 5705, section 4),
+ // but in TLS 1.3 they are the same (RFC 8446, section 7.5).
+ if ("TLSv1.2".equals(negotiatedVersion())) {
+ assertFalse(Arrays.equals(clientEkm, clientContextEkm));
+ } else {
+ assertTrue(Arrays.equals(clientEkm, clientContextEkm));
+ }
+ } finally {
+ pair.close();
+ }
+ }
+
+ // Tests that a socket will close cleanly even if it fails to create due to an
+ // internal IOException
+ @Test
+ public void test_SSLSocket_CloseCleanlyOnConstructorFailure() throws Exception {
+ TestSSLContext c = new TestSSLContext.Builder()
+ .clientProtocol(clientVersion)
+ .serverProtocol(serverVersion)
+ .build();
+ try {
+ c.clientContext.getSocketFactory().createSocket(c.host, 1);
+ fail();
+ } catch (ConnectException ignored) {
+ // Ignored.
+ }
+ }
+
+ private static void setWriteTimeout(Object socket, int timeout) {
+ Exception ex = null;
+ try {
+ Method method = socket.getClass().getMethod("setSoWriteTimeout", int.class);
+ method.setAccessible(true);
+ method.invoke(socket, timeout);
+ } catch (Exception e) {
+ ex = e;
+ }
+ // Engine-based socket currently has the method but throws UnsupportedOperationException.
+ assumeNoException("Client socket does not support setting write timeout", ex);
+ }
+
+ private static void setHostname(SSLSocket socket) {
+ try {
+ Method method = socket.getClass().getMethod("setHostname", String.class);
+ method.setAccessible(true);
+ method.invoke(socket, "sslsockettest.androidcts.google.com");
+ } catch (NoSuchMethodException ignored) {
+ // Ignored.
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to enable SNI", e);
+ }
+ }
+
+ private static void enableSessionTickets(SSLSocket socket) {
+ try {
+ Method method =
+ socket.getClass().getMethod("setUseSessionTickets", boolean.class);
+ method.setAccessible(true);
+ method.invoke(socket, true);
+ } catch (NoSuchMethodException ignored) {
+ // Ignored.
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to enable Session Tickets", e);
+ }
+ }
+
+ private static boolean isConscryptSocket(SSLSocket socket) {
+ return isConscryptFdSocket(socket) || isConscryptEngineSocket(socket);
+ }
+
+ private static boolean isConscryptFdSocket(SSLSocket socket) {
+ Class<?> clazz = socket.getClass();
+ while (clazz != Object.class && !"ConscryptFileDescriptorSocket".equals(clazz.getSimpleName())) {
+ clazz = clazz.getSuperclass();
+ }
+ return "ConscryptFileDescriptorSocket".equals(clazz.getSimpleName());
+ }
+
+ private static boolean isConscryptEngineSocket(SSLSocket socket) {
+ Class<?> clazz = socket.getClass();
+ while (clazz != Object.class && !"ConscryptEngineSocket".equals(clazz.getSimpleName())) {
+ clazz = clazz.getSuperclass();
+ }
+ return "ConscryptEngineSocket".equals(clazz.getSimpleName());
+ }
+
+ private <T> Future<T> runAsync(Callable<T> callable) {
+ return executor.submit(callable);
+ }
+
+ private static SSLContext defaultInit(SSLContext context) throws KeyManagementException {
+ context.init(null, null, null);
+ return context;
+ }
+
+ // Assumes that the negotiated connection will be TLS 1.2
+ private void assumeTlsV1_2Connection() {
+ assumeTrue("TLSv1.2".equals(negotiatedVersion()));
+ }
+
+ /**
+ * Returns the version that a connection between {@code clientVersion} and
+ * {@code serverVersion} should produce.
+ */
+ private String negotiatedVersion() {
+ if (clientVersion.equals("TLSv1.3") && serverVersion.equals("TLSv1.3")) {
+ return "TLSv1.3";
+ } else {
+ return "TLSv1.2";
+ }
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/TrustManagerFactoryTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/TrustManagerFactoryTest.java
new file mode 100644
index 0000000..e85787b
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/TrustManagerFactoryTest.java
@@ -0,0 +1,322 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.KeyStore.PrivateKeyEntry;
+import java.security.Provider;
+import java.security.cert.CertificateException;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.PKIXParameters;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import javax.net.ssl.CertPathTrustManagerParameters;
+import javax.net.ssl.ManagerFactoryParameters;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+import org.bouncycastle.asn1.x509.KeyPurposeId;
+import com.android.org.conscrypt.Conscrypt;
+import com.android.org.conscrypt.java.security.StandardNames;
+import com.android.org.conscrypt.java.security.TestKeyStore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class TrustManagerFactoryTest {
+ private static final String[] KEY_TYPES = new String[] {"RSA", "DSA", "EC", "EC_RSA"};
+
+ private static TestKeyStore TEST_KEY_STORE;
+
+ // note the rare usage of DSA keys here in addition to RSA
+ private static TestKeyStore getTestKeyStore() throws Exception {
+ if (TEST_KEY_STORE == null) {
+ TEST_KEY_STORE = new TestKeyStore.Builder()
+ .keyAlgorithms(KEY_TYPES)
+ .aliasPrefix("rsa-dsa-ec")
+ .build();
+ }
+ return TEST_KEY_STORE;
+ }
+
+ private static boolean supportsManagerFactoryParameters(TrustManagerFactory tmf) {
+ return (StandardNames.IS_RI && tmf.getAlgorithm().equals("PKIX")
+ && !Conscrypt.isConscrypt(tmf.getProvider()));
+ }
+
+ @Test
+ public void test_TrustManagerFactory_getDefaultAlgorithm() throws Exception {
+ String algorithm = TrustManagerFactory.getDefaultAlgorithm();
+ assertEquals(StandardNames.TRUST_MANAGER_FACTORY_DEFAULT, algorithm);
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
+ test_TrustManagerFactory(tmf);
+ }
+
+ private static class UselessManagerFactoryParameters implements ManagerFactoryParameters {}
+
+ private void test_TrustManagerFactory(TrustManagerFactory tmf) throws Exception {
+ assertNotNull(tmf);
+ assertNotNull(tmf.getAlgorithm());
+ assertNotNull(tmf.getProvider());
+
+ // before init
+ try {
+ tmf.getTrustManagers();
+ fail();
+ } catch (IllegalStateException expected) {
+ // Ignored.
+ }
+
+ // init with null ManagerFactoryParameters
+ try {
+ tmf.init((ManagerFactoryParameters) null);
+ fail();
+ } catch (InvalidAlgorithmParameterException expected) {
+ // Ignored.
+ }
+
+ // init with useless ManagerFactoryParameters
+ try {
+ tmf.init(new UselessManagerFactoryParameters());
+ fail();
+ } catch (InvalidAlgorithmParameterException expected) {
+ // Ignored.
+ }
+
+ // init with PKIXParameters ManagerFactoryParameters
+ try {
+ PKIXParameters pp = new PKIXParameters(getTestKeyStore().keyStore);
+ CertPathTrustManagerParameters cptmp = new CertPathTrustManagerParameters(pp);
+ tmf.init(cptmp);
+ fail();
+ } catch (InvalidAlgorithmParameterException expected) {
+ // Ignored.
+ }
+
+ // init with PKIXBuilderParameters ManagerFactoryParameters
+ X509CertSelector xcs = new X509CertSelector();
+ PKIXBuilderParameters pbp = new PKIXBuilderParameters(getTestKeyStore().keyStore, xcs);
+ CertPathTrustManagerParameters cptmp = new CertPathTrustManagerParameters(pbp);
+ if (supportsManagerFactoryParameters(tmf)) {
+ tmf.init(cptmp);
+ test_TrustManagerFactory_getTrustManagers(tmf);
+ } else {
+ try {
+ tmf.init(cptmp);
+ fail();
+ } catch (InvalidAlgorithmParameterException expected) {
+ // Ignored.
+ }
+ }
+
+ // init with null for default KeyStore
+ tmf.init((KeyStore) null);
+ test_TrustManagerFactory_getTrustManagers(tmf);
+
+ // init with specific key store
+ tmf.init(getTestKeyStore().keyStore);
+ test_TrustManagerFactory_getTrustManagers(tmf);
+ }
+
+ private void test_TrustManagerFactory_getTrustManagers(TrustManagerFactory tmf)
+ throws Exception {
+ TrustManager[] trustManagers = tmf.getTrustManagers();
+ assertNotNull(trustManagers);
+ assertTrue(trustManagers.length > 0);
+ for (TrustManager trustManager : trustManagers) {
+ assertNotNull(trustManager);
+ if (trustManager instanceof X509TrustManager) {
+ test_X509TrustManager(tmf.getProvider(), (X509TrustManager) trustManager);
+ }
+ }
+ }
+
+ private void test_X509TrustManager(Provider p, X509TrustManager tm) throws Exception {
+ for (String keyType : KEY_TYPES) {
+ X509Certificate[] issuers = tm.getAcceptedIssuers();
+ assertNotNull(issuers);
+ assertTrue(issuers.length > 1);
+ assertNotSame(issuers, tm.getAcceptedIssuers());
+ boolean defaultTrustManager
+ // RI de-duplicates certs from TrustedCertificateEntry and PrivateKeyEntry
+ = issuers.length >
+ (StandardNames.IS_RI && !Conscrypt.isConscrypt(p) ? 1 : 2) * KEY_TYPES.length;
+
+ String keyAlgName = TestKeyStore.keyAlgorithm(keyType);
+ String sigAlgName = TestKeyStore.signatureAlgorithm(keyType);
+ PrivateKeyEntry pke = getTestKeyStore().getPrivateKey(keyAlgName, sigAlgName);
+ X509Certificate[] chain = (X509Certificate[]) pke.getCertificateChain();
+ if (defaultTrustManager) {
+ try {
+ tm.checkClientTrusted(chain, keyType);
+ fail();
+ } catch (CertificateException expected) {
+ // Ignored.
+ }
+ try {
+ tm.checkServerTrusted(chain, keyType);
+ fail();
+ } catch (CertificateException expected) {
+ // Ignored.
+ }
+ } else {
+ tm.checkClientTrusted(chain, keyType);
+ tm.checkServerTrusted(chain, keyType);
+ }
+ }
+ }
+
+ @Test
+ public void test_TrustManagerFactory_getInstance() throws Exception {
+ ServiceTester.test("TrustManagerFactory")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider provider, String algorithm) throws Exception {
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
+ assertEquals(algorithm, tmf.getAlgorithm());
+ test_TrustManagerFactory(tmf);
+
+ tmf = TrustManagerFactory.getInstance(algorithm, provider);
+ assertEquals(algorithm, tmf.getAlgorithm());
+ assertEquals(provider, tmf.getProvider());
+ test_TrustManagerFactory(tmf);
+
+ tmf = TrustManagerFactory.getInstance(algorithm, provider.getName());
+ assertEquals(algorithm, tmf.getAlgorithm());
+ assertEquals(provider, tmf.getProvider());
+ test_TrustManagerFactory(tmf);
+ }
+ });
+ }
+
+ @Test
+ public void test_TrustManagerFactory_intermediate() throws Exception {
+ // chain should be server/intermediate/root
+ PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
+ final X509Certificate[] chain = (X509Certificate[]) pke.getCertificateChain();
+ assertEquals(3, chain.length);
+
+ // keyStore should contain only the intermediate CA so we can
+ // test proper validation even if there are extra certs after
+ // the trusted one (in this case the original root is "extra")
+ final KeyStore keyStore = TestKeyStore.createKeyStore();
+ keyStore.setCertificateEntry("alias", chain[1]);
+
+ ServiceTester.test("TrustManagerFactory")
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
+ tmf.init(keyStore);
+ TrustManager[] trustManagers = tmf.getTrustManagers();
+ for (TrustManager trustManager : trustManagers) {
+ if (!(trustManager instanceof X509TrustManager)) {
+ continue;
+ }
+ X509TrustManager tm = (X509TrustManager) trustManager;
+ tm.checkClientTrusted(chain, "RSA");
+ tm.checkServerTrusted(chain, "RSA");
+ }
+ }
+ });
+ }
+
+ @Test
+ public void test_TrustManagerFactory_keyOnly() throws Exception {
+ // create a KeyStore containing only a private key with chain.
+ // unlike PKIXParameters(KeyStore), the cert chain of the key should be trusted.
+ KeyStore ks = TestKeyStore.createKeyStore();
+ KeyStore.PrivateKeyEntry pke = getTestKeyStore().getPrivateKey("RSA", "RSA");
+ ks.setKeyEntry("key", pke.getPrivateKey(), "pw".toCharArray(), pke.getCertificateChain());
+
+ String algorithm = TrustManagerFactory.getDefaultAlgorithm();
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
+ tmf.init(ks);
+ X509TrustManager trustManager = (X509TrustManager) tmf.getTrustManagers()[0];
+ trustManager.checkServerTrusted((X509Certificate[]) pke.getCertificateChain(), "RSA");
+ }
+
+ @Test
+ public void test_TrustManagerFactory_extendedKeyUsage() throws Exception {
+ // anyExtendedKeyUsage should work for client or server
+ test_TrustManagerFactory_extendedKeyUsage(
+ KeyPurposeId.anyExtendedKeyUsage, false, true, true);
+ test_TrustManagerFactory_extendedKeyUsage(
+ KeyPurposeId.anyExtendedKeyUsage, true, true, true);
+
+ // critical clientAuth should work for client
+ test_TrustManagerFactory_extendedKeyUsage(
+ KeyPurposeId.id_kp_clientAuth, false, true, false);
+ test_TrustManagerFactory_extendedKeyUsage(KeyPurposeId.id_kp_clientAuth, true, true, false);
+
+ // critical serverAuth should work for server
+ test_TrustManagerFactory_extendedKeyUsage(
+ KeyPurposeId.id_kp_serverAuth, false, false, true);
+ test_TrustManagerFactory_extendedKeyUsage(KeyPurposeId.id_kp_serverAuth, true, false, true);
+
+ // codeSigning should not work
+ test_TrustManagerFactory_extendedKeyUsage(
+ KeyPurposeId.id_kp_codeSigning, false, false, false);
+ test_TrustManagerFactory_extendedKeyUsage(
+ KeyPurposeId.id_kp_codeSigning, true, false, false);
+ }
+
+ private void test_TrustManagerFactory_extendedKeyUsage(KeyPurposeId keyPurposeId,
+ boolean critical, boolean client, boolean server) throws Exception {
+ String algorithm = "RSA";
+ TestKeyStore intermediateCa = TestKeyStore.getIntermediateCa();
+ TestKeyStore leaf = new TestKeyStore.Builder()
+ .keyAlgorithms(algorithm)
+ .aliasPrefix("criticalCodeSigning")
+ .signer(intermediateCa.getPrivateKey("RSA", "RSA"))
+ .rootCa(intermediateCa.getRootCertificate("RSA"))
+ .addExtendedKeyUsage(keyPurposeId, critical)
+ .build();
+ // leaf.dump("test_TrustManagerFactory_criticalCodeSigning");
+ PrivateKeyEntry privateKeyEntry = leaf.getPrivateKey(algorithm, algorithm);
+ X509Certificate[] chain = (X509Certificate[]) privateKeyEntry.getCertificateChain();
+
+ TestKeyStore rootCa = TestKeyStore.getRootCa();
+ X509TrustManager trustManager = (X509TrustManager) rootCa.trustManagers[0];
+ try {
+ trustManager.checkClientTrusted(chain, algorithm);
+ assertTrue(client);
+ } catch (Exception e) {
+ assertFalse(client);
+ }
+ try {
+ trustManager.checkServerTrusted(chain, algorithm);
+ assertTrue(server);
+ } catch (Exception e) {
+ assertFalse(server);
+ }
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/X509KeyManagerTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/X509KeyManagerTest.java
new file mode 100644
index 0000000..96a573d
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/javax/net/ssl/X509KeyManagerTest.java
@@ -0,0 +1,83 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2013 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.X509KeyManager;
+import com.android.org.conscrypt.java.security.TestKeyStore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class X509KeyManagerTest {
+ /**
+ * Tests whether the key manager will select the right key when the CA is of
+ * one key type and the client is of a possibly different key type.
+ *
+ * <p>There was a bug where EC was being interpreted as EC_EC and only
+ * accepting EC signatures when it should accept any signature type.
+ */
+ @Test
+ public void testChooseClientAlias_Combinations() throws Exception {
+ test_ChooseClientAlias_KeyType("RSA", "RSA", "RSA", true);
+ test_ChooseClientAlias_KeyType("RSA", "EC", "RSA", true);
+ test_ChooseClientAlias_KeyType("RSA", "EC", "EC", false);
+
+ test_ChooseClientAlias_KeyType("EC", "RSA", "EC_RSA", true);
+ test_ChooseClientAlias_KeyType("EC", "EC", "EC_RSA", false);
+
+ test_ChooseClientAlias_KeyType("EC", "EC", "EC_EC", true);
+ test_ChooseClientAlias_KeyType("EC", "RSA", "EC_EC", false);
+
+ test_ChooseClientAlias_KeyType("EC", "RSA", "RSA", false);
+ }
+
+ private void test_ChooseClientAlias_KeyType(String clientKeyType, String caKeyType,
+ String selectedKeyType, boolean succeeds) throws Exception {
+ TestKeyStore ca = new TestKeyStore.Builder().keyAlgorithms(caKeyType).build();
+ TestKeyStore client = new TestKeyStore.Builder()
+ .keyAlgorithms(clientKeyType)
+ .signer(ca.getPrivateKey(caKeyType, caKeyType))
+ .build();
+
+ KeyManagerFactory kmf =
+ KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(client.keyStore, client.keyPassword);
+
+ String[] keyTypes = new String[] {selectedKeyType};
+ KeyManager[] managers = kmf.getKeyManagers();
+ for (KeyManager manager : managers) {
+ if (manager instanceof X509KeyManager) {
+ String alias = ((X509KeyManager) manager).chooseClientAlias(keyTypes, null, null);
+ if (succeeds) {
+ assertNotNull(alias);
+ } else {
+ assertNull(alias);
+ }
+ }
+ }
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/metrics/CipherSuiteTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/metrics/CipherSuiteTest.java
new file mode 100644
index 0000000..63283d1
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/metrics/CipherSuiteTest.java
@@ -0,0 +1,23 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt.metrics;
+
+import static org.junit.Assert.assertSame;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class CipherSuiteTest {
+
+ @Test
+ public void consistency() {
+ for (CipherSuite cipherSuite : CipherSuite.values()) {
+ assertSame(cipherSuite, CipherSuite.forName(cipherSuite.name()));
+ }
+ assertSame(CipherSuite.UNKNOWN_CIPHER_SUITE, CipherSuite.forName("random junk"));
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/metrics/OptionalMethodTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/metrics/OptionalMethodTest.java
new file mode 100644
index 0000000..adda44c
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/metrics/OptionalMethodTest.java
@@ -0,0 +1,77 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt.metrics;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class OptionalMethodTest {
+
+ @Test
+ public void workingMethod() {
+ OptionalMethod substring =
+ new OptionalMethod(String.class, "substring", int.class, int.class);
+ assertNotNull(substring);
+
+ assertEquals("put", substring.invoke("input", 2, 5));
+ }
+
+ @Test
+ public void nullClass() {
+ OptionalMethod substring =
+ new OptionalMethod(null, "substring", int.class, int.class);
+ assertNotNull(substring);
+
+ assertNull(substring.invoke("input", 2, 5));
+ }
+
+ @Test
+ public void nullMethodName() {
+ assertThrows(NullPointerException.class,
+ () -> new OptionalMethod(String.class, null, int.class, int.class));
+ }
+
+ @Test
+ public void nullArgumentClasses() {
+ OptionalMethod substring = new OptionalMethod(String.class, "substring", int.class, null);
+ assertNotNull(substring);
+
+ assertNull(substring.invoke("input", 2, 5));
+ }
+
+ @Test
+ public void noSuchMethodName() {
+ OptionalMethod subwrong =
+ new OptionalMethod(null, "subwrong", int.class, int.class);
+ assertNotNull(subwrong);
+
+ assertNull(subwrong.invoke("input", 2, 5));
+ }
+
+ @Test
+ public void noSuchMethodArgs() {
+ OptionalMethod subwrong =
+ new OptionalMethod(null, "substring", long.class, byte[].class);
+ assertNotNull(subwrong);
+
+ assertNull(subwrong.invoke("input", 2, 5));
+ }
+
+ @Test
+ public void nullReceiver() {
+ OptionalMethod substring =
+ new OptionalMethod(String.class, "substring", int.class, int.class);
+ assertNotNull(substring);
+
+ assertEquals(null, substring.invoke(null, 2, 5));
+ }
+}
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/metrics/ProtocolTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/metrics/ProtocolTest.java
new file mode 100644
index 0000000..e628add
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/metrics/ProtocolTest.java
@@ -0,0 +1,25 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt.metrics;
+
+import static org.junit.Assert.assertSame;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class ProtocolTest {
+ @Test
+ public void consistency() {
+ for (Protocol protocol : Protocol.values()) {
+ if (protocol == Protocol.TLS_PROTO_FAILED) {
+ continue;
+ }
+ String name = protocol.name().replace('_', '.');
+ assertSame(protocol, Protocol.forName(name));
+ }
+ }
+}
diff --git a/repackaged/openjdk/src/main/java/com/android/org/conscrypt/HostProperties.java b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/HostProperties.java
new file mode 100644
index 0000000..7adf930
--- /dev/null
+++ b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/HostProperties.java
@@ -0,0 +1,295 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+/*
+ * Copyright 2013 The Netty Project
+ *
+ * The Netty Project licenses this file to you 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.File;
+import java.util.Locale;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Utilities for interacting with properties of the host being run on.
+ */
+@Internal
+class HostProperties {
+ private static final Logger logger = Logger.getLogger(HostProperties.class.getName());
+
+ private static final String TEMP_DIR_PROPERTY_NAME = "com.android.org.conscrypt.tmpdir";
+
+ static final OperatingSystem OS;
+ static final Architecture ARCH;
+
+ static {
+ OS = getOperatingSystem(System.getProperty("os.name", ""));
+ ARCH = getArchitecture(System.getProperty("os.arch", ""));
+ }
+
+ /**
+ * Enumeration of operating systems.
+ */
+ enum OperatingSystem {
+ AIX,
+ HPUX,
+ OS400,
+ LINUX,
+ OSX,
+ FREEBSD,
+ OPENBSD,
+ NETBSD,
+ SUNOS,
+ WINDOWS,
+ UNKNOWN;
+
+ /**
+ * Returns the value to use when building filenames for this OS.
+ */
+ public String getFileComponent() {
+ return name().toLowerCase();
+ }
+ }
+
+ /**
+ * Enumeration of architectures.
+ */
+ enum Architecture {
+ X86_64,
+ X86_32 {
+ @Override public String getFileComponent() {
+ return "x86";
+ }
+ },
+ ITANIUM_64,
+ SPARC_32,
+ SPARC_64,
+ ARM_32,
+ AARCH_64,
+ PPC_32,
+ PPC_64,
+ PPCLE_64,
+ S390_32,
+ S390_64,
+ UNKNOWN;
+
+ /**
+ * Returns the value to use when building filenames for this architecture.
+ */
+ public String getFileComponent() {
+ return name().toLowerCase();
+ }
+ }
+
+ static boolean isWindows() {
+ return OS == OperatingSystem.WINDOWS;
+ }
+
+ static boolean isOSX() {
+ return OS == OperatingSystem.OSX;
+ }
+
+ static File getTempDir() {
+ File f;
+ try {
+ // First, see if the application specified a temp dir for conscrypt.
+ f = toDirectory(System.getProperty(TEMP_DIR_PROPERTY_NAME));
+ if (f != null) {
+ return f;
+ }
+
+ // Use the Java system property if available.
+ f = toDirectory(System.getProperty("java.io.tmpdir"));
+ if (f != null) {
+ return f;
+ }
+
+ // This shouldn't happen, but just in case ..
+ if (isWindows()) {
+ f = toDirectory(System.getenv("TEMP"));
+ if (f != null) {
+ return f;
+ }
+
+ String userprofile = System.getenv("USERPROFILE");
+ if (userprofile != null) {
+ f = toDirectory(userprofile + "\\AppData\\Local\\Temp");
+ if (f != null) {
+ return f;
+ }
+
+ f = toDirectory(userprofile + "\\Local Settings\\Temp");
+ if (f != null) {
+ return f;
+ }
+ }
+ } else {
+ f = toDirectory(System.getenv("TMPDIR"));
+ if (f != null) {
+ return f;
+ }
+ }
+ } catch (Exception ignored) {
+ // Environment variable inaccessible
+ }
+
+ // Last resort.
+ if (isWindows()) {
+ f = new File("C:\\Windows\\Temp");
+ } else {
+ f = new File("/tmp");
+ }
+
+ logger.log(Level.WARNING,
+ "Failed to get the temporary directory; falling back to: {0}", f);
+ return f;
+ }
+
+ @SuppressWarnings("ResultOfMethodCallIgnored")
+ private static File toDirectory(String path) {
+ if (path == null) {
+ return null;
+ }
+
+ File f = new File(path);
+ f.mkdirs();
+
+ if (!f.isDirectory()) {
+ return null;
+ }
+
+ try {
+ return f.getAbsoluteFile();
+ } catch (Exception ignored) {
+ return f;
+ }
+ }
+
+ private static String normalize(String value) {
+ return value.toLowerCase(Locale.US).replaceAll("[^a-z0-9]+", "");
+ }
+
+ /**
+ * Normalizes the os.name value into the value used by the Maven os plugin
+ * (https://github.com/trustin/os-maven-plugin). This plugin is used to generate
+ * platform-specific
+ * classifiers for artifacts.
+ */
+ private static OperatingSystem getOperatingSystem(String value) {
+ value = normalize(value);
+ if (value.startsWith("aix")) {
+ return OperatingSystem.AIX;
+ }
+ if (value.startsWith("hpux")) {
+ return OperatingSystem.HPUX;
+ }
+ if (value.startsWith("os400")) {
+ // Avoid the names such as os4000
+ if (value.length() <= 5 || !Character.isDigit(value.charAt(5))) {
+ return OperatingSystem.OS400;
+ }
+ }
+ if (value.startsWith("linux")) {
+ return OperatingSystem.LINUX;
+ }
+ if (value.startsWith("macosx") || value.startsWith("osx")) {
+ return OperatingSystem.OSX;
+ }
+ if (value.startsWith("freebsd")) {
+ return OperatingSystem.FREEBSD;
+ }
+ if (value.startsWith("openbsd")) {
+ return OperatingSystem.OPENBSD;
+ }
+ if (value.startsWith("netbsd")) {
+ return OperatingSystem.NETBSD;
+ }
+ if (value.startsWith("solaris") || value.startsWith("sunos")) {
+ return OperatingSystem.SUNOS;
+ }
+ if (value.startsWith("windows")) {
+ return OperatingSystem.WINDOWS;
+ }
+
+ return OperatingSystem.UNKNOWN;
+ }
+
+ /**
+ * Normalizes the os.arch value into the value used by the Maven os plugin
+ * (https://github.com/trustin/os-maven-plugin). This plugin is used to generate
+ * platform-specific
+ * classifiers for artifacts.
+ */
+ private static Architecture getArchitecture(String value) {
+ value = normalize(value);
+ if (value.matches("^(x8664|amd64|ia32e|em64t|x64)$")) {
+ return Architecture.X86_64;
+ }
+ if (value.matches("^(x8632|x86|i[3-6]86|ia32|x32)$")) {
+ return Architecture.X86_32;
+ }
+ if (value.matches("^(ia64|itanium64)$")) {
+ return Architecture.ITANIUM_64;
+ }
+ if (value.matches("^(sparc|sparc32)$")) {
+ return Architecture.SPARC_32;
+ }
+ if (value.matches("^(sparcv9|sparc64)$")) {
+ return Architecture.SPARC_64;
+ }
+ if (value.matches("^(arm|arm32)$")) {
+ return Architecture.ARM_32;
+ }
+ if ("aarch64".equals(value)) {
+ return Architecture.AARCH_64;
+ }
+ if (value.matches("^(ppc|ppc32)$")) {
+ return Architecture.PPC_32;
+ }
+ if ("ppc64".equals(value)) {
+ return Architecture.PPC_64;
+ }
+ if ("ppc64le".equals(value)) {
+ return Architecture.PPCLE_64;
+ }
+ if ("s390".equals(value)) {
+ return Architecture.S390_32;
+ }
+ if ("s390x".equals(value)) {
+ return Architecture.S390_64;
+ }
+
+ return Architecture.UNKNOWN;
+ }
+
+ private HostProperties() {}
+
+}
diff --git a/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Java8PlatformUtil.java b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Java8PlatformUtil.java
new file mode 100644
index 0000000..c5b8304
--- /dev/null
+++ b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Java8PlatformUtil.java
@@ -0,0 +1,128 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static javax.net.ssl.StandardConstants.SNI_HOST_NAME;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIMatcher;
+import javax.net.ssl.SNIServerName;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSession;
+
+/**
+ * Utility methods supported on Java 8+.
+ */
+final class Java8PlatformUtil {
+ static void setSSLParameters(
+ SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) {
+ setSSLParameters(params, impl);
+
+ String sniHost = getSniHostName(params);
+ if (sniHost != null) {
+ socket.setHostname(sniHost);
+ }
+ }
+
+ static void setSSLParameters(
+ SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) {
+ setSSLParameters(params, impl);
+
+ String sniHost = getSniHostName(params);
+ if (sniHost != null) {
+ engine.setHostname(sniHost);
+ }
+ }
+
+ static void getSSLParameters(
+ SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) {
+ getSSLParameters(params, impl);
+ if (impl.getUseSni() && AddressUtils.isValidSniHostname(socket.getHostname())) {
+ params.setServerNames(Collections.singletonList(
+ (SNIServerName) new SNIHostName(socket.getHostname())));
+ }
+ }
+
+ static void getSSLParameters(
+ SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) {
+ getSSLParameters(params, impl);
+ if (impl.getUseSni() && AddressUtils.isValidSniHostname(engine.getHostname())) {
+ params.setServerNames(Collections.singletonList(
+ (SNIServerName) new SNIHostName(engine.getHostname())));
+ }
+ }
+
+ private static String getSniHostName(SSLParameters params) {
+ List<SNIServerName> serverNames = params.getServerNames();
+ if (serverNames != null) {
+ for (SNIServerName serverName : serverNames) {
+ if (serverName.getType() == SNI_HOST_NAME) {
+ return ((SNIHostName) serverName).getAsciiName();
+ }
+ }
+ }
+ return null;
+ }
+
+ private static void setSSLParameters(SSLParameters params, SSLParametersImpl impl) {
+ impl.setEndpointIdentificationAlgorithm(params.getEndpointIdentificationAlgorithm());
+ impl.setUseCipherSuitesOrder(params.getUseCipherSuitesOrder());
+ impl.setSNIMatchers(params.getSNIMatchers());
+ impl.setAlgorithmConstraints(params.getAlgorithmConstraints());
+ }
+
+ private static void getSSLParameters(SSLParameters params, SSLParametersImpl impl) {
+ params.setEndpointIdentificationAlgorithm(impl.getEndpointIdentificationAlgorithm());
+ params.setUseCipherSuitesOrder(impl.getUseCipherSuitesOrder());
+ params.setSNIMatchers(impl.getSNIMatchers());
+ params.setAlgorithmConstraints(impl.getAlgorithmConstraints());
+ }
+
+ static boolean serverNamePermitted(SSLParametersImpl parameters, String serverName) {
+ Collection<SNIMatcher> sniMatchers = parameters.getSNIMatchers();
+ if (sniMatchers == null || sniMatchers.isEmpty()) {
+ return true;
+ }
+
+ for (SNIMatcher m : sniMatchers) {
+ boolean match = m.matches(new SNIHostName(serverName));
+ if (match) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static SSLEngine wrapEngine(ConscryptEngine engine) {
+ return new Java8EngineWrapper(engine);
+ }
+
+ static SSLEngine unwrapEngine(SSLEngine engine) {
+ return Java8EngineWrapper.getDelegate(engine);
+ }
+
+ static SSLSession wrapSSLSession(ExternalSession sslSession) {
+ return new Java8ExtendedSSLSession(sslSession);
+ }
+
+ private Java8PlatformUtil() {}
+}
diff --git a/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Java9PlatformUtil.java b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Java9PlatformUtil.java
new file mode 100644
index 0000000..9141d06
--- /dev/null
+++ b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Java9PlatformUtil.java
@@ -0,0 +1,98 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.lang.reflect.Method;
+import javax.net.ssl.SSLParameters;
+
+/**
+ * Utility methods supported on Java 9+.
+ */
+final class Java9PlatformUtil {
+ // TODO(nmittler): Remove reflection once we require Java 9 for building.
+ private static final Method SSL_PARAMETERS_GET_APPLICATION_PROTOCOLS_METHOD;
+ private static final Method SSL_PARAMETERS_SET_APPLICATION_PROTOCOLS_METHOD;
+
+ static {
+ Class<?> sslParameters = SSLParameters.class;
+ Method getApplicationProtocolsMethod;
+ Method setApplicationProtocolsMethod;
+ try {
+ getApplicationProtocolsMethod = sslParameters.getMethod("getApplicationProtocols");
+ setApplicationProtocolsMethod =
+ sslParameters.getMethod("setApplicationProtocols", String[].class);
+ } catch (NoSuchMethodException e) {
+ getApplicationProtocolsMethod = null;
+ setApplicationProtocolsMethod = null;
+ }
+
+ SSL_PARAMETERS_GET_APPLICATION_PROTOCOLS_METHOD = getApplicationProtocolsMethod;
+ SSL_PARAMETERS_SET_APPLICATION_PROTOCOLS_METHOD = setApplicationProtocolsMethod;
+ }
+
+ static void setSSLParameters(
+ SSLParameters src, SSLParametersImpl dest, AbstractConscryptSocket socket) {
+ Java8PlatformUtil.setSSLParameters(src, dest, socket);
+
+ dest.setApplicationProtocols(getApplicationProtocols(src));
+ }
+
+ static void getSSLParameters(
+ SSLParameters dest, SSLParametersImpl src, AbstractConscryptSocket socket) {
+ Java8PlatformUtil.getSSLParameters(dest, src, socket);
+
+ setApplicationProtocols(dest, src.getApplicationProtocols());
+ }
+
+ static void setSSLParameters(
+ SSLParameters src, SSLParametersImpl dest, ConscryptEngine engine) {
+ Java8PlatformUtil.setSSLParameters(src, dest, engine);
+
+ dest.setApplicationProtocols(getApplicationProtocols(src));
+ }
+
+ static void getSSLParameters(
+ SSLParameters dest, SSLParametersImpl src, ConscryptEngine engine) {
+ Java8PlatformUtil.getSSLParameters(dest, src, engine);
+
+ setApplicationProtocols(dest, src.getApplicationProtocols());
+ }
+
+ private static String[] getApplicationProtocols(SSLParameters params) {
+ if (SSL_PARAMETERS_GET_APPLICATION_PROTOCOLS_METHOD != null) {
+ try {
+ return (String[]) SSL_PARAMETERS_GET_APPLICATION_PROTOCOLS_METHOD.invoke(params);
+ } catch (ReflectiveOperationException ignored) {
+ // TODO(nmittler): Should we throw here?
+ }
+ }
+ return EmptyArray.STRING;
+ }
+
+ private static void setApplicationProtocols(SSLParameters params, String[] protocols) {
+ if (SSL_PARAMETERS_SET_APPLICATION_PROTOCOLS_METHOD != null) {
+ try {
+ SSL_PARAMETERS_SET_APPLICATION_PROTOCOLS_METHOD.invoke(params, (Object) protocols);
+ } catch (ReflectiveOperationException ignored) {
+ // TODO(nmittler): Should we throw here?
+ }
+ }
+ }
+
+ private Java9PlatformUtil() {}
+}
diff --git a/repackaged/openjdk/src/main/java/com/android/org/conscrypt/NativeCryptoJni.java b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/NativeCryptoJni.java
new file mode 100644
index 0000000..4b8f045
--- /dev/null
+++ b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/NativeCryptoJni.java
@@ -0,0 +1,129 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2014 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import com.android.org.conscrypt.NativeLibraryLoader.LoadResult;
+
+/**
+ * Helper to initialize the JNI libraries. This version runs when compiled as part of a host OpenJDK
+ * build.
+ */
+final class NativeCryptoJni {
+ private static final String STATIC_LIB_NAME = "conscrypt";
+ private static final String DYNAMIC_LIB_NAME_PREFIX = "conscrypt_openjdk_jni";
+
+ /**
+ * Attempts to load the shared JNI library. First try loading the platform-specific library
+ * name (e.g. conscrypt_openjdk_jni-linux-x86_64). If that doesn't work, try to load the
+ * library via just the prefix (e.g. conscrypt_openjdk_jni). If not found, try the static
+ * library name.
+ *
+ * The non-suffixed dynamic library name is used by the Android build system, which builds
+ * the appropriate library for the system it's being run on under that name.
+ *
+ * The static library name is needed in order to support Java 8 static linking
+ * (http://openjdk.java.net/jeps/178), where the library name is used to invoke a
+ * library-specific load method (i.e. {@code JNI_OnLoad_conscrypt}).
+ *
+ * @throws UnsatisfiedLinkError if the library failed to load.
+ */
+ static void init() throws UnsatisfiedLinkError {
+ List<LoadResult> results = new ArrayList<LoadResult>();
+ if (!NativeLibraryLoader.loadFirstAvailable(classLoader(), results,
+ platformLibName(), DYNAMIC_LIB_NAME_PREFIX, STATIC_LIB_NAME)) {
+ logResults(results);
+ throwBestError(results);
+ }
+ }
+
+ private NativeCryptoJni() {}
+
+ private static void logResults(List<LoadResult> results) {
+ for (LoadResult result : results) {
+ result.log();
+ }
+ }
+
+ private static void throwBestError(List<LoadResult> results) {
+ Collections.sort(results, ErrorComparator.INSTANCE);
+
+ Throwable bestError = results.get(0).error;
+ for (LoadResult result : results.subList(1, results.size())) {
+ // Suppress all of the other errors, so that they're available to the caller if
+ // desired.
+ bestError.addSuppressed(result.error);
+ }
+
+ if (bestError instanceof Error) {
+ throw (Error) bestError;
+ }
+
+ throw (Error) new UnsatisfiedLinkError(bestError.getMessage()).initCause(bestError);
+ }
+
+ private static ClassLoader classLoader() {
+ return NativeCrypto.class.getClassLoader();
+ }
+
+ private static String platformLibName() {
+ return DYNAMIC_LIB_NAME_PREFIX + "-" + osName() + '-' + archName();
+ }
+
+ private static String osName() {
+ return HostProperties.OS.getFileComponent();
+ }
+
+ private static String archName() {
+ return HostProperties.ARCH.getFileComponent();
+ }
+
+ /**
+ * Sorts the errors in a list in descending order of value. After a list is sorted,
+ * the first element is the most important error.
+ */
+ private static final class ErrorComparator implements Comparator<LoadResult> {
+ static final ErrorComparator INSTANCE = new ErrorComparator();
+
+ @Override
+ public int compare(LoadResult o1, LoadResult o2) {
+ Throwable e1 = o1.error;
+ Throwable e2 = o2.error;
+
+ // First, sort by error type.
+ int value1 = e1 instanceof UnsatisfiedLinkError ? 1 : 0;
+ int value2 = e2 instanceof UnsatisfiedLinkError ? 1 : 0;
+ if (value1 != value2) {
+ // Order so that the UnsatisfiedLinkError is first.
+ return value2 - value1;
+ }
+
+ // Both are either link errors or not. Compare the message. Treat messages in
+ // the form "no <libName> in java.library.path" as lower value, since there may be
+ // a more interesting message for a library that was found.
+ String m1 = e1.getMessage();
+ String m2 = e2.getMessage();
+ value1 = m1 != null && m1.contains("java.library.path") ? 0 : 1;
+ value2 = m2 != null && m2.contains("java.library.path") ? 0 : 1;
+ return value2 - value1;
+ }
+ }
+}
diff --git a/repackaged/openjdk/src/main/java/com/android/org/conscrypt/NativeLibraryLoader.java b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/NativeLibraryLoader.java
new file mode 100644
index 0000000..aa9c95f
--- /dev/null
+++ b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/NativeLibraryLoader.java
@@ -0,0 +1,423 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2014 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.
+ */
+
+/*
+ * Copyright 2014 The Netty Project
+ *
+ * The Netty Project licenses this file to you 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.
+ */
+package com.android.org.conscrypt;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.text.MessageFormat;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Helper class to load JNI resources.
+ */
+final class NativeLibraryLoader {
+ private static final Logger logger = Logger.getLogger(NativeLibraryLoader.class.getName());
+
+ private static final String WORK_DIR_PROPERTY_NAME = "com.android.org.conscrypt.native.workdir";
+ private static final String DELETE_LIB_PROPERTY_NAME =
+ "com.android.org.conscrypt.native.deleteLibAfterLoading";
+ private static final String NATIVE_RESOURCE_HOME = "META-INF/native/";
+ private static final File WORKDIR;
+ private static final boolean DELETE_NATIVE_LIB_AFTER_LOADING;
+
+ static {
+ File workdir = getWorkDir();
+ if (workdir == null) {
+ workdir = HostProperties.getTempDir();
+ }
+ WORKDIR = workdir;
+ log("-D{0}: {1}", WORK_DIR_PROPERTY_NAME, WORKDIR);
+
+ DELETE_NATIVE_LIB_AFTER_LOADING =
+ Boolean.valueOf(System.getProperty(DELETE_LIB_PROPERTY_NAME, "true"));
+ }
+
+ private static File getWorkDir() {
+ String dirName = System.getProperty(WORK_DIR_PROPERTY_NAME);
+ if (dirName == null) {
+ // Application didn't specify a workdir.
+ return null;
+ }
+
+ File f = new File(dirName);
+ // Create the directory if it doesn't already exist.
+ if (!f.mkdirs() && !f.exists()) {
+ // Unable to create the directory.
+ log("Unable to find or create working directory: {0}", dirName);
+ return null;
+ }
+
+ try {
+ f = f.getAbsoluteFile();
+ } catch (Exception ignored) {
+ // Good to have an absolute path, but it's OK.
+ }
+ return f;
+ }
+
+ /**
+ * Loads the first available library in the collection with the specified
+ * {@link ClassLoader}.
+ */
+ static boolean loadFirstAvailable(
+ ClassLoader loader, List<LoadResult> results, String... names) {
+ for (String name : names) {
+ if (load(name, loader, results)) {
+ // Successfully loaded
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * A result of a single attempt to load a library.
+ */
+ static final class LoadResult {
+ final String name;
+ final boolean absolute;
+ final boolean loaded;
+ final boolean usingHelperClassloader;
+ final Throwable error;
+
+ private static LoadResult newSuccessResult(
+ String name, boolean absolute, boolean usingHelperClassloader) {
+ return new LoadResult(name, absolute, true, usingHelperClassloader, null);
+ }
+
+ private static LoadResult newFailureResult(
+ String name, boolean absolute, boolean usingHelperClassloader, Throwable error) {
+ return new LoadResult(name, absolute, false, usingHelperClassloader, error);
+ }
+
+ private LoadResult(String name, boolean absolute, boolean loaded,
+ boolean usingHelperClassloader, Throwable error) {
+ this.name = name;
+ this.absolute = absolute;
+ this.loaded = loaded;
+ this.usingHelperClassloader = usingHelperClassloader;
+ this.error = error;
+ }
+
+ void log() {
+ if (error != null) {
+ NativeLibraryLoader.log(
+ "Unable to load the library {0} (using helper classloader={1})", name,
+ usingHelperClassloader, error);
+ } else {
+ NativeLibraryLoader.log(
+ "Successfully loaded library {0} (using helper classloader={1})", name,
+ usingHelperClassloader);
+ }
+ }
+ }
+
+ /**
+ * Load the given library with the specified {@link ClassLoader}
+ */
+ private static boolean load(String name, ClassLoader loader, List<LoadResult> results) {
+ // Try loading from the fully-qualified classpath resource first. Otherwise just try
+ // loading the non-absolute library name directly.
+ return loadFromWorkdir(name, loader, results) || loadLibrary(loader, name, false, results);
+ }
+
+ private static boolean loadFromWorkdir(
+ String name, ClassLoader loader, List<LoadResult> results) {
+ String libname = System.mapLibraryName(name);
+ String path = NATIVE_RESOURCE_HOME + libname;
+
+ URL url = loader.getResource(path);
+ if (url == null && HostProperties.isOSX()) {
+ if (path.endsWith(".jnilib")) {
+ url = loader.getResource(NATIVE_RESOURCE_HOME + "lib" + name + ".dynlib");
+ } else {
+ url = loader.getResource(NATIVE_RESOURCE_HOME + "lib" + name + ".jnilib");
+ }
+ }
+
+ if (url == null) {
+ return false;
+ }
+
+ int index = libname.lastIndexOf('.');
+ String prefix = libname.substring(0, index);
+ String suffix = libname.substring(index, libname.length());
+ File tmpFile = null;
+ try {
+ // Create a temporary file.
+ tmpFile = Platform.createTempFile(prefix, suffix, WORKDIR);
+ if (tmpFile.isFile() && tmpFile.canRead() && !Platform.canExecuteExecutable(tmpFile)) {
+ throw new IOException(MessageFormat.format("{0} exists but cannot be executed even "
+ + "when execute permissions set; check volume for "
+ + "\"noexec\" flag; use -D{1}=[path] to set native "
+ + "working directory separately.",
+ tmpFile.getPath(), WORK_DIR_PROPERTY_NAME));
+ }
+
+ // Copy the library from classpath to tmpFile
+ copyLibrary(url, tmpFile);
+
+ return loadLibrary(loader, tmpFile.getPath(), true, results);
+ } catch (IOException e) {
+ // Convert to an UnsatisfiedLinkError.
+ Throwable error = new UnsatisfiedLinkError(
+ MessageFormat.format("Failed creating temp file ({0})",
+ tmpFile)).initCause(e);
+ results.add(LoadResult.newFailureResult(name, true, false, error));
+ return false;
+ } finally {
+ // After we load the library it is safe to delete the file.
+ // We delete the file immediately to free up resources as soon as possible,
+ // and if this fails fallback to deleting on JVM exit.
+ if (tmpFile != null) {
+ boolean deleted = false;
+ if (DELETE_NATIVE_LIB_AFTER_LOADING) {
+ deleted = tmpFile.delete();
+ }
+ if (!deleted) {
+ tmpFile.deleteOnExit();
+ }
+ }
+ }
+ }
+
+ /**
+ * Copies the given shared library file from classpath to a temporary file.
+ *
+ * @param classpathUrl the URL of the library on classpath
+ * @param tmpFile the destination temporary file.
+ */
+ private static void copyLibrary(URL classpathUrl, File tmpFile) throws IOException {
+ InputStream in = null;
+ OutputStream out = null;
+ try {
+ in = classpathUrl.openStream();
+ out = new FileOutputStream(tmpFile);
+
+ byte[] buffer = new byte[8192];
+ int length;
+ while ((length = in.read(buffer)) > 0) {
+ out.write(buffer, 0, length);
+ }
+ out.flush();
+ } finally {
+ closeQuietly(in);
+ closeQuietly(out);
+ }
+ }
+
+ /**
+ * Loading the native library into the specified {@link ClassLoader}.
+ * @param loader - The {@link ClassLoader} where the native library will be loaded into
+ * @param name - The native library path or name
+ * @param absolute - Whether the native library will be loaded by path or by name
+ * @return {@code true} if the library was successfully loaded.
+ */
+ private static boolean loadLibrary(final ClassLoader loader, final String name,
+ final boolean absolute, List<LoadResult> results) {
+ try {
+ // Make sure the helper belongs to the target ClassLoader.
+ final Class<?> newHelper = tryToLoadClass(loader, NativeLibraryUtil.class);
+ LoadResult result = loadLibraryFromHelperClassloader(newHelper, name, absolute);
+ results.add(result);
+ if (result.loaded) {
+ // Successfully loaded the library.
+ return true;
+ }
+ } catch (Exception ignore) {
+ // Failed loading the helper in the provided classloader - ignore.
+ }
+
+ // Fallback to loading from the local classloader.
+ LoadResult result = loadLibraryFromCurrentClassloader(name, absolute);
+ results.add(result);
+ return result.loaded;
+ }
+
+ /**
+ * Attempts to load the library by reflectively using the {@link NativeLibraryUtil} helper
+ * from its classloader.
+ *
+ * @param helper The {@link NativeLibraryUtil} helper class
+ * @param name the name of the library to load.
+ * @param absolute true if {@code name} is an absolute path to the file.
+ * @return the result of the load operation.
+ */
+ private static LoadResult loadLibraryFromHelperClassloader(
+ final Class<?> helper, final String name, final boolean absolute) {
+ return AccessController.doPrivileged(new PrivilegedAction<LoadResult>() {
+ @Override
+ public LoadResult run() {
+ try {
+ // Invoke the helper to load the native library, if succeed, then the native
+ // library belongs to the specified ClassLoader.
+ Method method = helper.getMethod("loadLibrary", String.class, boolean.class);
+ method.setAccessible(true);
+ method.invoke(null, name, absolute);
+ return LoadResult.newSuccessResult(name, absolute, true);
+ } catch (InvocationTargetException e) {
+ return LoadResult.newFailureResult(name, absolute, true, e.getCause());
+ } catch (Throwable e) {
+ return LoadResult.newFailureResult(name, absolute, true, e);
+ }
+ }
+ });
+ }
+
+ /**
+ * Attempts to load the library using the {@link NativeLibraryUtil} helper from the current
+ * classloader.
+ *
+ * @param name the name of the library to load.
+ * @param absolute true if {@code name} is an absolute path
+ * @return the result of the load operation.
+ */
+ private static LoadResult loadLibraryFromCurrentClassloader(String name, boolean absolute) {
+ try {
+ NativeLibraryUtil.loadLibrary(name, absolute);
+ return LoadResult.newSuccessResult(name, absolute, false);
+ } catch (Throwable e) {
+ return LoadResult.newFailureResult(name, absolute, false, e);
+ }
+ }
+
+ /**
+ * Try to load the helper {@link Class} into specified {@link ClassLoader}.
+ * @param loader - The {@link ClassLoader} where to load the helper {@link Class}
+ * @param helper - The helper {@link Class}
+ * @return A new helper Class defined in the specified ClassLoader.
+ * @throws ClassNotFoundException Helper class not found or loading failed
+ */
+ private static Class<?> tryToLoadClass(final ClassLoader loader, final Class<?> helper)
+ throws ClassNotFoundException {
+ try {
+ return loader.loadClass(helper.getName());
+ } catch (ClassNotFoundException e) {
+ // The helper class is NOT found in target ClassLoader, we have to define the helper
+ // class.
+ final byte[] classBinary = classToByteArray(helper);
+ return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
+ @Override
+ public Class<?> run() {
+ try {
+ // Define the helper class in the target ClassLoader,
+ // then we can call the helper to load the native library.
+ Method defineClass = ClassLoader.class.getDeclaredMethod(
+ "defineClass", String.class, byte[].class, int.class, int.class);
+ defineClass.setAccessible(true);
+ return (Class<?>) defineClass.invoke(
+ loader, helper.getName(), classBinary, 0, classBinary.length);
+ } catch (Exception e) {
+ throw new IllegalStateException("Define class failed!", e);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Load the helper {@link Class} as a byte array, to be redefined in specified {@link
+ * ClassLoader}.
+ * @param clazz - The helper {@link Class} provided by this bundle
+ * @return The binary content of helper {@link Class}.
+ * @throws ClassNotFoundException Helper class not found or loading failed
+ */
+ private static byte[] classToByteArray(Class<?> clazz) throws ClassNotFoundException {
+ String fileName = clazz.getName();
+ int lastDot = fileName.lastIndexOf('.');
+ if (lastDot > 0) {
+ fileName = fileName.substring(lastDot + 1);
+ }
+ URL classUrl = clazz.getResource(fileName + ".class");
+ if (classUrl == null) {
+ throw new ClassNotFoundException(clazz.getName());
+ }
+ byte[] buf = new byte[1024];
+ ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
+ InputStream in = null;
+ try {
+ in = classUrl.openStream();
+ for (int r; (r = in.read(buf)) != -1;) {
+ out.write(buf, 0, r);
+ }
+ return out.toByteArray();
+ } catch (IOException ex) {
+ throw new ClassNotFoundException(clazz.getName(), ex);
+ } finally {
+ closeQuietly(in);
+ closeQuietly(out);
+ }
+ }
+
+ private static void closeQuietly(Closeable c) {
+ if (c != null) {
+ try {
+ c.close();
+ } catch (IOException ignore) {
+ // ignore
+ }
+ }
+ }
+
+ private NativeLibraryLoader() {
+ // Utility
+ }
+
+ private static void log(String format, Object arg) {
+ logger.log(Level.FINE, format, arg);
+ }
+
+ private static void log(String format, Object arg1, Object arg2) {
+ logger.log(Level.FINE, format, new Object[] {arg1, arg2});
+ }
+
+ private static void log(String format, Object arg1, Object arg2, Throwable t) {
+ debug(MessageFormat.format(format, arg1, arg2), t);
+ }
+
+ private static void debug(String message, Throwable t) {
+ logger.log(Level.FINE, message, t);
+ }
+}
diff --git a/repackaged/openjdk/src/main/java/com/android/org/conscrypt/NativeLibraryUtil.java b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/NativeLibraryUtil.java
new file mode 100644
index 0000000..2ebf789
--- /dev/null
+++ b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/NativeLibraryUtil.java
@@ -0,0 +1,60 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+/*
+ * Copyright 2017 The Netty Project
+ *
+ * The Netty Project licenses this file to you 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.
+ */
+package com.android.org.conscrypt;
+
+/**
+ * A Utility to Call the {@link System#load(String)} or {@link System#loadLibrary(String)}.
+ * Because the {@link System#load(String)} and {@link System#loadLibrary(String)} are both
+ * CallerSensitive, it will load the native library into its caller's {@link ClassLoader}.
+ * In OSGi environment, we need this helper to delegate the calling to {@link System#load(String)}
+ * and it should be as simple as possible. It will be injected into the native library's
+ * ClassLoader when it is undefined. And therefore, when the defined new helper is invoked,
+ * the native library would be loaded into the native library's ClassLoader, not the
+ * caller's ClassLoader.
+ */
+final class NativeLibraryUtil {
+ /**
+ * Delegate the calling to {@link System#load(String)} or {@link System#loadLibrary(String)}.
+ * @param libName - The native library path or name
+ * @param absolute - Whether the native library will be loaded by path or by name
+ */
+ public static void loadLibrary(String libName, boolean absolute) {
+ if (absolute) {
+ System.load(libName);
+ } else {
+ System.loadLibrary(libName);
+ }
+ }
+
+ private NativeLibraryUtil() {}
+}
diff --git a/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Platform.java b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Platform.java
new file mode 100644
index 0000000..d71d2f8
--- /dev/null
+++ b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Platform.java
@@ -0,0 +1,816 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2014 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.
+ */
+
+/*
+ * Copyright 2013 The Netty Project
+ *
+ * The Netty Project licenses this file to you 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static java.nio.file.attribute.PosixFilePermission.GROUP_EXECUTE;
+import static java.nio.file.attribute.PosixFilePermission.OTHERS_EXECUTE;
+import static java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketImpl;
+import java.nio.channels.SocketChannel;
+import java.nio.file.Files;
+import java.nio.file.attribute.PosixFilePermission;
+import java.security.AccessController;
+import java.security.AlgorithmParameters;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+import java.security.Security;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509ExtendedTrustManager;
+import javax.net.ssl.X509TrustManager;
+import com.android.org.conscrypt.ct.CTLogStore;
+import com.android.org.conscrypt.ct.CTPolicy;
+import sun.security.x509.AlgorithmId;
+
+/**
+ * Platform-specific methods for OpenJDK.
+ *
+ * Uses reflection to implement Java 8 SSL features for backwards compatibility.
+ */
+final class Platform {
+ private static final int JAVA_VERSION = javaVersion0();
+ private static final Method GET_CURVE_NAME_METHOD;
+
+ static {
+
+ Method getCurveNameMethod = null;
+ try {
+ getCurveNameMethod = ECParameterSpec.class.getDeclaredMethod("getCurveName");
+ getCurveNameMethod.setAccessible(true);
+ } catch (Exception ignored) {
+ // Method not available, leave it as null, which is checked before use
+ }
+ GET_CURVE_NAME_METHOD = getCurveNameMethod;
+ }
+
+ private Platform() {}
+
+ static void setup() {}
+
+
+ /**
+ * Approximates the behavior of File.createTempFile without depending on SecureRandom.
+ */
+ static File createTempFile(String prefix, String suffix, File directory)
+ throws IOException {
+ if (directory == null) {
+ throw new NullPointerException();
+ }
+ long time = System.currentTimeMillis();
+ prefix = new File(prefix).getName();
+ IOException suppressed = null;
+ for (int i = 0; i < 10000; i++) {
+ String tempName = String.format(Locale.US, "%s%d%04d%s", prefix, time, i, suffix);
+ File tempFile = new File(directory, tempName);
+ if (!tempName.equals(tempFile.getName())) {
+ // The given prefix or suffix contains path separators.
+ throw new IOException("Unable to create temporary file: " + tempFile);
+ }
+ try {
+ if (tempFile.createNewFile()) {
+ return tempFile.getCanonicalFile();
+ }
+ } catch (IOException e) {
+ // This may just be a transient error; store it just in case.
+ suppressed = e;
+ }
+ }
+ if (suppressed != null) {
+ throw suppressed;
+ } else {
+ throw new IOException("Unable to create temporary file");
+ }
+ }
+
+ /**
+ * Default name used in the {@link java.security.Security JCE system} by {@code OpenSSLProvider}
+ * if the default constructor is used.
+ */
+ static String getDefaultProviderName() {
+ return "Conscrypt";
+ }
+
+ static boolean provideTrustManagerByDefault() {
+ return true;
+ }
+
+ static boolean canExecuteExecutable(File file) throws IOException {
+ // If we can already execute, there is nothing to do.
+ if (file.canExecute()) {
+ return true;
+ }
+
+ // On volumes, with noexec set, even files with the executable POSIX permissions will
+ // fail to execute. The File#canExecute() method honors this behavior, probably via
+ // parsing the noexec flag when initializing the UnixFileStore, though the flag is not
+ // exposed via a public API. To find out if library is being loaded off a volume with
+ // noexec, confirm or add executable permissions, then check File#canExecute().
+
+ Set<PosixFilePermission> existingFilePermissions =
+ Files.getPosixFilePermissions(file.toPath());
+ Set<PosixFilePermission> executePermissions =
+ EnumSet.of(OWNER_EXECUTE, GROUP_EXECUTE, OTHERS_EXECUTE);
+ if (existingFilePermissions.containsAll(executePermissions)) {
+ return false;
+ }
+
+ Set<PosixFilePermission> newPermissions = EnumSet.copyOf(existingFilePermissions);
+ newPermissions.addAll(executePermissions);
+ Files.setPosixFilePermissions(file.toPath(), newPermissions);
+ return file.canExecute();
+ }
+
+ static FileDescriptor getFileDescriptor(Socket s) {
+ try {
+ SocketChannel channel = s.getChannel();
+ if (channel != null) {
+ Field f_fd = channel.getClass().getDeclaredField("fd");
+ f_fd.setAccessible(true);
+ return (FileDescriptor) f_fd.get(channel);
+ }
+ } catch (Exception e) {
+ // Try socket class below...
+ }
+
+ try {
+ Method m_getImpl = Socket.class.getDeclaredMethod("getImpl");
+ m_getImpl.setAccessible(true);
+ Object socketImpl = m_getImpl.invoke(s);
+ try {
+ Class<?> c_delegatingSocketImpl = Class.forName("java.net.DelegatingSocketImpl");
+ if (c_delegatingSocketImpl.isAssignableFrom(socketImpl.getClass())) {
+ Method m_delegate = c_delegatingSocketImpl.getDeclaredMethod("delegate");
+ m_delegate.setAccessible(true);
+ socketImpl = m_delegate.invoke(socketImpl);
+ }
+ } catch (Exception ignored) {
+ // Ignored
+ }
+ Field f_fd = SocketImpl.class.getDeclaredField("fd");
+ f_fd.setAccessible(true);
+ return (FileDescriptor) f_fd.get(socketImpl);
+ } catch (Exception e) {
+ throw new RuntimeException("Can't get FileDescriptor from socket", e);
+ }
+ }
+
+ @SuppressWarnings("unused")
+ static FileDescriptor getFileDescriptorFromSSLSocket(AbstractConscryptSocket socket) {
+ return getFileDescriptor(socket);
+ }
+
+ @SuppressWarnings("unused")
+ static String getCurveName(ECParameterSpec spec) {
+ if (GET_CURVE_NAME_METHOD != null) {
+ try {
+ return (String) GET_CURVE_NAME_METHOD.invoke(spec);
+ } catch (Exception ignored) {
+ // Ignored
+ }
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unused")
+ static void setCurveName(@SuppressWarnings("unused") ECParameterSpec spec,
+ @SuppressWarnings("unused") String curveName) {
+ // This doesn't appear to be needed.
+ }
+
+ @SuppressWarnings("unused")
+ static void setSocketWriteTimeout(@SuppressWarnings("unused") Socket s,
+ @SuppressWarnings("unused") long timeoutMillis) throws SocketException {
+ // TODO: figure this out on the RI
+ }
+
+ static void setSSLParameters(
+ SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) {
+ if (JAVA_VERSION >= 9) {
+ Java9PlatformUtil.setSSLParameters(params, impl, socket);
+ } else if (JAVA_VERSION >= 8) {
+ Java8PlatformUtil.setSSLParameters(params, impl, socket);
+ } else {
+ impl.setEndpointIdentificationAlgorithm(params.getEndpointIdentificationAlgorithm());
+ }
+ }
+
+ static void getSSLParameters(
+ SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) {
+ if (JAVA_VERSION >= 9) {
+ Java9PlatformUtil.getSSLParameters(params, impl, socket);
+ } else if (JAVA_VERSION >= 8) {
+ Java8PlatformUtil.getSSLParameters(params, impl, socket);
+ } else {
+ params.setEndpointIdentificationAlgorithm(impl.getEndpointIdentificationAlgorithm());
+ }
+ }
+
+ static void setSSLParameters(
+ SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) {
+ if (JAVA_VERSION >= 9) {
+ Java9PlatformUtil.setSSLParameters(params, impl, engine);
+ } else if (JAVA_VERSION >= 8) {
+ Java8PlatformUtil.setSSLParameters(params, impl, engine);
+ } else {
+ impl.setEndpointIdentificationAlgorithm(params.getEndpointIdentificationAlgorithm());
+ }
+ }
+
+ static void getSSLParameters(
+ SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) {
+ if (JAVA_VERSION >= 9) {
+ Java9PlatformUtil.getSSLParameters(params, impl, engine);
+ } else if (JAVA_VERSION >= 8) {
+ Java8PlatformUtil.getSSLParameters(params, impl, engine);
+ } else {
+ params.setEndpointIdentificationAlgorithm(impl.getEndpointIdentificationAlgorithm());
+ }
+ }
+
+ @SuppressWarnings("unused")
+ static void setEndpointIdentificationAlgorithm(
+ SSLParameters params, String endpointIdentificationAlgorithm) {
+ params.setEndpointIdentificationAlgorithm(endpointIdentificationAlgorithm);
+ }
+
+ @SuppressWarnings("unused")
+ static String getEndpointIdentificationAlgorithm(SSLParameters params) {
+ return params.getEndpointIdentificationAlgorithm();
+ }
+
+ @SuppressWarnings("unused")
+ static void checkClientTrusted(X509TrustManager tm, X509Certificate[] chain, String authType,
+ AbstractConscryptSocket socket) throws CertificateException {
+ if (tm instanceof X509ExtendedTrustManager) {
+ X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm;
+ x509etm.checkClientTrusted(chain, authType, socket);
+ } else {
+ tm.checkClientTrusted(chain, authType);
+ }
+ }
+
+ @SuppressWarnings("unused")
+ static void checkServerTrusted(X509TrustManager tm, X509Certificate[] chain, String authType,
+ AbstractConscryptSocket socket) throws CertificateException {
+ if (tm instanceof X509ExtendedTrustManager) {
+ X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm;
+ x509etm.checkServerTrusted(chain, authType, socket);
+ } else {
+ tm.checkServerTrusted(chain, authType);
+ }
+ }
+
+ @SuppressWarnings("unused")
+ static void checkClientTrusted(X509TrustManager tm, X509Certificate[] chain, String authType,
+ ConscryptEngine engine) throws CertificateException {
+ if (tm instanceof X509ExtendedTrustManager) {
+ X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm;
+ x509etm.checkClientTrusted(chain, authType, engine);
+ } else {
+ tm.checkClientTrusted(chain, authType);
+ }
+ }
+
+ @SuppressWarnings("unused")
+ static void checkServerTrusted(X509TrustManager tm, X509Certificate[] chain, String authType,
+ ConscryptEngine engine) throws CertificateException {
+ if (tm instanceof X509ExtendedTrustManager) {
+ X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm;
+ x509etm.checkServerTrusted(chain, authType, engine);
+ } else {
+ tm.checkServerTrusted(chain, authType);
+ }
+ }
+
+ /**
+ * Wraps an old AndroidOpenSSL key instance. This is not needed on RI.
+ */
+ @SuppressWarnings("unused")
+ static OpenSSLKey wrapRsaKey(@SuppressWarnings("unused") PrivateKey javaKey) {
+ return null;
+ }
+
+ /**
+ * Logs to the system EventLog system.
+ */
+ @SuppressWarnings("unused")
+ static void logEvent(@SuppressWarnings("unused") String message) {}
+
+ /**
+ * For unbundled versions, SNI is always enabled by default.
+ */
+ @SuppressWarnings("unused")
+ static boolean isSniEnabledByDefault() {
+ return true;
+ }
+
+ static SSLEngine wrapEngine(ConscryptEngine engine) {
+ if (JAVA_VERSION >= 8) {
+ return Java8PlatformUtil.wrapEngine(engine);
+ }
+ return engine;
+ }
+
+ static SSLEngine unwrapEngine(SSLEngine engine) {
+ if (JAVA_VERSION >= 8) {
+ return Java8PlatformUtil.unwrapEngine(engine);
+ }
+ return engine;
+ }
+
+ static ConscryptEngineSocket createEngineSocket(SSLParametersImpl sslParameters)
+ throws IOException {
+ if (JAVA_VERSION >= 8) {
+ return new Java8EngineSocket(sslParameters);
+ }
+ return new ConscryptEngineSocket(sslParameters);
+ }
+
+ static ConscryptEngineSocket createEngineSocket(String hostname, int port,
+ SSLParametersImpl sslParameters) throws IOException {
+ if (JAVA_VERSION >= 8) {
+ return new Java8EngineSocket(hostname, port, sslParameters);
+ }
+ return new ConscryptEngineSocket(hostname, port, sslParameters);
+ }
+
+ static ConscryptEngineSocket createEngineSocket(InetAddress address, int port,
+ SSLParametersImpl sslParameters) throws IOException {
+ if (JAVA_VERSION >= 8) {
+ return new Java8EngineSocket(address, port, sslParameters);
+ }
+ return new ConscryptEngineSocket(address, port, sslParameters);
+ }
+
+ static ConscryptEngineSocket createEngineSocket(String hostname, int port,
+ InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters)
+ throws IOException {
+ if (JAVA_VERSION >= 8) {
+ return new Java8EngineSocket(hostname, port, clientAddress, clientPort, sslParameters);
+ }
+ return new ConscryptEngineSocket(hostname, port, clientAddress, clientPort, sslParameters);
+ }
+
+ static ConscryptEngineSocket createEngineSocket(InetAddress address, int port,
+ InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters)
+ throws IOException {
+ if (JAVA_VERSION >= 8) {
+ return new Java8EngineSocket(address, port, clientAddress, clientPort, sslParameters);
+ }
+ return new ConscryptEngineSocket(address, port, clientAddress, clientPort, sslParameters);
+ }
+
+ static ConscryptEngineSocket createEngineSocket(Socket socket, String hostname, int port,
+ boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
+ if (JAVA_VERSION >= 8) {
+ return new Java8EngineSocket(socket, hostname, port, autoClose, sslParameters);
+ }
+ return new ConscryptEngineSocket(socket, hostname, port, autoClose, sslParameters);
+ }
+
+ static ConscryptFileDescriptorSocket createFileDescriptorSocket(SSLParametersImpl sslParameters)
+ throws IOException {
+ if (JAVA_VERSION >= 8) {
+ return new Java8FileDescriptorSocket(sslParameters);
+ }
+ return new ConscryptFileDescriptorSocket(sslParameters);
+ }
+
+ static ConscryptFileDescriptorSocket createFileDescriptorSocket(String hostname, int port,
+ SSLParametersImpl sslParameters) throws IOException {
+ if (JAVA_VERSION >= 8) {
+ return new Java8FileDescriptorSocket(hostname, port, sslParameters);
+ }
+ return new ConscryptFileDescriptorSocket(hostname, port, sslParameters);
+ }
+
+ static ConscryptFileDescriptorSocket createFileDescriptorSocket(InetAddress address, int port,
+ SSLParametersImpl sslParameters) throws IOException {
+ if (JAVA_VERSION >= 8) {
+ return new Java8FileDescriptorSocket(address, port, sslParameters);
+ }
+ return new ConscryptFileDescriptorSocket(address, port, sslParameters);
+ }
+
+ static ConscryptFileDescriptorSocket createFileDescriptorSocket(String hostname, int port,
+ InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters)
+ throws IOException {
+ if (JAVA_VERSION >= 8) {
+ return new Java8FileDescriptorSocket(
+ hostname, port, clientAddress, clientPort, sslParameters);
+ }
+ return new ConscryptFileDescriptorSocket(
+ hostname, port, clientAddress, clientPort, sslParameters);
+ }
+
+ static ConscryptFileDescriptorSocket createFileDescriptorSocket(InetAddress address, int port,
+ InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters)
+ throws IOException {
+ if (JAVA_VERSION >= 8) {
+ return new Java8FileDescriptorSocket(
+ address, port, clientAddress, clientPort, sslParameters);
+ }
+ return new ConscryptFileDescriptorSocket(
+ address, port, clientAddress, clientPort, sslParameters);
+ }
+
+ static ConscryptFileDescriptorSocket createFileDescriptorSocket(Socket socket, String hostname,
+ int port, boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
+ if (JAVA_VERSION >= 8) {
+ return new Java8FileDescriptorSocket(socket, hostname, port, autoClose, sslParameters);
+ }
+ return new ConscryptFileDescriptorSocket(socket, hostname, port, autoClose, sslParameters);
+ }
+
+ /**
+ * Currently we don't wrap anything from the RI.
+ */
+ @SuppressWarnings("unused")
+ static SSLSocketFactory wrapSocketFactoryIfNeeded(OpenSSLSocketFactoryImpl factory) {
+ return factory;
+ }
+
+ /**
+ * Convert from platform's GCMParameterSpec to our internal version.
+ */
+ @SuppressWarnings("unused")
+ static GCMParameters fromGCMParameterSpec(AlgorithmParameterSpec params) {
+ if (params instanceof GCMParameterSpec) {
+ GCMParameterSpec gcmParams = (GCMParameterSpec) params;
+ return new GCMParameters(gcmParams.getTLen(), gcmParams.getIV());
+ }
+ return null;
+ }
+
+ /**
+ * Convert from an opaque AlgorithmParameters to the platform's GCMParameterSpec.
+ */
+ static AlgorithmParameterSpec fromGCMParameters(AlgorithmParameters params) {
+ try {
+ return params.getParameterSpec(GCMParameterSpec.class);
+ } catch (InvalidParameterSpecException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Creates a platform version of {@code GCMParameterSpec}.
+ */
+ @SuppressWarnings("unused")
+ static AlgorithmParameterSpec toGCMParameterSpec(int tagLenInBits, byte[] iv) {
+ return new GCMParameterSpec(tagLenInBits, iv);
+ }
+
+ /*
+ * CloseGuard functions.
+ */
+
+ @SuppressWarnings("unused")
+ static Object closeGuardGet() {
+ return null;
+ }
+
+ @SuppressWarnings("unused")
+ static void closeGuardOpen(@SuppressWarnings("unused") Object guardObj,
+ @SuppressWarnings("unused") String message) {}
+
+ @SuppressWarnings("unused")
+ static void closeGuardClose(@SuppressWarnings("unused") Object guardObj) {}
+
+ @SuppressWarnings("unused")
+ static void closeGuardWarnIfOpen(@SuppressWarnings("unused") Object guardObj) {}
+
+ /*
+ * BlockGuard functions.
+ */
+
+ @SuppressWarnings("unused")
+ static void blockGuardOnNetwork() {}
+
+ /**
+ * OID to Algorithm Name mapping.
+ */
+ @SuppressWarnings("unused")
+ static String oidToAlgorithmName(String oid) {
+ try {
+ return AlgorithmId.get(oid).getName();
+ } catch (Exception e) {
+ return oid;
+ } catch (IllegalAccessError e) {
+ // This can happen under JPMS because AlgorithmId isn't exported by java.base
+ return oid;
+ }
+ }
+
+ /*
+ * Pre-Java-8 backward compatibility.
+ */
+
+ @SuppressWarnings("unused")
+ static SSLSession wrapSSLSession(ExternalSession sslSession) {
+ if (JAVA_VERSION >= 8) {
+ return Java8PlatformUtil.wrapSSLSession(sslSession);
+ }
+ return new Java7ExtendedSSLSession(sslSession);
+ }
+
+ public static String getOriginalHostNameFromInetAddress(InetAddress addr) {
+ try {
+ Method getHolder = InetAddress.class.getDeclaredMethod("holder");
+ getHolder.setAccessible(true);
+
+ Method getOriginalHostName = Class.forName("java.net.InetAddress$InetAddressHolder")
+ .getDeclaredMethod("getOriginalHostName");
+ getOriginalHostName.setAccessible(true);
+
+ String originalHostName = (String) getOriginalHostName.invoke(getHolder.invoke(addr));
+ if (originalHostName == null) {
+ return addr.getHostAddress();
+ }
+ return originalHostName;
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException("Failed to get originalHostName", e);
+ } catch (ClassNotFoundException | IllegalAccessException | NoSuchMethodException ignore) {
+ // passthrough and return addr.getHostAddress()
+ }
+
+ return addr.getHostAddress();
+ }
+
+ @SuppressWarnings("unused")
+ static String getHostStringFromInetSocketAddress(InetSocketAddress addr) {
+ return addr.getHostString();
+ }
+
+ // OpenJDK always has X509ExtendedTrustManager
+ static boolean supportsX509ExtendedTrustManager() {
+ return true;
+ }
+
+ /**
+ * Check if SCT verification is required for a given hostname.
+ *
+ * SCT Verification is enabled using {@code Security} properties.
+ * The "conscrypt.ct.enable" property must be true, as well as a per domain property.
+ * The reverse notation of the domain name, prefixed with "conscrypt.ct.enforce."
+ * is used as the property name.
+ * Basic globbing is also supported.
+ *
+ * For example, for the domain foo.bar.com, the following properties will be
+ * looked up, in order of precedence.
+ * - conscrypt.ct.enforce.com.bar.foo
+ * - conscrypt.ct.enforce.com.bar.*
+ * - conscrypt.ct.enforce.com.*
+ * - conscrypt.ct.enforce.*
+ */
+ static boolean isCTVerificationRequired(String hostname) {
+ if (hostname == null) {
+ return false;
+ }
+
+ String property = Security.getProperty("conscrypt.ct.enable");
+ if (property == null || !Boolean.valueOf(property.toLowerCase())) {
+ return false;
+ }
+
+ List<String> parts = Arrays.asList(hostname.split("\\."));
+ Collections.reverse(parts);
+
+ boolean enable = false;
+ StringBuilder propertyName = new StringBuilder("conscrypt.ct.enforce");
+ // The loop keeps going on even once we've found a match
+ // This allows for finer grained settings on subdomains
+ for (String part : parts) {
+ property = Security.getProperty(propertyName + ".*");
+ if (property != null) {
+ enable = Boolean.valueOf(property.toLowerCase());
+ }
+
+ propertyName.append(".").append(part);
+ }
+
+ property = Security.getProperty(propertyName.toString());
+ if (property != null) {
+ enable = Boolean.valueOf(property.toLowerCase());
+ }
+ return enable;
+ }
+
+ static boolean supportsConscryptCertStore() {
+ return false;
+ }
+
+ static KeyStore getDefaultCertKeyStore() throws KeyStoreException {
+ // Start with an empty KeyStore. In the worst case, we'll end up returning it.
+ KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ try {
+ ks.load(null, null);
+ } catch (NoSuchAlgorithmException ignored) {
+ // TODO(prb): Should this be re-thrown? It happens if "the algorithm used to check
+ // the integrity of the KeyStore cannot be found".
+ } catch (IOException | CertificateException ignored) {
+ // We're not loading anything, so ignore it
+ }
+ // Find the highest-priority non-Conscrypt provider that provides a PKIX
+ // TrustManagerFactory implementation and ask it for its trusted CAs. This is most
+ // likely the OpenJDK-provided provider, in which case the platform default properties
+ // for configuring CA certs will be used, but we'll accept any provider that can give
+ // us at least one cert.
+ Provider[] providers = Security.getProviders("TrustManagerFactory.PKIX");
+ for (Provider p : providers) {
+ if (Conscrypt.isConscrypt(p)) {
+ // We need to skip any Conscrypt provider we find because this method is called
+ // when we're trying to determine the default set of CA certs for one of our
+ // TrustManagers, so trying to construct a TrustManager from this provider
+ // would result in calling this method again and recursing infinitely.
+ continue;
+ }
+ try {
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX", p);
+ tmf.init((KeyStore) null);
+ TrustManager[] tms = tmf.getTrustManagers();
+ if (tms.length > 0) {
+ // Aliases are irrelevant for our purposes, so just number the certs
+ int certNum = 1;
+ for (TrustManager tm : tms) {
+ if (tm instanceof X509TrustManager) {
+ X509TrustManager xtm = (X509TrustManager) tm;
+ for (X509Certificate cert : xtm.getAcceptedIssuers()) {
+ ks.setCertificateEntry(Integer.toString(certNum++), cert);
+ }
+ }
+ }
+ if (certNum > 1) {
+ // We've loaded at least one certificate, so we're done.
+ break;
+ }
+ }
+ } catch (NoSuchAlgorithmException ignored) {
+ // This TrustManagerFactory didn't work, try another one
+ }
+ }
+ return ks;
+ }
+
+ static ConscryptCertStore newDefaultCertStore() {
+ return null;
+ }
+
+ static CertBlocklist newDefaultBlocklist() {
+ return null;
+ }
+
+ static CTLogStore newDefaultLogStore() {
+ return null;
+ }
+
+ static CTPolicy newDefaultPolicy(CTLogStore logStore) {
+ return null;
+ }
+
+ static boolean serverNamePermitted(SSLParametersImpl parameters, String serverName) {
+ if (JAVA_VERSION >= 8) {
+ return Java8PlatformUtil.serverNamePermitted(parameters, serverName);
+ }
+ return true;
+ }
+
+ private static boolean isAndroid() {
+ boolean android;
+ try {
+ Class.forName("android.app.Application", false, getSystemClassLoader());
+ android = true;
+ } catch (Throwable ignored) {
+ // Failed to load the class uniquely available in Android.
+ android = false;
+ }
+ return android;
+ }
+
+ static int javaVersion() {
+ return JAVA_VERSION;
+ }
+
+ private static int javaVersion0() {
+ final int majorVersion;
+
+ if (isAndroid()) {
+ majorVersion = 6;
+ } else {
+ majorVersion = majorVersionFromJavaSpecificationVersion();
+ }
+
+ return majorVersion;
+ }
+
+ private static int majorVersionFromJavaSpecificationVersion() {
+ return majorVersion(System.getProperty("java.specification.version", "1.6"));
+ }
+
+ private static int majorVersion(final String javaSpecVersion) {
+ final String[] components = javaSpecVersion.split("\\.", -1);
+ final int[] version = new int[components.length];
+ for (int i = 0; i < components.length; i++) {
+ version[i] = Integer.parseInt(components[i]);
+ }
+
+ if (version[0] == 1) {
+ assert version[1] >= 6;
+ return version[1];
+ } else {
+ return version[0];
+ }
+ }
+
+ private static ClassLoader getSystemClassLoader() {
+ if (System.getSecurityManager() == null) {
+ return ClassLoader.getSystemClassLoader();
+ } else {
+ return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+ @Override
+ public ClassLoader run() {
+ return ClassLoader.getSystemClassLoader();
+ }
+ });
+ }
+ }
+
+ public static ConscryptHostnameVerifier getDefaultHostnameVerifier() {
+ return OkHostnameVerifier.strictInstance();
+ }
+
+ @SuppressWarnings("unused")
+ static long getMillisSinceBoot() {
+ return 0;
+ }
+
+ @SuppressWarnings("unused")
+ static void countTlsHandshake(
+ boolean success, String protocol, String cipherSuite, long duration) {}
+
+ public static boolean isJavaxCertificateSupported() {
+ return JAVA_VERSION < 15;
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/AbstractSessionContextTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/AbstractSessionContextTest.java
new file mode 100644
index 0000000..7f3ed10
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/AbstractSessionContextTest.java
@@ -0,0 +1,160 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.security.cert.Certificate;
+import javax.net.ssl.SSLSession;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class AbstractSessionContextTest<T extends AbstractSessionContext> {
+ private T context;
+
+ @Before
+ public void setup() {
+ context = newContext();
+ }
+
+ abstract T newContext();
+ abstract int size(T context);
+ private static NativeSslSession[] toArray(NativeSslSession... sessions) {
+ return sessions;
+ }
+
+ abstract NativeSslSession getCachedSession(T context, NativeSslSession s);
+
+ @Test
+ public void testSimpleAddition() {
+ NativeSslSession a = newSession("a");
+ NativeSslSession b = newSession("b");
+
+ context.cacheSession(a);
+ assertSessionContextContents(toArray(a), toArray(b));
+
+ context.cacheSession(b);
+ assertSessionContextContents(toArray(a, b), toArray());
+ }
+
+ @Test
+ public void testTrimToSize() {
+ NativeSslSession a = newSession("a");
+ NativeSslSession b = newSession("b");
+ NativeSslSession c = newSession("c");
+ NativeSslSession d = newSession("d");
+
+ context.cacheSession(a);
+ context.cacheSession(b);
+ context.cacheSession(c);
+ context.cacheSession(d);
+ assertSessionContextContents(toArray(a, b, c, d), toArray());
+
+ context.setSessionCacheSize(2);
+ assertSessionContextContents(toArray(c, d), toArray(a, b));
+ }
+
+ @Test
+ public void testImplicitRemovalOfOldest() {
+ context.setSessionCacheSize(2);
+ NativeSslSession a = newSession("a");
+ NativeSslSession b = newSession("b");
+ NativeSslSession c = newSession("c");
+ NativeSslSession d = newSession("d");
+
+ context.cacheSession(a);
+ assertSessionContextContents(toArray(a), toArray(b, c, d));
+
+ context.cacheSession(b);
+ assertSessionContextContents(toArray(a, b), toArray(c, d));
+
+ context.cacheSession(c);
+ assertSessionContextContents(toArray(b, c), toArray(a, d));
+
+ context.cacheSession(d);
+ assertSessionContextContents(toArray(c, d), toArray(a, b));
+ }
+
+ @Test
+ public void testRemoveIfSingleUse() {
+ NativeSslSession multi = new MockSessionBuilder().host("multi").singleUse(false).build();
+ NativeSslSession single = new MockSessionBuilder().host("single").singleUse(true).build();
+
+ context.cacheSession(multi);
+ assertEquals(1, size(context));
+
+ context.cacheSession(single);
+ assertEquals(2, size(context));
+
+ NativeSslSession out = getCachedSession(context, multi);
+ assertEquals(multi, out);
+ assertEquals(2, size(context));
+
+ out = getCachedSession(context, single);
+ assertEquals(single, out);
+ assertEquals(1, size(context));
+
+ assertNull(getCachedSession(context, single));
+ }
+
+ @Test
+ public void testSerializeSession() throws Exception {
+ Certificate mockCert = mock(Certificate.class);
+ when(mockCert.getEncoded()).thenReturn(new byte[] {0x05, 0x06, 0x07, 0x10});
+
+ byte[] encodedBytes = new byte[] {0x01, 0x02, 0x03};
+ NativeSslSession session = new MockSessionBuilder()
+ .id(new byte[] {0x11, 0x09, 0x03, 0x20})
+ .host("ssl.example.com")
+ .encodedBytes(encodedBytes)
+ .build();
+
+ SSLClientSessionCache mockCache = mock(SSLClientSessionCache.class);
+ ClientSessionContext context = new ClientSessionContext();
+ context.setPersistentCache(mockCache);
+
+ context.cacheSession(session);
+ verify(mockCache).putSessionData(any(SSLSession.class), same(encodedBytes));
+ }
+
+ private void assertSessionContextContents(
+ NativeSslSession[] contains, NativeSslSession[] excludes) {
+ assertEquals(contains.length, size(context));
+
+ for (NativeSslSession s : contains) {
+ assertSame(s.getPeerHost(), s, getCachedSession(context, s));
+ }
+ for (NativeSslSession s : excludes) {
+ assertNull(s.getPeerHost(), getCachedSession(context, s));
+ }
+ }
+
+ private NativeSslSession newSession(String host) {
+ return new MockSessionBuilder().host(host).build();
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/AddressUtilsTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/AddressUtilsTest.java
new file mode 100644
index 0000000..bdf1fdd
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/AddressUtilsTest.java
@@ -0,0 +1,102 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2014 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.
+ */
+
+package com.android.org.conscrypt;
+
+import junit.framework.TestCase;
+
+/**
+ * Test for AddressUtils
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AddressUtilsTest extends TestCase {
+ public void test_isValidSniHostname_Success() throws Exception {
+ assertTrue(AddressUtils.isValidSniHostname("www.google.com"));
+ }
+
+ public void test_isValidSniHostname_NotFQDN_Failure() throws Exception {
+ assertFalse(AddressUtils.isValidSniHostname("www"));
+ }
+
+ public void test_isValidSniHostname_Localhost_Success() throws Exception {
+ assertTrue(AddressUtils.isValidSniHostname("LOCALhost"));
+ }
+
+ public void test_isValidSniHostname_IPv4_Failure() throws Exception {
+ assertFalse(AddressUtils.isValidSniHostname("192.168.0.1"));
+ }
+
+ public void test_isValidSniHostname_IPv6_Failure() throws Exception {
+ assertFalse(AddressUtils.isValidSniHostname("2001:db8::1"));
+ }
+
+ public void test_isValidSniHostname_TrailingDot() throws Exception {
+ assertFalse(AddressUtils.isValidSniHostname("www.google.com."));
+ }
+
+ public void test_isValidSniHostname_NullByte() throws Exception {
+ assertFalse(AddressUtils.isValidSniHostname("www\0.google.com"));
+ }
+
+ public void test_isLiteralIpAddress_IPv4_Success() throws Exception {
+ assertTrue(AddressUtils.isLiteralIpAddress("127.0.0.1"));
+ assertTrue(AddressUtils.isLiteralIpAddress("255.255.255.255"));
+ assertTrue(AddressUtils.isLiteralIpAddress("0.0.00.000"));
+ assertTrue(AddressUtils.isLiteralIpAddress("192.009.010.19"));
+ assertTrue(AddressUtils.isLiteralIpAddress("254.249.190.094"));
+ }
+
+ public void test_isLiteralIpAddress_IPv4_ExtraCharacters_Failure() throws Exception {
+ assertFalse(AddressUtils.isLiteralIpAddress("127.0.0.1a"));
+ assertFalse(AddressUtils.isLiteralIpAddress(" 255.255.255.255"));
+ assertFalse(AddressUtils.isLiteralIpAddress("0.0.00.0009"));
+ assertFalse(AddressUtils.isLiteralIpAddress("192.009z.010.19"));
+ assertFalse(AddressUtils.isLiteralIpAddress("254.249..094"));
+ assertFalse(AddressUtils.isLiteralIpAddress("192.168.2.1%1"));
+ assertFalse(AddressUtils.isLiteralIpAddress("192.168.2.1%eth0"));
+ }
+
+ public void test_isLiteralIpAddress_IPv4_NumbersTooLarge_Failure() throws Exception {
+ assertFalse(AddressUtils.isLiteralIpAddress("256.255.255.255"));
+ assertFalse(AddressUtils.isLiteralIpAddress("255.255.255.256"));
+ assertFalse(AddressUtils.isLiteralIpAddress("192.168.1.260"));
+ }
+
+ public void test_isLiteralIpAddress_IPv6_Success() throws Exception {
+ assertTrue(AddressUtils.isLiteralIpAddress("::1"));
+ assertTrue(AddressUtils.isLiteralIpAddress("2001:Db8::1"));
+ assertTrue(AddressUtils.isLiteralIpAddress("2001:cdbA:0000:0000:0000:0000:3257:9652"));
+ assertTrue(AddressUtils.isLiteralIpAddress("2001:cdba:0:0:0:0:3257:9652"));
+ assertTrue(AddressUtils.isLiteralIpAddress("2001:cdBA::3257:9652"));
+ assertTrue(AddressUtils.isLiteralIpAddress("2001:cdba::3257:9652%1"));
+ assertTrue(AddressUtils.isLiteralIpAddress("2001:cdba::3257:9652%eth0"));
+ assertTrue(AddressUtils.isLiteralIpAddress("2001:cdba::3257:9652%int2.3!"));
+ }
+
+ public void test_isLiteralIpAddress_IPv6_Failure() throws Exception {
+ assertFalse(AddressUtils.isLiteralIpAddress(":::1"));
+ assertFalse(AddressUtils.isLiteralIpAddress("::11111"));
+ assertFalse(AddressUtils.isLiteralIpAddress("20011::1111"));
+ assertFalse(AddressUtils.isLiteralIpAddress("2001:db8:::1"));
+ assertFalse(AddressUtils.isLiteralIpAddress("2001:cdba:0000:00000:0000:0000:3257:9652"));
+ assertFalse(AddressUtils.isLiteralIpAddress("2001:cdbA:0000:0000:0000:0000:0000:3257:9652"));
+ assertFalse(AddressUtils.isLiteralIpAddress("2001:cdba:0::0:0:0:3257:9652"));
+ assertFalse(AddressUtils.isLiteralIpAddress("02001:cdba::3257:9652"));
+ assertFalse(AddressUtils.isLiteralIpAddress("2001:cdba::3257:96521"));
+ assertFalse(AddressUtils.isLiteralIpAddress("2001:cdba::3257:9652%"));
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ApplicationProtocolSelectorAdapterTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ApplicationProtocolSelectorAdapterTest.java
new file mode 100644
index 0000000..f16d280
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ApplicationProtocolSelectorAdapterTest.java
@@ -0,0 +1,92 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.when;
+
+import java.nio.charset.Charset;
+import javax.net.ssl.SSLEngine;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ApplicationProtocolSelectorAdapterTest {
+ private static Charset US_ASCII = Charset.forName("US-ASCII");
+ private static final String[] PROTOCOLS = new String[] {"a", "b", "c"};
+ private static final byte[] PROTOCOL_BYTES = SSLUtils.encodeProtocols(PROTOCOLS);
+
+ @Mock private ApplicationProtocolSelector selector;
+
+ @Mock private SSLEngine engine;
+
+ private ApplicationProtocolSelectorAdapter adapter;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ adapter = new ApplicationProtocolSelectorAdapter(engine, selector);
+ }
+
+ @Test
+ public void nullProtocolsShouldNotSelect() {
+ mockSelection("a");
+ assertEquals(-1, select(null));
+ }
+
+ @Test
+ public void emptyProtocolsShouldNotSelect() {
+ mockSelection("a");
+ assertEquals(-1, select(EmptyArray.BYTE));
+ }
+
+ @Test
+ public void selectCorrectProtocol() {
+ for (String protocol : PROTOCOLS) {
+ mockSelection(protocol);
+ assertEquals(protocol, getProtocolAt(select(PROTOCOL_BYTES)));
+ }
+ }
+
+ @Test
+ public void invalidProtocolShouldNotSelect() {
+ mockSelection("d");
+ assertEquals(-1, select(PROTOCOL_BYTES));
+ }
+
+ private int select(byte[] protocols) {
+ return adapter.selectApplicationProtocol(protocols);
+ }
+
+ private void mockSelection(String returnValue) {
+ when(selector.selectApplicationProtocol(same(engine), ArgumentMatchers.<String>anyList()))
+ .thenReturn(returnValue);
+ }
+
+ private String getProtocolAt(int index) {
+ int len = PROTOCOL_BYTES[index];
+ return new String(PROTOCOL_BYTES, index + 1, len, US_ASCII);
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ClientSessionContextTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ClientSessionContextTest.java
new file mode 100644
index 0000000..a05ba8f
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ClientSessionContextTest.java
@@ -0,0 +1,120 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.MockSessionBuilder.DEFAULT_PORT;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+import java.security.KeyManagementException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class ClientSessionContextTest extends AbstractSessionContextTest<ClientSessionContext> {
+
+ @Override
+ ClientSessionContext newContext() {
+ return new ClientSessionContext();
+ }
+
+ @Override
+ NativeSslSession getCachedSession(ClientSessionContext context, NativeSslSession s) {
+ return context.getCachedSession(s.getPeerHost(), DEFAULT_PORT,
+ getDefaultSSLParameters());
+ }
+
+ @Override
+ int size(ClientSessionContext context) {
+ return context.size();
+ }
+
+ private static SSLParametersImpl getDefaultSSLParameters() {
+ try {
+ return SSLParametersImpl.getDefault();
+ } catch (KeyManagementException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ public void testNoMixingOfSingleAndMultiUseSessions() {
+ ClientSessionContext context = newContext();
+
+ NativeSslSession a = new MockSessionBuilder().host("a").singleUse(false).build();
+ NativeSslSession bSingle1 = new MockSessionBuilder()
+ .id(new byte[] {1}).host("b").singleUse(true).build();
+ NativeSslSession bSingle2 = new MockSessionBuilder()
+ .id(new byte[] {2}).host("b").singleUse(true).build();
+ NativeSslSession bMulti = new MockSessionBuilder()
+ .id(new byte[] {3}).host("b").singleUse(false).build();
+
+ context.cacheSession(a);
+ assertEquals(1, size(context));
+
+ context.cacheSession(bSingle1);
+ assertEquals(2, size(context));
+
+ context.cacheSession(bSingle2);
+ assertEquals(3, size(context));
+
+ context.cacheSession(bMulti);
+ assertEquals(2, size(context));
+
+ NativeSslSession out = context.getCachedSession(
+ "b", DEFAULT_PORT, getDefaultSSLParameters());
+ assertEquals(bMulti, out);
+
+ context.cacheSession(bSingle2);
+ assertEquals(2, size(context));
+
+ out = context.getCachedSession("b", DEFAULT_PORT, getDefaultSSLParameters());
+ assertEquals(bSingle2, out);
+
+ out = context.getCachedSession("b", DEFAULT_PORT, getDefaultSSLParameters());
+ assertNull(out);
+ }
+
+ @Test
+ public void testCanRetrieveMultipleSingleUseSessions() {
+ ClientSessionContext context = newContext();
+
+ NativeSslSession single1 = new MockSessionBuilder()
+ .id(new byte[] {1}).host("host").singleUse(true).build();
+ NativeSslSession single2 = new MockSessionBuilder()
+ .id(new byte[] {2}).host("host").singleUse(true).build();
+
+ context.cacheSession(single1);
+ assertEquals(1, size(context));
+
+ context.cacheSession(single2);
+ assertEquals(2, size(context));
+
+ assertSame(single1,
+ context.getCachedSession("host", DEFAULT_PORT, getDefaultSSLParameters()));
+ assertEquals(1, size(context));
+ assertSame(single2,
+ context.getCachedSession("host", DEFAULT_PORT, getDefaultSSLParameters()));
+ assertEquals(0, size(context));
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptEngineTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptEngineTest.java
new file mode 100644
index 0000000..e1f4a13
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptEngineTest.java
@@ -0,0 +1,587 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.TestUtils.getConscryptProvider;
+import static com.android.org.conscrypt.TestUtils.getJdkProvider;
+import static com.android.org.conscrypt.TestUtils.highestCommonProtocol;
+import static com.android.org.conscrypt.TestUtils.initSslContext;
+import static com.android.org.conscrypt.TestUtils.newTextMessage;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.when;
+
+import com.android.org.conscrypt.java.security.TestKeyStore;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLEngineResult.Status;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLSession;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mockito;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(Parameterized.class)
+public class ConscryptEngineTest {
+ private static final int MESSAGE_SIZE = 4096;
+ private static final int LARGE_MESSAGE_SIZE = 16413;
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @SuppressWarnings("ImmutableEnumChecker")
+ public enum BufferType {
+ HEAP_ALLOCATOR(BufferAllocator.unpooled()) {
+ @Override
+ ByteBuffer newBuffer(int size) {
+ return ByteBuffer.allocate(size);
+ }
+ },
+ HEAP_NO_ALLOCATOR(null) {
+ @Override
+ ByteBuffer newBuffer(int size) {
+ return ByteBuffer.allocate(size);
+ }
+ },
+ DIRECT(null) {
+ @Override
+ ByteBuffer newBuffer(int size) {
+ return ByteBuffer.allocateDirect(size);
+ }
+ };
+
+ abstract ByteBuffer newBuffer(int size);
+
+ BufferType(BufferAllocator allocator) {
+ this.allocator = allocator;
+ }
+
+ private final BufferAllocator allocator;
+ }
+
+ private enum ClientAuth {
+ NONE {
+ @Override
+ void apply(SSLEngine engine) {
+ engine.setWantClientAuth(false);
+ engine.setNeedClientAuth(false);
+ }
+ },
+ OPTIONAL {
+ @Override
+ void apply(SSLEngine engine) {
+ engine.setWantClientAuth(true);
+ engine.setNeedClientAuth(false);
+ }
+ },
+ REQUIRED {
+ @Override
+ void apply(SSLEngine engine) {
+ engine.setWantClientAuth(false);
+ engine.setNeedClientAuth(true);
+ }
+ };
+
+ abstract void apply(SSLEngine engine);
+ }
+
+ @Parameters(name = "{0}")
+ public static Iterable<BufferType> data() {
+ return Arrays.asList(
+ BufferType.HEAP_ALLOCATOR, BufferType.HEAP_NO_ALLOCATOR, BufferType.DIRECT);
+ }
+
+ @Parameter public BufferType bufferType;
+
+ private SSLEngine clientEngine;
+ private SSLEngine serverEngine;
+
+ @Test
+ public void closingOutboundBeforeHandshakeShouldCloseAll() throws Exception {
+ setupEngines(TestKeyStore.getClient(), TestKeyStore.getServer());
+ assertFalse(clientEngine.isInboundDone());
+ assertFalse(clientEngine.isOutboundDone());
+ assertFalse(serverEngine.isInboundDone());
+ assertFalse(serverEngine.isOutboundDone());
+
+ clientEngine.closeOutbound();
+ serverEngine.closeOutbound();
+
+ assertTrue(clientEngine.isInboundDone());
+ assertTrue(clientEngine.isOutboundDone());
+ assertTrue(serverEngine.isInboundDone());
+ assertTrue(serverEngine.isOutboundDone());
+ }
+
+ @Test
+ public void closingOutboundAfterHandshakeShouldOnlyCloseOutbound() throws Exception {
+ setupEngines(TestKeyStore.getClient(), TestKeyStore.getServer());
+ doHandshake(true);
+
+ assertFalse(clientEngine.isInboundDone());
+ assertFalse(clientEngine.isOutboundDone());
+ assertFalse(serverEngine.isInboundDone());
+ assertFalse(serverEngine.isOutboundDone());
+
+ clientEngine.closeOutbound();
+ serverEngine.closeOutbound();
+
+ // After closing the outbound direction, a shutdown alert should still be pending
+ assertFalse(clientEngine.isOutboundDone());
+ assertFalse(serverEngine.isOutboundDone());
+
+ ByteBuffer drain =
+ bufferType.newBuffer(Math.max(clientEngine.getSession().getPacketBufferSize(),
+ serverEngine.getSession().getPacketBufferSize()));
+ clientEngine.wrap(ByteBuffer.wrap(new byte[0]), drain);
+ drain.clear();
+ serverEngine.wrap(ByteBuffer.wrap(new byte[0]), drain);
+
+ assertTrue(clientEngine.isOutboundDone());
+ assertTrue(serverEngine.isOutboundDone());
+
+ // The inbound directions should still be open
+ assertFalse(clientEngine.isInboundDone());
+ assertFalse(serverEngine.isInboundDone());
+ }
+
+ @Test
+ public void closingInboundShouldOnlyCloseInbound() throws Exception {
+ setupEngines(TestKeyStore.getClient(), TestKeyStore.getServer());
+ doHandshake(true);
+
+ assertFalse(clientEngine.isInboundDone());
+ assertFalse(clientEngine.isOutboundDone());
+ assertFalse(serverEngine.isInboundDone());
+ assertFalse(serverEngine.isOutboundDone());
+
+ clientEngine.closeInbound();
+ serverEngine.closeInbound();
+
+ assertTrue(clientEngine.isInboundDone());
+ assertFalse(clientEngine.isOutboundDone());
+ assertTrue(serverEngine.isInboundDone());
+ assertFalse(serverEngine.isOutboundDone());
+ }
+
+ @Test
+ public void mutualAuthWithSameCertsShouldSucceed() throws Exception {
+ doMutualAuthHandshake(TestKeyStore.getServer(), TestKeyStore.getServer(), ClientAuth.NONE);
+ }
+
+ @Test
+ public void mutualAuthWithDifferentCertsShouldSucceed() throws Exception {
+ doMutualAuthHandshake(TestKeyStore.getClient(), TestKeyStore.getServer(), ClientAuth.NONE);
+ }
+
+ @Test(expected = SSLHandshakeException.class)
+ public void mutualAuthWithUntrustedServerShouldFail() throws Exception {
+ doMutualAuthHandshake(
+ TestKeyStore.getClientCA2(), TestKeyStore.getServer(), ClientAuth.NONE);
+ }
+
+ @Test(expected = SSLHandshakeException.class)
+ public void mutualAuthWithUntrustedClientShouldFail() throws Exception {
+ doMutualAuthHandshake(TestKeyStore.getClient(), TestKeyStore.getClient(), ClientAuth.NONE);
+ }
+
+ @Test
+ public void optionalClientAuthShouldSucceed() throws Exception {
+ doMutualAuthHandshake(
+ TestKeyStore.getClient(), TestKeyStore.getServer(), ClientAuth.OPTIONAL);
+ }
+
+ @Test(expected = SSLHandshakeException.class)
+ public void optionalClientAuthShouldFail() throws Exception {
+ doMutualAuthHandshake(
+ TestKeyStore.getClient(), TestKeyStore.getClient(), ClientAuth.OPTIONAL);
+ }
+
+ @Test
+ public void requiredClientAuthShouldSucceed() throws Exception {
+ doMutualAuthHandshake(
+ TestKeyStore.getServer(), TestKeyStore.getServer(), ClientAuth.REQUIRED);
+ }
+
+ @Test(expected = SSLHandshakeException.class)
+ public void requiredClientAuthShouldFail() throws Exception {
+ doMutualAuthHandshake(
+ TestKeyStore.getClient(), TestKeyStore.getClient(), ClientAuth.REQUIRED);
+ }
+
+ @Test
+ public void exchangeMessages() throws Exception {
+ setupEngines(TestKeyStore.getClient(), TestKeyStore.getServer());
+ doHandshake(true);
+
+ ByteBuffer message = newMessage(MESSAGE_SIZE);
+ byte[] messageBytes = toArray(message);
+
+ // Wrap the original message and create the encrypted data.
+ final int numMessages = 100;
+ ByteBuffer[] encryptedBuffers = new ByteBuffer[numMessages];
+ for (int i = 0; i < numMessages; ++i) {
+ List<ByteBuffer> wrapped = wrap(message.duplicate(), clientEngine);
+ // Small message, we should only have 1 buffer created.
+ assertEquals(1, wrapped.size());
+ encryptedBuffers[i] = wrapped.get(0);
+ }
+
+ // Unwrap the all of the encrypted messages.
+ byte[] actualBytes = unwrap(encryptedBuffers, serverEngine);
+ assertEquals(MESSAGE_SIZE * numMessages, actualBytes.length);
+ for (int i = 0; i < numMessages; ++i) {
+ int offset = i * MESSAGE_SIZE;
+ byte[] actualMessageBytes =
+ Arrays.copyOfRange(actualBytes, offset, offset + MESSAGE_SIZE);
+ assertArrayEquals(messageBytes, actualMessageBytes);
+ }
+ }
+
+ @Test
+ public void exchangeLargeMessage() throws Exception {
+ setupEngines(TestKeyStore.getClient(), TestKeyStore.getServer());
+ doHandshake(true);
+
+ ByteBuffer inputBuffer = newMessage(LARGE_MESSAGE_SIZE);
+ exchangeMessage(inputBuffer, clientEngine, serverEngine);
+ }
+
+ @Test
+ public void alpnWithProtocolListShouldSucceed() throws Exception {
+ setupEngines(TestKeyStore.getClient(), TestKeyStore.getServer());
+
+ // Configure ALPN protocols
+ String[] clientAlpnProtocols = new String[]{"http/1.1", "foo", "spdy/2"};
+ String[] serverAlpnProtocols = new String[]{"spdy/2", "foo", "bar"};
+
+ Conscrypt.setApplicationProtocols(clientEngine, clientAlpnProtocols);
+ Conscrypt.setApplicationProtocols(serverEngine, serverAlpnProtocols);
+
+ doHandshake(true);
+ assertEquals("spdy/2", Conscrypt.getApplicationProtocol(clientEngine));
+ assertEquals("spdy/2", Conscrypt.getApplicationProtocol(serverEngine));
+ }
+
+ @Test
+ public void alpnWithProtocolListShouldFail() throws Exception {
+ setupEngines(TestKeyStore.getClient(), TestKeyStore.getServer());
+
+ // Configure ALPN protocols
+ String[] clientAlpnProtocols = new String[]{"http/1.1", "foo", "spdy/2"};
+ String[] serverAlpnProtocols = new String[]{"h2", "bar", "baz"};
+
+ Conscrypt.setApplicationProtocols(clientEngine, clientAlpnProtocols);
+ Conscrypt.setApplicationProtocols(serverEngine, serverAlpnProtocols);
+
+ doHandshake(true);
+ assertNull(Conscrypt.getApplicationProtocol(clientEngine));
+ assertNull(Conscrypt.getApplicationProtocol(serverEngine));
+ }
+
+ @Test
+ public void alpnWithServerProtocolSelectorShouldSucceed() throws Exception {
+ setupEngines(TestKeyStore.getClient(), TestKeyStore.getServer());
+
+ // Configure client protocols.
+ String[] clientAlpnProtocols = new String[]{"http/1.1", "foo", "spdy/2"};
+ Conscrypt.setApplicationProtocols(clientEngine, clientAlpnProtocols);
+
+ // Configure server selector
+ ApplicationProtocolSelector selector = Mockito.mock(ApplicationProtocolSelector.class);
+ when(selector.selectApplicationProtocol(
+ same(serverEngine), ArgumentMatchers.<String>anyList()))
+ .thenReturn("spdy/2");
+ Conscrypt.setApplicationProtocolSelector(serverEngine, selector);
+
+ doHandshake(true);
+ assertEquals("spdy/2", Conscrypt.getApplicationProtocol(clientEngine));
+ assertEquals("spdy/2", Conscrypt.getApplicationProtocol(serverEngine));
+ }
+
+ @Test
+ public void alpnWithServerProtocolSelectorShouldFail() throws Exception {
+ setupEngines(TestKeyStore.getClient(), TestKeyStore.getServer());
+
+ // Configure client protocols.
+ String[] clientAlpnProtocols = new String[]{"http/1.1", "foo", "spdy/2"};
+ Conscrypt.setApplicationProtocols(clientEngine, clientAlpnProtocols);
+
+ // Configure server selector
+ ApplicationProtocolSelector selector = Mockito.mock(ApplicationProtocolSelector.class);
+ when(selector.selectApplicationProtocol(
+ same(serverEngine), ArgumentMatchers.<String>anyList()))
+ .thenReturn("h2");
+ Conscrypt.setApplicationProtocolSelector(serverEngine, selector);
+
+ doHandshake(true);
+ assertNull(Conscrypt.getApplicationProtocol(clientEngine));
+ assertNull(Conscrypt.getApplicationProtocol(serverEngine));
+ }
+
+ /**
+ * BoringSSL server doesn't support renegotiation. BoringSSL clients do not support
+ * initiating a renegotiation, only processing a renegotiation initiated by the
+ * (non-BoringSSL) server. For this reason we test a server-initiated renegotiation with
+ * a Conscrypt client and a JDK server.
+ */
+ @Test
+ public void serverInitiatedRenegotiationShouldSucceed() throws Exception {
+ setupClientEngine(getConscryptProvider(), TestKeyStore.getClient());
+ setupServerEngine(getJdkProvider(), TestKeyStore.getServer());
+
+ // Perform the initial handshake.
+ doHandshake(true);
+
+ // Send a message from client->server.
+ exchangeMessage(newMessage(MESSAGE_SIZE), clientEngine, serverEngine);
+
+ // Trigger a renegotiation from the server and send a message back from Server->Client
+ String[] ciphers = TestUtils.getCommonCipherSuites();
+ serverEngine.setEnabledCipherSuites(new String[] {ciphers[ciphers.length - 1]});
+ serverEngine.beginHandshake();
+ doHandshake(false);
+
+ exchangeMessage(newMessage(MESSAGE_SIZE), serverEngine, clientEngine);
+ }
+
+ @Test
+ public void savedSessionWorksAfterClose() throws Exception {
+ String alpnProtocol = "spdy/2";
+ String[] alpnProtocols = new String[] {alpnProtocol};
+
+ setupEngines(TestKeyStore.getClient(), TestKeyStore.getServer());
+ Conscrypt.setApplicationProtocols(clientEngine, alpnProtocols);
+ Conscrypt.setApplicationProtocols(serverEngine, alpnProtocols);
+
+ doHandshake(true);
+
+ SSLSession session = clientEngine.getSession();
+ String cipherSuite = session.getCipherSuite();
+ String protocol = session.getProtocol();
+ assertEquals(alpnProtocol, Conscrypt.getApplicationProtocol(clientEngine));
+
+ clientEngine.closeOutbound();
+ clientEngine.closeInbound();
+
+ assertEquals(cipherSuite, session.getCipherSuite());
+ assertEquals(protocol, session.getProtocol());
+ assertEquals(alpnProtocol, Conscrypt.getApplicationProtocol(clientEngine));
+ }
+
+ @Test
+ // getApplicationProtocol should initially return null and not trigger handshake. b/146235331
+ public void getAlpnIsNullBeforeHandshake() throws Exception {
+ String alpnProtocol = "spdy/2";
+ String[] alpnProtocols = new String[] {alpnProtocol};
+
+ setupEngines(TestKeyStore.getClient(), TestKeyStore.getServer());
+
+ assertNull(Conscrypt.getApplicationProtocol(clientEngine));
+ assertNull(Conscrypt.getApplicationProtocol(serverEngine));
+
+ Conscrypt.setApplicationProtocols(clientEngine, alpnProtocols);
+ Conscrypt.setApplicationProtocols(serverEngine, alpnProtocols);
+
+ doHandshake(true);
+
+ assertEquals(alpnProtocol, Conscrypt.getApplicationProtocol(clientEngine));
+ }
+
+ private void doMutualAuthHandshake(
+ TestKeyStore clientKs, TestKeyStore serverKs, ClientAuth clientAuth) throws Exception {
+ setupEngines(clientKs, serverKs);
+ clientAuth.apply(serverEngine);
+ doHandshake(true);
+ assertEquals(HandshakeStatus.NOT_HANDSHAKING, clientEngine.getHandshakeStatus());
+ assertEquals(HandshakeStatus.NOT_HANDSHAKING, serverEngine.getHandshakeStatus());
+ }
+
+ private void doHandshake(boolean beginHandshake) throws SSLException {
+ ByteBuffer clientApplicationBuffer =
+ bufferType.newBuffer(clientEngine.getSession().getApplicationBufferSize());
+ ByteBuffer clientPacketBuffer =
+ bufferType.newBuffer(clientEngine.getSession().getPacketBufferSize());
+ ByteBuffer serverApplicationBuffer =
+ bufferType.newBuffer(serverEngine.getSession().getApplicationBufferSize());
+ ByteBuffer serverPacketBuffer =
+ bufferType.newBuffer(serverEngine.getSession().getPacketBufferSize());
+ TestUtils.doEngineHandshake(clientEngine, serverEngine, clientApplicationBuffer,
+ clientPacketBuffer, serverApplicationBuffer, serverPacketBuffer, beginHandshake);
+ }
+
+ private void setupEngines(TestKeyStore clientKeyStore, TestKeyStore serverKeyStore) throws SSLException {
+ setupClientEngine(getConscryptProvider(), clientKeyStore);
+ setupServerEngine(getConscryptProvider(), serverKeyStore);
+ }
+
+ private void setupClientEngine(Provider provider, TestKeyStore clientKeyStore)
+ throws SSLException {
+ clientEngine = newEngine(provider, clientKeyStore, true);
+ }
+
+ private void setupServerEngine(Provider provider, TestKeyStore serverKeyStore)
+ throws SSLException {
+ serverEngine = newEngine(provider, serverKeyStore, false);
+ }
+
+ private SSLEngine newEngine(
+ Provider provider, TestKeyStore keyStore, boolean client) {
+ SSLContext serverContext = newContext(provider, keyStore);
+ SSLEngine engine = serverContext.createSSLEngine();
+ engine.setEnabledCipherSuites(TestUtils.getCommonCipherSuites());
+ engine.setUseClientMode(client);
+ if (Conscrypt.isConscrypt(engine)) {
+ Conscrypt.setBufferAllocator(engine, bufferType.allocator);
+ }
+ return engine;
+ }
+
+ private void exchangeMessage(ByteBuffer inputBuffer, SSLEngine src, SSLEngine dest)
+ throws IOException {
+ byte[] messageBytes = toArray(inputBuffer);
+
+ // Encrypt the input message.
+ List<ByteBuffer> encryptedBufferList = wrap(inputBuffer, src);
+
+ // Unwrap the all of the encrypted messages.
+ ByteBuffer[] encryptedBuffers =
+ encryptedBufferList.toArray(new ByteBuffer[encryptedBufferList.size()]);
+ byte[] actualBytes = unwrap(encryptedBuffers, dest);
+ assertArrayEquals(messageBytes, actualBytes);
+ }
+
+ private List<ByteBuffer> wrap(ByteBuffer input, SSLEngine engine) throws SSLException {
+ // Encrypt the input message.
+ List<ByteBuffer> wrapped = new ArrayList<ByteBuffer>();
+ while (input.hasRemaining()) {
+ ByteBuffer encryptedBuffer =
+ bufferType.newBuffer(engine.getSession().getPacketBufferSize());
+ SSLEngineResult wrapResult = engine.wrap(input, encryptedBuffer);
+ assertEquals(SSLEngineResult.Status.OK, wrapResult.getStatus());
+ encryptedBuffer.flip();
+ wrapped.add(encryptedBuffer);
+ }
+ return wrapped;
+ }
+
+ private byte[] unwrap(ByteBuffer[] encryptedBuffers, SSLEngine engine) throws IOException {
+ ByteArrayOutputStream cleartextStream = new ByteArrayOutputStream();
+ int decryptedBufferSize = 8192;
+ final ByteBuffer encryptedBuffer = combine(encryptedBuffers);
+ final ByteBuffer decryptedBuffer = bufferType.newBuffer(decryptedBufferSize);
+ while (encryptedBuffer.hasRemaining()) {
+ if (!decryptedBuffer.hasRemaining()) {
+ decryptedBuffer.clear();
+ }
+ int prevPos = decryptedBuffer.position();
+ SSLEngineResult unwrapResult = engine.unwrap(encryptedBuffer, decryptedBuffer);
+ SSLEngineResult.Status status = unwrapResult.getStatus();
+ switch (status) {
+ case BUFFER_OVERFLOW:
+ case OK: {
+ break;
+ }
+ default: {
+ throw new RuntimeException("Unexpected SSLEngine status: " + status);
+ }
+ }
+ int newPos = decryptedBuffer.position();
+ int bytesProduced = unwrapResult.bytesProduced();
+ assertEquals(bytesProduced, newPos - prevPos);
+
+ // Add any generated bytes to the output stream.
+ if (bytesProduced > 0 || status == Status.BUFFER_OVERFLOW) {
+ byte[] decryptedBytes = new byte[unwrapResult.bytesProduced()];
+
+ // Read the chunk that was just written to the output array.
+ int limit = decryptedBuffer.limit();
+ decryptedBuffer.limit(newPos);
+ decryptedBuffer.position(prevPos);
+ decryptedBuffer.get(decryptedBytes);
+
+ // Restore the position and limit.
+ decryptedBuffer.limit(limit);
+
+ // Write the decrypted bytes to the stream.
+ cleartextStream.write(decryptedBytes);
+ }
+ }
+
+ return cleartextStream.toByteArray();
+ }
+
+ private ByteBuffer combine(ByteBuffer[] buffers) {
+ int size = 0;
+ for (ByteBuffer buffer : buffers) {
+ size += buffer.remaining();
+ }
+ ByteBuffer combined = bufferType.newBuffer(size);
+ for (ByteBuffer buffer : buffers) {
+ combined.put(buffer);
+ }
+ combined.flip();
+ return combined;
+ }
+
+ private ByteBuffer newMessage(int size) {
+ ByteBuffer buffer = bufferType.newBuffer(size);
+ buffer.put(newTextMessage(size));
+ buffer.flip();
+ return buffer;
+ }
+
+ private static byte[] toArray(ByteBuffer buffer) {
+ int pos = buffer.position();
+ byte[] bytes = new byte[buffer.remaining()];
+ buffer.get(bytes);
+ buffer.position(pos);
+ return bytes;
+ }
+
+ private static SSLContext newContext(Provider provider, TestKeyStore keyStore) {
+ try {
+ SSLContext ctx = SSLContext.getInstance(highestCommonProtocol(), provider);
+ return initSslContext(ctx, keyStore);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptOpenJdkSuite.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptOpenJdkSuite.java
new file mode 100644
index 0000000..42d9663
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptOpenJdkSuite.java
@@ -0,0 +1,39 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.TestUtils.installConscryptAsDefaultProvider;
+
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+ AddressUtilsTest.class,
+ ApplicationProtocolSelectorAdapterTest.class,
+ ClientSessionContextTest.class,
+ ConscryptSocketTest.class,
+ ConscryptTest.class,
+ DuckTypedPSKKeyManagerTest.class,
+ FileClientSessionCacheTest.class,
+ NativeCryptoTest.class,
+ NativeRefTest.class,
+ NativeSslSessionTest.class,
+ OpenSSLKeyTest.class,
+ OpenSSLX509CertificateTest.class,
+ PlatformTest.class,
+ ServerSessionContextTest.class,
+ SSLUtilsTest.class,
+ TestSessionBuilderTest.class,
+})
+public class ConscryptOpenJdkSuite {
+
+ @BeforeClass
+ public static void setupStatic() {
+ installConscryptAsDefaultProvider();
+ }
+
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptSocketTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptSocketTest.java
new file mode 100644
index 0000000..2d169ab
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptSocketTest.java
@@ -0,0 +1,737 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.TestUtils.openTestFile;
+import static com.android.org.conscrypt.TestUtils.readTestFile;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Random;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import javax.net.ssl.HandshakeCompletedEvent;
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mockito;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(Parameterized.class)
+public class ConscryptSocketTest {
+ private static final long TIMEOUT_SECONDS = 5;
+ private static final char[] EMPTY_PASSWORD = new char[0];
+
+ /**
+ * Factories for underlying sockets.
+ * @hide This class is not part of the Android public SDK API
+ */
+ public enum UnderlyingSocketType {
+ NONE {
+ @Override
+ Socket newClientSocket(
+ OpenSSLContextImpl context, ServerSocket server, SSLSocketFactory factory) {
+ return null;
+ }
+ },
+ PLAIN {
+ @Override
+ Socket newClientSocket(OpenSSLContextImpl context, ServerSocket server,
+ SSLSocketFactory factory) throws IOException {
+ return new Socket(server.getInetAddress(), server.getLocalPort());
+ }
+ },
+ CHANNEL {
+ @Override
+ Socket newClientSocket(OpenSSLContextImpl context, ServerSocket server,
+ SSLSocketFactory factory) throws IOException {
+ SocketChannel channel = SocketChannel.open();
+ channel.connect(server.getLocalSocketAddress());
+ return channel.socket();
+ }
+ },
+ SSL {
+ @Override
+ Socket newClientSocket(OpenSSLContextImpl context, ServerSocket server,
+ SSLSocketFactory factory) throws IOException {
+ SSLSocket sslSocket = (SSLSocket) factory.createSocket(
+ server.getInetAddress(), server.getLocalPort());
+ sslSocket.setUseClientMode(true);
+ return sslSocket;
+ }
+
+ @Override
+ Socket newServerSocket(OpenSSLContextImpl context, ServerSocket server,
+ SSLSocketFactory factory) throws IOException {
+ SSLSocket sslSocket =
+ (SSLSocket) factory.createSocket(server.accept(), null, -1, true);
+ sslSocket.setUseClientMode(false);
+ return sslSocket;
+ }
+ };
+
+ abstract Socket newClientSocket(OpenSSLContextImpl context, ServerSocket server,
+ SSLSocketFactory factory) throws IOException;
+
+ Socket newServerSocket(OpenSSLContextImpl context, ServerSocket server,
+ SSLSocketFactory factory) throws IOException {
+ return server.accept();
+ }
+ }
+
+ /**
+ * Various factories for SSL server sockets.
+ * @hide This class is not part of the Android public SDK API
+ */
+ public enum SocketType {
+ FILE_DESCRIPTOR(false) {
+ @Override
+ void assertSocketType(Socket socket) {
+ assertTrue("Unexpected socket type: " + socket.getClass().getName(),
+ socket instanceof ConscryptFileDescriptorSocket);
+ }
+ },
+ ENGINE(true) {
+ @Override
+ void assertSocketType(Socket socket) {
+ assertTrue("Unexpected socket type: " + socket.getClass().getName(),
+ socket instanceof ConscryptEngineSocket);
+ }
+ };
+
+ private final boolean useEngineSocket;
+
+ SocketType(boolean useEngineSocket) {
+ this.useEngineSocket = useEngineSocket;
+ }
+
+ AbstractConscryptSocket newClientSocket(OpenSSLContextImpl context, ServerSocket server,
+ UnderlyingSocketType underlyingSocketType) throws IOException {
+ SSLSocketFactory factory = socketFactory(context);
+ Socket underlying = underlyingSocketType.newClientSocket(context, server, factory);
+ if (underlying != null) {
+ return newClientSocket(context, server, underlying);
+ }
+ return init(factory.createSocket(server.getInetAddress(), server.getLocalPort()), true);
+ }
+
+ AbstractConscryptSocket newClientSocket(OpenSSLContextImpl context, ServerSocket server,
+ Socket underlying) throws IOException {
+ SSLSocketFactory factory = socketFactory(context);
+ return init(factory.createSocket(underlying, server.getInetAddress().getHostName(),
+ server.getLocalPort(), true),
+ true);
+ }
+
+ AbstractConscryptSocket newServerSocket(OpenSSLContextImpl context, ServerSocket server,
+ UnderlyingSocketType underlyingSocketType) throws IOException {
+ SSLSocketFactory factory = socketFactory(context);
+ Socket underlying = underlyingSocketType.newServerSocket(context, server, factory);
+ return init(socketFactory(context).createSocket(underlying, null, -1, true), false);
+ }
+
+ abstract void assertSocketType(Socket socket);
+
+ private SSLSocketFactory socketFactory(OpenSSLContextImpl context) {
+ SSLSocketFactory factory = context.engineGetSocketFactory();
+ Conscrypt.setUseEngineSocket(factory, useEngineSocket);
+ return factory;
+ }
+
+ private AbstractConscryptSocket init(Socket socket, boolean useClientMode) {
+ assertSocketType(socket);
+ AbstractConscryptSocket sslSocket = (AbstractConscryptSocket) socket;
+ sslSocket.setUseClientMode(useClientMode);
+ return sslSocket;
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public enum ServerSocketType {
+ PLAIN {
+ @Override
+ public ServerSocket newServerSocket() throws IOException {
+ return new ServerSocket(0, 50, TestUtils.getLoopbackAddress());
+ }
+ },
+ CHANNEL {
+ @Override
+ public ServerSocket newServerSocket() throws IOException {
+ ServerSocketChannel channel = ServerSocketChannel.open();
+ InetAddress localAddress = TestUtils.getLoopbackAddress();
+ channel.socket().bind(new InetSocketAddress(localAddress.getHostName(), 0), 50);
+ return channel.socket();
+ }
+ };
+ public abstract ServerSocket newServerSocket() throws IOException;
+ }
+
+ @Parameters(name = "{0} wrapping {1} connecting to {2}")
+ public static Object[][] data() {
+ return new Object[][] {
+ {SocketType.FILE_DESCRIPTOR, UnderlyingSocketType.NONE, ServerSocketType.PLAIN},
+ {SocketType.FILE_DESCRIPTOR, UnderlyingSocketType.NONE, ServerSocketType.CHANNEL},
+ {SocketType.FILE_DESCRIPTOR, UnderlyingSocketType.PLAIN, ServerSocketType.PLAIN},
+ {SocketType.FILE_DESCRIPTOR, UnderlyingSocketType.PLAIN, ServerSocketType.CHANNEL},
+ {SocketType.FILE_DESCRIPTOR, UnderlyingSocketType.CHANNEL, ServerSocketType.PLAIN},
+ {SocketType.FILE_DESCRIPTOR, UnderlyingSocketType.CHANNEL,
+ ServerSocketType.CHANNEL},
+ // Not supported: {SocketType.FILE_DESCRIPTOR, UnderlyingSocketType.SSL},
+ {SocketType.ENGINE, UnderlyingSocketType.NONE, ServerSocketType.PLAIN},
+ {SocketType.ENGINE, UnderlyingSocketType.NONE, ServerSocketType.CHANNEL},
+ {SocketType.ENGINE, UnderlyingSocketType.PLAIN, ServerSocketType.PLAIN},
+ {SocketType.ENGINE, UnderlyingSocketType.PLAIN, ServerSocketType.CHANNEL},
+ {SocketType.ENGINE, UnderlyingSocketType.CHANNEL, ServerSocketType.PLAIN},
+ {SocketType.ENGINE, UnderlyingSocketType.CHANNEL, ServerSocketType.CHANNEL},
+ {SocketType.ENGINE, UnderlyingSocketType.SSL, ServerSocketType.PLAIN},
+ {SocketType.ENGINE, UnderlyingSocketType.SSL, ServerSocketType.CHANNEL}};
+ }
+
+ @Parameter
+ public SocketType socketType;
+
+ @Parameter(1)
+ public UnderlyingSocketType underlyingSocketType;
+
+ @Parameter(2) public ServerSocketType serverSocketType;
+
+ private X509Certificate ca;
+ private X509Certificate cert;
+ private X509Certificate certEmbedded;
+ private PrivateKey certKey;
+
+ private Field contextSSLParameters;
+ private ExecutorService executor;
+ private final Random random = new Random(System.currentTimeMillis());
+
+ @Before
+ public void setUp() throws Exception {
+ contextSSLParameters = OpenSSLContextImpl.class.getDeclaredField("sslParameters");
+ contextSSLParameters.setAccessible(true);
+
+ ca = OpenSSLX509Certificate.fromX509PemInputStream(openTestFile("ca-cert.pem"));
+ cert = OpenSSLX509Certificate.fromX509PemInputStream(openTestFile("cert.pem"));
+ certEmbedded =
+ OpenSSLX509Certificate.fromX509PemInputStream(openTestFile("cert-ct-embedded.pem"));
+ certKey = OpenSSLKey.fromPrivateKeyPemInputStream(openTestFile("cert-key.pem"))
+ .getPrivateKey();
+ executor = Executors.newCachedThreadPool();
+ }
+
+ @After
+ public void teardown() throws Exception {
+ executor.shutdown();
+ executor.awaitTermination(5, TimeUnit.SECONDS);
+ }
+
+ abstract class Hooks implements HandshakeCompletedListener {
+ KeyManager[] keyManagers;
+ TrustManager[] trustManagers;
+ String[] alpnProtocols;
+
+ abstract AbstractConscryptSocket createSocket(ServerSocket listener) throws IOException;
+
+ OpenSSLContextImpl createContext() throws IOException {
+ OpenSSLContextImpl context = OpenSSLContextImpl.getPreferred();
+ try {
+ context.engineInit(keyManagers, trustManagers, null);
+ } catch (KeyManagementException e) {
+ throw new IOException(e);
+ }
+ return context;
+ }
+
+ boolean isHandshakeCompleted = false;
+ @Override
+ public void handshakeCompleted(HandshakeCompletedEvent event) {
+ isHandshakeCompleted = true;
+ }
+
+ SSLParametersImpl getContextSSLParameters(OpenSSLContextImpl context)
+ throws IllegalAccessException {
+ return (SSLParametersImpl) contextSSLParameters.get(context);
+ }
+ }
+
+ class ClientHooks extends Hooks {
+ String hostname = "example.com";
+
+ @Override
+ public OpenSSLContextImpl createContext() throws IOException {
+ OpenSSLContextImpl context = super.createContext();
+ try {
+ SSLParametersImpl sslParameters = getContextSSLParameters(context);
+ sslParameters.setCTVerificationEnabled(true);
+ } catch (IllegalAccessException e) {
+ throw new IOException(e);
+ }
+ return context;
+ }
+
+ @Override
+ AbstractConscryptSocket createSocket(ServerSocket listener) throws IOException {
+ AbstractConscryptSocket socket =
+ socketType.newClientSocket(createContext(), listener, underlyingSocketType);
+ socket.setHostname(hostname);
+ // getApplicationProtocol should initially return null and not trigger handshake:
+ // b/146235331
+ assertNull(Conscrypt.getApplicationProtocol(socket));
+ if (alpnProtocols != null) {
+ Conscrypt.setApplicationProtocols(socket, alpnProtocols);
+ }
+ return socket;
+ }
+ }
+
+ class ServerHooks extends Hooks {
+ byte[] sctTLSExtension;
+ byte[] ocspResponse;
+ ApplicationProtocolSelector alpnProtocolSelector;
+
+ @Override
+ public OpenSSLContextImpl createContext() throws IOException {
+ OpenSSLContextImpl context = super.createContext();
+ try {
+ SSLParametersImpl sslParameters = getContextSSLParameters(context);
+ sslParameters.setSCTExtension(sctTLSExtension);
+ sslParameters.setOCSPResponse(ocspResponse);
+ return context;
+ } catch (IllegalAccessException e) {
+ throw new IOException(e);
+ }
+ }
+
+ @Override
+ AbstractConscryptSocket createSocket(ServerSocket listener) throws IOException {
+ AbstractConscryptSocket socket =
+ socketType.newServerSocket(createContext(), listener, underlyingSocketType);
+ if (alpnProtocols != null) {
+ Conscrypt.setApplicationProtocols(socket, alpnProtocols);
+ }
+ if (alpnProtocolSelector != null) {
+ Conscrypt.setApplicationProtocolSelector(socket, alpnProtocolSelector);
+ }
+ return socket;
+ }
+ }
+
+ class TestConnection {
+ ServerHooks serverHooks;
+ ClientHooks clientHooks;
+
+ AbstractConscryptSocket client;
+ AbstractConscryptSocket server;
+
+ Exception clientException;
+ Exception serverException;
+
+ TestConnection(X509Certificate[] chain, PrivateKey key) throws Exception {
+ clientHooks = new ClientHooks();
+ serverHooks = new ServerHooks();
+ setCertificates(chain, key);
+ }
+
+ private void setCertificates(X509Certificate[] chain, PrivateKey key) throws Exception {
+ KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ ks.load(null, null);
+ ks.setKeyEntry("default", key, EMPTY_PASSWORD, chain);
+ ks.setCertificateEntry("CA", chain[chain.length - 1]);
+
+ TrustManagerFactory tmf =
+ TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init(ks);
+ TrustManager[] tms = tmf.getTrustManagers();
+
+ KeyManagerFactory kmf =
+ KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(ks, EMPTY_PASSWORD);
+ KeyManager[] kms = kmf.getKeyManagers();
+
+ clientHooks.trustManagers = tms;
+ serverHooks.keyManagers = kms;
+ serverHooks.trustManagers = tms;
+ }
+
+ private <T> T getOrThrowCause(Future<T> future, long timeout, TimeUnit timeUnit)
+ throws Exception {
+ try {
+ return future.get(timeout, timeUnit);
+ } catch (ExecutionException e) {
+ if (e.getCause() instanceof Exception) {
+ throw(Exception) e.getCause();
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ void doHandshakeSuccess() throws Exception {
+ doHandshake();
+ if (clientException != null) {
+ throw clientException;
+ }
+ if (serverException != null) {
+ throw serverException;
+ }
+ }
+
+ void doHandshake() throws Exception {
+ ServerSocket listener = serverSocketType.newServerSocket();
+ Future<AbstractConscryptSocket> clientFuture = handshake(listener, clientHooks);
+ Future<AbstractConscryptSocket> serverFuture = handshake(listener, serverHooks);
+
+ try {
+ client = getOrThrowCause(clientFuture, TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ } catch (Exception e) {
+ clientException = e;
+ }
+ try {
+ server = getOrThrowCause(serverFuture, TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ } catch (Exception e) {
+ serverException = e;
+ }
+ }
+
+ Future<AbstractConscryptSocket> handshake(final ServerSocket listener, final Hooks hooks) {
+ return executor.submit(new Callable<AbstractConscryptSocket>() {
+ @Override
+ public AbstractConscryptSocket call() throws Exception {
+ AbstractConscryptSocket socket = hooks.createSocket(listener);
+ socket.addHandshakeCompletedListener(hooks);
+
+ socket.startHandshake();
+
+ return socket;
+ }
+ });
+ }
+ }
+
+ @Test
+ public void test_handshake() throws Exception {
+ TestConnection connection = new TestConnection(new X509Certificate[] {cert, ca}, certKey);
+ connection.doHandshakeSuccess();
+
+ assertTrue(connection.clientHooks.isHandshakeCompleted);
+ assertTrue(connection.serverHooks.isHandshakeCompleted);
+ }
+
+ @Test
+ public void alpnWithProtocolListShouldSucceed() throws Exception {
+ TestConnection c = new TestConnection(new X509Certificate[] {cert, ca}, certKey);
+
+ // Configure ALPN protocols
+ String[] clientAlpnProtocols = new String[]{"http/1.1", "foo", "spdy/2"};
+ String[] serverAlpnProtocols = new String[]{"spdy/2", "foo", "bar"};
+
+ c.clientHooks.alpnProtocols = clientAlpnProtocols;
+ c.serverHooks.alpnProtocols = serverAlpnProtocols;
+
+ c.doHandshakeSuccess();
+
+ assertEquals("spdy/2", Conscrypt.getApplicationProtocol(c.client));
+ assertEquals("spdy/2", Conscrypt.getApplicationProtocol(c.server));
+ }
+
+ @Test
+ public void alpnWithProtocolListShouldFail() throws Exception {
+ TestConnection c = new TestConnection(new X509Certificate[] {cert, ca}, certKey);
+
+ // Configure ALPN protocols
+ String[] clientAlpnProtocols = new String[]{"http/1.1", "foo", "spdy/2"};
+ String[] serverAlpnProtocols = new String[]{"h2", "bar", "baz"};
+
+ c.clientHooks.alpnProtocols = clientAlpnProtocols;
+ c.serverHooks.alpnProtocols = serverAlpnProtocols;
+
+ c.doHandshake();
+
+ assertNull(Conscrypt.getApplicationProtocol(c.client));
+ assertNull(Conscrypt.getApplicationProtocol(c.server));
+ }
+
+ @Test
+ public void alpnWithServerProtocolSelectorShouldSucceed() throws Exception {
+ TestConnection c = new TestConnection(new X509Certificate[] {cert, ca}, certKey);
+
+ // Configure client ALPN protocols
+ String[] clientAlpnProtocols = new String[]{"http/1.1", "foo", "spdy/2"};
+ c.clientHooks.alpnProtocols = clientAlpnProtocols;
+
+ // Configure server selector
+ ApplicationProtocolSelector selector = Mockito.mock(ApplicationProtocolSelector.class);
+ when(selector.selectApplicationProtocol(
+ any(SSLSocket.class), ArgumentMatchers.<String>anyList()))
+ .thenReturn("spdy/2");
+ c.serverHooks.alpnProtocolSelector = selector;
+
+ c.doHandshakeSuccess();
+
+ assertEquals("spdy/2", Conscrypt.getApplicationProtocol(c.client));
+ assertEquals("spdy/2", Conscrypt.getApplicationProtocol(c.server));
+ }
+
+ @Test
+ public void alpnWithServerProtocolSelectorShouldFail() throws Exception {
+ TestConnection c = new TestConnection(new X509Certificate[] {cert, ca}, certKey);
+
+ // Configure client ALPN protocols
+ String[] clientAlpnProtocols = new String[]{"http/1.1", "foo", "spdy/2"};
+ c.clientHooks.alpnProtocols = clientAlpnProtocols;
+
+ // Configure server selector
+ ApplicationProtocolSelector selector = Mockito.mock(ApplicationProtocolSelector.class);
+ when(selector.selectApplicationProtocol(
+ any(SSLSocket.class), ArgumentMatchers.<String>anyList()))
+ .thenReturn("h2");
+ c.serverHooks.alpnProtocolSelector = selector;
+
+ c.doHandshake();
+
+ assertNull(Conscrypt.getApplicationProtocol(c.client));
+ assertNull(Conscrypt.getApplicationProtocol(c.server));
+ }
+
+ @Test
+ public void test_handshakeWithEmbeddedSCT() throws Exception {
+ TestConnection connection =
+ new TestConnection(new X509Certificate[] {certEmbedded, ca}, certKey);
+
+ connection.doHandshakeSuccess();
+
+ assertTrue(connection.clientHooks.isHandshakeCompleted);
+ assertTrue(connection.serverHooks.isHandshakeCompleted);
+ }
+
+ @Test
+ public void test_handshakeWithSCTFromOCSPResponse() throws Exception {
+ TestConnection connection = new TestConnection(new X509Certificate[] {cert, ca}, certKey);
+
+ connection.serverHooks.ocspResponse = readTestFile("ocsp-response.der");
+
+ connection.doHandshakeSuccess();
+
+ assertTrue(connection.clientHooks.isHandshakeCompleted);
+ assertTrue(connection.serverHooks.isHandshakeCompleted);
+ }
+
+ @Test
+ public void test_handshakeWithSCTFromTLSExtension() throws Exception {
+ TestConnection connection = new TestConnection(new X509Certificate[] {cert, ca}, certKey);
+
+ connection.serverHooks.sctTLSExtension = readTestFile("ct-signed-timestamp-list");
+
+ connection.doHandshakeSuccess();
+
+ assertTrue(connection.clientHooks.isHandshakeCompleted);
+ assertTrue(connection.serverHooks.isHandshakeCompleted);
+ }
+
+ @Ignore("TODO(nathanmittler): Fix or remove")
+ @Test
+ public void test_handshake_failsWithMissingSCT() throws Exception {
+ TestConnection connection = new TestConnection(new X509Certificate[] {cert, ca}, certKey);
+
+ connection.doHandshake();
+ assertThat(connection.clientException, instanceOf(SSLHandshakeException.class));
+ assertThat(connection.clientException.getCause(), instanceOf(CertificateException.class));
+ }
+
+ @Ignore("TODO(nathanmittler): Fix or remove")
+ @Test
+ public void test_handshake_failsWithInvalidSCT() throws Exception {
+ TestConnection connection = new TestConnection(new X509Certificate[] {cert, ca}, certKey);
+
+ connection.serverHooks.sctTLSExtension = readTestFile("ct-signed-timestamp-list-invalid");
+
+ connection.doHandshake();
+ assertThat(connection.clientException, instanceOf(SSLHandshakeException.class));
+ assertThat(connection.clientException.getCause(), instanceOf(CertificateException.class));
+ }
+
+ @Test
+ @SuppressWarnings("deprecation")
+ public void setAlpnProtocolWithNullShouldSucceed() throws Exception {
+ ServerSocket listening = serverSocketType.newServerSocket();
+ OpenSSLSocketImpl clientSocket = null;
+ try {
+ Socket underlying = new Socket(listening.getInetAddress(), listening.getLocalPort());
+ clientSocket = (OpenSSLSocketImpl) socketType.newClientSocket(
+ new ClientHooks().createContext(), listening, underlying);
+
+ // Both versions should succeed.
+ clientSocket.setAlpnProtocols((byte[]) null);
+ clientSocket.setAlpnProtocols((String[]) null);
+ } finally {
+ if (clientSocket != null) {
+ clientSocket.close();
+ }
+ listening.close();
+ }
+ }
+
+ // http://b/27250522
+ @Test
+ public void test_setSoTimeout_doesNotCreateSocketImpl() throws Exception {
+ ServerSocket listening = serverSocketType.newServerSocket();
+ try {
+ Socket underlying = new Socket(listening.getInetAddress(), listening.getLocalPort());
+ Socket socket = socketType.newClientSocket(
+ new ClientHooks().createContext(), listening, underlying);
+ socketType.assertSocketType(socket);
+ socket.setSoTimeout(1000);
+ socket.close();
+
+ Field f = Socket.class.getDeclaredField("created");
+ f.setAccessible(true);
+ assertFalse(f.getBoolean(socket));
+ } finally {
+ listening.close();
+ }
+ }
+
+ @Test
+ public void test_setEnabledProtocols_FiltersSSLv3_HandshakeException() throws Exception {
+ TestConnection connection = new TestConnection(new X509Certificate[] {cert, ca}, certKey);
+
+ connection.clientHooks = new ClientHooks() {
+ @Override
+ public AbstractConscryptSocket createSocket(ServerSocket listener) throws IOException {
+ AbstractConscryptSocket socket = super.createSocket(listener);
+ socket.setEnabledProtocols(new String[] {"SSLv3"});
+ assertEquals(
+ "SSLv3 should be filtered out", 0, socket.getEnabledProtocols().length);
+ return socket;
+ }
+ };
+
+ connection.doHandshake();
+ assertThat(connection.clientException, instanceOf(SSLHandshakeException.class));
+ assertTrue(
+ connection.clientException.getMessage().contains("SSLv3 is no longer supported"));
+ assertThat(connection.serverException, instanceOf(SSLHandshakeException.class));
+
+ assertFalse(connection.clientHooks.isHandshakeCompleted);
+ assertFalse(connection.serverHooks.isHandshakeCompleted);
+ }
+
+ @Test
+ public void savedSessionWorksAfterClose() throws Exception {
+ String alpnProtocol = "spdy/2";
+ String[] alpnProtocols = new String[] {alpnProtocol};
+ TestConnection connection = new TestConnection(new X509Certificate[] {cert, ca}, certKey);
+ connection.clientHooks.alpnProtocols = alpnProtocols;
+ connection.serverHooks.alpnProtocols = alpnProtocols;
+ connection.doHandshakeSuccess();
+
+ SSLSession session = connection.client.getSession();
+ String cipherSuite = session.getCipherSuite();
+ String protocol = session.getProtocol();
+ assertEquals(alpnProtocol, Conscrypt.getApplicationProtocol(connection.client));
+
+ connection.client.close();
+
+ assertEquals(cipherSuite, session.getCipherSuite());
+ assertEquals(protocol, session.getProtocol());
+ assertEquals(alpnProtocol, Conscrypt.getApplicationProtocol(connection.client));
+ }
+
+ @Test
+ public void dataFlows() throws Exception {
+ final TestConnection connection =
+ new TestConnection(new X509Certificate[] {cert, ca}, certKey);
+ connection.doHandshakeSuccess();
+
+ // Basic data flow assurance. Send random buffers in each direction, each less than 16K
+ // so should fit in a single TLS packet. 50% chance of sending in each direction on
+ // each iteration to randomize the flow.
+ for (int i = 0; i < 50; i++) {
+ if (random.nextBoolean()) {
+ sendData(connection.client, connection.server, randomBuffer());
+ }
+ if (random.nextBoolean()) {
+ sendData(connection.server, connection.client, randomBuffer());
+ }
+ }
+ }
+
+ private void sendData(SSLSocket source, final SSLSocket destination, byte[] data)
+ throws Exception {
+ final byte[] received = new byte[data.length];
+
+ Future<Integer> readFuture = executor.submit(new Callable<Integer>() {
+ @Override
+ public Integer call() throws Exception {
+ return destination.getInputStream().read(received);
+ }
+ });
+
+ source.getOutputStream().write(data);
+ assertEquals(data.length, (int) readFuture.get());
+ assertArrayEquals(data, received);
+ }
+
+ private byte[] randomBuffer() {
+ byte[] buffer = new byte[random.nextInt(16 * 1024)];
+ random.nextBytes(buffer);
+ return buffer;
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptTest.java
new file mode 100644
index 0000000..59cd9d9
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptTest.java
@@ -0,0 +1,111 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.org.conscrypt.java.security.StandardNames;
+import java.security.Provider;
+import java.security.Security;
+import javax.net.ssl.SSLContext;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class ConscryptTest {
+
+ /**
+ * This confirms that the version machinery is working.
+ */
+ @Test
+ public void testVersionIsSensible() {
+ Conscrypt.Version version = Conscrypt.version();
+ assertNotNull(version);
+ // The version object should be a singleton
+ assertSame(version, Conscrypt.version());
+
+ assertTrue("Major version: " + version.major(), 1 <= version.major());
+ assertTrue("Minor version: " + version.minor(), 0 <= version.minor());
+ assertTrue("Patch version: " + version.patch(), 0 <= version.patch());
+ }
+
+ @Test
+ public void buildTls12WithTrustManager() throws Exception {
+ buildProvider("TLSv1.2", true);
+ }
+ @Test
+ public void buildTls12WithoutTrustManager() throws Exception {
+ buildProvider("TLSv1.2", false);
+ }
+
+ @Test
+ public void buildTls13WithTrustManager() throws Exception {
+ buildProvider("TLSv1.3", true);
+ }
+
+ @Test
+ public void buildTls13WithoutTrustManager() throws Exception {
+ buildProvider("TLSv1.3", false);
+ }
+
+ @Test
+ public void buildInvalid() {
+ try {
+ Conscrypt.newProviderBuilder().defaultTlsProtocol("invalid").build();
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected.
+ }
+ }
+
+ private void buildProvider(String defaultProtocol, boolean withTrustManager) throws Exception {
+ Provider provider = Conscrypt.newProviderBuilder()
+ .setName("test name")
+ .provideTrustManager(withTrustManager)
+ .defaultTlsProtocol(defaultProtocol)
+ .build();
+
+ assertEquals("test name", provider.getName());
+ assertEquals(withTrustManager, provider.containsKey("TrustManagerFactory.PKIX"));
+
+ try {
+ Security.insertProviderAt(provider, 1);
+
+ SSLContext context = SSLContext.getInstance("TLS");
+ context.init(null, null, null);
+ assertEquals(provider, context.getProvider());
+ StandardNames.assertSSLContextEnabledProtocols(
+ defaultProtocol, context.createSSLEngine().getEnabledProtocols());
+
+ context = SSLContext.getInstance("Default");
+ assertEquals(provider, context.getProvider());
+ StandardNames.assertSSLContextEnabledProtocols(
+ defaultProtocol, context.createSSLEngine().getEnabledProtocols());
+ } finally {
+ Security.removeProvider("test name");
+ }
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/DuckTypedPSKKeyManagerTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/DuckTypedPSKKeyManagerTest.java
new file mode 100644
index 0000000..8d03c21
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/DuckTypedPSKKeyManagerTest.java
@@ -0,0 +1,321 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2014 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.Socket;
+import java.security.Key;
+import java.util.Arrays;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import junit.framework.TestCase;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DuckTypedPSKKeyManagerTest extends TestCase {
+ private SSLSocket mSSLSocket;
+ private SSLEngine mSSLEngine;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ SSLContext sslContext = SSLContext.getDefault();
+ SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+ mSSLSocket = (SSLSocket) sslSocketFactory.createSocket();
+ mSSLEngine = sslContext.createSSLEngine();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ if (mSSLSocket != null) {
+ try {
+ mSSLSocket.close();
+ } catch (Exception ignored) {}
+ }
+ } finally {
+ super.tearDown();
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testDuckTypingFailsWhenOneMethodMissing() throws Exception {
+ try {
+ DuckTypedPSKKeyManager.getInstance(new AlmostPSKKeyManager());
+ fail();
+ } catch (NoSuchMethodException expected) {}
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testDuckTypingFailsWhenOneMethodReturnTypeIncompatible() throws Exception {
+ try {
+ assertNotNull(DuckTypedPSKKeyManager.getInstance(
+ new KeyManagerOfferingAllPSKKeyManagerMethodsWithIncompatibleReturnTypes()));
+ fail();
+ } catch (NoSuchMethodException expected) {}
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testDuckTypingSucceedsWhenAllMethodsPresentWithExactReturnTypes() throws Exception {
+ assertNotNull(DuckTypedPSKKeyManager.getInstance(
+ new KeyManagerOfferingAllPSKKeyManagerMethodsWithExactReturnTypes()));
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testDuckTypingSucceedsWhenAllMethodsPresentWithDifferentButCompatibleReturnTypes()
+ throws Exception {
+ assertNotNull(DuckTypedPSKKeyManager.getInstance(
+ new KeyManagerOfferingAllPSKKeyManagerMethodsWithCompatibleReturnTypes()));
+ }
+
+ public void testMethodInvocationDelegation() throws Exception {
+ // IMPLEMENTATION NOTE: We create a DuckTypedPSKKeyManager wrapping a Reflection Proxy,
+ // invoke each method of the PSKKeyManager interface on the DuckTypedPSKKeyManager instance,
+ // and assert that invocations on the Proxy are as expected and that values returned by the
+ // Proxy are returned to us.
+
+ MockInvocationHandler mockInvocationHandler = new MockInvocationHandler();
+ @SuppressWarnings("deprecation")
+ PSKKeyManager delegate = (PSKKeyManager) Proxy.newProxyInstance(
+ DuckTypedPSKKeyManager.class.getClassLoader(), new Class<?>[] {PSKKeyManager.class},
+ mockInvocationHandler);
+ @SuppressWarnings("deprecation")
+ PSKKeyManager pskKeyManager = DuckTypedPSKKeyManager.getInstance(delegate);
+ String identityHint = "hint";
+ String identity = "identity";
+
+ mockInvocationHandler.returnValue = identityHint;
+ assertSame(identityHint, pskKeyManager.chooseServerKeyIdentityHint(mSSLSocket));
+ assertEquals("chooseServerKeyIdentityHint",
+ mockInvocationHandler.lastInvokedMethod.getName());
+ assertEquals(Arrays.asList(new Class<?>[] {Socket.class}),
+ Arrays.asList(mockInvocationHandler.lastInvokedMethod.getParameterTypes()));
+ assertEquals(1, mockInvocationHandler.lastInvokedMethodArgs.length);
+ assertSame(mSSLSocket, mockInvocationHandler.lastInvokedMethodArgs[0]);
+
+ mockInvocationHandler.returnValue = identityHint;
+ assertSame(identityHint, pskKeyManager.chooseServerKeyIdentityHint(mSSLEngine));
+ assertEquals("chooseServerKeyIdentityHint",
+ mockInvocationHandler.lastInvokedMethod.getName());
+ assertEquals(Arrays.asList(new Class<?>[] {SSLEngine.class}),
+ Arrays.asList(mockInvocationHandler.lastInvokedMethod.getParameterTypes()));
+ assertEquals(1, mockInvocationHandler.lastInvokedMethodArgs.length);
+ assertSame(mSSLEngine, mockInvocationHandler.lastInvokedMethodArgs[0]);
+
+ mockInvocationHandler.returnValue = identity;
+ assertSame(identity, pskKeyManager.chooseClientKeyIdentity(identityHint, mSSLSocket));
+ assertEquals("chooseClientKeyIdentity", mockInvocationHandler.lastInvokedMethod.getName());
+ assertEquals(Arrays.asList(new Class<?>[] {String.class, Socket.class}),
+ Arrays.asList(mockInvocationHandler.lastInvokedMethod.getParameterTypes()));
+ assertEquals(2, mockInvocationHandler.lastInvokedMethodArgs.length);
+ assertSame(identityHint, mockInvocationHandler.lastInvokedMethodArgs[0]);
+ assertSame(mSSLSocket, mockInvocationHandler.lastInvokedMethodArgs[1]);
+
+ mockInvocationHandler.returnValue = identity;
+ assertSame(identity, pskKeyManager.chooseClientKeyIdentity(identityHint, mSSLEngine));
+ assertEquals("chooseClientKeyIdentity", mockInvocationHandler.lastInvokedMethod.getName());
+ assertEquals(Arrays.asList(new Class<?>[] {String.class, SSLEngine.class}),
+ Arrays.asList(mockInvocationHandler.lastInvokedMethod.getParameterTypes()));
+ assertEquals(2, mockInvocationHandler.lastInvokedMethodArgs.length);
+ assertSame(identityHint, mockInvocationHandler.lastInvokedMethodArgs[0]);
+ assertSame(mSSLEngine, mockInvocationHandler.lastInvokedMethodArgs[1]);
+
+ SecretKey key = new SecretKeySpec("arbitrary".getBytes("UTF-8"), "RAW");
+ mockInvocationHandler.returnValue = key;
+ assertSame(key, pskKeyManager.getKey(identityHint, identity, mSSLSocket));
+ assertEquals("getKey", mockInvocationHandler.lastInvokedMethod.getName());
+ assertEquals(Arrays.asList(new Class<?>[] {String.class, String.class, Socket.class}),
+ Arrays.asList(mockInvocationHandler.lastInvokedMethod.getParameterTypes()));
+ assertEquals(3, mockInvocationHandler.lastInvokedMethodArgs.length);
+ assertSame(identityHint, mockInvocationHandler.lastInvokedMethodArgs[0]);
+ assertSame(identity, mockInvocationHandler.lastInvokedMethodArgs[1]);
+ assertSame(mSSLSocket, mockInvocationHandler.lastInvokedMethodArgs[2]);
+
+ mockInvocationHandler.returnValue = key;
+ assertSame(key, pskKeyManager.getKey(identityHint, identity, mSSLEngine));
+ assertEquals("getKey", mockInvocationHandler.lastInvokedMethod.getName());
+ assertEquals(Arrays.asList(new Class<?>[] {String.class, String.class, SSLEngine.class}),
+ Arrays.asList(mockInvocationHandler.lastInvokedMethod.getParameterTypes()));
+ assertEquals(3, mockInvocationHandler.lastInvokedMethodArgs.length);
+ assertSame(identityHint, mockInvocationHandler.lastInvokedMethodArgs[0]);
+ assertSame(identity, mockInvocationHandler.lastInvokedMethodArgs[1]);
+ assertSame(mSSLEngine, mockInvocationHandler.lastInvokedMethodArgs[2]);
+ }
+
+ public void testMethodInvocationDelegationWithDifferentButCompatibleReturnType()
+ throws Exception {
+ // Check that nothing blows up when we invoke getKey which is declared to return
+ // SecretKeySpec rather than SecretKey as declared in the PSKKeyManager interface.
+ @SuppressWarnings("deprecation")
+ PSKKeyManager pskKeyManager = DuckTypedPSKKeyManager.getInstance(
+ new KeyManagerOfferingAllPSKKeyManagerMethodsWithCompatibleReturnTypes());
+ pskKeyManager.getKey(null, "", mSSLSocket);
+ pskKeyManager.getKey(null, "", mSSLEngine);
+ }
+
+ /**
+ * {@link KeyManager} which implements all methods of {@link PSKKeyManager} except for one.
+ */
+ @SuppressWarnings("unused")
+ private static class AlmostPSKKeyManager implements KeyManager {
+ public String chooseServerKeyIdentityHint(Socket socket) {
+ return null;
+ }
+
+ public String chooseServerKeyIdentityHint(SSLEngine engine) {
+ return null;
+ }
+
+ public String chooseClientKeyIdentity(String identityHint, Socket socket) {
+ return null;
+ }
+
+ public String chooseClientKeyIdentity(String identityHint, SSLEngine engine) {
+ return null;
+ }
+
+ public SecretKey getKey(String identityHint, String identity, Socket socket) {
+ return null;
+ }
+
+ // Missing method from the PSKKeyManager interface:
+ // SecretKey getKey(String identityHint, String identity, SSLEngine engine);
+ }
+
+ /**
+ * {@link KeyManager} which exposes all methods of the {@link PSKKeyManager} interface but does
+ * not implement the interface.
+ */
+ @SuppressWarnings("unused")
+ private static class KeyManagerOfferingAllPSKKeyManagerMethodsWithExactReturnTypes
+ implements KeyManager {
+ public String chooseServerKeyIdentityHint(Socket socket) {
+ return null;
+ }
+
+ public String chooseServerKeyIdentityHint(SSLEngine engine) {
+ return null;
+ }
+
+ public String chooseClientKeyIdentity(String identityHint, Socket socket) {
+ return null;
+ }
+
+ public String chooseClientKeyIdentity(String identityHint, SSLEngine engine) {
+ return null;
+ }
+
+ public SecretKey getKey(String identityHint, String identity, Socket socket) {
+ return null;
+ }
+
+ public SecretKey getKey(String identityHint, String identity, SSLEngine engine) {
+ return null;
+ }
+ }
+
+ /**
+ * {@link KeyManager} which exposes all methods of the {@link PSKKeyManager} interface but does
+ * not implement the interface. Additionally, the return types of some methods are different
+ * but compatible with the {@code PSKKeyManager} interface.
+ */
+ @SuppressWarnings("unused")
+ private static class KeyManagerOfferingAllPSKKeyManagerMethodsWithCompatibleReturnTypes
+ implements KeyManager {
+ public String chooseServerKeyIdentityHint(Socket socket) {
+ return null;
+ }
+
+ public String chooseServerKeyIdentityHint(SSLEngine engine) {
+ return null;
+ }
+
+ public String chooseClientKeyIdentity(String identityHint, Socket socket) {
+ return null;
+ }
+
+ public String chooseClientKeyIdentity(String identityHint, SSLEngine engine) {
+ return null;
+ }
+
+ // PSKKeyManager's return type: SecretKey
+ public SecretKeySpec getKey(String identityHint, String identity, Socket socket) {
+ return null;
+ }
+
+ // PSKKeyManager's return type: SecretKey
+ public SecretKeySpec getKey(String identityHint, String identity, SSLEngine engine) {
+ return null;
+ }
+ }
+
+ /**
+ * {@link KeyManager} which exposes all methods of the {@link PSKKeyManager} interface but does
+ * not implement the interface. Additionally, the return types of some methods are incompatible
+ * with the {@code PSKKeyManager} interface.
+ */
+ @SuppressWarnings("unused")
+ private static class KeyManagerOfferingAllPSKKeyManagerMethodsWithIncompatibleReturnTypes
+ implements KeyManager {
+ public String chooseServerKeyIdentityHint(Socket socket) {
+ return null;
+ }
+
+ public String chooseServerKeyIdentityHint(SSLEngine engine) {
+ return null;
+ }
+
+ public String chooseClientKeyIdentity(String identityHint, Socket socket) {
+ return null;
+ }
+
+ public String chooseClientKeyIdentity(String identityHint, SSLEngine engine) {
+ return null;
+ }
+
+ public SecretKey getKey(String identityHint, String identity, Socket socket) {
+ return null;
+ }
+
+ // PSKKeyManager's return type: SecretKey
+ public Key getKey(String identityHint, String identity, SSLEngine engine) {
+ return null;
+ }
+ }
+
+ static class MockInvocationHandler implements InvocationHandler {
+ Object returnValue;
+ Method lastInvokedMethod;
+ Object[] lastInvokedMethodArgs;
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ lastInvokedMethod = method;
+ lastInvokedMethodArgs = args;
+ return returnValue;
+ }
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/FileClientSessionCacheTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/FileClientSessionCacheTest.java
new file mode 100644
index 0000000..38d2b99
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/FileClientSessionCacheTest.java
@@ -0,0 +1,60 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.File;
+import java.io.IOException;
+import junit.framework.TestCase;
+import com.android.org.conscrypt.javax.net.ssl.FakeSSLSession;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class FileClientSessionCacheTest extends TestCase {
+
+ public void testMaxSize() throws IOException, InterruptedException {
+ String tmpDir = System.getProperty("java.io.tmpdir");
+ if (tmpDir == null) {
+ fail("Please set 'java.io.tmpdir' system property.");
+ }
+ File cacheDir = new File(tmpDir
+ + "/" + FileClientSessionCacheTest.class.getName() + "/cache");
+ final SSLClientSessionCache cache
+ = FileClientSessionCache.usingDirectory(cacheDir);
+ Thread[] threads = new Thread[10];
+ final int iterations = FileClientSessionCache.MAX_SIZE * 10;
+ for (int i = 0; i < threads.length; i++) {
+ final int id = i;
+ threads[i] = new Thread() {
+ @Override
+ public void run() {
+ for (int i = 0; i < iterations; i++) {
+ cache.putSessionData(new FakeSSLSession(id + "" + i), new byte[10]);
+ }
+ }
+ };
+ }
+ for (Thread thread : threads) {
+ thread.start();
+ }
+ for (Thread thread : threads) {
+ thread.join();
+ }
+ assertEquals(FileClientSessionCache.MAX_SIZE, cacheDir.list().length);
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/MockSessionBuilder.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/MockSessionBuilder.java
new file mode 100644
index 0000000..aafc595
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/MockSessionBuilder.java
@@ -0,0 +1,89 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.TestUtils.UTF_8;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import javax.net.ssl.SSLSession;
+
+/**
+ * Utility class for constructing mock sessions.
+ */
+final class MockSessionBuilder {
+ static final String DEFAULT_CIPHER_SUITE = "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256";
+ static final int DEFAULT_PORT = 443;
+
+ private byte[] id;
+ private boolean valid = true;
+ private boolean singleUse = false;
+ private String host;
+ private int port = DEFAULT_PORT;
+ private String cipherSuite = DEFAULT_CIPHER_SUITE;
+ private byte[] encodedBytes = EmptyArray.BYTE;
+
+ MockSessionBuilder id(byte[] id) {
+ this.id = id;
+ return this;
+ }
+
+ MockSessionBuilder host(String host) {
+ this.host = host;
+ return this;
+ }
+
+ MockSessionBuilder port(int port) {
+ this.port = port;
+ return this;
+ }
+
+ MockSessionBuilder valid(boolean valid) {
+ this.valid = valid;
+ return this;
+ }
+
+ MockSessionBuilder cipherSuite(String cipherSuite) {
+ this.cipherSuite = cipherSuite;
+ return this;
+ }
+
+ MockSessionBuilder encodedBytes(byte[] encodedBytes) {
+ this.encodedBytes = encodedBytes;
+ return this;
+ }
+
+ MockSessionBuilder singleUse(boolean singleUse) {
+ this.singleUse = singleUse;
+ return this;
+ }
+
+ NativeSslSession build() {
+ NativeSslSession session = mock(NativeSslSession.class);
+ byte[] id = this.id == null ? host.getBytes(UTF_8) : this.id;
+ when(session.getId()).thenReturn(id);
+ when(session.isValid()).thenReturn(valid);
+ when(session.isSingleUse()).thenReturn(singleUse);
+ when(session.getProtocol()).thenReturn(TestUtils.highestCommonProtocol());
+ when(session.getPeerHost()).thenReturn(host);
+ when(session.getPeerPort()).thenReturn(port);
+ when(session.getCipherSuite()).thenReturn(cipherSuite);
+ when(session.toBytes()).thenReturn(encodedBytes);
+ when(session.toSSLSession()).thenReturn(mock(SSLSession.class));
+ return session;
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/NativeCryptoTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/NativeCryptoTest.java
new file mode 100644
index 0000000..ea274a1
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/NativeCryptoTest.java
@@ -0,0 +1,3181 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.NativeConstants.SSL_MODE_CBC_RECORD_SPLITTING;
+import static com.android.org.conscrypt.NativeConstants.SSL_MODE_ENABLE_FALSE_START;
+import static com.android.org.conscrypt.NativeConstants.SSL_OP_CIPHER_SERVER_PREFERENCE;
+import static com.android.org.conscrypt.NativeConstants.SSL_OP_NO_TICKET;
+import static com.android.org.conscrypt.NativeConstants.SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+import static com.android.org.conscrypt.NativeConstants.SSL_VERIFY_NONE;
+import static com.android.org.conscrypt.NativeConstants.SSL_VERIFY_PEER;
+import static com.android.org.conscrypt.NativeConstants.TLS1_1_VERSION;
+import static com.android.org.conscrypt.NativeConstants.TLS1_2_VERSION;
+import static com.android.org.conscrypt.NativeConstants.TLS1_VERSION;
+import static com.android.org.conscrypt.TestUtils.openTestFile;
+import static com.android.org.conscrypt.TestUtils.readTestFile;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.when;
+
+import com.android.org.conscrypt.NativeCrypto.SSLHandshakeCallbacks;
+import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+import com.android.org.conscrypt.io.IoUtils;
+import com.android.org.conscrypt.java.security.StandardNames;
+import com.android.org.conscrypt.java.security.TestKeyStore;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Method;
+import java.math.BigInteger;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStore.PrivateKeyEntry;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.ECPrivateKeySpec;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLProtocolException;
+import javax.security.auth.x500.X500Principal;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mockito;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class NativeCryptoTest {
+ private static final long NULL = 0;
+ private static final FileDescriptor INVALID_FD = new FileDescriptor();
+ private static final SSLHandshakeCallbacks DUMMY_CB =
+ new TestSSLHandshakeCallbacks(null, 0, null, null);
+
+ private static final long TIMEOUT_SECONDS = 5;
+
+ private static OpenSSLKey SERVER_PRIVATE_KEY;
+ private static OpenSSLX509Certificate[] SERVER_CERTIFICATES_HOLDER;
+ private static long[] SERVER_CERTIFICATE_REFS;
+ private static byte[][] ENCODED_SERVER_CERTIFICATES;
+ private static OpenSSLKey CLIENT_PRIVATE_KEY;
+ private static OpenSSLX509Certificate[] CLIENT_CERTIFICATES_HOLDER;
+ private static long[] CLIENT_CERTIFICATE_REFS;
+ private static byte[][] ENCODED_CLIENT_CERTIFICATES;
+ private static byte[][] CA_PRINCIPALS;
+ private static OpenSSLKey CHANNEL_ID_PRIVATE_KEY;
+ private static byte[] CHANNEL_ID;
+ private static Method m_Platform_getFileDescriptor;
+
+ @BeforeClass
+ public static void getPlatformMethods() throws Exception {
+ Class<?> c_Platform = TestUtils.conscryptClass("Platform");
+ m_Platform_getFileDescriptor =
+ c_Platform.getDeclaredMethod("getFileDescriptor", Socket.class);
+ m_Platform_getFileDescriptor.setAccessible(true);
+ }
+
+ private static OpenSSLKey getServerPrivateKey() {
+ initCerts();
+ return SERVER_PRIVATE_KEY;
+ }
+
+ private static long[] getServerCertificateRefs() {
+ initCerts();
+ return SERVER_CERTIFICATE_REFS;
+ }
+
+ private static byte[][] getEncodedServerCertificates() {
+ initCerts();
+ return ENCODED_SERVER_CERTIFICATES;
+ }
+
+ private static OpenSSLKey getClientPrivateKey() {
+ initCerts();
+ return CLIENT_PRIVATE_KEY;
+ }
+
+ private static long[] getClientCertificateRefs() {
+ initCerts();
+ return CLIENT_CERTIFICATE_REFS;
+ }
+
+ private static byte[][] getEncodedClientCertificates() {
+ initCerts();
+ return ENCODED_CLIENT_CERTIFICATES;
+ }
+
+ private static byte[][] getCaPrincipals() {
+ initCerts();
+ return CA_PRINCIPALS;
+ }
+
+ /**
+ * Lazily create shared test certificates.
+ */
+ @SuppressWarnings("JdkObsolete") // Public API KeyStore.aliases() uses Enumeration
+ private static synchronized void initCerts() {
+ if (SERVER_PRIVATE_KEY != null) {
+ return;
+ }
+
+ try {
+ PrivateKeyEntry serverPrivateKeyEntry =
+ TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
+ SERVER_PRIVATE_KEY = OpenSSLKey.fromPrivateKey(serverPrivateKeyEntry.getPrivateKey());
+ SERVER_CERTIFICATES_HOLDER =
+ encodeCertificateList(serverPrivateKeyEntry.getCertificateChain());
+ SERVER_CERTIFICATE_REFS = getCertificateReferences(SERVER_CERTIFICATES_HOLDER);
+ ENCODED_SERVER_CERTIFICATES = getEncodedCertificates(SERVER_CERTIFICATES_HOLDER);
+
+ PrivateKeyEntry clientPrivateKeyEntry =
+ TestKeyStore.getClientCertificate().getPrivateKey("RSA", "RSA");
+ CLIENT_PRIVATE_KEY = OpenSSLKey.fromPrivateKey(clientPrivateKeyEntry.getPrivateKey());
+ CLIENT_CERTIFICATES_HOLDER =
+ encodeCertificateList(clientPrivateKeyEntry.getCertificateChain());
+ CLIENT_CERTIFICATE_REFS = getCertificateReferences(CLIENT_CERTIFICATES_HOLDER);
+ ENCODED_CLIENT_CERTIFICATES = getEncodedCertificates(CLIENT_CERTIFICATES_HOLDER);
+
+ KeyStore ks = TestKeyStore.getClient().keyStore;
+ String caCertAlias = ks.aliases().nextElement();
+ X509Certificate certificate = (X509Certificate) ks.getCertificate(caCertAlias);
+ X500Principal principal = certificate.getIssuerX500Principal();
+ CA_PRINCIPALS = new byte[][] {principal.getEncoded()};
+ initChannelIdKey();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static long[] getCertificateReferences(OpenSSLX509Certificate[] certs) {
+ final long[] certRefs = new long[certs.length];
+ for (int i = 0; i < certs.length; i++) {
+ certRefs[i] = certs[i].getContext();
+ }
+ return certRefs;
+ }
+
+ private static byte[][] getEncodedCertificates(OpenSSLX509Certificate[] certs) {
+ try {
+ final byte[][] encoded = new byte[certs.length][];
+ for (int i = 0; i < certs.length; i++) {
+ encoded[i] = certs[i].getEncoded();
+ }
+ return encoded;
+ } catch (CertificateEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static OpenSSLX509Certificate[] encodeCertificateList(Certificate[] chain)
+ throws CertificateEncodingException {
+ final OpenSSLX509Certificate[] openSslCerts = new OpenSSLX509Certificate[chain.length];
+ for (int i = 0; i < chain.length; i++) {
+ openSslCerts[i] = OpenSSLX509Certificate.fromCertificate(chain[i]);
+ }
+ return openSslCerts;
+ }
+
+ private static synchronized void initChannelIdKey() throws Exception {
+ if (CHANNEL_ID_PRIVATE_KEY != null) {
+ return;
+ }
+
+ // NIST P-256 aka SECG secp256r1 aka X9.62 prime256v1
+ OpenSSLECGroupContext openSslSpec = OpenSSLECGroupContext.getCurveByName("prime256v1");
+ BigInteger s = new BigInteger(
+ "229cdbbf489aea584828a261a23f9ff8b0f66f7ccac98bf2096ab3aee41497c5", 16);
+ CHANNEL_ID_PRIVATE_KEY =
+ new OpenSSLECPrivateKey(new ECPrivateKeySpec(s, openSslSpec.getECParameterSpec()))
+ .getOpenSSLKey();
+
+ // Channel ID is the concatenation of the X and Y coordinates of the public key.
+ CHANNEL_ID = new BigInteger(
+ "702b07871fd7955c320b26f15e244e47eed60272124c92b9ebecf0b42f90069b"
+ + "ab53592ebfeb4f167dbf3ce61513afb0e354c479b1c1b69874fa471293494f77",
+ 16).toByteArray();
+ }
+
+ private static RSAPrivateCrtKey generateRsaKey() throws Exception {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ kpg.initialize(512);
+
+ KeyPair keyPair = kpg.generateKeyPair();
+ return (RSAPrivateCrtKey) keyPair.getPrivate();
+ }
+
+ private static NativeRef.EVP_PKEY getRsaPkey(RSAPrivateCrtKey privKey) throws Exception {
+ return new NativeRef.EVP_PKEY(NativeCrypto.EVP_PKEY_new_RSA(
+ privKey.getModulus().toByteArray(), privKey.getPublicExponent().toByteArray(),
+ privKey.getPrivateExponent().toByteArray(), privKey.getPrimeP().toByteArray(),
+ privKey.getPrimeQ().toByteArray(), privKey.getPrimeExponentP().toByteArray(),
+ privKey.getPrimeExponentQ().toByteArray(),
+ privKey.getCrtCoefficient().toByteArray()));
+ }
+
+ public static void assertEqualSessions(long expected, long actual) {
+ assertEqualByteArrays(NativeCrypto.SSL_SESSION_session_id(expected),
+ NativeCrypto.SSL_SESSION_session_id(actual));
+ }
+ public static void assertEqualByteArrays(byte[] expected, byte[] actual) {
+ assertEquals(Arrays.toString(expected), Arrays.toString(actual));
+ }
+
+ public static void assertEqualPrincipals(byte[][] expected, byte[][] actual) {
+ assertEqualByteArrays(expected, actual);
+ }
+
+ public static void assertEqualCertificateChains(long[] expected, long[] actual) {
+ assertEquals(expected.length, actual.length);
+ for (int i = 0; i < expected.length; i++) {
+ NativeCrypto.X509_cmp(expected[i], null, actual[i], null);
+ }
+ }
+
+ public static void assertEqualByteArrays(byte[][] expected, byte[][] actual) {
+ assertEquals(Arrays.deepToString(expected), Arrays.deepToString(actual));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void EVP_PKEY_cmp_BothNullParameters() throws Exception {
+ NativeCrypto.EVP_PKEY_cmp(null, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void EVP_PKEY_cmp_withNullShouldThrow() throws Exception {
+ RSAPrivateCrtKey privKey1 = generateRsaKey();
+ NativeRef.EVP_PKEY pkey1 = getRsaPkey(privKey1);
+ assertNotSame(NULL, pkey1);
+ NativeCrypto.EVP_PKEY_cmp(pkey1, null);
+ }
+
+ @Test
+ public void test_EVP_PKEY_cmp() throws Exception {
+ RSAPrivateCrtKey privKey1 = generateRsaKey();
+
+ NativeRef.EVP_PKEY pkey1 = getRsaPkey(privKey1);
+ assertNotSame(NULL, pkey1);
+
+ NativeRef.EVP_PKEY pkey1_copy = getRsaPkey(privKey1);
+ assertNotSame(NULL, pkey1_copy);
+
+ NativeRef.EVP_PKEY pkey2 = getRsaPkey(generateRsaKey());
+ assertNotSame(NULL, pkey2);
+
+ assertEquals("Same keys should be the equal", 1, NativeCrypto.EVP_PKEY_cmp(pkey1, pkey1));
+
+ assertEquals(
+ "Same keys should be the equal", 1, NativeCrypto.EVP_PKEY_cmp(pkey1, pkey1_copy));
+
+ assertEquals(
+ "Different keys should not be equal", 0, NativeCrypto.EVP_PKEY_cmp(pkey1, pkey2));
+ }
+
+ @Test
+ public void test_SSL_CTX_new() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ assertTrue(c != NULL);
+ long c2 = NativeCrypto.SSL_CTX_new();
+ assertTrue(c != c2);
+ NativeCrypto.SSL_CTX_free(c, null);
+ NativeCrypto.SSL_CTX_free(c2, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void test_SSL_CTX_free_NullArgument() throws Exception {
+ NativeCrypto.SSL_CTX_free(NULL, null);
+ }
+
+ @Test
+ public void test_SSL_CTX_free() throws Exception {
+ NativeCrypto.SSL_CTX_free(NativeCrypto.SSL_CTX_new(), null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_CTX_set_session_id_context_NullContextArgument() throws Exception {
+ NativeCrypto.SSL_CTX_set_session_id_context(NULL, null, new byte[0]);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_CTX_set_session_id_context_withNullShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ try {
+ NativeCrypto.SSL_CTX_set_session_id_context(c, null, null);
+ } finally {
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void test_SSL_CTX_set_session_id_context_withInvalidIdShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ try {
+ NativeCrypto.SSL_CTX_set_session_id_context(c, null, new byte[33]);
+ } finally {
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test
+ public void test_SSL_CTX_set_session_id_context() throws Exception {
+ byte[] empty = new byte[0];
+
+ long c = NativeCrypto.SSL_CTX_new();
+ try {
+ NativeCrypto.SSL_CTX_set_session_id_context(c, null, empty);
+ NativeCrypto.SSL_CTX_set_session_id_context(c, null, new byte[32]);
+ } finally {
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test
+ public void test_SSL_new() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+
+ assertTrue(s != NULL);
+ assertTrue((NativeCrypto.SSL_get_options(s, null) & SSL_OP_NO_TICKET) != 0);
+
+ long s2 = NativeCrypto.SSL_new(c, null);
+ assertTrue(s != s2);
+ NativeCrypto.SSL_free(s2, null);
+
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void setLocalCertsAndPrivateKey_withNullSSLShouldThrow() throws Exception {
+ NativeCrypto.setLocalCertsAndPrivateKey(
+ NULL, null, getEncodedServerCertificates(), getServerPrivateKey().getNativeRef());
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void setLocalCertsAndPrivateKey_withNullCertificatesShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ try {
+ NativeCrypto.setLocalCertsAndPrivateKey(s, null, null, getServerPrivateKey().getNativeRef());
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void setLocalCertsAndPrivateKey_withNullKeyShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ try {
+ NativeCrypto.setLocalCertsAndPrivateKey(s, null, getEncodedServerCertificates(), null);
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test
+ public void setLocalCertsAndPrivateKey() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+
+ NativeCrypto.setLocalCertsAndPrivateKey(
+ s, null, getEncodedServerCertificates(), getServerPrivateKey().getNativeRef());
+
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_set1_tls_channel_id_withNullChannelShouldThrow() throws Exception {
+ NativeCrypto.SSL_set1_tls_channel_id(NULL, null, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_set1_tls_channel_id_withNullKeyShouldThrow() throws Exception {
+ initChannelIdKey();
+
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ try {
+ NativeCrypto.SSL_set1_tls_channel_id(s, null, null);
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test
+ public void test_SSL_use_PrivateKey_for_tls_channel_id() throws Exception {
+ initChannelIdKey();
+
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+
+ // Use the key natively. This works because the initChannelIdKey method ensures that the
+ // key is backed by OpenSSL.
+ NativeCrypto.SSL_set1_tls_channel_id(s, null, CHANNEL_ID_PRIVATE_KEY.getNativeRef());
+
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_get_mode_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_get_mode(NULL, null);
+ }
+
+ @Test
+ public void test_SSL_get_mode() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ assertTrue(NativeCrypto.SSL_get_mode(s, null) != 0);
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_mode_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_set_mode(NULL, null, 0);
+ }
+
+ @Test
+ public void test_SSL_set_mode_and_clear_mode() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ // check SSL_MODE_ENABLE_FALSE_START on by default for BoringSSL
+ assertEquals(SSL_MODE_ENABLE_FALSE_START,
+ NativeCrypto.SSL_get_mode(s, null) & SSL_MODE_ENABLE_FALSE_START);
+ // check SSL_MODE_CBC_RECORD_SPLITTING off by default
+ assertEquals(0, NativeCrypto.SSL_get_mode(s, null) & SSL_MODE_CBC_RECORD_SPLITTING);
+
+ // set SSL_MODE_ENABLE_FALSE_START on
+ NativeCrypto.SSL_set_mode(s, null, SSL_MODE_ENABLE_FALSE_START);
+ assertTrue((NativeCrypto.SSL_get_mode(s, null) & SSL_MODE_ENABLE_FALSE_START) != 0);
+ // clear SSL_MODE_ENABLE_FALSE_START off
+ NativeCrypto.SSL_clear_mode(s, null, SSL_MODE_ENABLE_FALSE_START);
+ assertTrue((NativeCrypto.SSL_get_mode(s, null) & SSL_MODE_ENABLE_FALSE_START) == 0);
+
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_get_options_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_get_options(NULL, null);
+ }
+
+ @Test
+ public void test_SSL_get_options() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ assertTrue(NativeCrypto.SSL_get_options(s, null) != 0);
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_options_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_set_options(NULL, null, 0);
+ }
+
+ @Test
+ public void test_SSL_set_options() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ assertTrue((NativeCrypto.SSL_get_options(s, null) & SSL_OP_CIPHER_SERVER_PREFERENCE) == 0);
+ NativeCrypto.SSL_set_options(s, null, SSL_OP_CIPHER_SERVER_PREFERENCE);
+ assertTrue((NativeCrypto.SSL_get_options(s, null) & SSL_OP_CIPHER_SERVER_PREFERENCE) != 0);
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_clear_options_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_clear_options(NULL, null, 0);
+ }
+
+ @Test
+ public void test_SSL_clear_options() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ assertTrue((NativeCrypto.SSL_get_options(s, null) & SSL_OP_CIPHER_SERVER_PREFERENCE) == 0);
+ NativeCrypto.SSL_set_options(s, null, SSL_OP_CIPHER_SERVER_PREFERENCE);
+ assertTrue((NativeCrypto.SSL_get_options(s, null) & SSL_OP_CIPHER_SERVER_PREFERENCE) != 0);
+ NativeCrypto.SSL_clear_options(s, null, SSL_OP_CIPHER_SERVER_PREFERENCE);
+ assertTrue((NativeCrypto.SSL_get_options(s, null) & SSL_OP_CIPHER_SERVER_PREFERENCE) == 0);
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_protocol_versions_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_set_protocol_versions(NULL, null, 0, 0);
+ }
+
+ @Test
+ public void SSL_set_protocol_versions() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ assertEquals(1, NativeCrypto.SSL_set_protocol_versions(s, null, TLS1_VERSION, TLS1_1_VERSION));
+ assertEquals(1, NativeCrypto.SSL_set_protocol_versions(s, null, TLS1_2_VERSION, TLS1_2_VERSION));
+ assertEquals(0, NativeCrypto.SSL_set_protocol_versions(s, null, TLS1_2_VERSION + 413, TLS1_1_VERSION));
+ assertEquals(0, NativeCrypto.SSL_set_protocol_versions(s, null, TLS1_1_VERSION, TLS1_2_VERSION + 413));
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_cipher_lists_withNullSslShouldThrow() throws Exception {
+ NativeCrypto.SSL_set_cipher_lists(NULL, null, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_cipher_lists_withNullCiphersShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ try {
+ NativeCrypto.SSL_set_cipher_lists(s, null, null);
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void test_SSL_set_cipher_lists_withNullCipherShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ try {
+ NativeCrypto.SSL_set_cipher_lists(s, null, new String[] {null});
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test
+ public void SSL_set_cipher_lists_withEmptyCiphersShouldSucceed() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+
+ // Explicitly checking that the empty list is allowed.
+ // b/21816861
+ NativeCrypto.SSL_set_cipher_lists(s, null, new String[] {});
+
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+
+ @Test
+ public void SSL_set_cipher_lists_withIllegalCipherShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+
+ // see OpenSSL ciphers man page
+ String[] illegals = new String[] {// empty
+ "",
+ // never standardized
+ "EXP1024-DES-CBC-SHA",
+ // IDEA
+ "IDEA-CBC-SHA", "IDEA-CBC-MD5"};
+
+ for (String illegal : illegals) {
+ try {
+ NativeCrypto.SSL_set_cipher_lists(s, null, new String[] {illegal});
+ fail("Exception now thrown for illegal cipher: " + illegal);
+ } catch (IllegalArgumentException expected) {
+ // Expected.
+ }
+ }
+
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+
+ @Test
+ public void SSL_set_cipher_lists_withValidCiphersShouldSucceed() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+
+ List<String> ciphers = new ArrayList<String>(NativeCrypto.SUPPORTED_TLS_1_2_CIPHER_SUITES_SET);
+ NativeCrypto.SSL_set_cipher_lists(s, null, ciphers.toArray(new String[ciphers.size()]));
+
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_verify_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_set_verify(NULL, null, 0);
+ }
+
+ @Test
+ public void test_SSL_set_verify() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ NativeCrypto.SSL_set_verify(s, null, SSL_VERIFY_NONE);
+ NativeCrypto.SSL_set_verify(s, null, SSL_VERIFY_PEER);
+ NativeCrypto.SSL_set_verify(s, null, SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
+ NativeCrypto.SSL_set_verify(s, null, (SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT));
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+
+ private static final boolean DEBUG = false;
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class Hooks {
+ String negotiatedCipherSuite;
+ private OpenSSLKey channelIdPrivateKey;
+ boolean pskEnabled;
+ byte[] pskKey;
+ List<String> enabledCipherSuites;
+
+ /**
+ * @throws SSLException if an error occurs creating the context.
+ */
+ public long getContext() throws SSLException {
+ return NativeCrypto.SSL_CTX_new();
+ }
+
+ public long beforeHandshake(long context) throws SSLException {
+ long s = NativeCrypto.SSL_new(context, null);
+ // Limit cipher suites to a known set so authMethod is known.
+ List<String> cipherSuites = new ArrayList<String>();
+ if (enabledCipherSuites == null) {
+ cipherSuites.add("ECDHE-RSA-AES128-SHA");
+ if (pskEnabled) {
+ // In TLS-PSK the client indicates that PSK key exchange is desired by offering
+ // at least one PSK cipher suite.
+ cipherSuites.add(0, "PSK-AES128-CBC-SHA");
+ }
+ } else {
+ cipherSuites.addAll(enabledCipherSuites);
+ }
+ // Protocol list is included for determining whether to send TLS_FALLBACK_SCSV
+ NativeCrypto.setEnabledCipherSuites(s, null,
+ cipherSuites.toArray(new String[cipherSuites.size()]),
+ new String[] {"TLSv1.2"});
+
+ if (channelIdPrivateKey != null) {
+ NativeCrypto.SSL_set1_tls_channel_id(s, null, channelIdPrivateKey.getNativeRef());
+ }
+ return s;
+ }
+ public void configureCallbacks(
+ @SuppressWarnings("unused") TestSSLHandshakeCallbacks callbacks) {}
+ public void clientCertificateRequested(@SuppressWarnings("unused") long s)
+ throws CertificateEncodingException, SSLException {}
+ public void afterHandshake(long session, long ssl, long context, Socket socket,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ if (session != NULL) {
+ negotiatedCipherSuite = NativeCrypto.SSL_SESSION_cipher(session);
+ NativeCrypto.SSL_SESSION_free(session);
+ }
+ if (ssl != NULL) {
+ try {
+ NativeCrypto.SSL_shutdown(ssl, null, fd, callback);
+ } catch (IOException e) {
+ // Expected.
+ }
+ NativeCrypto.SSL_free(ssl, null);
+ }
+ if (context != NULL) {
+ NativeCrypto.SSL_CTX_free(context, null);
+ }
+ if (socket != null) {
+ socket.close();
+ }
+ }
+ }
+
+ static class TestSSLHandshakeCallbacks implements SSLHandshakeCallbacks {
+ private final Socket socket;
+ private final long sslNativePointer;
+ private final Hooks hooks;
+ private final ApplicationProtocolSelectorAdapter alpnSelector;
+
+ TestSSLHandshakeCallbacks(Socket socket, long sslNativePointer, Hooks hooks,
+ ApplicationProtocolSelectorAdapter alpnSelector) {
+ this.socket = socket;
+ this.sslNativePointer = sslNativePointer;
+ this.hooks = hooks;
+ this.alpnSelector = alpnSelector;
+ }
+
+ private long[] certificateChainRefs;
+ private String authMethod;
+ private boolean verifyCertificateChainCalled;
+
+ @Override
+ public void verifyCertificateChain(byte[][] certs, String authMethod)
+ throws CertificateException {
+ certificateChainRefs = new long[certs.length];
+ for (int i = 0; i < certs.length; ++i) {
+ byte[] cert = certs[i];
+ try {
+ certificateChainRefs[i] = NativeCrypto.d2i_X509(cert);
+ } catch (ParsingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ this.authMethod = authMethod;
+ this.verifyCertificateChainCalled = true;
+ }
+
+ private byte[] keyTypes;
+ private int[] signatureAlgs;
+ private byte[][] asn1DerEncodedX500Principals;
+ private boolean clientCertificateRequestedCalled;
+
+ @Override
+ public void clientCertificateRequested(
+ byte[] keyTypes, int[] signatureAlgs, byte[][] asn1DerEncodedX500Principals)
+ throws CertificateEncodingException, SSLException {
+ if (DEBUG) {
+ System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16)
+ + " clientCertificateRequested"
+ + " keyTypes=" + Arrays.toString(keyTypes)
+ + " asn1DerEncodedX500Principals="
+ + Arrays.toString(asn1DerEncodedX500Principals));
+ }
+ this.keyTypes = keyTypes;
+ this.signatureAlgs = signatureAlgs;
+ this.asn1DerEncodedX500Principals = asn1DerEncodedX500Principals;
+ this.clientCertificateRequestedCalled = true;
+ if (hooks != null) {
+ hooks.clientCertificateRequested(sslNativePointer);
+ }
+ }
+
+ private boolean handshakeCompletedCalled;
+
+ @Override
+ public void onSSLStateChange(int type, int val) {
+ if (DEBUG) {
+ System.out.println(
+ "ssl=0x" + Long.toString(sslNativePointer, 16) + " onSSLStateChange");
+ }
+ this.handshakeCompletedCalled = true;
+ }
+
+ Socket getSocket() {
+ return socket;
+ }
+
+ private boolean clientPSKKeyRequestedInvoked;
+ private String clientPSKKeyRequestedIdentityHint;
+ private int clientPSKKeyRequestedResult;
+ private byte[] clientPSKKeyRequestedResultKey;
+ private byte[] clientPSKKeyRequestedResultIdentity;
+
+ @Override
+ public int clientPSKKeyRequested(String identityHint, byte[] identity, byte[] key) {
+ if (DEBUG) {
+ System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16)
+ + " clientPSKKeyRequested"
+ + " identityHint=" + identityHint + " identity capacity=" + identity.length
+ + " key capacity=" + key.length);
+ }
+ clientPSKKeyRequestedInvoked = true;
+ clientPSKKeyRequestedIdentityHint = identityHint;
+ if (clientPSKKeyRequestedResultKey != null) {
+ System.arraycopy(clientPSKKeyRequestedResultKey, 0, key, 0,
+ clientPSKKeyRequestedResultKey.length);
+ }
+ if (clientPSKKeyRequestedResultIdentity != null) {
+ System.arraycopy(clientPSKKeyRequestedResultIdentity, 0, identity, 0,
+ Math.min(clientPSKKeyRequestedResultIdentity.length, identity.length));
+ }
+ return clientPSKKeyRequestedResult;
+ }
+
+ private boolean serverPSKKeyRequestedInvoked;
+ private int serverPSKKeyRequestedResult;
+ private byte[] serverPSKKeyRequestedResultKey;
+ private String serverPSKKeyRequestedIdentityHint;
+ private String serverPSKKeyRequestedIdentity;
+
+ @Override
+ public int serverPSKKeyRequested(String identityHint, String identity, byte[] key) {
+ if (DEBUG) {
+ System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16)
+ + " serverPSKKeyRequested"
+ + " identityHint=" + identityHint + " identity=" + identity
+ + " key capacity=" + key.length);
+ }
+ serverPSKKeyRequestedInvoked = true;
+ serverPSKKeyRequestedIdentityHint = identityHint;
+ serverPSKKeyRequestedIdentity = identity;
+ if (serverPSKKeyRequestedResultKey != null) {
+ System.arraycopy(serverPSKKeyRequestedResultKey, 0, key, 0,
+ serverPSKKeyRequestedResultKey.length);
+ }
+ return serverPSKKeyRequestedResult;
+ }
+
+ private boolean onNewSessionEstablishedInvoked;
+ private boolean onNewSessionEstablishedSaveSession;
+ private long onNewSessionEstablishedSessionNativePointer;
+
+ @Override
+ public void onNewSessionEstablished(long sslSessionNativePtr) {
+ if (DEBUG) {
+ System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16)
+ + " onNewSessionCreated"
+ + " ssl=0x" + Long.toString(sslSessionNativePtr, 16));
+ }
+ onNewSessionEstablishedInvoked = true;
+
+ if (onNewSessionEstablishedSaveSession) {
+ NativeCrypto.SSL_SESSION_up_ref(sslSessionNativePtr);
+ onNewSessionEstablishedSessionNativePointer = sslSessionNativePtr;
+ }
+ }
+
+ @Override
+ public long serverSessionRequested(byte[] id) {
+ // TODO(nathanmittler): Implement server-side caching for TLS < 1.3
+ return 0;
+ }
+
+ private boolean serverCertificateRequestedInvoked;
+
+ @Override
+ public void serverCertificateRequested() {
+ serverCertificateRequestedInvoked = true;
+ }
+
+ @Override
+ public int selectApplicationProtocol(byte[] protocols) {
+ if (alpnSelector == null) {
+ fail("Should not be called when no alpnSelector");
+ }
+ return alpnSelector.selectApplicationProtocol(protocols);
+ }
+ }
+
+ static class ClientHooks extends Hooks {
+ private String pskIdentity;
+
+ @Override
+ public void configureCallbacks(TestSSLHandshakeCallbacks callbacks) {
+ super.configureCallbacks(callbacks);
+ if (pskEnabled) {
+ if (pskIdentity != null) {
+ // Create a NULL-terminated modified UTF-8 representation of pskIdentity.
+ byte[] b;
+ try {
+ b = pskIdentity.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 encoding not supported", e);
+ }
+ callbacks.clientPSKKeyRequestedResultIdentity = Arrays.copyOf(b, b.length + 1);
+ }
+ callbacks.clientPSKKeyRequestedResultKey = pskKey;
+ callbacks.clientPSKKeyRequestedResult = (pskKey != null) ? pskKey.length : 0;
+ }
+ }
+
+ @Override
+ public long beforeHandshake(long c) throws SSLException {
+ long s = super.beforeHandshake(c);
+ if (pskEnabled) {
+ NativeCrypto.set_SSL_psk_client_callback_enabled(s, null, true);
+ }
+ return s;
+ }
+ }
+
+ static class ServerHooks extends Hooks {
+ private final OpenSSLKey privateKey;
+ private final byte[][] certificates;
+ private boolean channelIdEnabled;
+ private byte[] channelIdAfterHandshake;
+ private Throwable channelIdAfterHandshakeException;
+
+ private String pskIdentityHint;
+
+ public ServerHooks() {
+ this(null, null);
+ }
+
+ ServerHooks(OpenSSLKey privateKey, byte[][] certificates) {
+ this.privateKey = privateKey;
+ this.certificates = certificates;
+ }
+
+ @Override
+ public long beforeHandshake(long c) throws SSLException {
+ long s = super.beforeHandshake(c);
+ if (privateKey != null && certificates != null) {
+ NativeCrypto.setLocalCertsAndPrivateKey(s, null, certificates, privateKey.getNativeRef());
+ }
+ if (channelIdEnabled) {
+ NativeCrypto.SSL_enable_tls_channel_id(s, null);
+ }
+ if (pskEnabled) {
+ NativeCrypto.set_SSL_psk_server_callback_enabled(s, null, true);
+ NativeCrypto.SSL_use_psk_identity_hint(s, null, pskIdentityHint);
+ }
+ NativeCrypto.SSL_set_verify(s, null, SSL_VERIFY_NONE);
+ return s;
+ }
+
+ @Override
+ public void configureCallbacks(TestSSLHandshakeCallbacks callbacks) {
+ super.configureCallbacks(callbacks);
+ if (pskEnabled) {
+ callbacks.serverPSKKeyRequestedResultKey = pskKey;
+ callbacks.serverPSKKeyRequestedResult = (pskKey != null) ? pskKey.length : 0;
+ }
+ }
+
+ @Override
+ public void afterHandshake(long session, long ssl, long context, Socket socket,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ if (channelIdEnabled) {
+ try {
+ channelIdAfterHandshake = NativeCrypto.SSL_get_tls_channel_id(ssl, null);
+ } catch (Exception e) {
+ channelIdAfterHandshakeException = e;
+ }
+ }
+ super.afterHandshake(session, ssl, context, socket, fd, callback);
+ }
+
+ @Override
+ public void clientCertificateRequested(long s) {
+ fail("Server asked for client certificates");
+ }
+ }
+
+ public static Future<TestSSLHandshakeCallbacks> handshake(final ServerSocket listener,
+ final int timeout, final boolean client, final Hooks hooks, final byte[] alpnProtocols,
+ final ApplicationProtocolSelectorAdapter alpnSelector) {
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Future<TestSSLHandshakeCallbacks> future =
+ executor.submit(new Callable<TestSSLHandshakeCallbacks>() {
+ @Override
+ public TestSSLHandshakeCallbacks call() throws Exception {
+ @SuppressWarnings("resource")
+ // Socket needs to remain open after the handshake
+ Socket socket = (client ? new Socket(listener.getInetAddress(),
+ listener.getLocalPort())
+ : listener.accept());
+ if (timeout == -1) {
+ return new TestSSLHandshakeCallbacks(socket, 0, null, null);
+ }
+ FileDescriptor fd =
+ (FileDescriptor) m_Platform_getFileDescriptor.invoke(
+ null, socket);
+ long c = hooks.getContext();
+ long s = hooks.beforeHandshake(c);
+ TestSSLHandshakeCallbacks callback =
+ new TestSSLHandshakeCallbacks(socket, s, hooks, alpnSelector);
+ hooks.configureCallbacks(callback);
+ if (DEBUG) {
+ System.out.println("ssl=0x" + Long.toString(s, 16) + " handshake"
+ + " context=0x" + Long.toString(c, 16) + " socket=" + socket
+ + " fd=0x" + Long.toString(System.identityHashCode(fd), 16)
+ + " timeout=" + timeout + " client=" + client);
+ }
+ long session = NULL;
+ try {
+ if (client) {
+ NativeCrypto.SSL_set_connect_state(s, null);
+ } else {
+ NativeCrypto.SSL_set_accept_state(s, null);
+ }
+ if (alpnProtocols != null) {
+ NativeCrypto.setApplicationProtocols(s, null, client, alpnProtocols);
+ }
+ if (!client && alpnSelector != null) {
+ NativeCrypto.setHasApplicationProtocolSelector(s, null, true);
+ }
+ NativeCrypto.SSL_do_handshake(s, null, fd, callback, timeout);
+ session = NativeCrypto.SSL_get1_session(s, null);
+ if (DEBUG) {
+ System.out.println("ssl=0x" + Long.toString(s, 16)
+ + " handshake"
+ + " session=0x" + Long.toString(session, 16));
+ }
+ } finally {
+ // Ensure afterHandshake is called to free resources
+ hooks.afterHandshake(session, s, c, socket, fd, callback);
+ }
+ return callback;
+ }
+ });
+ executor.shutdown();
+ return future;
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void test_SSL_do_handshake_NULL_SSL() throws Exception {
+ NativeCrypto.SSL_do_handshake(NULL, null, null, null, 0);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void test_SSL_do_handshake_withNullFdShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ NativeCrypto.SSL_set_connect_state(s, null);
+ try {
+ NativeCrypto.SSL_do_handshake(s, null, null, null, 0);
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void test_SSL_do_handshake_withNullShcShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ NativeCrypto.SSL_set_connect_state(s, null);
+ try {
+ NativeCrypto.SSL_do_handshake(s, null, INVALID_FD, null, 0);
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test
+ public void test_SSL_do_handshake_normal() throws Exception {
+ // normal client and server case
+ final ServerSocket listener = newServerSocket();
+ Hooks cHooks = new Hooks();
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates());
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertTrue(clientCallback.verifyCertificateChainCalled);
+ assertEqualCertificateChains(
+ getServerCertificateRefs(), clientCallback.certificateChainRefs);
+ assertEquals("ECDHE_RSA", clientCallback.authMethod);
+ assertFalse(serverCallback.verifyCertificateChainCalled);
+ assertFalse(clientCallback.clientCertificateRequestedCalled);
+ assertFalse(serverCallback.clientCertificateRequestedCalled);
+ assertFalse(clientCallback.clientPSKKeyRequestedInvoked);
+ assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
+ assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
+ assertFalse(serverCallback.serverPSKKeyRequestedInvoked);
+ assertTrue(clientCallback.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback.onNewSessionEstablishedInvoked);
+ assertTrue(clientCallback.handshakeCompletedCalled);
+ assertTrue(serverCallback.handshakeCompletedCalled);
+ assertFalse(clientCallback.serverCertificateRequestedInvoked);
+ assertTrue(serverCallback.serverCertificateRequestedInvoked);
+ }
+
+ @Test
+ public void test_SSL_do_handshake_reusedSession() throws Exception {
+ // normal client and server case
+ final ServerSocket listener = newServerSocket();
+
+ Future<TestSSLHandshakeCallbacks> client1 = handshake(listener, 0, true, new ClientHooks() {
+ @Override
+ public void configureCallbacks(TestSSLHandshakeCallbacks callbacks) {
+ callbacks.onNewSessionEstablishedSaveSession = true;
+ }
+ }, null, null);
+ Future<TestSSLHandshakeCallbacks> server1 = handshake(listener, 0,
+ false, new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) {
+ @Override
+ public void configureCallbacks(TestSSLHandshakeCallbacks callbacks) {
+ callbacks.onNewSessionEstablishedSaveSession = true;
+ }
+ }, null, null);
+ TestSSLHandshakeCallbacks clientCallback1 = client1.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ TestSSLHandshakeCallbacks serverCallback1 = server1.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertTrue(clientCallback1.verifyCertificateChainCalled);
+ assertEqualCertificateChains(
+ getServerCertificateRefs(), clientCallback1.certificateChainRefs);
+ assertEquals("ECDHE_RSA", clientCallback1.authMethod);
+ assertFalse(serverCallback1.verifyCertificateChainCalled);
+ assertFalse(clientCallback1.clientCertificateRequestedCalled);
+ assertFalse(serverCallback1.clientCertificateRequestedCalled);
+ assertFalse(clientCallback1.clientPSKKeyRequestedInvoked);
+ assertFalse(serverCallback1.clientPSKKeyRequestedInvoked);
+ assertFalse(clientCallback1.serverPSKKeyRequestedInvoked);
+ assertFalse(serverCallback1.serverPSKKeyRequestedInvoked);
+ assertTrue(clientCallback1.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback1.onNewSessionEstablishedInvoked);
+ assertTrue(clientCallback1.handshakeCompletedCalled);
+ assertTrue(serverCallback1.handshakeCompletedCalled);
+ assertFalse(clientCallback1.serverCertificateRequestedInvoked);
+ assertTrue(serverCallback1.serverCertificateRequestedInvoked);
+
+ final long clientSessionContext =
+ clientCallback1.onNewSessionEstablishedSessionNativePointer;
+ final long serverSessionContext =
+ serverCallback1.onNewSessionEstablishedSessionNativePointer;
+
+ Future<TestSSLHandshakeCallbacks> client2 = handshake(listener, 0, true, new ClientHooks() {
+ @Override
+ public long beforeHandshake(long c) throws SSLException {
+ long sslNativePtr = super.beforeHandshake(c);
+ NativeCrypto.SSL_set_session(sslNativePtr, null, clientSessionContext);
+ return sslNativePtr;
+ }
+ }, null, null);
+ Future<TestSSLHandshakeCallbacks> server2 = handshake(listener, 0,
+ false, new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) {
+ @Override
+ public long beforeHandshake(long c) throws SSLException {
+ long sslNativePtr = super.beforeHandshake(c);
+ NativeCrypto.SSL_set_session(sslNativePtr, null, serverSessionContext);
+ return sslNativePtr;
+ }
+ }, null, null);
+ TestSSLHandshakeCallbacks clientCallback2 = client2.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ TestSSLHandshakeCallbacks serverCallback2 = server2.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertTrue(clientCallback2.verifyCertificateChainCalled);
+ assertEqualCertificateChains(
+ getServerCertificateRefs(), clientCallback2.certificateChainRefs);
+ assertEquals("ECDHE_RSA", clientCallback2.authMethod);
+ assertFalse(serverCallback2.verifyCertificateChainCalled);
+ assertFalse(clientCallback2.clientCertificateRequestedCalled);
+ assertFalse(serverCallback2.clientCertificateRequestedCalled);
+ assertFalse(clientCallback2.clientPSKKeyRequestedInvoked);
+ assertFalse(serverCallback2.clientPSKKeyRequestedInvoked);
+ assertFalse(clientCallback2.serverPSKKeyRequestedInvoked);
+ assertFalse(serverCallback2.serverPSKKeyRequestedInvoked);
+ assertTrue(clientCallback2.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback2.onNewSessionEstablishedInvoked);
+ assertTrue(clientCallback2.handshakeCompletedCalled);
+ assertTrue(serverCallback2.handshakeCompletedCalled);
+ assertFalse(clientCallback2.serverCertificateRequestedInvoked);
+ assertTrue(serverCallback2.serverCertificateRequestedInvoked);
+
+ NativeCrypto.SSL_SESSION_free(clientSessionContext);
+ NativeCrypto.SSL_SESSION_free(serverSessionContext);
+ }
+
+ @Test
+ public void test_SSL_do_handshake_optional_client_certificate() throws Exception {
+ // optional client certificate case
+ final ServerSocket listener = newServerSocket();
+
+ Hooks cHooks = new Hooks() {
+ @Override
+ public void clientCertificateRequested(long s)
+ throws CertificateEncodingException, SSLException {
+ super.clientCertificateRequested(s);
+ NativeCrypto.setLocalCertsAndPrivateKey(
+ s, null, getEncodedClientCertificates(), getClientPrivateKey().getNativeRef());
+ }
+ };
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) {
+ @Override
+ public long beforeHandshake(long c) throws SSLException {
+ long s = super.beforeHandshake(c);
+ NativeCrypto.SSL_set_client_CA_list(s, null, getCaPrincipals());
+ NativeCrypto.SSL_set_verify(s, null, SSL_VERIFY_PEER);
+ return s;
+ }
+ };
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertTrue(clientCallback.verifyCertificateChainCalled);
+ assertEqualCertificateChains(
+ getServerCertificateRefs(), clientCallback.certificateChainRefs);
+ assertEquals("ECDHE_RSA", clientCallback.authMethod);
+ assertTrue(serverCallback.verifyCertificateChainCalled);
+ assertEqualCertificateChains(
+ getClientCertificateRefs(), serverCallback.certificateChainRefs);
+ assertEquals("ECDHE_RSA", serverCallback.authMethod);
+
+ assertTrue(clientCallback.clientCertificateRequestedCalled);
+ assertNotNull(clientCallback.keyTypes);
+ assertNotNull(clientCallback.signatureAlgs);
+ assertEquals(new HashSet<String>(Arrays.asList("EC", "RSA")),
+ SSLUtils.getSupportedClientKeyTypes(
+ clientCallback.keyTypes, clientCallback.signatureAlgs));
+ assertEqualPrincipals(getCaPrincipals(), clientCallback.asn1DerEncodedX500Principals);
+ assertFalse(serverCallback.clientCertificateRequestedCalled);
+
+ assertFalse(clientCallback.clientPSKKeyRequestedInvoked);
+ assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
+ assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
+ assertFalse(serverCallback.serverPSKKeyRequestedInvoked);
+ assertTrue(clientCallback.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback.onNewSessionEstablishedInvoked);
+ assertTrue(clientCallback.handshakeCompletedCalled);
+ assertTrue(serverCallback.handshakeCompletedCalled);
+ assertFalse(clientCallback.serverCertificateRequestedInvoked);
+ assertTrue(serverCallback.serverCertificateRequestedInvoked);
+ }
+
+ @Test
+ public void test_SSL_do_handshake_missing_required_certificate() throws Exception {
+ // required client certificate negative case
+ final ServerSocket listener = newServerSocket();
+ try {
+ Hooks cHooks = new Hooks();
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) {
+ @Override
+ public long beforeHandshake(long c) throws SSLException {
+ long s = super.beforeHandshake(c);
+ NativeCrypto.SSL_set_client_CA_list(s, null, getCaPrincipals());
+ NativeCrypto.SSL_set_verify(
+ s, null, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
+ return s;
+ }
+ };
+ @SuppressWarnings("unused")
+ Future<TestSSLHandshakeCallbacks> client =
+ handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ fail();
+ } catch (ExecutionException expected) {
+ assertEquals(SSLProtocolException.class, expected.getCause().getClass());
+ }
+ }
+
+ @Test
+ public void test_SSL_do_handshake_client_timeout() throws Exception {
+ // client timeout
+ final ServerSocket listener = newServerSocket();
+ Socket serverSocket = null;
+ try {
+ Hooks cHooks = new Hooks();
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates());
+ Future<TestSSLHandshakeCallbacks> client =
+ handshake(listener, 1, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, -1, false, sHooks, null, null);
+ serverSocket = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS).getSocket();
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ fail();
+ } catch (ExecutionException expected) {
+ assertEquals(SocketTimeoutException.class, expected.getCause().getClass());
+ } finally {
+ // Manually close peer socket when testing timeout
+ IoUtils.closeQuietly(serverSocket);
+ }
+ }
+
+ @Test
+ public void test_SSL_do_handshake_server_timeout() throws Exception {
+ // server timeout
+ final ServerSocket listener = newServerSocket();
+ Socket clientSocket = null;
+ try {
+ Hooks cHooks = new Hooks();
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates());
+ Future<TestSSLHandshakeCallbacks> client =
+ handshake(listener, -1, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 1, false, sHooks, null, null);
+ clientSocket = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS).getSocket();
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ fail();
+ } catch (ExecutionException expected) {
+ assertEquals(SocketTimeoutException.class, expected.getCause().getClass());
+ } finally {
+ // Manually close peer socket when testing timeout
+ IoUtils.closeQuietly(clientSocket);
+ }
+ }
+
+ @Test
+ public void test_SSL_do_handshake_with_channel_id_normal() throws Exception {
+ initChannelIdKey();
+
+ // Normal handshake with TLS Channel ID.
+ final ServerSocket listener = newServerSocket();
+ Hooks cHooks = new Hooks();
+ cHooks.channelIdPrivateKey = CHANNEL_ID_PRIVATE_KEY;
+ // TLS Channel ID currently requires ECDHE-based key exchanges.
+ cHooks.enabledCipherSuites = Collections.singletonList("ECDHE-RSA-AES128-SHA");
+ ServerHooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates());
+ sHooks.channelIdEnabled = true;
+ sHooks.enabledCipherSuites = cHooks.enabledCipherSuites;
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertTrue(clientCallback.verifyCertificateChainCalled);
+ assertEqualCertificateChains(
+ getServerCertificateRefs(), clientCallback.certificateChainRefs);
+ assertEquals("ECDHE_RSA", clientCallback.authMethod);
+ assertFalse(serverCallback.verifyCertificateChainCalled);
+ assertFalse(clientCallback.clientCertificateRequestedCalled);
+ assertFalse(serverCallback.clientCertificateRequestedCalled);
+ assertFalse(clientCallback.clientPSKKeyRequestedInvoked);
+ assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
+ assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
+ assertFalse(serverCallback.serverPSKKeyRequestedInvoked);
+ assertTrue(clientCallback.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback.onNewSessionEstablishedInvoked);
+ assertTrue(clientCallback.handshakeCompletedCalled);
+ assertTrue(serverCallback.handshakeCompletedCalled);
+ assertNull(sHooks.channelIdAfterHandshakeException);
+ assertFalse(clientCallback.serverCertificateRequestedInvoked);
+ assertTrue(serverCallback.serverCertificateRequestedInvoked);
+ assertEqualByteArrays(CHANNEL_ID, sHooks.channelIdAfterHandshake);
+ }
+
+ @Test
+ public void test_SSL_do_handshake_with_channel_id_not_supported_by_server() throws Exception {
+ initChannelIdKey();
+
+ // Client tries to use TLS Channel ID but the server does not enable/offer the extension.
+ final ServerSocket listener = newServerSocket();
+ Hooks cHooks = new Hooks();
+ cHooks.channelIdPrivateKey = CHANNEL_ID_PRIVATE_KEY;
+ // TLS Channel ID currently requires ECDHE-based key exchanges.
+ cHooks.enabledCipherSuites = Collections.singletonList("ECDHE-RSA-AES128-SHA");
+ ServerHooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates());
+ sHooks.channelIdEnabled = false;
+ sHooks.enabledCipherSuites = cHooks.enabledCipherSuites;
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertTrue(clientCallback.verifyCertificateChainCalled);
+ assertEqualCertificateChains(
+ getServerCertificateRefs(), clientCallback.certificateChainRefs);
+ assertEquals("ECDHE_RSA", clientCallback.authMethod);
+ assertFalse(serverCallback.verifyCertificateChainCalled);
+ assertFalse(clientCallback.clientCertificateRequestedCalled);
+ assertFalse(serverCallback.clientCertificateRequestedCalled);
+ assertFalse(clientCallback.clientPSKKeyRequestedInvoked);
+ assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
+ assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
+ assertFalse(serverCallback.serverPSKKeyRequestedInvoked);
+ assertTrue(clientCallback.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback.onNewSessionEstablishedInvoked);
+ assertTrue(clientCallback.handshakeCompletedCalled);
+ assertTrue(serverCallback.handshakeCompletedCalled);
+ assertFalse(clientCallback.serverCertificateRequestedInvoked);
+ assertTrue(serverCallback.serverCertificateRequestedInvoked);
+ assertNull(sHooks.channelIdAfterHandshakeException);
+ assertNull(sHooks.channelIdAfterHandshake);
+ }
+
+ @Test
+ public void test_SSL_do_handshake_with_channel_id_not_enabled_by_client() throws Exception {
+ initChannelIdKey();
+
+ // Client does not use TLS Channel ID when the server has the extension enabled/offered.
+ final ServerSocket listener = newServerSocket();
+ Hooks cHooks = new Hooks();
+ cHooks.channelIdPrivateKey = null;
+ // TLS Channel ID currently requires ECDHE-based key exchanges.
+ cHooks.enabledCipherSuites = Collections.singletonList("ECDHE-RSA-AES128-SHA");
+ ServerHooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates());
+ sHooks.channelIdEnabled = true;
+ sHooks.enabledCipherSuites = cHooks.enabledCipherSuites;
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertTrue(clientCallback.verifyCertificateChainCalled);
+ assertEqualCertificateChains(
+ getServerCertificateRefs(), clientCallback.certificateChainRefs);
+ assertEquals("ECDHE_RSA", clientCallback.authMethod);
+ assertFalse(serverCallback.verifyCertificateChainCalled);
+ assertFalse(clientCallback.clientCertificateRequestedCalled);
+ assertFalse(serverCallback.clientCertificateRequestedCalled);
+ assertFalse(clientCallback.clientPSKKeyRequestedInvoked);
+ assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
+ assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
+ assertFalse(serverCallback.serverPSKKeyRequestedInvoked);
+ assertTrue(clientCallback.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback.onNewSessionEstablishedInvoked);
+ assertTrue(clientCallback.handshakeCompletedCalled);
+ assertTrue(serverCallback.handshakeCompletedCalled);
+ assertFalse(clientCallback.serverCertificateRequestedInvoked);
+ assertTrue(serverCallback.serverCertificateRequestedInvoked);
+ assertNull(sHooks.channelIdAfterHandshakeException);
+ assertNull(sHooks.channelIdAfterHandshake);
+ }
+
+ @Test
+ public void test_SSL_do_handshake_with_psk_normal() throws Exception {
+ // normal TLS-PSK client and server case
+ final ServerSocket listener = newServerSocket();
+ Hooks cHooks = new ClientHooks();
+ ServerHooks sHooks = new ServerHooks();
+ cHooks.pskEnabled = true;
+ sHooks.pskEnabled = true;
+ cHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8");
+ sHooks.pskKey = cHooks.pskKey;
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertFalse(clientCallback.verifyCertificateChainCalled);
+ assertFalse(serverCallback.verifyCertificateChainCalled);
+ assertFalse(clientCallback.clientCertificateRequestedCalled);
+ assertFalse(serverCallback.clientCertificateRequestedCalled);
+ assertTrue(clientCallback.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback.onNewSessionEstablishedInvoked);
+ assertTrue(clientCallback.handshakeCompletedCalled);
+ assertTrue(serverCallback.handshakeCompletedCalled);
+ assertTrue(clientCallback.clientPSKKeyRequestedInvoked);
+ assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
+ assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
+ assertTrue(serverCallback.serverPSKKeyRequestedInvoked);
+ assertContains(cHooks.negotiatedCipherSuite, "PSK");
+ assertEquals(cHooks.negotiatedCipherSuite, sHooks.negotiatedCipherSuite);
+ assertNull(clientCallback.clientPSKKeyRequestedIdentityHint);
+ assertNull(serverCallback.serverPSKKeyRequestedIdentityHint);
+ assertEquals("", serverCallback.serverPSKKeyRequestedIdentity);
+ assertFalse(clientCallback.serverCertificateRequestedInvoked);
+ assertTrue(serverCallback.serverCertificateRequestedInvoked);
+ }
+
+ @Test
+ public void test_SSL_do_handshake_with_psk_with_identity_and_hint() throws Exception {
+ // normal TLS-PSK client and server case where the server provides the client with a PSK
+ // identity hint, and the client provides the server with a PSK identity.
+ final ServerSocket listener = newServerSocket();
+ ClientHooks cHooks = new ClientHooks();
+ ServerHooks sHooks = new ServerHooks();
+ cHooks.pskEnabled = true;
+ sHooks.pskEnabled = true;
+ cHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8");
+ sHooks.pskKey = cHooks.pskKey;
+ sHooks.pskIdentityHint = "Some non-ASCII characters: \u00c4\u0332";
+ cHooks.pskIdentity = "More non-ASCII characters: \u00f5\u044b";
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertFalse(clientCallback.verifyCertificateChainCalled);
+ assertFalse(serverCallback.verifyCertificateChainCalled);
+ assertFalse(clientCallback.clientCertificateRequestedCalled);
+ assertFalse(serverCallback.clientCertificateRequestedCalled);
+ assertTrue(clientCallback.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback.onNewSessionEstablishedInvoked);
+ assertTrue(clientCallback.handshakeCompletedCalled);
+ assertTrue(serverCallback.handshakeCompletedCalled);
+ assertTrue(clientCallback.clientPSKKeyRequestedInvoked);
+ assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
+ assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
+ assertTrue(serverCallback.serverPSKKeyRequestedInvoked);
+ assertContains(cHooks.negotiatedCipherSuite, "PSK");
+ assertEquals(cHooks.negotiatedCipherSuite, sHooks.negotiatedCipherSuite);
+ assertEquals(sHooks.pskIdentityHint, clientCallback.clientPSKKeyRequestedIdentityHint);
+ assertEquals(sHooks.pskIdentityHint, serverCallback.serverPSKKeyRequestedIdentityHint);
+ assertEquals(cHooks.pskIdentity, serverCallback.serverPSKKeyRequestedIdentity);
+ assertFalse(clientCallback.serverCertificateRequestedInvoked);
+ assertTrue(serverCallback.serverCertificateRequestedInvoked);
+ }
+
+ @Test
+ @SuppressWarnings("deprecation")
+ public void test_SSL_do_handshake_with_psk_with_identity_and_hint_of_max_length()
+ throws Exception {
+ // normal TLS-PSK client and server case where the server provides the client with a PSK
+ // identity hint, and the client provides the server with a PSK identity.
+ final ServerSocket listener = newServerSocket();
+ ClientHooks cHooks = new ClientHooks();
+ ServerHooks sHooks = new ServerHooks();
+ cHooks.pskEnabled = true;
+ sHooks.pskEnabled = true;
+ cHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8");
+ sHooks.pskKey = cHooks.pskKey;
+ sHooks.pskIdentityHint = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
+ + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx";
+ cHooks.pskIdentity = "123456789012345678901234567890123456789012345678901234567890"
+ + "12345678901234567890123456789012345678901234567890123456789012345678";
+ assertEquals(PSKKeyManager.MAX_IDENTITY_HINT_LENGTH_BYTES, sHooks.pskIdentityHint.length());
+ assertEquals(PSKKeyManager.MAX_IDENTITY_LENGTH_BYTES, cHooks.pskIdentity.length());
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertFalse(clientCallback.verifyCertificateChainCalled);
+ assertFalse(serverCallback.verifyCertificateChainCalled);
+ assertFalse(clientCallback.clientCertificateRequestedCalled);
+ assertFalse(serverCallback.clientCertificateRequestedCalled);
+ assertTrue(clientCallback.handshakeCompletedCalled);
+ assertTrue(serverCallback.handshakeCompletedCalled);
+ assertTrue(clientCallback.clientPSKKeyRequestedInvoked);
+ assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
+ assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
+ assertTrue(serverCallback.serverPSKKeyRequestedInvoked);
+ assertContains(cHooks.negotiatedCipherSuite, "PSK");
+ assertEquals(cHooks.negotiatedCipherSuite, sHooks.negotiatedCipherSuite);
+ assertEquals(sHooks.pskIdentityHint, clientCallback.clientPSKKeyRequestedIdentityHint);
+ assertEquals(sHooks.pskIdentityHint, serverCallback.serverPSKKeyRequestedIdentityHint);
+ assertEquals(cHooks.pskIdentity, serverCallback.serverPSKKeyRequestedIdentity);
+ }
+
+ @Test
+ public void test_SSL_do_handshake_with_psk_key_mismatch() throws Exception {
+ final ServerSocket listener = newServerSocket();
+ ClientHooks cHooks = new ClientHooks();
+ ServerHooks sHooks = new ServerHooks();
+ cHooks.pskEnabled = true;
+ sHooks.pskEnabled = true;
+ cHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8");
+ sHooks.pskKey = "1, 2, 3, 3, Testing...".getBytes("UTF-8");
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ try {
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ fail();
+ } catch (ExecutionException expected) {
+ assertEquals(SSLProtocolException.class, expected.getCause().getClass());
+ }
+ }
+
+ @Test
+ public void test_SSL_do_handshake_with_psk_with_no_client_key() throws Exception {
+ final ServerSocket listener = newServerSocket();
+ ClientHooks cHooks = new ClientHooks();
+ ServerHooks sHooks = new ServerHooks();
+ cHooks.pskEnabled = true;
+ sHooks.pskEnabled = true;
+ cHooks.pskKey = null;
+ sHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8");
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ try {
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ fail();
+ } catch (ExecutionException expected) {
+ assertEquals(SSLProtocolException.class, expected.getCause().getClass());
+ }
+ }
+
+ @Test
+ public void test_SSL_do_handshake_with_psk_with_no_server_key() throws Exception {
+ final ServerSocket listener = newServerSocket();
+ ClientHooks cHooks = new ClientHooks();
+ ServerHooks sHooks = new ServerHooks();
+ cHooks.pskEnabled = true;
+ sHooks.pskEnabled = true;
+ cHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8");
+ sHooks.pskKey = null;
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ try {
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ fail();
+ } catch (ExecutionException expected) {
+ assertEquals(SSLProtocolException.class, expected.getCause().getClass());
+ }
+ }
+
+ @Test
+ @SuppressWarnings("deprecation")
+ public void test_SSL_do_handshake_with_psk_key_too_long() throws Exception {
+ final ServerSocket listener = newServerSocket();
+ ClientHooks cHooks = new ClientHooks() {
+ @Override
+ public void configureCallbacks(TestSSLHandshakeCallbacks callbacks) {
+ super.configureCallbacks(callbacks);
+ callbacks.clientPSKKeyRequestedResult = PSKKeyManager.MAX_KEY_LENGTH_BYTES + 1;
+ }
+ };
+ ServerHooks sHooks = new ServerHooks();
+ cHooks.pskEnabled = true;
+ sHooks.pskEnabled = true;
+ cHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8");
+ sHooks.pskKey = cHooks.pskKey;
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ try {
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ fail();
+ } catch (ExecutionException expected) {
+ assertEquals(SSLProtocolException.class, expected.getCause().getClass());
+ }
+ }
+
+ @Test
+ public void test_SSL_do_handshake_with_ocsp_response() throws Exception {
+ final byte[] OCSP_TEST_DATA = new byte[] {1, 2, 3, 4};
+
+ final ServerSocket listener = newServerSocket();
+ Hooks cHooks = new Hooks() {
+ @Override
+ public long beforeHandshake(long c) throws SSLException {
+ long s = super.beforeHandshake(c);
+ NativeCrypto.SSL_enable_ocsp_stapling(s, null);
+ return s;
+ }
+
+ @Override
+ public void afterHandshake(long session, long ssl, long context, Socket socket,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ assertEqualByteArrays(OCSP_TEST_DATA, NativeCrypto.SSL_get_ocsp_response(ssl, null));
+ super.afterHandshake(session, ssl, context, socket, fd, callback);
+ }
+ };
+
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) {
+ @Override
+ public long beforeHandshake(long c) throws SSLException {
+ long s = super.beforeHandshake(c);
+ NativeCrypto.SSL_set_ocsp_response(s, null, OCSP_TEST_DATA);
+ return s;
+ }
+ };
+
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+
+ assertTrue(clientCallback.handshakeCompletedCalled);
+ assertTrue(serverCallback.handshakeCompletedCalled);
+ }
+
+ @Test
+ public void test_SSL_do_handshake_with_sct_extension() throws Exception {
+ // Fake SCT extension has a length of overall extension (unsigned 16-bit).
+ // Each SCT entry has a length (unsigned 16-bit) and data.
+ final byte[] SCT_TEST_DATA = new byte[] {0, 6, 0, 4, 1, 2, 3, 4};
+
+ final ServerSocket listener = newServerSocket();
+ Hooks cHooks = new Hooks() {
+ @Override
+ public long beforeHandshake(long c) throws SSLException {
+ long s = super.beforeHandshake(c);
+ NativeCrypto.SSL_enable_signed_cert_timestamps(s, null);
+ return s;
+ }
+
+ @Override
+ public void afterHandshake(long session, long ssl, long context, Socket socket,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ assertEqualByteArrays(
+ SCT_TEST_DATA, NativeCrypto.SSL_get_signed_cert_timestamp_list(ssl, null));
+ super.afterHandshake(session, ssl, context, socket, fd, callback);
+ }
+ };
+
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) {
+ @Override
+ public long beforeHandshake(long c) throws SSLException {
+ long s = super.beforeHandshake(c);
+ NativeCrypto.SSL_set_signed_cert_timestamp_list(s, null, SCT_TEST_DATA);
+ return s;
+ }
+ };
+
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+
+ assertTrue(clientCallback.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback.onNewSessionEstablishedInvoked);
+ assertTrue(clientCallback.handshakeCompletedCalled);
+ assertTrue(serverCallback.handshakeCompletedCalled);
+ assertFalse(clientCallback.serverCertificateRequestedInvoked);
+ assertTrue(serverCallback.serverCertificateRequestedInvoked);
+ }
+
+ @Test
+ @SuppressWarnings("deprecation")
+ public void test_SSL_use_psk_identity_hint() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ try {
+ NativeCrypto.SSL_use_psk_identity_hint(s, null, null);
+ NativeCrypto.SSL_use_psk_identity_hint(s, null, "test");
+
+ try {
+ // 800 characters is much longer than the permitted maximum.
+ StringBuilder pskIdentityHint = new StringBuilder();
+ for (int i = 0; i < 160; i++) {
+ pskIdentityHint.append(" long");
+ }
+ assertTrue(pskIdentityHint.length() > PSKKeyManager.MAX_IDENTITY_HINT_LENGTH_BYTES);
+ NativeCrypto.SSL_use_psk_identity_hint(s, null, pskIdentityHint.toString());
+ fail();
+ } catch (SSLException expected) {
+ // Expected.
+ }
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_session_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_set_session(NULL, null, NULL);
+ }
+
+ @Test
+ public void test_SSL_set_session() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ NativeCrypto.SSL_set_session(s, null, NULL);
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+
+ {
+ final long clientContext = NativeCrypto.SSL_CTX_new();
+ final long serverContext = NativeCrypto.SSL_CTX_new();
+ final ServerSocket listener = newServerSocket();
+ final long[] clientSession = new long[] {NULL};
+ final long[] serverSession = new long[] {NULL};
+ {
+ Hooks cHooks = new Hooks() {
+ @Override
+ public long getContext() throws SSLException {
+ return clientContext;
+ }
+ @Override
+ public void afterHandshake(long session, long s, long c, Socket sock,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ super.afterHandshake(NULL, s, NULL, sock, fd, callback);
+ clientSession[0] = session;
+ }
+ };
+ Hooks sHooks = new ServerHooks(
+ getServerPrivateKey(), getEncodedServerCertificates()) {
+ @Override
+ public long getContext() throws SSLException {
+ return serverContext;
+ }
+ @Override
+ public void afterHandshake(long session, long s, long c, Socket sock,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ super.afterHandshake(NULL, s, NULL, sock, fd, callback);
+ serverSession[0] = session;
+ }
+ };
+ Future<TestSSLHandshakeCallbacks> client =
+ handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ }
+ assertEqualSessions(clientSession[0], serverSession[0]);
+ {
+ Hooks cHooks = new Hooks() {
+ @Override
+ public long getContext() throws SSLException {
+ return clientContext;
+ }
+ @Override
+ public long beforeHandshake(long c) throws SSLException {
+ long s = NativeCrypto.SSL_new(clientContext, null);
+ NativeCrypto.SSL_set_session(s, null, clientSession[0]);
+ return s;
+ }
+ @Override
+ public void afterHandshake(long session, long s, long c, Socket sock,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ assertEqualSessions(clientSession[0], session);
+ super.afterHandshake(NULL, s, NULL, sock, fd, callback);
+ }
+ };
+ Hooks sHooks = new ServerHooks(
+ getServerPrivateKey(), getEncodedServerCertificates()) {
+ @Override
+ public long getContext() throws SSLException {
+ return serverContext;
+ }
+ @Override
+ public void afterHandshake(long session, long s, long c, Socket sock,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ assertEqualSessions(serverSession[0], session);
+ super.afterHandshake(NULL, s, NULL, sock, fd, callback);
+ }
+ };
+ Future<TestSSLHandshakeCallbacks> client =
+ handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ }
+ NativeCrypto.SSL_SESSION_free(clientSession[0]);
+ NativeCrypto.SSL_SESSION_free(serverSession[0]);
+ NativeCrypto.SSL_CTX_free(serverContext, null);
+ NativeCrypto.SSL_CTX_free(clientContext, null);
+ }
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_session_creation_enabled_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_set_session_creation_enabled(NULL, null, false);
+ }
+
+ @Test
+ public void test_SSL_set_session_creation_enabled() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ NativeCrypto.SSL_set_session_creation_enabled(s, null, false);
+ NativeCrypto.SSL_set_session_creation_enabled(s, null, true);
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+
+ final ServerSocket listener = newServerSocket();
+
+ // negative test case for SSL_set_session_creation_enabled(false) on client
+ {
+ Hooks cHooks = new Hooks() {
+ @Override
+ public long beforeHandshake(long c) throws SSLException {
+ long s = super.beforeHandshake(c);
+ NativeCrypto.SSL_set_session_creation_enabled(s, null, false);
+ return s;
+ }
+ };
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates());
+ Future<TestSSLHandshakeCallbacks> client =
+ handshake(listener, 0, true, cHooks, null, null);
+ @SuppressWarnings("unused")
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ try {
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ fail();
+ } catch (ExecutionException expected) {
+ assertEquals(SSLProtocolException.class, expected.getCause().getClass());
+ }
+ try {
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ fail();
+ } catch (ExecutionException expected) {
+ assertEquals(SSLProtocolException.class, expected.getCause().getClass());
+ }
+ }
+
+ // negative test case for SSL_set_session_creation_enabled(false) on server
+ {
+ Hooks cHooks = new Hooks();
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) {
+ @Override
+ public long beforeHandshake(long c) throws SSLException {
+ long s = super.beforeHandshake(c);
+ NativeCrypto.SSL_set_session_creation_enabled(s, null, false);
+ return s;
+ }
+ };
+ Future<TestSSLHandshakeCallbacks> client =
+ handshake(listener, 0, true, cHooks, null, null);
+ @SuppressWarnings("unused")
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ try {
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ fail();
+ } catch (ExecutionException expected) {
+ assertEquals(SSLHandshakeException.class, expected.getCause().getClass());
+ }
+ try {
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ fail();
+ } catch (ExecutionException expected) {
+ assertEquals(SSLProtocolException.class, expected.getCause().getClass());
+ }
+ }
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_tlsext_host_name_withNullSslShouldThrow() throws Exception {
+ NativeCrypto.SSL_set_tlsext_host_name(NULL, null, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_tlsext_host_name_withNullHostnameShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+
+ try {
+ NativeCrypto.SSL_set_tlsext_host_name(s, null, null);
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test(expected = SSLException.class)
+ public void SSL_set_tlsext_host_name_withTooLongHostnameShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+
+ try {
+ char[] longHostname = new char[256];
+ Arrays.fill(longHostname, 'w');
+ NativeCrypto.SSL_set_tlsext_host_name(s, null, new String(longHostname));
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test
+ public void test_SSL_set_tlsext_host_name() throws Exception {
+ final String hostname = "www.android.com";
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+
+ assertNull(NativeCrypto.SSL_get_servername(s, null));
+ NativeCrypto.SSL_set_tlsext_host_name(s, null, hostname);
+ assertEquals(hostname, NativeCrypto.SSL_get_servername(s, null));
+
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+
+ final ServerSocket listener = newServerSocket();
+
+ // normal
+ Hooks cHooks = new Hooks() {
+ @Override
+ public long beforeHandshake(long c) throws SSLException {
+ long s = super.beforeHandshake(c);
+ NativeCrypto.SSL_set_tlsext_host_name(s, null, hostname);
+ return s;
+ }
+ };
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) {
+ @Override
+ public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd,
+ SSLHandshakeCallbacks callback) throws Exception {
+ assertEquals(hostname, NativeCrypto.SSL_get_servername(s, null));
+ super.afterHandshake(session, s, c, sock, fd, callback);
+ }
+ };
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ }
+
+ @Test
+ public void alpnWithProtocolListShouldSucceed() throws Exception {
+ final byte[] clientAlpnProtocols =
+ SSLUtils.encodeProtocols(new String[] {"http/1.1", "foo", "spdy/2"});
+ final byte[] serverAlpnProtocols =
+ SSLUtils.encodeProtocols(new String[] {"spdy/2", "foo", "bar"});
+
+ Hooks cHooks = new Hooks() {
+ @Override
+ public void afterHandshake(long session, long ssl, long context, Socket socket,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ byte[] negotiated = NativeCrypto.getApplicationProtocol(ssl, null);
+ assertEquals("spdy/2", new String(negotiated, "UTF-8"));
+ super.afterHandshake(session, ssl, context, socket, fd, callback);
+ }
+ };
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) {
+ @Override
+ public void afterHandshake(long session, long ssl, long c, Socket sock,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ byte[] negotiated = NativeCrypto.getApplicationProtocol(ssl, null);
+ assertEquals("spdy/2", new String(negotiated, "UTF-8"));
+ super.afterHandshake(session, ssl, c, sock, fd, callback);
+ }
+ };
+
+ ServerSocket listener = newServerSocket();
+ Future<TestSSLHandshakeCallbacks> client =
+ handshake(listener, 0, true, cHooks, clientAlpnProtocols, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, serverAlpnProtocols, null);
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ }
+
+ @Test
+ public void alpnWithProtocolListShouldFail() throws Exception {
+ final byte[] clientAlpnProtocols =
+ SSLUtils.encodeProtocols(new String[] {"http/1.1", "foo", "spdy/2"});
+ final byte[] serverAlpnProtocols =
+ SSLUtils.encodeProtocols(new String[] {"h2", "bar", "baz"});
+
+ Hooks cHooks = new Hooks() {
+ @Override
+ public void afterHandshake(long session, long ssl, long context, Socket socket,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ byte[] negotiated = NativeCrypto.getApplicationProtocol(ssl, null);
+ assertNull(negotiated);
+ super.afterHandshake(session, ssl, context, socket, fd, callback);
+ }
+ };
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) {
+ @Override
+ public void afterHandshake(long session, long ssl, long c, Socket sock,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ byte[] negotiated = NativeCrypto.getApplicationProtocol(ssl, null);
+ assertNull(negotiated);
+ super.afterHandshake(session, ssl, c, sock, fd, callback);
+ }
+ };
+
+ ServerSocket listener = newServerSocket();
+ Future<TestSSLHandshakeCallbacks> client =
+ handshake(listener, 0, true, cHooks, clientAlpnProtocols, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, serverAlpnProtocols, null);
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ }
+
+ @Test
+ public void alpnWithServerProtocolSelectorShouldSucceed() throws Exception {
+ final byte[] clientAlpnProtocols =
+ SSLUtils.encodeProtocols(new String[] {"http/1.1", "foo", "spdy/2"});
+
+ Hooks cHooks = new Hooks() {
+ @Override
+ public void afterHandshake(long session, long ssl, long context, Socket socket,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ byte[] negotiated = NativeCrypto.getApplicationProtocol(ssl, null);
+ assertEquals("spdy/2", new String(negotiated, "UTF-8"));
+ super.afterHandshake(session, ssl, context, socket, fd, callback);
+ }
+ };
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) {
+ @Override
+ public void afterHandshake(long session, long ssl, long c, Socket sock,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ byte[] negotiated = NativeCrypto.getApplicationProtocol(ssl, null);
+ assertEquals("spdy/2", new String(negotiated, "UTF-8"));
+ super.afterHandshake(session, ssl, c, sock, fd, callback);
+ }
+ };
+
+ ApplicationProtocolSelector selector = Mockito.mock(ApplicationProtocolSelector.class);
+ SSLEngine engine = Mockito.mock(SSLEngine.class);
+ ApplicationProtocolSelectorAdapter adapter = new ApplicationProtocolSelectorAdapter(engine, selector);
+ when(selector.selectApplicationProtocol(same(engine), ArgumentMatchers.<String>anyList()))
+ .thenReturn("spdy/2");
+
+ ServerSocket listener = newServerSocket();
+ Future<TestSSLHandshakeCallbacks> client =
+ handshake(listener, 0, true, cHooks, clientAlpnProtocols, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, adapter);
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ }
+
+ @Test
+ public void alpnWithServerProtocolSelectorShouldFail() throws Exception {
+ final byte[] clientAlpnProtocols =
+ SSLUtils.encodeProtocols(new String[] {"http/1.1", "foo", "spdy/2"});
+
+ Hooks cHooks = new Hooks() {
+ @Override
+ public void afterHandshake(long session, long ssl, long context, Socket socket,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ byte[] negotiated = NativeCrypto.getApplicationProtocol(ssl, null);
+ assertNull(negotiated);
+ super.afterHandshake(session, ssl, context, socket, fd, callback);
+ }
+ };
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) {
+ @Override
+ public void afterHandshake(long session, long ssl, long c, Socket sock,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ byte[] negotiated = NativeCrypto.getApplicationProtocol(ssl, null);
+ assertNull(negotiated);
+ super.afterHandshake(session, ssl, c, sock, fd, callback);
+ }
+ };
+
+ ApplicationProtocolSelector selector = Mockito.mock(ApplicationProtocolSelector.class);
+ SSLEngine engine = Mockito.mock(SSLEngine.class);
+ ApplicationProtocolSelectorAdapter adapter = new ApplicationProtocolSelectorAdapter(engine, selector);
+ when(selector.selectApplicationProtocol(same(engine), ArgumentMatchers.<String>anyList()))
+ .thenReturn("h2");
+
+ ServerSocket listener = newServerSocket();
+ Future<TestSSLHandshakeCallbacks> client =
+ handshake(listener, 0, true, cHooks, clientAlpnProtocols, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, adapter);
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void test_SSL_get_servername_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_get_servername(NULL, null);
+ }
+
+ @Test
+ public void SSL_get_servername_shouldReturnNull() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ assertNull(NativeCrypto.SSL_get_servername(s, null));
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+
+ // additional positive testing by test_SSL_set_tlsext_host_name
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_get0_peer_certificates_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_get0_peer_certificates(NULL, null);
+ }
+
+ @Test
+ public void test_SSL_get0_peer_certificates() throws Exception {
+ final ServerSocket listener = newServerSocket();
+
+ Hooks cHooks = new Hooks() {
+ @Override
+ public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd,
+ SSLHandshakeCallbacks callback) throws Exception {
+ byte[][] cc = NativeCrypto.SSL_get0_peer_certificates(s, null);
+ assertEqualByteArrays(getEncodedServerCertificates(), cc);
+ super.afterHandshake(session, s, c, sock, fd, callback);
+ }
+ };
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates());
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ }
+
+ @Test
+ public void test_SSL_cipher_names() throws Exception {
+ final ServerSocket listener = newServerSocket();
+ Hooks cHooks = new Hooks();
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates());
+ // Both legacy and standard names are accepted.
+ cHooks.enabledCipherSuites = Collections.singletonList("ECDHE-RSA-AES128-GCM-SHA256");
+ sHooks.enabledCipherSuites =
+ Collections.singletonList("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256");
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ // The standard name is always reported.
+ assertEquals("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", cHooks.negotiatedCipherSuite);
+ assertEquals("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", sHooks.negotiatedCipherSuite);
+ }
+
+ private final byte[] BYTES = new byte[] {2, -3, 5, 127, 0, -128};
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_read_withNullSslShouldThrow() throws Exception {
+ NativeCrypto.SSL_read(NULL, null, null, null, null, 0, 0, 0);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_read_withNullFdShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ try {
+ NativeCrypto.SSL_read(s, null, null, DUMMY_CB, null, 0, 0, 0);
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_read_withNullCallbacksShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ try {
+ NativeCrypto.SSL_read(s, null, INVALID_FD, null, null, 0, 0, 0);
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_read_withNullBytesShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ try {
+ NativeCrypto.SSL_read(s, null, INVALID_FD, DUMMY_CB, null, 0, 0, 0);
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test(expected = SSLException.class)
+ public void SSL_read_beforeHandshakeShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ try {
+ NativeCrypto.SSL_read(s, null, INVALID_FD, DUMMY_CB, new byte[1], 0, 1, 0);
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test
+ public void test_SSL_read() throws Exception {
+ final ServerSocket listener = newServerSocket();
+
+ // normal case
+ {
+ Hooks cHooks = new Hooks() {
+ @Override
+ public void afterHandshake(long session, long s, long c, Socket sock,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ byte[] in = new byte[256];
+ assertEquals(BYTES.length,
+ NativeCrypto.SSL_read(s, null, fd, callback, in, 0, BYTES.length, 0));
+ for (int i = 0; i < BYTES.length; i++) {
+ assertEquals(BYTES[i], in[i]);
+ }
+ super.afterHandshake(session, s, c, sock, fd, callback);
+ }
+ };
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) {
+ @Override
+ public void afterHandshake(long session, long s, long c, Socket sock,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ NativeCrypto.SSL_write(s, null, fd, callback, BYTES, 0, BYTES.length, 0);
+ super.afterHandshake(session, s, c, sock, fd, callback);
+ }
+ };
+ Future<TestSSLHandshakeCallbacks> client =
+ handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ }
+
+ // timeout case
+ try {
+ Hooks cHooks = new Hooks() {
+ @Override
+ public void afterHandshake(long session, long s, long c, Socket sock,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ NativeCrypto.SSL_read(s, null, fd, callback, new byte[1], 0, 1, 1);
+ fail();
+ }
+ };
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) {
+ @Override
+ public void afterHandshake(long session, long s, long c, Socket sock,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ NativeCrypto.SSL_read(s, null, fd, callback, new byte[1], 0, 1, 0);
+ super.afterHandshake(session, s, c, sock, fd, callback);
+ }
+ };
+ Future<TestSSLHandshakeCallbacks> client =
+ handshake(listener, 0, true, cHooks, null, null);
+ @SuppressWarnings("unused")
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ fail();
+ } catch (ExecutionException expected) {
+ assertEquals(SocketTimeoutException.class, expected.getCause().getClass());
+ }
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_write_withNullSslShouldThrow() throws Exception {
+ NativeCrypto.SSL_write(NULL, null, null, null, null, 0, 0, 0);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_write_withNullFdShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ try {
+ NativeCrypto.SSL_write(s, null, null, DUMMY_CB, null, 0, 1, 0);
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_write_withNullCallbacksShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ try {
+ NativeCrypto.SSL_write(s, null, INVALID_FD, null, null, 0, 1, 0);
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_write_withNullBytesShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ try {
+ NativeCrypto.SSL_write(s, null, INVALID_FD, DUMMY_CB, null, 0, 1, 0);
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test(expected = SSLException.class)
+ public void SSL_write_beforeHandshakeShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ try {
+ NativeCrypto.SSL_write(s, null, INVALID_FD, DUMMY_CB, new byte[1], 0, 1, 0);
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test
+ public void SSL_interrupt_withNullShouldSucceed() {
+ // SSL_interrupt is a rare case that tolerates a null SSL argument
+ NativeCrypto.SSL_interrupt(NULL, null);
+ }
+
+ @Test
+ public void SSL_interrupt_withoutHandshakeShouldSucceed() throws Exception {
+ // also works without handshaking
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ NativeCrypto.SSL_interrupt(s, null);
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+
+ @Test
+ public void test_SSL_interrupt() throws Exception {
+ final ServerSocket listener = newServerSocket();
+
+ Hooks cHooks = new Hooks() {
+ @Override
+ public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd,
+ SSLHandshakeCallbacks callback) throws Exception {
+ NativeCrypto.SSL_read(s, null, fd, callback, new byte[1], 0, 1, 0);
+ super.afterHandshake(session, s, c, sock, fd, callback);
+ }
+ };
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) {
+ @Override
+ public void afterHandshake(long session, final long s, long c, Socket sock,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ new Thread() {
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(1000);
+ NativeCrypto.SSL_interrupt(s, null);
+ } catch (Exception e) {
+ // Expected.
+ }
+ }
+ }.start();
+ assertEquals(-1, NativeCrypto.SSL_read(s, null, fd, callback, new byte[1], 0, 1, 0));
+ super.afterHandshake(session, s, c, sock, fd, callback);
+ }
+ };
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ }
+
+ private static abstract class SSLSessionWrappedTask {
+ public abstract void run(long sslSession) throws Exception;
+ }
+
+ private void wrapWithSSLSession(SSLSessionWrappedTask task) throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c, null);
+ try {
+ task.run(s);
+ } finally {
+ NativeCrypto.SSL_free(s, null);
+ NativeCrypto.SSL_CTX_free(c, null);
+ }
+ }
+
+ @Test
+ public void SSL_shutdown_withNullFdShouldSucceed() throws Exception {
+ // We tolerate a null FileDescriptor
+ wrapWithSSLSession(new SSLSessionWrappedTask() {
+ @Override
+ public void run(long sslSession) throws Exception {
+ NativeCrypto.SSL_shutdown(sslSession, null, null, DUMMY_CB);
+ }
+ });
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_shutdown_withNullCallbacksShouldThrow() throws Exception {
+ wrapWithSSLSession(new SSLSessionWrappedTask() {
+ @Override
+ public void run(long sslSession) throws Exception {
+ NativeCrypto.SSL_shutdown(sslSession, null, INVALID_FD, null);
+ }
+ });
+ }
+
+ @Test
+ public void SSL_shutdown_withNullSslShouldSucceed() throws Exception {
+ // SSL_shutdown is a rare case that tolerates a null SSL argument
+ NativeCrypto.SSL_shutdown(NULL, null, INVALID_FD, DUMMY_CB);
+ }
+
+ @Test(expected = SocketException.class)
+ public void SSL_shutdown_beforeHandshakeShouldThrow() throws Exception {
+ // handshaking not yet performed
+ wrapWithSSLSession(new SSLSessionWrappedTask() {
+ @Override
+ public void run(long sslSession) throws Exception {
+ NativeCrypto.SSL_shutdown(sslSession, null, INVALID_FD, DUMMY_CB);
+ }
+ });
+
+ // positively tested elsewhere because handshake uses use
+ // SSL_shutdown to ensure SSL_SESSIONs are reused.
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_free_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_free(NULL, null);
+ }
+
+ @Test
+ public void test_SSL_free() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ NativeCrypto.SSL_free(NativeCrypto.SSL_new(c, null), null);
+ NativeCrypto.SSL_CTX_free(c, null);
+
+ // additional positive testing elsewhere because handshake
+ // uses use SSL_free to cleanup in afterHandshake.
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_SESSION_session_id_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_SESSION_session_id(NULL);
+ }
+
+ @Test
+ public void test_SSL_SESSION_session_id() throws Exception {
+ final ServerSocket listener = newServerSocket();
+
+ Hooks cHooks = new Hooks() {
+ @Override
+ public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd,
+ SSLHandshakeCallbacks callback) throws Exception {
+ byte[] id = NativeCrypto.SSL_SESSION_session_id(session);
+ assertNotNull(id);
+ assertEquals(32, id.length);
+ super.afterHandshake(session, s, c, sock, fd, callback);
+ }
+ };
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates());
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_SESSION_get_time_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_SESSION_get_time(NULL);
+ }
+
+ @Test
+ public void test_SSL_SESSION_get_time() throws Exception {
+ final ServerSocket listener = newServerSocket();
+
+ {
+ Hooks cHooks = new Hooks() {
+ @Override
+ public void afterHandshake(long session, long s, long c, Socket sock,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ long time = NativeCrypto.SSL_SESSION_get_time(session);
+ assertTrue(time != 0);
+ assertTrue(time < System.currentTimeMillis());
+ super.afterHandshake(session, s, c, sock, fd, callback);
+ }
+ };
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates());
+ Future<TestSSLHandshakeCallbacks> client =
+ handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ }
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_SESSION_get_version_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_SESSION_get_version(NULL);
+ }
+
+ @Test
+ public void test_SSL_SESSION_get_version() throws Exception {
+ final ServerSocket listener = newServerSocket();
+
+ Hooks cHooks = new Hooks() {
+ @Override
+ public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd,
+ SSLHandshakeCallbacks callback) throws Exception {
+ String v = NativeCrypto.SSL_SESSION_get_version(session);
+ assertTrue(StandardNames.SSL_SOCKET_PROTOCOLS.contains(v));
+ super.afterHandshake(session, s, c, sock, fd, callback);
+ }
+ };
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates());
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_SESSION_cipher_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_SESSION_cipher(NULL);
+ }
+
+ @Test
+ public void test_SSL_SESSION_cipher() throws Exception {
+ final ServerSocket listener = newServerSocket();
+
+ Hooks cHooks = new Hooks() {
+ @Override
+ public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd,
+ SSLHandshakeCallbacks callback) throws Exception {
+ String nativeCipher = NativeCrypto.SSL_SESSION_cipher(session);
+ String javaCipher = NativeCrypto.cipherSuiteFromJava(nativeCipher);
+ assertTrue(NativeCrypto.SUPPORTED_TLS_1_2_CIPHER_SUITES_SET.contains(javaCipher));
+ // SSL_SESSION_cipher should return a standard name rather than an OpenSSL name.
+ assertTrue(nativeCipher.startsWith("TLS_"));
+ super.afterHandshake(session, s, c, sock, fd, callback);
+ }
+ };
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates());
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ }
+
+ /*
+ * Additional positive testing elsewhere because handshake
+ * uses use SSL_SESSION_free to cleanup in afterHandshake.
+ */
+ @Test(expected = NullPointerException.class)
+ public void SSL_SESSION_free_NullArgument() throws Exception {
+ NativeCrypto.SSL_SESSION_free(NULL);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void i2d_SSL_Session_WithNullSessionShouldThrow() throws Exception {
+ NativeCrypto.i2d_SSL_SESSION(NULL);
+ }
+
+ @Test
+ public void test_i2d_SSL_SESSION() throws Exception {
+ final ServerSocket listener = newServerSocket();
+
+ Hooks cHooks = new Hooks() {
+ @Override
+ public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd,
+ SSLHandshakeCallbacks callback) throws Exception {
+ byte[] b = NativeCrypto.i2d_SSL_SESSION(session);
+ assertNotNull(b);
+ long session2 = NativeCrypto.d2i_SSL_SESSION(b);
+ assertTrue(session2 != NULL);
+
+ // Make sure d2i_SSL_SESSION retores SSL_SESSION_cipher value http://b/7091840
+ assertTrue(NativeCrypto.SSL_SESSION_cipher(session2) != null);
+ assertEquals(NativeCrypto.SSL_SESSION_cipher(session),
+ NativeCrypto.SSL_SESSION_cipher(session2));
+
+ NativeCrypto.SSL_SESSION_free(session2);
+ super.afterHandshake(session, s, c, sock, fd, callback);
+ }
+ };
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates());
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
+ Future<TestSSLHandshakeCallbacks> server =
+ handshake(listener, 0, false, sHooks, null, null);
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void d2i_SSL_SESSION_NullArgument() throws Exception {
+ NativeCrypto.d2i_SSL_SESSION(null);
+ }
+
+ @Test(expected = IOException.class)
+ public void d2i_SSL_SESSION_EmptyArgument() throws Exception {
+ NativeCrypto.d2i_SSL_SESSION(new byte[0]);
+ }
+
+ @Test(expected = IOException.class)
+ public void d2i_SSL_SESSION_InvalidArgument() throws Exception {
+ NativeCrypto.d2i_SSL_SESSION(new byte[1]);
+ }
+
+ @Test
+ public void test_X509_NAME_hashes() {
+ // ensure these hash functions are stable over time since the
+ // /system/etc/security/cacerts CA filenames have to be
+ // consistent with the output.
+ X500Principal name = new X500Principal("CN=localhost");
+ assertEquals(-1372642656, NativeCrypto.X509_NAME_hash(name)); // SHA1
+ assertEquals(-1626170662, NativeCrypto.X509_NAME_hash_old(name)); // MD5
+ }
+
+ @Test
+ public void test_RAND_bytes_Success() throws Exception {
+ byte[] output = new byte[128];
+ NativeCrypto.RAND_bytes(output);
+
+ boolean isZero = true;
+ for (byte anOutput : output) {
+ isZero &= (anOutput == 0);
+ }
+
+ assertFalse("Random output was zero. This is a very low probability event (1 in 2^128) "
+ + "and probably indicates an error.",
+ isZero);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void RAND_bytes_withNullShouldThrow() throws Exception {
+ NativeCrypto.RAND_bytes(null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void test_EVP_get_digestbyname_NullArgument() throws Exception {
+ NativeCrypto.EVP_get_digestbyname(null);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void EVP_get_digestbyname_withEmptyShouldThrow() throws Exception {
+ NativeCrypto.EVP_get_digestbyname("");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void EVP_get_digestbyname_withInvalidDigestShouldThrow() throws Exception {
+ NativeCrypto.EVP_get_digestbyname("foobar");
+ }
+
+ @Test
+ public void test_EVP_get_digestbyname() throws Exception {
+ assertTrue(NativeCrypto.EVP_get_digestbyname("sha256") != NULL);
+ }
+
+ @Test
+ public void test_EVP_DigestSignInit() throws Exception {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ kpg.initialize(512);
+
+ KeyPair kp = kpg.generateKeyPair();
+ RSAPrivateCrtKey privKey = (RSAPrivateCrtKey) kp.getPrivate();
+
+ NativeRef.EVP_PKEY pkey;
+ pkey = new NativeRef.EVP_PKEY(NativeCrypto.EVP_PKEY_new_RSA(
+ privKey.getModulus().toByteArray(), privKey.getPublicExponent().toByteArray(),
+ privKey.getPrivateExponent().toByteArray(), privKey.getPrimeP().toByteArray(),
+ privKey.getPrimeQ().toByteArray(), privKey.getPrimeExponentP().toByteArray(),
+ privKey.getPrimeExponentQ().toByteArray(),
+ privKey.getCrtCoefficient().toByteArray()));
+ assertNotNull(pkey);
+
+ final NativeRef.EVP_MD_CTX ctx = new NativeRef.EVP_MD_CTX(NativeCrypto.EVP_MD_CTX_create());
+ long evpMd = NativeCrypto.EVP_get_digestbyname("sha256");
+ NativeCrypto.EVP_DigestSignInit(ctx, evpMd, pkey);
+
+ try {
+ NativeCrypto.EVP_DigestSignInit(ctx, 0, pkey);
+ fail();
+ } catch (RuntimeException expected) {
+ // Expected.
+ }
+
+ try {
+ NativeCrypto.EVP_DigestSignInit(ctx, evpMd, null);
+ fail();
+ } catch (RuntimeException expected) {
+ // Expected.
+ }
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void get_RSA_private_params_NullArgument() throws Exception {
+ NativeCrypto.get_RSA_private_params(null);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void test_get_RSA_private_params() throws Exception {
+ // Test getting params for the wrong kind of key.
+ final long groupCtx = NativeCrypto.EC_GROUP_new_by_curve_name("prime256v1");
+ assertFalse(groupCtx == NULL);
+ NativeRef.EC_GROUP group = new NativeRef.EC_GROUP(groupCtx);
+ NativeRef.EVP_PKEY ctx = new NativeRef.EVP_PKEY(NativeCrypto.EC_KEY_generate_key(group));
+ NativeCrypto.get_RSA_private_params(ctx);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void get_RSA_public_params_NullArgument() throws Exception {
+ NativeCrypto.get_RSA_public_params(null);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void test_get_RSA_public_params() throws Exception {
+ // Test getting params for the wrong kind of key.
+ final long groupCtx = NativeCrypto.EC_GROUP_new_by_curve_name("prime256v1");
+ assertFalse(groupCtx == NULL);
+ NativeRef.EC_GROUP group = new NativeRef.EC_GROUP(groupCtx);
+ NativeRef.EVP_PKEY ctx = new NativeRef.EVP_PKEY(NativeCrypto.EC_KEY_generate_key(group));
+ NativeCrypto.get_RSA_public_params(ctx);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void RSA_size_NullArgumentFailure() throws Exception {
+ NativeCrypto.RSA_size(null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void RSA_private_encrypt_NullArgumentFailure() throws Exception {
+ NativeCrypto.RSA_private_encrypt(0, new byte[0], new byte[0], null, 0);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void RSA_private_decrypt_NullArgumentFailure() throws Exception {
+ NativeCrypto.RSA_private_decrypt(0, new byte[0], new byte[0], null, 0);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void test_RSA_public_encrypt_NullArgumentFailure() throws Exception {
+ NativeCrypto.RSA_public_encrypt(0, new byte[0], new byte[0], null, 0);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void test_RSA_public_decrypt_NullArgumentFailure() throws Exception {
+ NativeCrypto.RSA_public_decrypt(0, new byte[0], new byte[0], null, 0);
+ }
+
+ /*
+ * Test vector generation:
+ * openssl rand -hex 16
+ */
+ private static final byte[] AES_128_KEY = new byte[] {
+ (byte) 0x3d, (byte) 0x4f, (byte) 0x89, (byte) 0x70, (byte) 0xb1, (byte) 0xf2,
+ (byte) 0x75, (byte) 0x37, (byte) 0xf4, (byte) 0x0a, (byte) 0x39, (byte) 0x29,
+ (byte) 0x8a, (byte) 0x41, (byte) 0x55, (byte) 0x5f,
+ };
+
+ @Test
+ public void testEC_GROUP() throws Exception {
+ /* Test using NIST's P-256 curve */
+ check_EC_GROUP("prime256v1",
+ "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
+ "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
+ "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
+ "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
+ "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 1L);
+ }
+
+ private void check_EC_GROUP(String name, String pStr, String aStr, String bStr, String xStr,
+ String yStr, String nStr, long hLong) throws Exception {
+ long groupRef = NativeCrypto.EC_GROUP_new_by_curve_name(name);
+ assertFalse(groupRef == NULL);
+ NativeRef.EC_GROUP group = new NativeRef.EC_GROUP(groupRef);
+
+ // prime
+ BigInteger p = new BigInteger(pStr, 16);
+ // first coefficient
+ BigInteger a = new BigInteger(aStr, 16);
+ // second coefficient
+ BigInteger b = new BigInteger(bStr, 16);
+ // x affine coordinate of generator
+ BigInteger x = new BigInteger(xStr, 16);
+ // y affine coordinate of generator
+ BigInteger y = new BigInteger(yStr, 16);
+ // order of the generator
+ BigInteger n = new BigInteger(nStr, 16);
+ // cofactor of generator
+ BigInteger h = BigInteger.valueOf(hLong);
+
+ byte[][] pab = NativeCrypto.EC_GROUP_get_curve(group);
+ assertEquals(3, pab.length);
+
+ BigInteger p2 = new BigInteger(pab[0]);
+ assertEquals(p, p2);
+
+ BigInteger a2 = new BigInteger(pab[1]);
+ assertEquals(a, a2);
+
+ BigInteger b2 = new BigInteger(pab[2]);
+ assertEquals(b, b2);
+
+ NativeRef.EC_POINT point =
+ new NativeRef.EC_POINT(NativeCrypto.EC_GROUP_get_generator(group));
+
+ byte[][] xy = NativeCrypto.EC_POINT_get_affine_coordinates(group, point);
+ assertEquals(2, xy.length);
+
+ BigInteger x2 = new BigInteger(xy[0]);
+ assertEquals(x, x2);
+
+ BigInteger y2 = new BigInteger(xy[1]);
+ assertEquals(y, y2);
+
+ BigInteger n2 = new BigInteger(NativeCrypto.EC_GROUP_get_order(group));
+ assertEquals(n, n2);
+
+ BigInteger h2 = new BigInteger(NativeCrypto.EC_GROUP_get_cofactor(group));
+ assertEquals(h, h2);
+
+ NativeRef.EVP_PKEY key1 = new NativeRef.EVP_PKEY(NativeCrypto.EC_KEY_generate_key(group));
+ NativeRef.EC_GROUP groupTmp = new NativeRef.EC_GROUP(NativeCrypto.EC_KEY_get1_group(key1));
+ assertEquals(NativeCrypto.EC_GROUP_get_curve_name(group),
+ NativeCrypto.EC_GROUP_get_curve_name(groupTmp));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void test_EC_KEY_get_private_key_NullArgumentFailure() throws Exception {
+ NativeCrypto.EC_KEY_get_private_key(null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void test_EC_KEY_get_public_key_NullArgumentFailure() throws Exception {
+ NativeCrypto.EC_KEY_get_public_key(null);
+ }
+
+ @Test
+ public void test_ECKeyPairGenerator_CurvesAreValid() throws Exception {
+ OpenSSLECKeyPairGenerator.assertCurvesAreValid();
+ }
+
+ @Test
+ public void test_ECDH_compute_key_null_key_Failure() throws Exception {
+ final long groupCtx = NativeCrypto.EC_GROUP_new_by_curve_name("prime256v1");
+ assertFalse(groupCtx == NULL);
+ NativeRef.EC_GROUP groupRef = new NativeRef.EC_GROUP(groupCtx);
+ NativeRef.EVP_PKEY pkey1Ref =
+ new NativeRef.EVP_PKEY(NativeCrypto.EC_KEY_generate_key(groupRef));
+ NativeRef.EVP_PKEY pkey2Ref =
+ new NativeRef.EVP_PKEY(NativeCrypto.EC_KEY_generate_key(groupRef));
+
+ byte[] out = new byte[128];
+ int outOffset = 0;
+ // Assert that the method under test works fine with the two
+ // non-null keys
+ NativeCrypto.ECDH_compute_key(out, outOffset, pkey1Ref, pkey2Ref);
+
+ // Assert that it fails when only the first key is null
+ try {
+ NativeCrypto.ECDH_compute_key(out, outOffset, null, pkey2Ref);
+ fail();
+ } catch (NullPointerException expected) {
+ // Expected.
+ }
+
+ // Assert that it fails when only the second key is null
+ try {
+ NativeCrypto.ECDH_compute_key(out, outOffset, pkey1Ref, null);
+ fail();
+ } catch (NullPointerException expected) {
+ // Expected.
+ }
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void EVP_CipherInit_ex_withNullCtxShouldThrow() throws Exception {
+ final long evpCipher = NativeCrypto.EVP_get_cipherbyname("aes-128-ecb");
+ NativeCrypto.EVP_CipherInit_ex(null, evpCipher, null, null, true);
+ }
+
+ @Test
+ public void test_EVP_CipherInit_ex_Null_Failure() throws Exception {
+ final NativeRef.EVP_CIPHER_CTX ctx =
+ new NativeRef.EVP_CIPHER_CTX(NativeCrypto.EVP_CIPHER_CTX_new());
+ final long evpCipher = NativeCrypto.EVP_get_cipherbyname("aes-128-ecb");
+
+ /* Initialize encrypting. */
+ NativeCrypto.EVP_CipherInit_ex(ctx, evpCipher, null, null, true);
+ NativeCrypto.EVP_CipherInit_ex(ctx, NULL, null, null, true);
+
+ /* Initialize decrypting. */
+ NativeCrypto.EVP_CipherInit_ex(ctx, evpCipher, null, null, false);
+ NativeCrypto.EVP_CipherInit_ex(ctx, NULL, null, null, false);
+ }
+
+ @Test
+ public void test_EVP_CipherInit_ex_Success() throws Exception {
+ final NativeRef.EVP_CIPHER_CTX ctx =
+ new NativeRef.EVP_CIPHER_CTX(NativeCrypto.EVP_CIPHER_CTX_new());
+ final long evpCipher = NativeCrypto.EVP_get_cipherbyname("aes-128-ecb");
+ NativeCrypto.EVP_CipherInit_ex(ctx, evpCipher, AES_128_KEY, null, true);
+ }
+
+ @Test
+ public void test_EVP_CIPHER_iv_length() throws Exception {
+ long aes128ecb = NativeCrypto.EVP_get_cipherbyname("aes-128-ecb");
+ assertEquals(0, NativeCrypto.EVP_CIPHER_iv_length(aes128ecb));
+
+ long aes128cbc = NativeCrypto.EVP_get_cipherbyname("aes-128-cbc");
+ assertEquals(16, NativeCrypto.EVP_CIPHER_iv_length(aes128cbc));
+ }
+
+ @Test
+ public void test_OpenSSLKey_toJava() throws Exception {
+ OpenSSLKey key1;
+
+ BigInteger e = BigInteger.valueOf(65537);
+ key1 = new OpenSSLKey(NativeCrypto.RSA_generate_key_ex(1024, e.toByteArray()));
+ assertTrue(key1.getPublicKey() instanceof RSAPublicKey);
+
+ final long groupCtx = NativeCrypto.EC_GROUP_new_by_curve_name("prime256v1");
+ assertFalse(groupCtx == NULL);
+ NativeRef.EC_GROUP group1 = new NativeRef.EC_GROUP(groupCtx);
+ key1 = new OpenSSLKey(NativeCrypto.EC_KEY_generate_key(group1));
+ assertTrue(key1.getPublicKey() instanceof ECPublicKey);
+ }
+
+ @Test
+ public void test_create_BIO_InputStream() throws Exception {
+ byte[] actual = "Test".getBytes("UTF-8");
+ ByteArrayInputStream is = new ByteArrayInputStream(actual);
+
+ @SuppressWarnings("resource")
+ OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is, true);
+ try {
+ byte[] buffer = new byte[1024];
+ int numRead = NativeCrypto.BIO_read(bis.getBioContext(), buffer);
+ assertEquals(actual.length, numRead);
+ assertEquals(Arrays.toString(actual),
+ Arrays.toString(Arrays.copyOfRange(buffer, 0, numRead)));
+ } finally {
+ bis.release();
+ }
+ }
+
+ @Test
+ public void test_create_BIO_OutputStream() throws Exception {
+ byte[] actual = "Test".getBytes("UTF-8");
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ long ctx = NativeCrypto.create_BIO_OutputStream(os);
+ try {
+ NativeCrypto.BIO_write(ctx, actual, 0, actual.length);
+ assertEquals(actual.length, os.size());
+ assertEquals(Arrays.toString(actual), Arrays.toString(os.toByteArray()));
+ } finally {
+ NativeCrypto.BIO_free_all(ctx);
+ }
+ }
+
+ @Test
+ public void test_get_ocsp_single_extension() throws Exception {
+ final String OCSP_SCT_LIST_OID = "1.3.6.1.4.1.11129.2.4.5";
+
+ byte[] ocspResponse = readTestFile("ocsp-response.der");
+ byte[] expected = readTestFile("ocsp-response-sct-extension.der");
+ OpenSSLX509Certificate certificate =
+ OpenSSLX509Certificate.fromX509PemInputStream(openTestFile("cert-ct-poisoned.pem"));
+ OpenSSLX509Certificate issuer =
+ OpenSSLX509Certificate.fromX509PemInputStream(openTestFile("ca-cert.pem"));
+
+ byte[] extension = NativeCrypto.get_ocsp_single_extension(
+ ocspResponse, OCSP_SCT_LIST_OID, certificate.getContext(), certificate, issuer.getContext(), issuer);
+
+ assertEqualByteArrays(expected, extension);
+ }
+
+ private static long getRawPkeyCtxForEncrypt() throws Exception {
+ return NativeCrypto.EVP_PKEY_encrypt_init(getRsaPkey(generateRsaKey()));
+ }
+
+ private static NativeRef.EVP_PKEY_CTX getPkeyCtxForEncrypt() throws Exception {
+ return new NativeRef.EVP_PKEY_CTX(getRawPkeyCtxForEncrypt());
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void EVP_PKEY_encrypt_NullKeyArgument() throws Exception {
+ NativeCrypto.EVP_PKEY_encrypt(null, new byte[128], 0, new byte[128], 0, 128);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void EVP_PKEY_encrypt_NullOutputArgument() throws Exception {
+ NativeCrypto.EVP_PKEY_encrypt(getPkeyCtxForEncrypt(), null, 0, new byte[128], 0, 128);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void EVP_PKEY_encrypt_NullInputArgument() throws Exception {
+ NativeCrypto.EVP_PKEY_encrypt(getPkeyCtxForEncrypt(), new byte[128], 0, null, 0, 128);
+ }
+
+ @Test(expected = ArrayIndexOutOfBoundsException.class)
+ public void EVP_PKEY_encrypt_OutputIndexOOBUnder() throws Exception {
+ NativeCrypto.EVP_PKEY_encrypt(
+ getPkeyCtxForEncrypt(), new byte[128], -1, new byte[128], 0, 128);
+ }
+
+ @Test(expected = ArrayIndexOutOfBoundsException.class)
+ public void EVP_PKEY_encrypt_OutputIndexOOBOver() throws Exception {
+ NativeCrypto.EVP_PKEY_encrypt(
+ getPkeyCtxForEncrypt(), new byte[128], 129, new byte[128], 0, 128);
+ }
+
+ @Test(expected = ArrayIndexOutOfBoundsException.class)
+ public void EVP_PKEY_encrypt_InputIndexOOBUnder() throws Exception {
+ NativeCrypto.EVP_PKEY_encrypt(
+ getPkeyCtxForEncrypt(), new byte[128], 0, new byte[128], -1, 128);
+ }
+
+ @Test(expected = ArrayIndexOutOfBoundsException.class)
+ public void EVP_PKEY_encrypt_InputIndexOOBOver() throws Exception {
+ NativeCrypto.EVP_PKEY_encrypt(
+ getPkeyCtxForEncrypt(), new byte[128], 0, new byte[128], 128, 128);
+ }
+
+ @Test(expected = ArrayIndexOutOfBoundsException.class)
+ public void EVP_PKEY_encrypt_InputLengthNegative() throws Exception {
+ NativeCrypto.EVP_PKEY_encrypt(
+ getPkeyCtxForEncrypt(), new byte[128], 0, new byte[128], 0, -1);
+ }
+
+ @Test(expected = ArrayIndexOutOfBoundsException.class)
+ public void EVP_PKEY_encrypt_InputIndexLengthOOB() throws Exception {
+ NativeCrypto.EVP_PKEY_encrypt(
+ getPkeyCtxForEncrypt(), new byte[128], 0, new byte[128], 100, 29);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void EVP_PKEY_CTX_set_rsa_mgf1_md_NullPkeyCtx() throws Exception {
+ NativeCrypto.EVP_PKEY_CTX_set_rsa_mgf1_md(NULL, EvpMdRef.SHA256.EVP_MD);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void EVP_PKEY_CTX_set_rsa_mgf1_md_NullMdCtx() throws Exception {
+ long pkeyCtx = getRawPkeyCtxForEncrypt();
+ NativeRef.EVP_PKEY_CTX holder = new NativeRef.EVP_PKEY_CTX(pkeyCtx);
+ NativeCrypto.EVP_PKEY_CTX_set_rsa_mgf1_md(pkeyCtx, NULL);
+ assertNotNull(holder);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void EVP_PKEY_CTX_set_rsa_oaep_md_NullPkeyCtx() throws Exception {
+ NativeCrypto.EVP_PKEY_CTX_set_rsa_oaep_md(NULL, EvpMdRef.SHA256.EVP_MD);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void EVP_PKEY_CTX_set_rsa_oaep_md_NullMdCtx() throws Exception {
+ long pkeyCtx = getRawPkeyCtxForEncrypt();
+ NativeRef.EVP_PKEY_CTX holder = new NativeRef.EVP_PKEY_CTX(pkeyCtx);
+ NativeCrypto.EVP_PKEY_CTX_set_rsa_oaep_md(pkeyCtx, NULL);
+ assertNotNull(holder);
+ }
+
+ @Test(expected = ParsingException.class)
+ public void d2i_X509_InvalidFailure() throws Exception {
+ NativeCrypto.d2i_X509(new byte[1]);
+ }
+
+ private static void assertContains(String actualValue, String expectedSubstring) {
+ if (actualValue == null) {
+ return;
+ }
+ if (actualValue.contains(expectedSubstring)) {
+ return;
+ }
+ fail("\"" + actualValue + "\" does not contain \"" + expectedSubstring + "\"");
+ }
+
+ private static ServerSocket newServerSocket() throws IOException {
+ return new ServerSocket(0, 50, TestUtils.getLoopbackAddress());
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/NativeRefTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/NativeRefTest.java
new file mode 100644
index 0000000..18a81aa
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/NativeRefTest.java
@@ -0,0 +1,37 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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
+ */
+
+package com.android.org.conscrypt;
+
+import junit.framework.TestCase;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class NativeRefTest extends TestCase {
+ public void test_zeroContextThrowsNullPointException() {
+ try {
+ new NativeRef(0) {
+ @Override
+ void doFree(long context) {
+ }
+ };
+ fail("Should throw NullPointerException when arguments are NULL");
+ } catch (NullPointerException expected) {
+ }
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/NativeSslSessionTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/NativeSslSessionTest.java
new file mode 100644
index 0000000..c80461f
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/NativeSslSessionTest.java
@@ -0,0 +1,627 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License", "www.google.com", 443);
+ * 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class NativeSslSessionTest {
+ /*
+ * Taken from external/boringssl/src/ssl/ssl_test.cc: kOpenSSLSession is a
+ * serialized SSL_SESSION.
+ */
+ private static final byte[] kOpenSSLSession = new byte[] {(byte) 0x30, (byte) 0x82, (byte) 0x05,
+ (byte) 0xAA, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x02, (byte) 0x02,
+ (byte) 0x03, (byte) 0x03, (byte) 0x04, (byte) 0x02, (byte) 0xC0, (byte) 0x2F,
+ (byte) 0x04, (byte) 0x20, (byte) 0x06, (byte) 0xE5, (byte) 0x0D, (byte) 0x67,
+ (byte) 0x76, (byte) 0xAE, (byte) 0x18, (byte) 0x7E, (byte) 0x66, (byte) 0xDE,
+ (byte) 0xA3, (byte) 0x5C, (byte) 0xF0, (byte) 0x2E, (byte) 0x43, (byte) 0x51,
+ (byte) 0x2A, (byte) 0x60, (byte) 0x97, (byte) 0x19, (byte) 0xD3, (byte) 0x60,
+ (byte) 0x5A, (byte) 0xF1, (byte) 0x93, (byte) 0xDD, (byte) 0xCB, (byte) 0x24,
+ (byte) 0x57, (byte) 0x4C, (byte) 0x90, (byte) 0x90, (byte) 0x04, (byte) 0x30,
+ (byte) 0x26, (byte) 0x5A, (byte) 0xE5, (byte) 0xCE, (byte) 0x40, (byte) 0x16,
+ (byte) 0x04, (byte) 0xE5, (byte) 0xA2, (byte) 0x2E, (byte) 0x3F, (byte) 0xE3,
+ (byte) 0x27, (byte) 0xBE, (byte) 0x83, (byte) 0xEE, (byte) 0x5F, (byte) 0x94,
+ (byte) 0x5E, (byte) 0x88, (byte) 0xB3, (byte) 0x3F, (byte) 0x62, (byte) 0x88,
+ (byte) 0xD8, (byte) 0x2E, (byte) 0xC8, (byte) 0xD8, (byte) 0x57, (byte) 0x1C,
+ (byte) 0xA8, (byte) 0xC9, (byte) 0x88, (byte) 0x7C, (byte) 0x59, (byte) 0xA6,
+ (byte) 0x91, (byte) 0x4C, (byte) 0xB7, (byte) 0xDA, (byte) 0x72, (byte) 0x09,
+ (byte) 0xD2, (byte) 0x66, (byte) 0x47, (byte) 0x21, (byte) 0x6A, (byte) 0x09,
+ (byte) 0xA1, (byte) 0x06, (byte) 0x02, (byte) 0x04, (byte) 0x54, (byte) 0x43,
+ (byte) 0x3B, (byte) 0x8E, (byte) 0xA2, (byte) 0x04, (byte) 0x02, (byte) 0x02,
+ (byte) 0x01, (byte) 0x2C, (byte) 0xA3, (byte) 0x82, (byte) 0x04, (byte) 0x7A,
+ (byte) 0x30, (byte) 0x82, (byte) 0x04, (byte) 0x76, (byte) 0x30, (byte) 0x82,
+ (byte) 0x03, (byte) 0x5E, (byte) 0xA0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
+ (byte) 0x02, (byte) 0x02, (byte) 0x08, (byte) 0x2B, (byte) 0xD7, (byte) 0x54,
+ (byte) 0xBE, (byte) 0xC3, (byte) 0xD6, (byte) 0x4A, (byte) 0x55, (byte) 0x30,
+ (byte) 0x0D, (byte) 0x06, (byte) 0x09, (byte) 0x2A, (byte) 0x86, (byte) 0x48,
+ (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01, (byte) 0x01, (byte) 0x05,
+ (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x49, (byte) 0x31, (byte) 0x0B,
+ (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+ (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31,
+ (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+ (byte) 0x04, (byte) 0x0A, (byte) 0x13, (byte) 0x0A, (byte) 0x47, (byte) 0x6F,
+ (byte) 0x6F, (byte) 0x67, (byte) 0x6C, (byte) 0x65, (byte) 0x20, (byte) 0x49,
+ (byte) 0x6E, (byte) 0x63, (byte) 0x31, (byte) 0x25, (byte) 0x30, (byte) 0x23,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x13,
+ (byte) 0x1C, (byte) 0x47, (byte) 0x6F, (byte) 0x6F, (byte) 0x67, (byte) 0x6C,
+ (byte) 0x65, (byte) 0x20, (byte) 0x49, (byte) 0x6E, (byte) 0x74, (byte) 0x65,
+ (byte) 0x72, (byte) 0x6E, (byte) 0x65, (byte) 0x74, (byte) 0x20, (byte) 0x41,
+ (byte) 0x75, (byte) 0x74, (byte) 0x68, (byte) 0x6F, (byte) 0x72, (byte) 0x69,
+ (byte) 0x74, (byte) 0x79, (byte) 0x20, (byte) 0x47, (byte) 0x32, (byte) 0x30,
+ (byte) 0x1E, (byte) 0x17, (byte) 0x0D, (byte) 0x31, (byte) 0x34, (byte) 0x31,
+ (byte) 0x30, (byte) 0x30, (byte) 0x38, (byte) 0x31, (byte) 0x32, (byte) 0x30,
+ (byte) 0x37, (byte) 0x35, (byte) 0x37, (byte) 0x5A, (byte) 0x17, (byte) 0x0D,
+ (byte) 0x31, (byte) 0x35, (byte) 0x30, (byte) 0x31, (byte) 0x30, (byte) 0x36,
+ (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30,
+ (byte) 0x5A, (byte) 0x30, (byte) 0x68, (byte) 0x31, (byte) 0x0B, (byte) 0x30,
+ (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
+ (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x13,
+ (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+ (byte) 0x08, (byte) 0x0C, (byte) 0x0A, (byte) 0x43, (byte) 0x61, (byte) 0x6C,
+ (byte) 0x69, (byte) 0x66, (byte) 0x6F, (byte) 0x72, (byte) 0x6E, (byte) 0x69,
+ (byte) 0x61, (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x0C, (byte) 0x0D,
+ (byte) 0x4D, (byte) 0x6F, (byte) 0x75, (byte) 0x6E, (byte) 0x74, (byte) 0x61,
+ (byte) 0x69, (byte) 0x6E, (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65,
+ (byte) 0x77, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0A, (byte) 0x0C, (byte) 0x0A,
+ (byte) 0x47, (byte) 0x6F, (byte) 0x6F, (byte) 0x67, (byte) 0x6C, (byte) 0x65,
+ (byte) 0x20, (byte) 0x49, (byte) 0x6E, (byte) 0x63, (byte) 0x31, (byte) 0x17,
+ (byte) 0x30, (byte) 0x15, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+ (byte) 0x03, (byte) 0x0C, (byte) 0x0E, (byte) 0x77, (byte) 0x77, (byte) 0x77,
+ (byte) 0x2E, (byte) 0x67, (byte) 0x6F, (byte) 0x6F, (byte) 0x67, (byte) 0x6C,
+ (byte) 0x65, (byte) 0x2E, (byte) 0x63, (byte) 0x6F, (byte) 0x6D, (byte) 0x30,
+ (byte) 0x82, (byte) 0x01, (byte) 0x22, (byte) 0x30, (byte) 0x0D, (byte) 0x06,
+ (byte) 0x09, (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7,
+ (byte) 0x0D, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00,
+ (byte) 0x03, (byte) 0x82, (byte) 0x01, (byte) 0x0F, (byte) 0x00, (byte) 0x30,
+ (byte) 0x82, (byte) 0x01, (byte) 0x0A, (byte) 0x02, (byte) 0x82, (byte) 0x01,
+ (byte) 0x01, (byte) 0x00, (byte) 0x9C, (byte) 0x29, (byte) 0xE2, (byte) 0xEB,
+ (byte) 0xA6, (byte) 0x50, (byte) 0x02, (byte) 0xF8, (byte) 0xBA, (byte) 0x1F,
+ (byte) 0xCB, (byte) 0xCB, (byte) 0x7F, (byte) 0xC0, (byte) 0x3C, (byte) 0x2D,
+ (byte) 0x07, (byte) 0xA7, (byte) 0xAE, (byte) 0xEF, (byte) 0x60, (byte) 0x95,
+ (byte) 0xA7, (byte) 0x47, (byte) 0x09, (byte) 0xE1, (byte) 0x5D, (byte) 0xE5,
+ (byte) 0x92, (byte) 0x73, (byte) 0x7A, (byte) 0x86, (byte) 0xE1, (byte) 0xFD,
+ (byte) 0x72, (byte) 0xDE, (byte) 0x85, (byte) 0x16, (byte) 0x4E, (byte) 0xF4,
+ (byte) 0xA1, (byte) 0x12, (byte) 0x21, (byte) 0xFD, (byte) 0x50, (byte) 0x4D,
+ (byte) 0x04, (byte) 0x1C, (byte) 0xFD, (byte) 0xD3, (byte) 0x48, (byte) 0xD8,
+ (byte) 0xCB, (byte) 0xEE, (byte) 0xF5, (byte) 0xD7, (byte) 0x52, (byte) 0x66,
+ (byte) 0xD5, (byte) 0xBF, (byte) 0x22, (byte) 0xA8, (byte) 0xE4, (byte) 0xD0,
+ (byte) 0xF5, (byte) 0xA4, (byte) 0xF9, (byte) 0x0B, (byte) 0xB4, (byte) 0x84,
+ (byte) 0x84, (byte) 0xD7, (byte) 0x10, (byte) 0x14, (byte) 0x9B, (byte) 0xEA,
+ (byte) 0xCC, (byte) 0x7D, (byte) 0xDE, (byte) 0x30, (byte) 0xF9, (byte) 0x1B,
+ (byte) 0xE9, (byte) 0x94, (byte) 0x96, (byte) 0x1A, (byte) 0x6D, (byte) 0x72,
+ (byte) 0x18, (byte) 0x5E, (byte) 0xCC, (byte) 0x09, (byte) 0x04, (byte) 0xC6,
+ (byte) 0x41, (byte) 0x71, (byte) 0x76, (byte) 0xD1, (byte) 0x29, (byte) 0x3F,
+ (byte) 0x3B, (byte) 0x5E, (byte) 0x85, (byte) 0x4A, (byte) 0x30, (byte) 0x32,
+ (byte) 0x9D, (byte) 0x4F, (byte) 0xDB, (byte) 0xDE, (byte) 0x82, (byte) 0x66,
+ (byte) 0x39, (byte) 0xCB, (byte) 0x5C, (byte) 0xC9, (byte) 0xC5, (byte) 0x98,
+ (byte) 0x91, (byte) 0x8D, (byte) 0x32, (byte) 0xB5, (byte) 0x2F, (byte) 0xE4,
+ (byte) 0xDC, (byte) 0xB0, (byte) 0x6E, (byte) 0x21, (byte) 0xDE, (byte) 0x39,
+ (byte) 0x3C, (byte) 0x96, (byte) 0xA8, (byte) 0x32, (byte) 0xA8, (byte) 0xC1,
+ (byte) 0xD1, (byte) 0x6C, (byte) 0xA9, (byte) 0xAA, (byte) 0xF3, (byte) 0x5E,
+ (byte) 0x24, (byte) 0x70, (byte) 0xB7, (byte) 0xAB, (byte) 0x92, (byte) 0x63,
+ (byte) 0x08, (byte) 0x1E, (byte) 0x11, (byte) 0x3F, (byte) 0xB3, (byte) 0x5F,
+ (byte) 0xC7, (byte) 0x98, (byte) 0xE3, (byte) 0x1D, (byte) 0x2A, (byte) 0xC2,
+ (byte) 0x32, (byte) 0x1C, (byte) 0x3C, (byte) 0x95, (byte) 0x43, (byte) 0x16,
+ (byte) 0xE0, (byte) 0x46, (byte) 0x83, (byte) 0xC6, (byte) 0x36, (byte) 0x91,
+ (byte) 0xF4, (byte) 0xA0, (byte) 0xE1, (byte) 0x3C, (byte) 0xB8, (byte) 0x23,
+ (byte) 0xB2, (byte) 0x4F, (byte) 0x8B, (byte) 0x0C, (byte) 0x8C, (byte) 0x92,
+ (byte) 0x45, (byte) 0x24, (byte) 0x43, (byte) 0x68, (byte) 0x24, (byte) 0x06,
+ (byte) 0x84, (byte) 0x43, (byte) 0x96, (byte) 0x2C, (byte) 0x96, (byte) 0x55,
+ (byte) 0x2F, (byte) 0x32, (byte) 0xE8, (byte) 0xE0, (byte) 0xDE, (byte) 0xBF,
+ (byte) 0x52, (byte) 0x57, (byte) 0x2D, (byte) 0x08, (byte) 0x71, (byte) 0x25,
+ (byte) 0x96, (byte) 0x90, (byte) 0x54, (byte) 0x4A, (byte) 0xF1, (byte) 0x0E,
+ (byte) 0xC8, (byte) 0x58, (byte) 0x1A, (byte) 0xE7, (byte) 0x6A, (byte) 0xAB,
+ (byte) 0xA0, (byte) 0x68, (byte) 0xE0, (byte) 0xAD, (byte) 0xFD, (byte) 0xD6,
+ (byte) 0x39, (byte) 0x0F, (byte) 0x76, (byte) 0xE4, (byte) 0xC1, (byte) 0x70,
+ (byte) 0xCD, (byte) 0xDE, (byte) 0x80, (byte) 0x2B, (byte) 0xE2, (byte) 0x1C,
+ (byte) 0x87, (byte) 0x48, (byte) 0x03, (byte) 0x46, (byte) 0x0F, (byte) 0x2C,
+ (byte) 0x41, (byte) 0xF7, (byte) 0x4B, (byte) 0x1F, (byte) 0x93, (byte) 0xAE,
+ (byte) 0x3F, (byte) 0x57, (byte) 0x1F, (byte) 0x2D, (byte) 0xF5, (byte) 0x35,
+ (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xA3,
+ (byte) 0x82, (byte) 0x01, (byte) 0x41, (byte) 0x30, (byte) 0x82, (byte) 0x01,
+ (byte) 0x3D, (byte) 0x30, (byte) 0x1D, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+ (byte) 0x1D, (byte) 0x25, (byte) 0x04, (byte) 0x16, (byte) 0x30, (byte) 0x14,
+ (byte) 0x06, (byte) 0x08, (byte) 0x2B, (byte) 0x06, (byte) 0x01, (byte) 0x05,
+ (byte) 0x05, (byte) 0x07, (byte) 0x03, (byte) 0x01, (byte) 0x06, (byte) 0x08,
+ (byte) 0x2B, (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07,
+ (byte) 0x03, (byte) 0x02, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03,
+ (byte) 0x55, (byte) 0x1D, (byte) 0x11, (byte) 0x04, (byte) 0x12, (byte) 0x30,
+ (byte) 0x10, (byte) 0x82, (byte) 0x0E, (byte) 0x77, (byte) 0x77, (byte) 0x77,
+ (byte) 0x2E, (byte) 0x67, (byte) 0x6F, (byte) 0x6F, (byte) 0x67, (byte) 0x6C,
+ (byte) 0x65, (byte) 0x2E, (byte) 0x63, (byte) 0x6F, (byte) 0x6D, (byte) 0x30,
+ (byte) 0x68, (byte) 0x06, (byte) 0x08, (byte) 0x2B, (byte) 0x06, (byte) 0x01,
+ (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x01, (byte) 0x01, (byte) 0x04,
+ (byte) 0x5C, (byte) 0x30, (byte) 0x5A, (byte) 0x30, (byte) 0x2B, (byte) 0x06,
+ (byte) 0x08, (byte) 0x2B, (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05,
+ (byte) 0x07, (byte) 0x30, (byte) 0x02, (byte) 0x86, (byte) 0x1F, (byte) 0x68,
+ (byte) 0x74, (byte) 0x74, (byte) 0x70, (byte) 0x3A, (byte) 0x2F, (byte) 0x2F,
+ (byte) 0x70, (byte) 0x6B, (byte) 0x69, (byte) 0x2E, (byte) 0x67, (byte) 0x6F,
+ (byte) 0x6F, (byte) 0x67, (byte) 0x6C, (byte) 0x65, (byte) 0x2E, (byte) 0x63,
+ (byte) 0x6F, (byte) 0x6D, (byte) 0x2F, (byte) 0x47, (byte) 0x49, (byte) 0x41,
+ (byte) 0x47, (byte) 0x32, (byte) 0x2E, (byte) 0x63, (byte) 0x72, (byte) 0x74,
+ (byte) 0x30, (byte) 0x2B, (byte) 0x06, (byte) 0x08, (byte) 0x2B, (byte) 0x06,
+ (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x30, (byte) 0x01,
+ (byte) 0x86, (byte) 0x1F, (byte) 0x68, (byte) 0x74, (byte) 0x74, (byte) 0x70,
+ (byte) 0x3A, (byte) 0x2F, (byte) 0x2F, (byte) 0x63, (byte) 0x6C, (byte) 0x69,
+ (byte) 0x65, (byte) 0x6E, (byte) 0x74, (byte) 0x73, (byte) 0x31, (byte) 0x2E,
+ (byte) 0x67, (byte) 0x6F, (byte) 0x6F, (byte) 0x67, (byte) 0x6C, (byte) 0x65,
+ (byte) 0x2E, (byte) 0x63, (byte) 0x6F, (byte) 0x6D, (byte) 0x2F, (byte) 0x6F,
+ (byte) 0x63, (byte) 0x73, (byte) 0x70, (byte) 0x30, (byte) 0x1D, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x1D, (byte) 0x0E, (byte) 0x04, (byte) 0x16,
+ (byte) 0x04, (byte) 0x14, (byte) 0x3B, (byte) 0x6B, (byte) 0xE0, (byte) 0x9C,
+ (byte) 0xC6, (byte) 0xC6, (byte) 0x41, (byte) 0xC8, (byte) 0xEA, (byte) 0x5C,
+ (byte) 0xFB, (byte) 0x1A, (byte) 0x58, (byte) 0x15, (byte) 0xC2, (byte) 0x1B,
+ (byte) 0x9D, (byte) 0x43, (byte) 0x19, (byte) 0x85, (byte) 0x30, (byte) 0x0C,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1D, (byte) 0x13, (byte) 0x01,
+ (byte) 0x01, (byte) 0xFF, (byte) 0x04, (byte) 0x02, (byte) 0x30, (byte) 0x00,
+ (byte) 0x30, (byte) 0x1F, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1D,
+ (byte) 0x23, (byte) 0x04, (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x80,
+ (byte) 0x14, (byte) 0x4A, (byte) 0xDD, (byte) 0x06, (byte) 0x16, (byte) 0x1B,
+ (byte) 0xBC, (byte) 0xF6, (byte) 0x68, (byte) 0xB5, (byte) 0x76, (byte) 0xF5,
+ (byte) 0x81, (byte) 0xB6, (byte) 0xBB, (byte) 0x62, (byte) 0x1A, (byte) 0xBA,
+ (byte) 0x5A, (byte) 0x81, (byte) 0x2F, (byte) 0x30, (byte) 0x17, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x1D, (byte) 0x20, (byte) 0x04, (byte) 0x10,
+ (byte) 0x30, (byte) 0x0E, (byte) 0x30, (byte) 0x0C, (byte) 0x06, (byte) 0x0A,
+ (byte) 0x2B, (byte) 0x06, (byte) 0x01, (byte) 0x04, (byte) 0x01, (byte) 0xD6,
+ (byte) 0x79, (byte) 0x02, (byte) 0x05, (byte) 0x01, (byte) 0x30, (byte) 0x30,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1D, (byte) 0x1F, (byte) 0x04,
+ (byte) 0x29, (byte) 0x30, (byte) 0x27, (byte) 0x30, (byte) 0x25, (byte) 0xA0,
+ (byte) 0x23, (byte) 0xA0, (byte) 0x21, (byte) 0x86, (byte) 0x1F, (byte) 0x68,
+ (byte) 0x74, (byte) 0x74, (byte) 0x70, (byte) 0x3A, (byte) 0x2F, (byte) 0x2F,
+ (byte) 0x70, (byte) 0x6B, (byte) 0x69, (byte) 0x2E, (byte) 0x67, (byte) 0x6F,
+ (byte) 0x6F, (byte) 0x67, (byte) 0x6C, (byte) 0x65, (byte) 0x2E, (byte) 0x63,
+ (byte) 0x6F, (byte) 0x6D, (byte) 0x2F, (byte) 0x47, (byte) 0x49, (byte) 0x41,
+ (byte) 0x47, (byte) 0x32, (byte) 0x2E, (byte) 0x63, (byte) 0x72, (byte) 0x6C,
+ (byte) 0x30, (byte) 0x0D, (byte) 0x06, (byte) 0x09, (byte) 0x2A, (byte) 0x86,
+ (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01, (byte) 0x01,
+ (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x82, (byte) 0x01,
+ (byte) 0x01, (byte) 0x00, (byte) 0x9A, (byte) 0x39, (byte) 0x70, (byte) 0x81,
+ (byte) 0x76, (byte) 0x8A, (byte) 0x94, (byte) 0xCB, (byte) 0x96, (byte) 0xF1,
+ (byte) 0xCA, (byte) 0xAF, (byte) 0x96, (byte) 0xAE, (byte) 0x1D, (byte) 0x73,
+ (byte) 0xB3, (byte) 0x2C, (byte) 0x82, (byte) 0x16, (byte) 0x29, (byte) 0xB5,
+ (byte) 0x3C, (byte) 0x7E, (byte) 0x55, (byte) 0x53, (byte) 0x6F, (byte) 0xB2,
+ (byte) 0xBC, (byte) 0x34, (byte) 0x96, (byte) 0xAE, (byte) 0x00, (byte) 0xD8,
+ (byte) 0xF2, (byte) 0x26, (byte) 0xD1, (byte) 0x18, (byte) 0x99, (byte) 0x9F,
+ (byte) 0x7D, (byte) 0xFD, (byte) 0xEB, (byte) 0xE0, (byte) 0xBB, (byte) 0x9D,
+ (byte) 0xE6, (byte) 0x46, (byte) 0xA5, (byte) 0x74, (byte) 0xAB, (byte) 0x3D,
+ (byte) 0x93, (byte) 0xC6, (byte) 0x25, (byte) 0x28, (byte) 0x3D, (byte) 0xC8,
+ (byte) 0x4C, (byte) 0x6E, (byte) 0xCF, (byte) 0xD1, (byte) 0x84, (byte) 0xFF,
+ (byte) 0x46, (byte) 0x4F, (byte) 0x21, (byte) 0x2E, (byte) 0x07, (byte) 0xC4,
+ (byte) 0xB8, (byte) 0xB7, (byte) 0x2A, (byte) 0xE5, (byte) 0xC7, (byte) 0x34,
+ (byte) 0xC6, (byte) 0xA9, (byte) 0x84, (byte) 0xE3, (byte) 0x6C, (byte) 0x49,
+ (byte) 0xF8, (byte) 0x4A, (byte) 0x36, (byte) 0xBB, (byte) 0x3A, (byte) 0xBD,
+ (byte) 0xAD, (byte) 0x8A, (byte) 0x2B, (byte) 0x73, (byte) 0x97, (byte) 0xA6,
+ (byte) 0x30, (byte) 0x2C, (byte) 0x5F, (byte) 0xE4, (byte) 0xBD, (byte) 0x13,
+ (byte) 0x24, (byte) 0xE5, (byte) 0xD9, (byte) 0xA8, (byte) 0x74, (byte) 0x29,
+ (byte) 0x38, (byte) 0x47, (byte) 0x2E, (byte) 0xA6, (byte) 0xD6, (byte) 0x50,
+ (byte) 0xE0, (byte) 0xE8, (byte) 0xDD, (byte) 0x60, (byte) 0xC7, (byte) 0xD2,
+ (byte) 0xC6, (byte) 0x4E, (byte) 0x54, (byte) 0xCE, (byte) 0xE7, (byte) 0x94,
+ (byte) 0x84, (byte) 0x0D, (byte) 0xE8, (byte) 0x81, (byte) 0x92, (byte) 0x91,
+ (byte) 0x71, (byte) 0x19, (byte) 0x1D, (byte) 0x07, (byte) 0x75, (byte) 0x9E,
+ (byte) 0x59, (byte) 0x1A, (byte) 0x7E, (byte) 0x9D, (byte) 0x84, (byte) 0x61,
+ (byte) 0xC7, (byte) 0x84, (byte) 0xAD, (byte) 0xA3, (byte) 0x6A, (byte) 0xED,
+ (byte) 0xD8, (byte) 0x0D, (byte) 0x0C, (byte) 0x2A, (byte) 0x66, (byte) 0x3D,
+ (byte) 0xD7, (byte) 0xAE, (byte) 0x46, (byte) 0x1D, (byte) 0x4A, (byte) 0x8C,
+ (byte) 0x2B, (byte) 0xD6, (byte) 0x1A, (byte) 0x69, (byte) 0x71, (byte) 0xC3,
+ (byte) 0x5E, (byte) 0xA0, (byte) 0x6E, (byte) 0xED, (byte) 0x27, (byte) 0x9F,
+ (byte) 0xAF, (byte) 0x5B, (byte) 0x92, (byte) 0xA0, (byte) 0x03, (byte) 0xFD,
+ (byte) 0x83, (byte) 0x22, (byte) 0x09, (byte) 0x29, (byte) 0xE8, (byte) 0xA1,
+ (byte) 0x32, (byte) 0x2B, (byte) 0xEC, (byte) 0x1A, (byte) 0xA2, (byte) 0x75,
+ (byte) 0x4C, (byte) 0x3E, (byte) 0x99, (byte) 0x71, (byte) 0xCE, (byte) 0x8B,
+ (byte) 0x31, (byte) 0xEF, (byte) 0x9D, (byte) 0x37, (byte) 0x63, (byte) 0xFC,
+ (byte) 0x71, (byte) 0x91, (byte) 0x10, (byte) 0x1E, (byte) 0xD0, (byte) 0xF5,
+ (byte) 0xCB, (byte) 0x6F, (byte) 0x7A, (byte) 0xBA, (byte) 0x5E, (byte) 0x0C,
+ (byte) 0x8A, (byte) 0xFA, (byte) 0xA4, (byte) 0xDE, (byte) 0x36, (byte) 0xAD,
+ (byte) 0x51, (byte) 0x52, (byte) 0xFC, (byte) 0xFE, (byte) 0x10, (byte) 0xB0,
+ (byte) 0x81, (byte) 0xC8, (byte) 0x7D, (byte) 0x03, (byte) 0xC3, (byte) 0xB8,
+ (byte) 0x3C, (byte) 0x66, (byte) 0x6A, (byte) 0xF5, (byte) 0x6A, (byte) 0x81,
+ (byte) 0x7C, (byte) 0x45, (byte) 0xA6, (byte) 0x23, (byte) 0x21, (byte) 0xE1,
+ (byte) 0xD5, (byte) 0xD3, (byte) 0xED, (byte) 0x6E, (byte) 0x0D, (byte) 0x65,
+ (byte) 0x39, (byte) 0x77, (byte) 0x58, (byte) 0x09, (byte) 0x6B, (byte) 0x63,
+ (byte) 0xA4, (byte) 0x02, (byte) 0x04, (byte) 0x00, (byte) 0xA5, (byte) 0x03,
+ (byte) 0x02, (byte) 0x01, (byte) 0x14, (byte) 0xA9, (byte) 0x05, (byte) 0x02,
+ (byte) 0x03, (byte) 0x01, (byte) 0x89, (byte) 0xC0, (byte) 0xAA, (byte) 0x81,
+ (byte) 0xA7, (byte) 0x04, (byte) 0x81, (byte) 0xA4, (byte) 0x1C, (byte) 0x14,
+ (byte) 0x42, (byte) 0xFA, (byte) 0x1E, (byte) 0x3A, (byte) 0x4D, (byte) 0x0A,
+ (byte) 0x83, (byte) 0x7E, (byte) 0x92, (byte) 0x61, (byte) 0x37, (byte) 0x0B,
+ (byte) 0x12, (byte) 0x45, (byte) 0xEA, (byte) 0x2B, (byte) 0x03, (byte) 0x81,
+ (byte) 0x7C, (byte) 0x5F, (byte) 0x6F, (byte) 0x13, (byte) 0x82, (byte) 0x97,
+ (byte) 0xD0, (byte) 0xDC, (byte) 0x5E, (byte) 0x2F, (byte) 0x08, (byte) 0xDC,
+ (byte) 0x0D, (byte) 0x3A, (byte) 0x6C, (byte) 0xBA, (byte) 0x1D, (byte) 0xEA,
+ (byte) 0x5C, (byte) 0x46, (byte) 0x99, (byte) 0xF7, (byte) 0xDD, (byte) 0xAB,
+ (byte) 0xD4, (byte) 0xDD, (byte) 0xFC, (byte) 0x54, (byte) 0x37, (byte) 0x32,
+ (byte) 0x4B, (byte) 0xA3, (byte) 0xFB, (byte) 0x23, (byte) 0xA1, (byte) 0xC1,
+ (byte) 0x60, (byte) 0xDF, (byte) 0x41, (byte) 0xB0, (byte) 0xD1, (byte) 0xCC,
+ (byte) 0xDF, (byte) 0xAD, (byte) 0xB3, (byte) 0x66, (byte) 0x76, (byte) 0x36,
+ (byte) 0xEC, (byte) 0x6A, (byte) 0x53, (byte) 0xC3, (byte) 0xE2, (byte) 0xB0,
+ (byte) 0x77, (byte) 0xBE, (byte) 0x75, (byte) 0x08, (byte) 0xBA, (byte) 0x17,
+ (byte) 0x14, (byte) 0xFA, (byte) 0x1A, (byte) 0x30, (byte) 0xE7, (byte) 0xB9,
+ (byte) 0xED, (byte) 0xD6, (byte) 0xC1, (byte) 0xA5, (byte) 0x7A, (byte) 0x2B,
+ (byte) 0xA3, (byte) 0xA3, (byte) 0xDD, (byte) 0xDC, (byte) 0x14, (byte) 0xDB,
+ (byte) 0x7F, (byte) 0xF4, (byte) 0xF3, (byte) 0xAF, (byte) 0xCF, (byte) 0x0A,
+ (byte) 0xD3, (byte) 0xAC, (byte) 0x84, (byte) 0x39, (byte) 0x30, (byte) 0xCA,
+ (byte) 0x3C, (byte) 0xD8, (byte) 0xF7, (byte) 0xFA, (byte) 0x29, (byte) 0xDB,
+ (byte) 0x31, (byte) 0xA5, (byte) 0x62, (byte) 0x82, (byte) 0xD2, (byte) 0xB8,
+ (byte) 0x3C, (byte) 0xBC, (byte) 0x8F, (byte) 0xAB, (byte) 0xE4, (byte) 0xE8,
+ (byte) 0xA7, (byte) 0x2C, (byte) 0xEF, (byte) 0xC7, (byte) 0xD5, (byte) 0x12,
+ (byte) 0x16, (byte) 0x04, (byte) 0x6F, (byte) 0xCA, (byte) 0xEA, (byte) 0x31,
+ (byte) 0x9F, (byte) 0x41, (byte) 0xE0, (byte) 0x6F, (byte) 0xE4, (byte) 0x74,
+ (byte) 0x03, (byte) 0x78, (byte) 0xFA, (byte) 0x48, (byte) 0xB4, (byte) 0x6E,
+ (byte) 0xC8, (byte) 0xE7, (byte) 0x40, (byte) 0x8B, (byte) 0x88, (byte) 0x2F,
+ (byte) 0xED, (byte) 0x8E, (byte) 0x68, (byte) 0x96, (byte) 0x2C, (byte) 0xA7,
+ (byte) 0xB6, (byte) 0x03, (byte) 0x01, (byte) 0x01, (byte) 0x00};
+
+ private static final byte[] DUMMY_CERT =
+ new byte[] {(byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x58, (byte) 0x30,
+ (byte) 0x82, (byte) 0x01, (byte) 0xC1, (byte) 0xA0, (byte) 0x03, (byte) 0x02,
+ (byte) 0x01, (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0xFB,
+ (byte) 0xB0, (byte) 0x4C, (byte) 0x2E, (byte) 0xAB, (byte) 0x10, (byte) 0x9B,
+ (byte) 0x0C, (byte) 0x30, (byte) 0x0D, (byte) 0x06, (byte) 0x09, (byte) 0x2A,
+ (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01,
+ (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x45,
+ (byte) 0x31, (byte) 0x0B, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03,
+ (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41,
+ (byte) 0x55, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0C, (byte) 0x0A,
+ (byte) 0x53, (byte) 0x6F, (byte) 0x6D, (byte) 0x65, (byte) 0x2D, (byte) 0x53,
+ (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x21,
+ (byte) 0x30, (byte) 0x1F, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+ (byte) 0x0A, (byte) 0x0C, (byte) 0x18, (byte) 0x49, (byte) 0x6E, (byte) 0x74,
+ (byte) 0x65, (byte) 0x72, (byte) 0x6E, (byte) 0x65, (byte) 0x74, (byte) 0x20,
+ (byte) 0x57, (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69, (byte) 0x74,
+ (byte) 0x73, (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79, (byte) 0x20,
+ (byte) 0x4C, (byte) 0x74, (byte) 0x64, (byte) 0x30, (byte) 0x1E, (byte) 0x17,
+ (byte) 0x0D, (byte) 0x31, (byte) 0x34, (byte) 0x30, (byte) 0x34, (byte) 0x32,
+ (byte) 0x33, (byte) 0x32, (byte) 0x30, (byte) 0x35, (byte) 0x30, (byte) 0x34,
+ (byte) 0x30, (byte) 0x5A, (byte) 0x17, (byte) 0x0D, (byte) 0x31, (byte) 0x37,
+ (byte) 0x30, (byte) 0x34, (byte) 0x32, (byte) 0x32, (byte) 0x32, (byte) 0x30,
+ (byte) 0x35, (byte) 0x30, (byte) 0x34, (byte) 0x30, (byte) 0x5A, (byte) 0x30,
+ (byte) 0x45, (byte) 0x31, (byte) 0x0B, (byte) 0x30, (byte) 0x09, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02,
+ (byte) 0x41, (byte) 0x55, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0C,
+ (byte) 0x0A, (byte) 0x53, (byte) 0x6F, (byte) 0x6D, (byte) 0x65, (byte) 0x2D,
+ (byte) 0x53, (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31,
+ (byte) 0x21, (byte) 0x30, (byte) 0x1F, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+ (byte) 0x04, (byte) 0x0A, (byte) 0x0C, (byte) 0x18, (byte) 0x49, (byte) 0x6E,
+ (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x6E, (byte) 0x65, (byte) 0x74,
+ (byte) 0x20, (byte) 0x57, (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69,
+ (byte) 0x74, (byte) 0x73, (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79,
+ (byte) 0x20, (byte) 0x4C, (byte) 0x74, (byte) 0x64, (byte) 0x30, (byte) 0x81,
+ (byte) 0x9F, (byte) 0x30, (byte) 0x0D, (byte) 0x06, (byte) 0x09, (byte) 0x2A,
+ (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01,
+ (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81,
+ (byte) 0x8D, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89, (byte) 0x02,
+ (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xD8, (byte) 0x2B, (byte) 0xC8,
+ (byte) 0xA6, (byte) 0x32, (byte) 0xE4, (byte) 0x62, (byte) 0xFF, (byte) 0x4D,
+ (byte) 0xF3, (byte) 0xD0, (byte) 0xAD, (byte) 0x59, (byte) 0x8B, (byte) 0x45,
+ (byte) 0xA7, (byte) 0xBD, (byte) 0xF1, (byte) 0x47, (byte) 0xBF, (byte) 0x09,
+ (byte) 0x58, (byte) 0x7B, (byte) 0x22, (byte) 0xBD, (byte) 0x35, (byte) 0xAE,
+ (byte) 0x97, (byte) 0x25, (byte) 0x86, (byte) 0x94, (byte) 0xA0, (byte) 0x80,
+ (byte) 0xC0, (byte) 0xB4, (byte) 0x1F, (byte) 0x76, (byte) 0x91, (byte) 0x67,
+ (byte) 0x46, (byte) 0x31, (byte) 0xD0, (byte) 0x10, (byte) 0x84, (byte) 0xB7,
+ (byte) 0x22, (byte) 0x1E, (byte) 0x70, (byte) 0x23, (byte) 0x91, (byte) 0x72,
+ (byte) 0xC8, (byte) 0xE9, (byte) 0x6D, (byte) 0x79, (byte) 0x3A, (byte) 0x85,
+ (byte) 0x77, (byte) 0x80, (byte) 0x0F, (byte) 0xC4, (byte) 0x95, (byte) 0x16,
+ (byte) 0x75, (byte) 0xC5, (byte) 0x4A, (byte) 0x71, (byte) 0x4C, (byte) 0xC8,
+ (byte) 0x63, (byte) 0x3F, (byte) 0xA3, (byte) 0xF2, (byte) 0x63, (byte) 0x9C,
+ (byte) 0x2A, (byte) 0x4F, (byte) 0x9A, (byte) 0xFA, (byte) 0xCB, (byte) 0xC1,
+ (byte) 0x71, (byte) 0x6E, (byte) 0x28, (byte) 0x85, (byte) 0x28, (byte) 0xA0,
+ (byte) 0x27, (byte) 0x1E, (byte) 0x65, (byte) 0x1C, (byte) 0xAE, (byte) 0x07,
+ (byte) 0xD5, (byte) 0x5B, (byte) 0x6F, (byte) 0x2D, (byte) 0x43, (byte) 0xED,
+ (byte) 0x2B, (byte) 0x90, (byte) 0xB1, (byte) 0x8C, (byte) 0xAF, (byte) 0x24,
+ (byte) 0x6D, (byte) 0xAE, (byte) 0xE9, (byte) 0x17, (byte) 0x3A, (byte) 0x05,
+ (byte) 0xC1, (byte) 0xBF, (byte) 0xB8, (byte) 0x1C, (byte) 0xAE, (byte) 0x65,
+ (byte) 0x3B, (byte) 0x1B, (byte) 0x58, (byte) 0xC2, (byte) 0xD9, (byte) 0xAE,
+ (byte) 0xD6, (byte) 0xAA, (byte) 0x67, (byte) 0x88, (byte) 0xF1, (byte) 0x02,
+ (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xA3, (byte) 0x50,
+ (byte) 0x30, (byte) 0x4E, (byte) 0x30, (byte) 0x1D, (byte) 0x06, (byte) 0x03,
+ (byte) 0x55, (byte) 0x1D, (byte) 0x0E, (byte) 0x04, (byte) 0x16, (byte) 0x04,
+ (byte) 0x14, (byte) 0x8B, (byte) 0x75, (byte) 0xD5, (byte) 0xAC, (byte) 0xCB,
+ (byte) 0x08, (byte) 0xBE, (byte) 0x0E, (byte) 0x1F, (byte) 0x65, (byte) 0xB7,
+ (byte) 0xFA, (byte) 0x56, (byte) 0xBE, (byte) 0x6C, (byte) 0xA7, (byte) 0x75,
+ (byte) 0xDA, (byte) 0x85, (byte) 0xAF, (byte) 0x30, (byte) 0x1F, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x1D, (byte) 0x23, (byte) 0x04, (byte) 0x18,
+ (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x8B, (byte) 0x75,
+ (byte) 0xD5, (byte) 0xAC, (byte) 0xCB, (byte) 0x08, (byte) 0xBE, (byte) 0x0E,
+ (byte) 0x1F, (byte) 0x65, (byte) 0xB7, (byte) 0xFA, (byte) 0x56, (byte) 0xBE,
+ (byte) 0x6C, (byte) 0xA7, (byte) 0x75, (byte) 0xDA, (byte) 0x85, (byte) 0xAF,
+ (byte) 0x30, (byte) 0x0C, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1D,
+ (byte) 0x13, (byte) 0x04, (byte) 0x05, (byte) 0x30, (byte) 0x03, (byte) 0x01,
+ (byte) 0x01, (byte) 0xFF, (byte) 0x30, (byte) 0x0D, (byte) 0x06, (byte) 0x09,
+ (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D,
+ (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x03,
+ (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x3B, (byte) 0xE8, (byte) 0x78,
+ (byte) 0x6D, (byte) 0x95, (byte) 0xD6, (byte) 0x3D, (byte) 0x6A, (byte) 0xF7,
+ (byte) 0x13, (byte) 0x19, (byte) 0x2C, (byte) 0x1B, (byte) 0xC2, (byte) 0x88,
+ (byte) 0xAE, (byte) 0x22, (byte) 0xAB, (byte) 0xF4, (byte) 0x8D, (byte) 0x32,
+ (byte) 0xF5, (byte) 0x7C, (byte) 0x71, (byte) 0x67, (byte) 0xCF, (byte) 0x2D,
+ (byte) 0xD1, (byte) 0x1C, (byte) 0xC2, (byte) 0xC3, (byte) 0x87, (byte) 0xE2,
+ (byte) 0xE9, (byte) 0xBE, (byte) 0x89, (byte) 0x5C, (byte) 0xE4, (byte) 0x34,
+ (byte) 0xAB, (byte) 0x48, (byte) 0x91, (byte) 0xC2, (byte) 0x3F, (byte) 0x95,
+ (byte) 0xAE, (byte) 0x2B, (byte) 0x47, (byte) 0x9E, (byte) 0x25, (byte) 0x78,
+ (byte) 0x6B, (byte) 0x4F, (byte) 0x9A, (byte) 0x10, (byte) 0xA4, (byte) 0x72,
+ (byte) 0xFD, (byte) 0xCF, (byte) 0xF7, (byte) 0x02, (byte) 0x0C, (byte) 0xB0,
+ (byte) 0x0A, (byte) 0x08, (byte) 0xA4, (byte) 0x5A, (byte) 0xE2, (byte) 0xE5,
+ (byte) 0x74, (byte) 0x7E, (byte) 0x11, (byte) 0x1D, (byte) 0x39, (byte) 0x60,
+ (byte) 0x6A, (byte) 0xC9, (byte) 0x1F, (byte) 0x69, (byte) 0xF3, (byte) 0x2E,
+ (byte) 0x63, (byte) 0x26, (byte) 0xDC, (byte) 0x9E, (byte) 0xEF, (byte) 0x6B,
+ (byte) 0x7A, (byte) 0x0A, (byte) 0xE1, (byte) 0x54, (byte) 0x57, (byte) 0x98,
+ (byte) 0xAA, (byte) 0x72, (byte) 0x91, (byte) 0x78, (byte) 0x04, (byte) 0x7E,
+ (byte) 0x1F, (byte) 0x8F, (byte) 0x65, (byte) 0x4D, (byte) 0x1F, (byte) 0x0B,
+ (byte) 0x12, (byte) 0xAC, (byte) 0x9C, (byte) 0x24, (byte) 0x0F, (byte) 0x84,
+ (byte) 0x14, (byte) 0x1A, (byte) 0x55, (byte) 0x2D, (byte) 0x1F, (byte) 0xBB,
+ (byte) 0xF0, (byte) 0x9D, (byte) 0x09, (byte) 0xB2, (byte) 0x08, (byte) 0x5C,
+ (byte) 0x59, (byte) 0x32, (byte) 0x65, (byte) 0x80, (byte) 0x26};
+
+ private static final byte[] DUMMY_OCSP_DATA = new byte[1];
+
+ private static final byte[] DUMMY_TLS_SCT_DATA = new byte[1];
+
+ private static TestSessionBuilder getType1() {
+ return new TestSessionBuilder()
+ .setType(0x01)
+ .setSessionData(kOpenSSLSession)
+ .addCertificate(DUMMY_CERT);
+ }
+
+ private static TestSessionBuilder getType2() {
+ return new TestSessionBuilder()
+ .setType(0x02)
+ .setSessionData(kOpenSSLSession)
+ .addCertificate(DUMMY_CERT)
+ .addOcspData(DUMMY_OCSP_DATA);
+ }
+
+ private static TestSessionBuilder getType3() {
+ return new TestSessionBuilder()
+ .setType(0x03)
+ .setSessionData(kOpenSSLSession)
+ .addCertificate(DUMMY_CERT)
+ .addOcspData(DUMMY_OCSP_DATA)
+ .setTlsSctData(DUMMY_TLS_SCT_DATA);
+ }
+
+ @Test
+ public void toSession_EmptyArray_Invalid_Failure() throws Exception {
+ assertInvalidSession(new byte[0]);
+ }
+
+ @Test
+ public void toSession_Type1_Valid_Success() throws Exception {
+ assertValidSession(getType1().build());
+ }
+
+ @Test
+ public void toSession_Type2_Valid_Success() throws Exception {
+ assertValidSession(getType2().build());
+ }
+
+ @Test
+ public void toSession_Type3_Valid_Success() throws Exception {
+ assertValidSession(getType3().build());
+ }
+
+ private static void assertValidSession(byte[] data) {
+ assertNotNull(NativeSslSession.newInstance(null, data, "www.google.com", 443));
+ }
+
+ @Test
+ public void toSession_Type3_Truncated_Failure() throws Exception {
+ assertTruncatedSessionFails(getType3().build());
+ }
+
+ private static void assertInvalidSession(byte[] data) {
+ assertNull(NativeSslSession.newInstance(null, data, "www.google.com", 443));
+ }
+
+ private static void check_reserializableFromByteArray_roundTrip(
+ byte[] data, byte[] expectedTrailingBytesAfterReserialization) throws Exception {
+ NativeSslSession session =
+ NativeSslSession.newInstance(null, data, "www.example.com", 12345);
+ byte[] sessionBytes = session.toBytes();
+
+ NativeSslSession session2 =
+ NativeSslSession.newInstance(null, sessionBytes, "www.example.com", 12345);
+ byte[] sessionBytes2 = session2.toBytes();
+
+ assertSSLSessionEquals(session, session2);
+ assertByteArrayEquals(sessionBytes, sessionBytes2);
+
+ assertEquals("www.example.com", session.getPeerHost());
+ assertEquals(12345, session.getPeerPort());
+ assertTrue(sessionBytes.length >= data.length);
+
+ byte[] expectedReserializedData = concat(data, expectedTrailingBytesAfterReserialization);
+ // AbstractSessionContext.toBytes() always writes type 3 == OPEN_SSL_WITH_TLS_SCT
+ expectedReserializedData[3] = 3;
+ assertByteArrayEquals(expectedReserializedData, sessionBytes);
+ }
+
+ @Test
+ public void toSession_UnknownType_Failure() throws Exception {
+ assertInvalidSession(getType3().setType((byte) 0xEE).build());
+ }
+
+ @Test
+ public void toSession_CertificatesCountTooLarge_Failure() throws Exception {
+ assertInvalidSession(getType3().setCertificatesLength(16834).build());
+ }
+
+ @Test
+ public void toSession_CertificatesCountNegative_Failure() throws Exception {
+ assertInvalidSession(getType3().setCertificatesLength(-1).build());
+ }
+
+ @Test
+ public void toSession_CertificateSizeNegative_Failure() throws Exception {
+ assertInvalidSession(getType3().setCertificateLength(0, -1).build());
+ }
+
+ @Test
+ public void toSession_CertificateSizeTooLarge_Failure() throws Exception {
+ assertInvalidSession(getType3().setCertificateLength(0, 16834).build());
+ }
+
+ @Test
+ public void toSession_SessionDataSizeTooLarge_Failure() throws Exception {
+ assertInvalidSession(getType3().setSessionDataLength(16834).build());
+ }
+
+ @Test
+ public void toSession_SessionDataSizeNegative_Failure() throws Exception {
+ assertInvalidSession(getType3().setSessionDataLength(-1).build());
+ }
+
+ @Test
+ public void toSession_OcspDatasNumberTooMany_Failure() throws Exception {
+ assertInvalidSession(getType3().setOcspDatasLength(32791).build());
+ }
+
+ @Test
+ public void toSession_OcspDatasNumberNegative_Failure() throws Exception {
+ assertInvalidSession(getType3().setOcspDatasLength(-1).build());
+ }
+
+ @Test
+ public void toSession_OcspDataSizeNegative_Failure() throws Exception {
+ assertInvalidSession(getType3().setOcspDataLength(0, -1).build());
+ }
+
+ @Test
+ public void toSession_OcspDataSizeTooLarge_Failure() throws Exception {
+ assertInvalidSession(getType3().setOcspDataLength(0, 92948).build());
+ }
+
+ @Test
+ public void toSession_TlsSctDataSizeNegative_Failure() throws Exception {
+ assertInvalidSession(getType3().setTlsSctDataLength(-1).build());
+ }
+
+ @Test
+ public void toSession_TlsSctDataSizeTooLarge_Failure() throws Exception {
+ assertInvalidSession(getType3().setTlsSctDataLength(931148).build());
+ }
+
+ @Test
+ public void toSession_Type2OcspDataEmpty_Success() throws Exception {
+ assertValidSession(getType1().setType(0x02).setOcspDataEmpty().build());
+ }
+
+ @Test
+ public void toSession_Type3TlsSctDataEmpty_Success() throws Exception {
+ assertValidSession(getType2().setType(0x03).setTlsSctDataEmpty().build());
+ }
+
+ @Test
+ public void toSession_Type3OcspAndTlsSctDataEmpty_Success() throws Exception {
+ assertValidSession(
+ getType1().setType(0x03).setOcspDataEmpty().setTlsSctDataEmpty().build());
+ }
+
+ private static void assertTrailingDataFails(byte[] validSession) {
+ byte[] invalidSession = new byte[validSession.length + 1];
+ System.arraycopy(validSession, 0, invalidSession, 0, validSession.length);
+ assertInvalidSession(invalidSession);
+ }
+
+ @Test
+ public void toSession_Type1TrailingData_Failure() throws Exception {
+ assertTrailingDataFails(getType1().build());
+ }
+
+ @Test
+ public void toSession_Type2TrailingData_Failure() throws Exception {
+ assertTrailingDataFails(getType2().build());
+ }
+
+ @Test
+ public void toSession_Type3TrailingData_Failure() throws Exception {
+ assertTrailingDataFails(getType3().build());
+ }
+
+ @Test
+ public void test_reserializableFromByteArray_roundTrip_type1() throws Exception {
+ // Converting OPEN_SSL (type 1) -> OPEN_SSL_WITH_TLS_SCT (type 3) adds
+ // eight zero-bytes:
+ // 1.) 4 bytes for int32 value 0 == countOcspResponses
+ // 2.) 4 bytes for int32 value 0 == tlsSctDataLength
+ // since OPEN_SSL (type 1) cannot contain OSCP or TLS SCT data.
+ check_reserializableFromByteArray_roundTrip(getType1().build(), new byte[8]);
+ }
+
+ @Test
+ public void test_reserializableFromByteArray_roundTrip_type2() throws Exception {
+ // Converting OPEN_SSL_WITH_OCSP (type 2) -> OPEN_SSL_WITH_TLS_SCT (type 3) adds
+ // four zero-bytes for int32 value 0 == tlsSctDataLength
+ // since OPEN_SSL_WITH_OCSP (type 2) cannot contain TLS SCT data.
+ check_reserializableFromByteArray_roundTrip(getType2().build(), new byte[4]);
+ }
+
+ @Test
+ public void test_reserializableFromByteArray_roundTrip_type3() throws Exception {
+ check_reserializableFromByteArray_roundTrip(getType3().build(), new byte[0]);
+ }
+
+ private static void assertSSLSessionEquals(NativeSslSession a, NativeSslSession b)
+ throws Exception {
+ assertEquals(a.getCipherSuite(), b.getCipherSuite());
+ assertByteArrayEquals(a.getId(), b.getId());
+ assertEquals(a.getPeerHost(), b.getPeerHost());
+ assertEquals(a.getPeerPort(), b.getPeerPort());
+ assertEquals(a.getProtocol(), b.getProtocol());
+ }
+
+ private static byte[] concat(byte[] a, byte[] b) {
+ byte[] result = new byte[a.length + b.length];
+ System.arraycopy(a, 0, result, 0, a.length);
+ System.arraycopy(b, 0, result, a.length, b.length);
+ return result;
+ }
+
+ private void assertTruncatedSessionFails(byte[] validSession) {
+ for (int i = 0; i < validSession.length - 1; i++) {
+ byte[] truncatedSession = new byte[i];
+ System.arraycopy(validSession, 0, truncatedSession, 0, i);
+ assertNull("Truncating to " + i + " bytes of " + validSession.length
+ + " should not succeed",
+ NativeSslSession.newInstance(null, truncatedSession, "www.google.com", 443));
+ }
+ }
+
+ private static void assertByteArrayEquals(byte[] expected, byte[] actual) {
+ // If running on OpenJDK 8+, could use java.util.Base64 for better failure messages:
+ // assertEquals(Base64.encode(expected), Base64.encode(actual));
+ assertTrue("Expected " + Arrays.toString(expected) + ", got " + Arrays.toString(actual),
+ Arrays.equals(expected, actual));
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/OpenSSLKeyTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/OpenSSLKeyTest.java
new file mode 100644
index 0000000..51e7077
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/OpenSSLKeyTest.java
@@ -0,0 +1,70 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.ByteArrayInputStream;
+import java.math.BigInteger;
+import junit.framework.TestCase;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class OpenSSLKeyTest extends TestCase {
+ static final String RSA_PUBLIC_KEY =
+ "-----BEGIN PUBLIC KEY-----\n" +
+ "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAOHsK2E2FLYfEMWEVH/rJMTqDZLLLysh\n" +
+ "AH5odcfhYdF9xvFFU9rqJT7zXUDH4SjdhZGUUAO5IOC1e8ZIyRsbiY0CAwEAAQ==\n" +
+ "-----END PUBLIC KEY-----";
+
+ static final String RSA_PRIVATE_KEY =
+ "-----BEGIN RSA PRIVATE KEY-----\n" +
+ "MIIBOgIBAAJBAOHsK2E2FLYfEMWEVH/rJMTqDZLLLyshAH5odcfhYdF9xvFFU9rq\n" +
+ "JT7zXUDH4SjdhZGUUAO5IOC1e8ZIyRsbiY0CAwEAAQJBALcu+oGJC0QcbknpIWbT\n" +
+ "L+4mZTkYXLeYu8DDTHT0j47+6eEyYBOoRGcZDdlMWquvFIrV48RSot0GPh1MBE1p\n" +
+ "lKECIQD4krM4UshCwUHH9ZVkoxcPsxzPTTW7ukky4RZVN6mgWQIhAOisOAXVVjon\n" +
+ "fbGNQ6CezH7oOttEeZmiWCu48AVCyixVAiAaDZ41OA//Vywi3i2jV6iyH47Ud347\n" +
+ "R+ImMAtcMTJZOQIgF0+Z1UvIdc8bErzad68xQc22h91WaYQQXWEL+xrz8nkCIDcA\n" +
+ "MpCP/H5qTCj/l5rxQg+/NUGCg2pHHNLL+cy5N5RM\n" +
+ "-----END RSA PRIVATE KEY-----";
+
+ static final BigInteger RSA_MODULUS = new BigInteger(
+ "e1ec2b613614b61f10c584547feb24c4ea0d92cb2f2b21007e6875c7e161d17d" +
+ "c6f14553daea253ef35d40c7e128dd8591945003b920e0b57bc648c91b1b898d", 16);
+
+ static final BigInteger RSA_PUBLIC_EXPONENT = new BigInteger("10001", 16);
+ static final BigInteger RSA_PRIVATE_EXPONENT = new BigInteger(
+ "b72efa81890b441c6e49e92166d32fee266539185cb798bbc0c34c74f48f8efe" +
+ "e9e1326013a84467190dd94c5aabaf148ad5e3c452a2dd063e1d4c044d6994a1", 16);
+
+ public void test_fromPublicKeyPemInputStream() throws Exception {
+ ByteArrayInputStream is = new ByteArrayInputStream(RSA_PUBLIC_KEY.getBytes("UTF-8"));
+ OpenSSLKey key = OpenSSLKey.fromPublicKeyPemInputStream(is);
+ OpenSSLRSAPublicKey publicKey = (OpenSSLRSAPublicKey)key.getPublicKey();
+ assertEquals(RSA_MODULUS, publicKey.getModulus());
+ assertEquals(RSA_PUBLIC_EXPONENT, publicKey.getPublicExponent());
+ }
+
+ public void test_fromPrivateKeyPemInputStream() throws Exception {
+ ByteArrayInputStream is = new ByteArrayInputStream(RSA_PRIVATE_KEY.getBytes("UTF-8"));
+ OpenSSLKey key = OpenSSLKey.fromPrivateKeyPemInputStream(is);
+ OpenSSLRSAPrivateKey privateKey = (OpenSSLRSAPrivateKey)key.getPrivateKey();
+ assertEquals(RSA_MODULUS, privateKey.getModulus());
+ assertEquals(RSA_PRIVATE_EXPONENT, privateKey.getPrivateExponent());
+ }
+}
+
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/OpenSSLServerSocketImplTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/OpenSSLServerSocketImplTest.java
new file mode 100644
index 0000000..7cf7072
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/OpenSSLServerSocketImplTest.java
@@ -0,0 +1,129 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.TestUtils.LOCALHOST;
+import static com.android.org.conscrypt.TestUtils.getConscryptServerSocketFactory;
+import static com.android.org.conscrypt.TestUtils.getJdkSocketFactory;
+import static com.android.org.conscrypt.TestUtils.getProtocols;
+import static com.android.org.conscrypt.TestUtils.newTextMessage;
+import static com.android.org.conscrypt.TestUtils.pickUnusedPort;
+import static org.junit.Assert.assertArrayEquals;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(Parameterized.class)
+public class OpenSSLServerSocketImplTest {
+ private static final String CIPHER = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256";
+ private static final int MESSAGE_SIZE = 4096;
+
+ /**
+ * Various factories for SSL server sockets.
+ * @hide This class is not part of the Android public SDK API
+ */
+ public enum SocketType {
+ DEFAULT(getConscryptServerSocketFactory(false)),
+ ENGINE(getConscryptServerSocketFactory(true));
+
+ @SuppressWarnings("ImmutableEnumChecker")
+ private final SSLServerSocketFactory serverSocketFactory;
+
+ SocketType(SSLServerSocketFactory serverSocketFactory) {
+ this.serverSocketFactory = serverSocketFactory;
+ }
+
+ final SSLServerSocket newServerSocket(String cipher) {
+ try {
+ int port = pickUnusedPort();
+ SSLServerSocket sslSocket =
+ (SSLServerSocket) serverSocketFactory.createServerSocket(port);
+ sslSocket.setEnabledProtocols(getProtocols());
+ sslSocket.setEnabledCipherSuites(new String[] {cipher});
+ return sslSocket;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ @Parameters(name = "{0}")
+ public static Iterable<SocketType> data() {
+ // Android-changed: Temporarily (2017 Q2) disable ENGINE tests. http://b/37271061#comment9
+ // This experimental (unused by default) implementation is unstable and causing test
+ // failures on Android.
+ // return Arrays.asList(SocketType.DEFAULT, SocketType.ENGINE);
+ return Arrays.asList(SocketType.DEFAULT);
+ }
+
+ @Parameter public SocketType socketType;
+
+ private TestClient client;
+ private TestServer server;
+
+ @Before
+ public void setup() throws Exception {
+ // Create and start the server.
+ server = new TestServer(socketType.newServerSocket(CIPHER), MESSAGE_SIZE);
+ Future<?> connectedFuture = server.start();
+
+ // Create and start the client.
+ SSLSocketFactory socketFactory = getJdkSocketFactory();
+ SSLSocket socket = (SSLSocket) socketFactory.createSocket(LOCALHOST, server.port());
+ socket.setEnabledProtocols(getProtocols());
+ socket.setEnabledCipherSuites(new String[] {CIPHER});
+ client = new TestClient(socket);
+ client.start();
+
+ // Wait for the initial connection to complete.
+ connectedFuture.get(5, TimeUnit.SECONDS);
+ }
+
+ @After
+ public void teardown() throws Exception {
+ client.stop();
+ server.stop();
+ }
+
+ @Test
+ public void pingPong() throws IOException {
+ byte[] request = newTextMessage(MESSAGE_SIZE);
+ byte[] responseBuffer = new byte[MESSAGE_SIZE];
+ client.sendMessage(request);
+ client.flush();
+ int numBytes = client.readMessage(responseBuffer);
+ byte[] response = Arrays.copyOfRange(responseBuffer, 0, numBytes);
+ assertArrayEquals(request, response);
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/OpenSSLX509CertificateTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/OpenSSLX509CertificateTest.java
new file mode 100644
index 0000000..ab89f45
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/OpenSSLX509CertificateTest.java
@@ -0,0 +1,161 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2015 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.TestUtils.openTestFile;
+
+import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import junit.framework.TestCase;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class OpenSSLX509CertificateTest extends TestCase {
+ public void testSerialization_NoContextDeserialization() throws Exception {
+ // Set correct serialVersionUID
+ {
+ ObjectStreamClass clDesc = ObjectStreamClass.lookup(OpenSSLX509Certificate.class);
+ assertNotNull(clDesc);
+
+ // Set our fake class's serialization UID.
+ Field targetUID = ZpenSSLX509Certificate.class.getDeclaredField("serialVersionUID");
+ targetUID.setAccessible(true);
+
+ // Mark the field as non-final on JVM that need it.
+ try {
+ Field modifiersField = null;
+ try {
+ modifiersField = Field.class.getDeclaredField("modifiers");
+ } catch (NoSuchFieldException e) {
+ try {
+ Method getDeclaredFields0 =
+ Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class);
+ getDeclaredFields0.setAccessible(true);
+ Field[] fields = (Field[]) getDeclaredFields0.invoke(Field.class, false);
+ for (Field field : fields) {
+ if ("modifiers".equals(field.getName())) {
+ modifiersField = field;
+ break;
+ }
+ }
+ } catch (NoSuchMethodException | InvocationTargetException ignored) {
+ }
+ }
+ if (modifiersField != null) {
+ modifiersField.setAccessible(true);
+ modifiersField.setInt(targetUID, targetUID.getModifiers() & ~Modifier.FINAL);
+ }
+ } catch (Exception ignored) {
+ }
+
+ targetUID.set(null, clDesc.getSerialVersionUID());
+ }
+
+ final byte[] impostorBytes;
+ // Serialization
+ {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(new ZpenSSLX509Certificate(0xA5A5A5A5A5A5A5A5L));
+ oos.close();
+ impostorBytes = baos.toByteArray();
+ }
+
+ // Fix class name
+ {
+ boolean fixed = false;
+ for (int i = 0; i < impostorBytes.length - 4; i++) {
+ if (impostorBytes[i] == 'Z' && impostorBytes[i + 1] == 'p'
+ && impostorBytes[i + 2] == 'e' && impostorBytes[i + 3] == 'n') {
+ impostorBytes[i] = 'O';
+ fixed = true;
+ break;
+ }
+ }
+ assertTrue(fixed);
+ }
+
+ // Deserialization
+ {
+ ByteArrayInputStream bais = new ByteArrayInputStream(impostorBytes);
+ ObjectInputStream ois = new ObjectInputStream(bais);
+ OpenSSLX509Certificate cert = (OpenSSLX509Certificate) ois.readObject();
+ ois.close();
+ assertEquals(0L, cert.getContext());
+ }
+ }
+
+ static final String CT_POISON_EXTENSION = "1.3.6.1.4.1.11129.2.4.3";
+
+ private OpenSSLX509Certificate loadTestCertificate(String name)
+ throws FileNotFoundException, ParsingException {
+ return OpenSSLX509Certificate.fromX509PemInputStream(openTestFile(name));
+ }
+
+ public void test_deletingCTPoisonExtension() throws Exception {
+ /* certPoisoned has an extra poison extension.
+ * With the extension, the certificates have different TBS.
+ * Without it, the certificates should have the same TBS.
+ */
+ OpenSSLX509Certificate cert = loadTestCertificate("cert.pem");
+ OpenSSLX509Certificate certPoisoned = loadTestCertificate("cert-ct-poisoned.pem");
+
+ assertFalse(Arrays.equals(
+ certPoisoned.getTBSCertificate(),
+ cert.getTBSCertificate()));
+
+ assertTrue(
+ Arrays.equals(certPoisoned.getTBSCertificateWithoutExtension(CT_POISON_EXTENSION),
+ cert.getTBSCertificate()));
+ }
+
+ public void test_deletingExtensionMakesCopy() throws Exception {
+ /* Calling getTBSCertificateWithoutExtension should not modify the original certificate.
+ * Make sure the extension is still present in the original object.
+ */
+ OpenSSLX509Certificate certPoisoned = loadTestCertificate("cert-ct-poisoned.pem");
+ assertTrue(certPoisoned.getCriticalExtensionOIDs().contains(CT_POISON_EXTENSION));
+
+ certPoisoned.getTBSCertificateWithoutExtension(CT_POISON_EXTENSION);
+ assertTrue(certPoisoned.getCriticalExtensionOIDs().contains(CT_POISON_EXTENSION));
+ }
+
+ public void test_deletingMissingExtension() throws Exception {
+ /* getTBSCertificateWithoutExtension should throw on a certificate without the extension.
+ */
+ OpenSSLX509Certificate cert = loadTestCertificate("cert.pem");
+ assertFalse(cert.getCriticalExtensionOIDs().contains(CT_POISON_EXTENSION));
+
+ try {
+ cert.getTBSCertificateWithoutExtension(CT_POISON_EXTENSION);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/PlatformTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/PlatformTest.java
new file mode 100644
index 0000000..abaf996
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/PlatformTest.java
@@ -0,0 +1,214 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2014 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.TestUtils.assumeJava8;
+import static com.android.org.conscrypt.TestUtils.isJavaVersion;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import com.android.org.conscrypt.testing.FailingSniMatcher;
+import com.android.org.conscrypt.testing.RestrictedAlgorithmConstraints;
+import java.lang.reflect.Method;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIMatcher;
+import javax.net.ssl.SNIServerName;
+import javax.net.ssl.SSLParameters;
+import org.junit.Test;
+
+/**
+ * Test for Platform
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PlatformTest {
+ private static final Method SSL_PARAMETERS_GET_APPLICATION_PROTOCOLS_METHOD;
+ private static final Method SSL_PARAMETERS_SET_APPLICATION_PROTOCOLS_METHOD;
+
+ static {
+ Class<?> sslParameters = SSLParameters.class;
+ Method getApplicationProtocolsMethod;
+ Method setApplicationProtocolsMethod;
+ try {
+ getApplicationProtocolsMethod = sslParameters.getMethod("getApplicationProtocols");
+ setApplicationProtocolsMethod =
+ sslParameters.getMethod("setApplicationProtocols", String[].class);
+ } catch (NoSuchMethodException e) {
+ getApplicationProtocolsMethod = null;
+ setApplicationProtocolsMethod = null;
+ }
+
+ SSL_PARAMETERS_GET_APPLICATION_PROTOCOLS_METHOD = getApplicationProtocolsMethod;
+ SSL_PARAMETERS_SET_APPLICATION_PROTOCOLS_METHOD = setApplicationProtocolsMethod;
+ }
+
+ @Test
+ public void test_setSSLParameters_Socket() throws Exception {
+ assumeJava8();
+ Socket socket = new OpenSSLSocketFactoryImpl().createSocket();
+ SSLParametersImpl impl = SSLParametersImpl.getDefault();
+ SSLParameters params = new SSLParameters();
+ List<SNIServerName> names = new ArrayList<SNIServerName>();
+ names.add(new SNIHostName("some.host"));
+ params.setServerNames(names);
+ params.setUseCipherSuitesOrder(false);
+ params.setEndpointIdentificationAlgorithm("ABC");
+ String[] applicationProtocols = new String[] {"foo", "bar"};
+ if (isJavaVersion(9)) {
+ setApplicationProtocols(params, applicationProtocols);
+ }
+ Platform.setSSLParameters(params, impl, (AbstractConscryptSocket) socket);
+ assertEquals("some.host", ((AbstractConscryptSocket) socket).getHostname());
+ assertFalse(impl.getUseCipherSuitesOrder());
+ assertEquals("ABC", impl.getEndpointIdentificationAlgorithm());
+ if (isJavaVersion(9)) {
+ assertArrayEquals(applicationProtocols, impl.getApplicationProtocols());
+ }
+ }
+
+ @Test
+ public void test_getSSLParameters_Socket() throws Exception {
+ assumeJava8();
+ Socket socket = new OpenSSLSocketFactoryImpl().createSocket();
+ SSLParametersImpl impl = SSLParametersImpl.getDefault();
+ SSLParameters params = new SSLParameters();
+ impl.setUseCipherSuitesOrder(false);
+ impl.setEndpointIdentificationAlgorithm("ABC");
+ String[] applicationProtocols = new String[] {"foo", "bar"};
+ if (isJavaVersion(9)) {
+ impl.setApplicationProtocols(applicationProtocols);
+ }
+ ((AbstractConscryptSocket) socket).setHostname("some.host");
+ Platform.getSSLParameters(params, impl, (AbstractConscryptSocket) socket);
+ assertEquals("some.host", ((SNIHostName) params.getServerNames().get(0)).getAsciiName());
+ assertFalse(params.getUseCipherSuitesOrder());
+ assertEquals("ABC", params.getEndpointIdentificationAlgorithm());
+ if (isJavaVersion(9)) {
+ assertArrayEquals(applicationProtocols, getApplicationProtocols(params));
+ }
+ }
+
+ @Test
+ public void test_setSSLParameters_Engine() throws Exception {
+ assumeJava8();
+ SSLParametersImpl impl = SSLParametersImpl.getDefault();
+ SSLParameters params = new SSLParameters();
+ ConscryptEngine engine = new ConscryptEngine(impl);
+ List<SNIServerName> names = new ArrayList<SNIServerName>();
+ names.add(new SNIHostName("some.host"));
+ params.setServerNames(names);
+ params.setUseCipherSuitesOrder(false);
+ params.setEndpointIdentificationAlgorithm("ABC");
+ String[] applicationProtocols = new String[] {"foo", "bar"};
+ if (isJavaVersion(9)) {
+ setApplicationProtocols(params, applicationProtocols);
+ }
+ Platform.setSSLParameters(params, impl, engine);
+ assertEquals("some.host", engine.getHostname());
+ assertFalse(impl.getUseCipherSuitesOrder());
+ assertEquals("ABC", impl.getEndpointIdentificationAlgorithm());
+ if (isJavaVersion(9)) {
+ assertArrayEquals(applicationProtocols, impl.getApplicationProtocols());
+ }
+ }
+
+ @Test
+ public void test_getSSLParameters_Engine() throws Exception {
+ assumeJava8();
+ SSLParametersImpl impl = SSLParametersImpl.getDefault();
+ SSLParameters params = new SSLParameters();
+ ConscryptEngine engine = new ConscryptEngine(impl);
+ impl.setUseCipherSuitesOrder(false);
+ impl.setEndpointIdentificationAlgorithm("ABC");
+ engine.setHostname("some.host");
+ String[] applicationProtocols = new String[] {"foo", "bar"};
+ if (isJavaVersion(9)) {
+ impl.setApplicationProtocols(applicationProtocols);
+ }
+ Platform.getSSLParameters(params, impl, engine);
+ assertEquals("some.host", ((SNIHostName) params.getServerNames().get(0)).getAsciiName());
+ assertFalse(params.getUseCipherSuitesOrder());
+ assertEquals("ABC", params.getEndpointIdentificationAlgorithm());
+ if (isJavaVersion(9)) {
+ assertArrayEquals(applicationProtocols, getApplicationProtocols(params));
+ }
+ }
+
+ @Test
+ public void test_setAndGetSSLParameters() throws Exception {
+ assumeJava8();
+ ConscryptEngine engine = new ConscryptEngine(SSLParametersImpl.getDefault());
+ SSLParameters paramsIn = new SSLParameters();
+
+ List<SNIServerName> names = new ArrayList<>();
+ names.add(new SNIHostName("some.host"));
+ paramsIn.setServerNames(names);
+ paramsIn.setUseCipherSuitesOrder(true);
+ paramsIn.setEndpointIdentificationAlgorithm("ABC");
+ paramsIn.setWantClientAuth(true);
+ paramsIn.setSNIMatchers(Collections.singleton(FailingSniMatcher.create()));
+ paramsIn.setAlgorithmConstraints(new RestrictedAlgorithmConstraints());
+
+ engine.setSSLParameters(paramsIn);
+ SSLParameters paramsOut = engine.getSSLParameters();
+
+ assertEquals(paramsIn.getServerNames(), paramsOut.getServerNames());
+ assertEquals(paramsIn.getUseCipherSuitesOrder(), paramsOut.getUseCipherSuitesOrder());
+ assertEquals(paramsIn.getEndpointIdentificationAlgorithm(),
+ paramsOut.getEndpointIdentificationAlgorithm());
+ assertEquals(paramsIn.getWantClientAuth(), paramsOut.getWantClientAuth());
+ assertEquals(paramsIn.getNeedClientAuth(), paramsOut.getNeedClientAuth());
+ assertSNIMatchersEqual(paramsIn.getSNIMatchers(), paramsOut.getSNIMatchers());
+ assertEquals(paramsIn.getAlgorithmConstraints(), paramsOut.getAlgorithmConstraints());
+ }
+
+ private static void assertSNIMatchersEqual(Collection<SNIMatcher> a, Collection<SNIMatcher> b) {
+ assertEquals(a.size(), b.size());
+
+ HashSet<SNIMatcher> aSet = new HashSet<>(a);
+ aSet.removeAll(b);
+ assertEquals(0, aSet.size());
+ }
+
+ private static String[] getApplicationProtocols(SSLParameters params) {
+ if (SSL_PARAMETERS_GET_APPLICATION_PROTOCOLS_METHOD != null) {
+ try {
+ return (String[]) SSL_PARAMETERS_GET_APPLICATION_PROTOCOLS_METHOD.invoke(params);
+ } catch (Exception ignored) {
+ // TODO(nmittler): Should we throw here?
+ }
+ }
+ return EmptyArray.STRING;
+ }
+
+ private static void setApplicationProtocols(SSLParameters params, String[] protocols) {
+ if (SSL_PARAMETERS_SET_APPLICATION_PROTOCOLS_METHOD != null) {
+ try {
+ SSL_PARAMETERS_SET_APPLICATION_PROTOCOLS_METHOD.invoke(params, (Object) protocols);
+ } catch (Exception ignored) {
+ // TODO(nmittler): Should we throw here?
+ }
+ }
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/RenegotiationTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/RenegotiationTest.java
new file mode 100644
index 0000000..e2541cb
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/RenegotiationTest.java
@@ -0,0 +1,447 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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
+ */
+
+package com.android.org.conscrypt;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLEngineResult.Status;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import com.android.org.conscrypt.java.security.TestKeyStore;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * This tests that server-initiated cipher renegotiation works properly with a Conscrypt client.
+ * BoringSSL does not support user-initiated renegotiation, so we use the JDK implementation for
+ * the server.
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(Parameterized.class)
+public class RenegotiationTest {
+ private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocateDirect(0);
+ private static final byte[] MESSAGE_BYTES = "Hello".getBytes(TestUtils.UTF_8);
+ private static final ByteBuffer MESSAGE_BUFFER =
+ ByteBuffer.wrap(MESSAGE_BYTES).asReadOnlyBuffer();
+ private static final int MESSAGE_LENGTH = MESSAGE_BYTES.length;
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public enum SocketType {
+ FILE_DESCRIPTOR {
+ @Override
+ Client newClient(int port) {
+ return new Client(false, port);
+ }
+ },
+ ENGINE {
+ @Override
+ Client newClient(int port) {
+ return new Client(true, port);
+ }
+ };
+
+ abstract Client newClient(int port);
+ }
+
+ @Parameters(name = "{0}")
+ public static Object[] data() {
+ return new Object[] {SocketType.FILE_DESCRIPTOR, SocketType.ENGINE};
+ }
+
+ @Parameter
+ public SocketType socketType;
+
+ private Client client;
+ private Server server;
+
+ @Before
+ public void setup() throws Exception {
+ server = new Server();
+ Future<?> connectedFuture = server.start();
+
+ client = socketType.newClient(server.port());
+ client.start();
+
+ // Wait for the initial connection to complete.
+ connectedFuture.get(5, TimeUnit.SECONDS);
+ }
+
+ @After
+ public void teardown() {
+ client.stop();
+ server.stop();
+ }
+
+ @Test
+ public void test() throws Exception {
+ client.socket.startHandshake();
+ String initialCipher = client.socket.getSession().getCipherSuite();
+
+ client.sendMessage();
+
+ Future<?> repliesFuture = client.readReplies();
+ server.await(5, TimeUnit.SECONDS);
+ repliesFuture.get(5, TimeUnit.SECONDS);
+
+ // Verify that the cipher has changed.
+ assertNotEquals(initialCipher, client.socket.getSession().getCipherSuite());
+ }
+
+ private static SSLContext newConscryptClientContext() {
+ SSLContext context = TestUtils.newContext(TestUtils.getConscryptProvider());
+ return TestUtils.initSslContext(context, TestKeyStore.getClient());
+ }
+
+ private static SSLContext newJdkServerContext() {
+ SSLContext context = TestUtils.newContext(TestUtils.getJdkProvider());
+ return TestUtils.initSslContext(context, TestKeyStore.getServer());
+ }
+
+ private static final class Client {
+ private final SSLSocket socket;
+ private ExecutorService executor;
+
+ Client(boolean useEngineSocket, int port) {
+ try {
+ SSLSocketFactory socketFactory = newConscryptClientContext().getSocketFactory();
+ Conscrypt.setUseEngineSocket(socketFactory, useEngineSocket);
+ socket = (SSLSocket) socketFactory.createSocket(
+ TestUtils.getLoopbackAddress(), port);
+ socket.setEnabledProtocols(TestUtils.getCommonProtocolSuites());
+ socket.setEnabledCipherSuites(TestUtils.getCommonCipherSuites());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ void start() {
+ try {
+ executor = Executors.newSingleThreadExecutor();
+ socket.startHandshake();
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
+ }
+
+ void stop() {
+ try {
+ socket.close();
+
+ if (executor != null) {
+ executor.shutdown();
+ executor.awaitTermination(5, TimeUnit.SECONDS);
+ executor = null;
+ }
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ Future<?> readReplies() {
+ return executor.submit(new Runnable() {
+ @Override
+ public void run() {
+ readReply();
+ }
+ });
+ }
+
+ private void readReply() {
+ try {
+ byte[] buffer = new byte[MESSAGE_LENGTH];
+ int totalBytesRead = 0;
+ while (totalBytesRead < MESSAGE_LENGTH) {
+ int remaining = MESSAGE_LENGTH - totalBytesRead;
+ int bytesRead = socket.getInputStream().read(buffer, totalBytesRead, remaining);
+ if (bytesRead == -1) {
+ throw new EOFException();
+ }
+ totalBytesRead += bytesRead;
+ }
+
+ // Verify the reply is correct.
+ assertEquals(MESSAGE_LENGTH, totalBytesRead);
+ assertArrayEquals(MESSAGE_BYTES, buffer);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ void sendMessage() throws IOException {
+ try {
+ socket.getOutputStream().write(MESSAGE_BYTES);
+ socket.getOutputStream().flush();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private static final class Server {
+ private final ServerSocketChannel serverChannel;
+ private final SSLEngine engine;
+ private final ByteBuffer inboundPacketBuffer;
+ private final ByteBuffer inboundAppBuffer;
+ private final ByteBuffer outboundPacketBuffer;
+ private final Set<String> ciphers =
+ new LinkedHashSet<String>(Arrays.asList(TestUtils.getCommonCipherSuites()));
+ private SocketChannel channel;
+ private ExecutorService executor;
+ private volatile boolean stopping;
+ private volatile Future<?> echoFuture;
+
+ Server() throws IOException {
+ serverChannel = ServerSocketChannel.open();
+ serverChannel.socket().bind(new InetSocketAddress(TestUtils.getLoopbackAddress(), 0));
+ engine = newJdkServerContext().createSSLEngine();
+ engine.setEnabledProtocols(TestUtils.getCommonProtocolSuites());
+ engine.setEnabledCipherSuites(TestUtils.getCommonCipherSuites());
+ engine.setUseClientMode(false);
+
+ inboundPacketBuffer =
+ ByteBuffer.allocateDirect(engine.getSession().getPacketBufferSize());
+ inboundAppBuffer =
+ ByteBuffer.allocateDirect(engine.getSession().getApplicationBufferSize());
+ outboundPacketBuffer =
+ ByteBuffer.allocateDirect(engine.getSession().getPacketBufferSize());
+ }
+
+ Future<?> start() throws IOException {
+ executor = Executors.newSingleThreadExecutor();
+ return executor.submit(new AcceptTask());
+ }
+
+ void await(long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ echoFuture.get(timeout, unit);
+ }
+
+ void stop() {
+ try {
+ stopping = true;
+
+ if (channel != null) {
+ channel.close();
+ channel = null;
+ }
+
+ serverChannel.close();
+
+ if (executor != null) {
+ executor.shutdown();
+ executor.awaitTermination(5, TimeUnit.SECONDS);
+ executor = null;
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ int port() {
+ return serverChannel.socket().getLocalPort();
+ }
+
+ private final class AcceptTask implements Runnable {
+ @Override
+ public void run() {
+ try {
+ if (stopping) {
+ return;
+ }
+ channel = serverChannel.accept();
+ channel.configureBlocking(false);
+
+ doHandshake();
+
+ if (stopping) {
+ return;
+ }
+ echoFuture = executor.submit(new EchoTask());
+ } catch (Throwable e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private final class EchoTask implements Runnable {
+ @Override
+ public void run() {
+ try {
+ readMessage();
+ renegotiate();
+ reply();
+ } catch (Throwable e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void renegotiate() throws Exception {
+ // Remove the current cipher from the set and renegotiate to force a new
+ // cipher to be selected.
+ String currentCipher = engine.getSession().getCipherSuite();
+ ciphers.remove(currentCipher);
+ engine.setEnabledCipherSuites(ciphers.toArray(new String[ciphers.size()]));
+ doHandshake();
+ }
+
+ private void reply() throws IOException {
+ SSLEngineResult result = wrap(newMessage());
+ if (result.getStatus() != Status.OK) {
+ throw new RuntimeException("Wrap failed. Status: " + result.getStatus());
+ }
+ }
+
+ private ByteBuffer newMessage() {
+ return MESSAGE_BUFFER.duplicate();
+ }
+
+ private void readMessage() throws IOException {
+ int totalProduced = 0;
+ while (!stopping) {
+ SSLEngineResult result = unwrap();
+ if (result.getStatus() != Status.OK) {
+ throw new RuntimeException("Failed reading message: " + result);
+ }
+ totalProduced += result.bytesProduced();
+ if (totalProduced == MESSAGE_LENGTH) {
+ return;
+ }
+ }
+ }
+ }
+
+ private SSLEngineResult wrap(ByteBuffer src) throws IOException {
+ outboundPacketBuffer.clear();
+
+ // Check if the engine has bytes to wrap.
+ SSLEngineResult result = engine.wrap(src, outboundPacketBuffer);
+
+ // Write any wrapped bytes to the socket.
+ outboundPacketBuffer.flip();
+
+ do {
+ channel.write(outboundPacketBuffer);
+ } while (outboundPacketBuffer.hasRemaining());
+
+ return result;
+ }
+
+ private SSLEngineResult unwrap() throws IOException {
+ // Unwrap any available bytes from the socket.
+ SSLEngineResult result = null;
+ boolean done = false;
+ while (!done) {
+ if (channel.read(inboundPacketBuffer) == -1) {
+ throw new EOFException();
+ }
+ // Just clear the app buffer - we don't really use it.
+ inboundAppBuffer.clear();
+ inboundPacketBuffer.flip();
+ result = engine.unwrap(inboundPacketBuffer, inboundAppBuffer);
+ switch (result.getStatus()) {
+ case BUFFER_UNDERFLOW:
+ // Continue reading from the socket in a moment.
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ break;
+ case OK:
+ done = true;
+ break;
+ default: { throw new RuntimeException("Unexpected unwrap result: " + result); }
+ }
+
+ // Compact for the next socket read.
+ inboundPacketBuffer.compact();
+ }
+ return result;
+ }
+
+ private void doHandshake() throws IOException {
+ engine.beginHandshake();
+
+ boolean done = false;
+ while (!done) {
+ switch (engine.getHandshakeStatus()) {
+ case NEED_WRAP: {
+ wrap(EMPTY_BUFFER);
+ break;
+ }
+ case NEED_UNWRAP: {
+ unwrap();
+ break;
+ }
+ case NEED_TASK: {
+ runDelegatedTasks();
+ break;
+ }
+ default: {
+ done = true;
+ break;
+ }
+ }
+ }
+ }
+
+ private void runDelegatedTasks() {
+ for (;;) {
+ Runnable task = engine.getDelegatedTask();
+ if (task == null) {
+ break;
+ }
+ task.run();
+ }
+ }
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/SSLUtilsTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/SSLUtilsTest.java
new file mode 100644
index 0000000..274eb24
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/SSLUtilsTest.java
@@ -0,0 +1,249 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static com.android.org.conscrypt.TestUtils.UTF_8;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class SSLUtilsTest {
+ private static final byte[] VALID_CHARACTERS =
+ "0123456789abcdefghijklmnopqrstuvwxyz".getBytes(UTF_8);
+
+ @Test
+ public void noProtocolsShouldSucceed() {
+ byte[] expected = new byte[0];
+ byte[] actual = SSLUtils.encodeProtocols(EmptyArray.STRING);
+ assertArrayEquals(expected, actual);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void emptyProtocolShouldThrow() {
+ SSLUtils.encodeProtocols(new String[] {""});
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void longProtocolShouldThrow() {
+ SSLUtils.encodeProtocols(new String[] {new String(newValidProtocol(256), UTF_8)});
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void protocolWithInvalidCharacterShouldThrow() {
+ SSLUtils.encodeProtocols(new String[] {"This is a bad character: €"});
+ }
+
+ @Test
+ public void encodeProtocolsShouldSucceed() {
+ byte[][] protocols = new byte[][]{
+ "protocol-1".getBytes(UTF_8),
+ "protocol-2".getBytes(UTF_8),
+ "protocol-3".getBytes(UTF_8),
+ };
+ byte[] expected = getExpectedEncodedBytes(protocols);
+ byte[] actual = SSLUtils.encodeProtocols(toStrings(protocols));
+ assertArrayEquals(expected, actual);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void decodeNullProtocolsShouldThrow() {
+ SSLUtils.decodeProtocols(null);
+ }
+
+ @Test
+ public void decodeEmptyProtocolsShouldSucceed() {
+ assertArrayEquals(EmptyArray.STRING, SSLUtils.decodeProtocols(EmptyArray.BYTE));
+ }
+
+ @Test
+ public void decodeProtocolsShouldSucceed() {
+ byte[][] protocols = new byte[][]{
+ "protocol-1".getBytes(UTF_8),
+ "protocol-2".getBytes(UTF_8),
+ "protocol-3".getBytes(UTF_8),
+ };
+ byte[] encoded = getExpectedEncodedBytes(protocols);
+ String[] strings = SSLUtils.decodeProtocols(encoded);
+ assertArrayEquals(toStrings(protocols), strings);
+ }
+
+ @Test
+ public void testGetClientKeyType() throws Exception {
+ // See http://www.ietf.org/assignments/tls-parameters/tls-parameters.xml
+ byte b = Byte.MIN_VALUE;
+ do {
+ String byteString = Byte.toString(b);
+ String keyType = SSLUtils.getClientKeyType(b);
+ switch (b) {
+ case 1:
+ assertEquals(byteString, "RSA", keyType);
+ break;
+ case 64:
+ assertEquals(byteString, "EC", keyType);
+ break;
+ default:
+ assertNull(byteString, keyType);
+ }
+ b++;
+ } while (b != Byte.MIN_VALUE);
+ }
+
+ @Test
+ public void testGetSupportedClientKeyTypes_onlyCertTypes() throws Exception {
+ // Create an array with all possible values. Also, duplicate all values.
+ byte[] allClientCertificateTypes = new byte[512];
+ for (int i = 0; i < allClientCertificateTypes.length; i++) {
+ allClientCertificateTypes[i] = (byte) i;
+ }
+ assertEquals(new HashSet<String>(Arrays.asList("RSA", "EC")),
+ SSLUtils.getSupportedClientKeyTypes(allClientCertificateTypes, new int[0]));
+ }
+
+ @Test
+ public void testGetSupportedClientKeyTypes_onlySignatureAlgs() {
+ // Create an array with lots of values in the supported range
+ int[] allSignatureAlgTypes = new int[7 * 7];
+ int i = 0;
+ for (int upper = 0x02; upper < 0x09; upper++) {
+ for (int lower = 0x01; lower < 0x08; lower++) {
+ allSignatureAlgTypes[i++] = (upper << 8) | lower;
+ }
+ }
+ assertEquals(new HashSet<String>(Arrays.asList("RSA", "EC")),
+ SSLUtils.getSupportedClientKeyTypes(new byte[0], allSignatureAlgTypes));
+ }
+
+ @Test
+ public void testGetSupportedClientKeyTypes_intersection() {
+ assertEquals(new HashSet<String>(Arrays.asList("EC")),
+ SSLUtils.getSupportedClientKeyTypes(
+ new byte[] { NativeConstants.TLS_CT_RSA_SIGN,
+ NativeConstants.TLS_CT_ECDSA_SIGN },
+ new int[] { NativeConstants.SSL_SIGN_ECDSA_SECP256R1_SHA256,
+ NativeConstants.SSL_SIGN_ECDSA_SECP384R1_SHA384,
+ NativeConstants.SSL_SIGN_ECDSA_SECP521R1_SHA512 }));
+ }
+
+ @Test
+ public void testGetSupportedClientKeyTypes_intersection_empty() {
+ assertEquals(new HashSet<String>(),
+ SSLUtils.getSupportedClientKeyTypes(
+ new byte[] { NativeConstants.TLS_CT_RSA_SIGN },
+ new int[] { NativeConstants.SSL_SIGN_ECDSA_SECP256R1_SHA256,
+ NativeConstants.SSL_SIGN_ECDSA_SECP384R1_SHA384,
+ NativeConstants.SSL_SIGN_ECDSA_SECP521R1_SHA512 }));
+ }
+
+ @Test
+ public void testGetSupportedClientKeyTypes_ordered() {
+ List<String> keyTypes = new ArrayList<String>(SSLUtils.getSupportedClientKeyTypes(
+ new byte[0],
+ new int[] { NativeConstants.SSL_SIGN_RSA_PKCS1_SHA1,
+ NativeConstants.SSL_SIGN_ECDSA_SECP256R1_SHA256 }));
+ assertEquals(Arrays.asList("RSA", "EC"), keyTypes);
+
+ keyTypes = new ArrayList<String>(SSLUtils.getSupportedClientKeyTypes(
+ new byte[0],
+ new int[] { NativeConstants.SSL_SIGN_ECDSA_SECP256R1_SHA256,
+ NativeConstants.SSL_SIGN_RSA_PKCS1_SHA1 }));
+ assertEquals(Arrays.asList("EC", "RSA"), keyTypes);
+
+ keyTypes = new ArrayList<String>(SSLUtils.getSupportedClientKeyTypes(
+ new byte[0],
+ new int[] { NativeConstants.SSL_SIGN_RSA_PKCS1_SHA512,
+ NativeConstants.SSL_SIGN_ECDSA_SECP256R1_SHA256,
+ NativeConstants.SSL_SIGN_RSA_PKCS1_SHA1 }));
+ assertEquals(Arrays.asList("RSA", "EC"), keyTypes);
+
+ keyTypes = new ArrayList<String>(SSLUtils.getSupportedClientKeyTypes(
+ new byte[0],
+ new int[] { NativeConstants.SSL_SIGN_ECDSA_SECP256R1_SHA256,
+ NativeConstants.SSL_SIGN_RSA_PKCS1_SHA1,
+ NativeConstants.SSL_SIGN_ECDSA_SECP521R1_SHA512 }));
+ assertEquals(Arrays.asList("EC", "RSA"), keyTypes);
+ }
+
+ @Test
+ public void engineStateValues() {
+ int[] expectedValues = {
+ SSLUtils.EngineStates.STATE_NEW,
+ SSLUtils.EngineStates.STATE_MODE_SET,
+ SSLUtils.EngineStates.STATE_HANDSHAKE_STARTED,
+ SSLUtils.EngineStates.STATE_HANDSHAKE_COMPLETED,
+ SSLUtils.EngineStates.STATE_READY_HANDSHAKE_CUT_THROUGH,
+ SSLUtils.EngineStates.STATE_READY,
+ SSLUtils.EngineStates.STATE_CLOSED_INBOUND,
+ SSLUtils.EngineStates.STATE_CLOSED_OUTBOUND,
+ SSLUtils.EngineStates.STATE_CLOSED,
+ };
+
+ // Check the values for the engine state are as expected because logic
+ // in the engine and sockets relies on it,
+ // e.g. STATE_NEW < STATE_HANDSHAKE_STARTED < STATE_READY < STATE_CLOSED
+ // But to be sure we assert the exact ordering.
+ for (int i = 0; i < expectedValues.length; i++) {
+ assertEquals(i, expectedValues[i]);
+ }
+ }
+
+ private static String[] toStrings(byte[][] protocols) {
+ int numProtocols = protocols.length;
+ String[] out = new String[numProtocols];
+ for(int i = 0; i < numProtocols; ++i) {
+ out[i] = new String(protocols[i], UTF_8);
+ }
+ return out;
+ }
+
+ private static byte[] getExpectedEncodedBytes(byte[][] protocols) {
+ int numProtocols = protocols.length;
+ int encodedLength = numProtocols;
+ for (byte[] protocol : protocols) {
+ encodedLength += protocol.length;
+ }
+ byte[] encoded = new byte[encodedLength];
+ for(int encodedIndex = 0, i = 0; i < numProtocols; ++i) {
+ byte[] protocol = protocols[i];
+ encoded[encodedIndex++] = (byte) protocol.length;
+ System.arraycopy(protocol, 0, encoded, encodedIndex, protocol.length);
+ encodedIndex += protocol.length;
+ }
+ return encoded;
+ }
+
+ private static byte[] newValidProtocol(int length) {
+ byte[] chars = new byte[length];
+ for (int i = 0; i < length; ++i) {
+ int charIndex = i % VALID_CHARACTERS.length;
+ chars[i] = VALID_CHARACTERS[charIndex];
+ }
+ return chars;
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ServerSessionContextTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ServerSessionContextTest.java
new file mode 100644
index 0000000..2502615
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ServerSessionContextTest.java
@@ -0,0 +1,51 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.util.Enumeration;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class ServerSessionContextTest extends AbstractSessionContextTest<ServerSessionContext> {
+
+ @Override
+ ServerSessionContext newContext() {
+ return new ServerSessionContext();
+ }
+
+ @Override
+ NativeSslSession getCachedSession(ServerSessionContext context, NativeSslSession s) {
+ return context.getSessionFromCache(s.getId());
+ }
+
+ @Override
+ @SuppressWarnings("JdkObsolete") // Public API SSLSessionContext.getIds() uses Enumeration
+ int size(ServerSessionContext context) {
+ int count = 0;
+ Enumeration<byte[]> ids = context.getIds();
+ while (ids.hasMoreElements()) {
+ ids.nextElement();
+ count++;
+ }
+ return count;
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/TestSessionBuilder.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/TestSessionBuilder.java
new file mode 100644
index 0000000..3962c81
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/TestSessionBuilder.java
@@ -0,0 +1,171 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2016 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class TestSessionBuilder {
+ private int type;
+
+ private boolean sessionDataSet;
+ private byte[] sessionData;
+ private int sessionDataLength;
+
+ private boolean certificatesSet;
+ private ArrayList<byte[]> certificates = new ArrayList<byte[]>();
+ private int certificatesLength;
+ private ArrayList<Integer> certificateLengths = new ArrayList<Integer>();
+
+ private boolean ocspDataSet;
+ private ArrayList<byte[]> ocspDatas = new ArrayList<byte[]>();
+ private int ocspDatasLength;
+ private ArrayList<Integer> ocspDataLengths = new ArrayList<Integer>();
+
+ private boolean tlsSctDataSet;
+ private byte[] tlsSctData;
+ private int tlsSctDataLength;
+
+ public TestSessionBuilder setType(int type) {
+ this.type = type;
+ return this;
+ }
+
+ public TestSessionBuilder setSessionData(byte[] sessionData) {
+ sessionDataSet = true;
+ this.sessionData = sessionData;
+ sessionDataLength = sessionData.length;
+ return this;
+ }
+
+ public TestSessionBuilder setSessionDataLength(int sessionDataLength) {
+ assertTrue("call setSessionData first", sessionDataSet);
+ this.sessionDataLength = sessionDataLength;
+ return this;
+ }
+
+ public TestSessionBuilder addCertificate(byte[] certificate) {
+ certificatesSet = true;
+ certificates.add(certificate);
+ certificateLengths.add(certificate.length);
+ certificatesLength = certificates.size();
+ return this;
+ }
+
+ public TestSessionBuilder setCertificatesLength(int certificatesLength) {
+ assertTrue("call addCertificate first", certificatesSet);
+ this.certificatesLength = certificatesLength;
+ return this;
+ }
+
+ public TestSessionBuilder setCertificateLength(int certIndex, int certLength) {
+ assertTrue("call addCertificate first", certificatesSet);
+ certificateLengths.set(certIndex, certLength);
+ return this;
+ }
+
+ public TestSessionBuilder setOcspDataEmpty() {
+ ocspDataSet = true;
+ return this;
+ }
+
+ public TestSessionBuilder addOcspData(byte[] ocspData) {
+ ocspDataSet = true;
+ ocspDatas.add(ocspData);
+ ocspDataLengths.add(ocspData.length);
+ ocspDatasLength = ocspDatas.size();
+ return this;
+ }
+
+ public TestSessionBuilder setOcspDatasLength(int ocspDatasLength) {
+ assertTrue("Call addOcspData before setting length", ocspDataSet);
+ this.ocspDatasLength = ocspDatasLength;
+ return this;
+ }
+
+ public TestSessionBuilder setOcspDataLength(int ocspDataIndex, int ocspDataLength) {
+ assertTrue("Call addOcspData before setting length", ocspDataSet);
+ this.ocspDataLengths.set(ocspDataIndex, ocspDataLength);
+ return this;
+ }
+
+ public TestSessionBuilder setTlsSctData(byte[] tlsSctData) {
+ tlsSctDataSet = true;
+ this.tlsSctData = tlsSctData.clone();
+ tlsSctDataLength = tlsSctData.length;
+ return this;
+ }
+
+ public TestSessionBuilder setTlsSctDataLength(int tlsSctDataLength) {
+ assertTrue("Call setTlsSctData before setting length", tlsSctDataSet);
+ this.tlsSctDataLength = tlsSctDataLength;
+ return this;
+ }
+
+ public TestSessionBuilder setTlsSctDataEmpty() {
+ tlsSctDataSet = true;
+ return this;
+ }
+
+ public byte[] build() {
+ assertTrue("Must set session data", sessionDataSet);
+ assertTrue("Must call addCertificate at least once", certificatesSet);
+
+ ByteBuffer buf = ByteBuffer.allocate(4096);
+ buf.putInt(type);
+
+ buf.putInt(sessionDataLength);
+ buf.put(sessionData);
+
+ buf.putInt(certificatesLength);
+ for (int i = 0; i < certificates.size(); i++) {
+ buf.putInt(certificateLengths.get(i));
+ buf.put(certificates.get(i));
+ }
+
+ if (ocspDataSet) {
+ buf.putInt(ocspDatasLength);
+ for (int i = 0; i < ocspDatas.size(); i++) {
+ buf.putInt(ocspDataLengths.get(i));
+ buf.put(ocspDatas.get(i));
+ }
+
+ if (tlsSctDataSet) {
+ if (tlsSctData == null) {
+ buf.putInt(0);
+ } else {
+ buf.putInt(tlsSctDataLength);
+ buf.put(tlsSctData);
+ }
+ }
+ } else {
+ assertFalse("If ocspData is not set, then tlsSctData must not be set", tlsSctDataSet);
+ }
+
+ buf.flip();
+ byte[] output = new byte[buf.remaining()];
+ buf.get(output);
+ return output;
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/TestSessionBuilderTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/TestSessionBuilderTest.java
new file mode 100644
index 0000000..624110f
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/TestSessionBuilderTest.java
@@ -0,0 +1,111 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2016 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import org.junit.Test;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class TestSessionBuilderTest {
+ @Test
+ public void buildsValidBasicSession() {
+ assertArrayEquals(new byte[] {0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x22, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x33},
+ new TestSessionBuilder()
+ .setType(0x11)
+ .setSessionData(new byte[] {0x22})
+ .addCertificate(new byte[] {0x33})
+ .build());
+ }
+
+ @Test
+ public void buildsValidOcspSession() {
+ assertArrayEquals(
+ new byte[] {
+ 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x22, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x33, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x44,
+ },
+ new TestSessionBuilder()
+ .setType(0x11)
+ .setSessionData(new byte[] {0x22})
+ .addCertificate(new byte[] {0x33})
+ .addOcspData(new byte[] {0x44})
+ .build());
+ }
+
+ @Test
+ public void buildsValidOcspAndTlsSctSession() {
+ assertArrayEquals(
+ new byte[] {
+ 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x22, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x33, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x44, 0x00, 0x00, 0x00, 0x01, 0x55,
+ },
+ new TestSessionBuilder()
+ .setType(0x11)
+ .setSessionData(new byte[] {0x22})
+ .addCertificate(new byte[] {0x33})
+ .addOcspData(new byte[] {0x44})
+ .setTlsSctData(new byte[] {0x55})
+ .build());
+ }
+
+ @Test
+ public void buildsValidButEmptyOcspAndTlsSctSession() {
+ assertArrayEquals(
+ new byte[] {
+ 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x22, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ },
+ new TestSessionBuilder()
+ .setType(0x11)
+ .setSessionData(new byte[] {0x22})
+ .addCertificate(new byte[] {0x33})
+ .setOcspDataEmpty()
+ .setTlsSctDataEmpty()
+ .build());
+ }
+
+ @Test
+ public void buildsInvalidOcspAndTlsSctSession() {
+ assertArrayEquals(
+ new byte[] {
+ 0x00, 0x00, 0x00, 0x11, 0x00, 0x33, 0x22, 0x11, 0x22, 0x12, 0x11, 0x22,
+ 0x34, 0x10, 0x20, 0x30, 0x40, 0x33, 0x38, 0x48, 0x18, 0x28, 0x13, 0x24,
+ 0x57, 0x68, 0x44, (byte) 0x99, (byte) 0x88, 0x77, 0x66, 0x55,
+ },
+ new TestSessionBuilder()
+ .setType(0x11)
+ .setSessionData(new byte[] {0x22})
+ .setSessionDataLength(0x332211)
+ .addCertificate(new byte[] {0x33})
+ .setCertificatesLength(0x12112234)
+ .setCertificateLength(0, 0x10203040)
+ .addOcspData(new byte[] {0x44})
+ .setOcspDatasLength(0x38481828)
+ .setOcspDataLength(0, 0x13245768)
+ .setTlsSctData(new byte[] {0x55})
+ .setTlsSctDataLength(0x99887766)
+ .build());
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/VeryBasicHttpServerTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/VeryBasicHttpServerTest.java
new file mode 100644
index 0000000..f372e4f
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/VeryBasicHttpServerTest.java
@@ -0,0 +1,117 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2023 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for VeryBasicHttpServer.
+ * <p>
+ * These test VeryBasicHttpServer using plain HTTP connections. They are essentially the same as
+ * the ones in HttpsUrlConnectionTest. That way we can differentiate failures due to the
+ * HTTP server implementation and failures due to TLS.
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class VeryBasicHttpServerTest {
+ private final ExecutorService executor = Executors.newSingleThreadExecutor();
+ private final VeryBasicHttpServer server = new VeryBasicHttpServer();
+
+ public VeryBasicHttpServerTest() throws IOException {
+ }
+
+ @After
+ public void after() {
+ executor.shutdownNow();
+ }
+
+ @Test
+ public void failedConnect() throws Exception {
+ VeryBasicHttpServer.Op op = server
+ .opBuilder()
+ .noTls()
+ .build();
+ Future<Void> future = executor.submit(server.run(op));
+
+ HttpURLConnection connection = server.plainConnection("/file");
+ int response = connection.getResponseCode();
+ assertEquals(404, response);
+
+ future.get(2000, TimeUnit.MILLISECONDS);
+ }
+
+ @Test
+ public void successfulConnect() throws Exception {
+ VeryBasicHttpServer.Op op = server.opBuilder()
+ .content("/file", "Hello\nWorld\n")
+ .noTls()
+ .build();
+ Future<Void> future = executor.submit(server.run(op));
+
+ HttpURLConnection connection = server.plainConnection("/file");
+ int response = connection.getResponseCode();
+ assertEquals(200, response);
+
+ future.get(2000, TimeUnit.MILLISECONDS);
+ }
+
+ @Test
+ public void urlReadTimeout() throws Exception {
+ TestUtils.assumeEngineSocket();
+ VeryBasicHttpServer.Op op = server
+ .opBuilder()
+ .noTls()
+ .postAcceptDelay(5000)
+ .closeBeforeRead()
+ .build();
+ Future<Void> future = executor.submit(server.run(op));
+
+ HttpURLConnection connection = server.plainConnection("/file");
+ connection.setConnectTimeout(0);
+ connection.setReadTimeout(1000);
+
+ try {
+ connection.getInputStream();
+ fail("Connection succeeded unexpectedly");
+ } catch (SocketException e) {
+ if (e.getMessage().contains("reset")) {
+ fail("HttpsURLConnection's Read timeout failed, got: " + e.getMessage());
+ } else {
+ fail("Unexpected SocketException");
+ }
+ } catch (SocketTimeoutException expected) {
+ // Expected
+ }
+
+ future.get(6000, TimeUnit.MILLISECONDS);
+ }
+}
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ZpenSSLX509Certificate.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ZpenSSLX509Certificate.java
new file mode 100644
index 0000000..256f4a4
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ZpenSSLX509Certificate.java
@@ -0,0 +1,35 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2015 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.Serializable;
+
+/**
+ * This is a fake class to test de-serialization with malicious payloads.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ZpenSSLX509Certificate implements Serializable {
+ /** This will be set via reflection in the test. */
+ private static final long serialVersionUID = 0L;
+
+ public final long mContext;
+
+ ZpenSSLX509Certificate(long ctx) {
+ mContext = ctx;
+ }
+}
diff --git a/repackaged/platform/src/main/java/com/android/org/conscrypt/CertBlocklistImpl.java b/repackaged/platform/src/main/java/com/android/org/conscrypt/CertBlocklistImpl.java
new file mode 100644
index 0000000..06de29a
--- /dev/null
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/CertBlocklistImpl.java
@@ -0,0 +1,303 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class CertBlocklistImpl implements CertBlocklist {
+ private static final Logger logger = Logger.getLogger(CertBlocklistImpl.class.getName());
+
+ private final Set<BigInteger> serialBlocklist;
+ private final Set<ByteString> pubkeyBlocklist;
+
+ /**
+ * public for testing only.
+ */
+ public CertBlocklistImpl(Set<BigInteger> serialBlocklist, Set<ByteString> pubkeyBlocklist) {
+ this.serialBlocklist = serialBlocklist;
+ this.pubkeyBlocklist = pubkeyBlocklist;
+ }
+
+ public static CertBlocklist getDefault() {
+ String androidData = System.getenv("ANDROID_DATA");
+ String blocklistRoot = androidData + "/misc/keychain/";
+ String defaultPubkeyBlocklistPath = blocklistRoot + "pubkey_blacklist.txt";
+ String defaultSerialBlocklistPath = blocklistRoot + "serial_blacklist.txt";
+
+ Set<ByteString> pubkeyBlocklist = readPublicKeyBlockList(defaultPubkeyBlocklistPath);
+ Set<BigInteger> serialBlocklist = readSerialBlockList(defaultSerialBlocklistPath);
+ return new CertBlocklistImpl(serialBlocklist, pubkeyBlocklist);
+ }
+
+ private static boolean isHex(String value) {
+ try {
+ new BigInteger(value, 16);
+ return true;
+ } catch (NumberFormatException e) {
+ logger.log(Level.WARNING, "Could not parse hex value " + value, e);
+ return false;
+ }
+ }
+
+ private static boolean isPubkeyHash(String value) {
+ if (value.length() != 40) {
+ logger.log(Level.WARNING, "Invalid pubkey hash length: " + value.length());
+ return false;
+ }
+ return isHex(value);
+ }
+
+ private static String readBlocklist(String path) {
+ try {
+ return readFileAsString(path);
+ } catch (FileNotFoundException ignored) {
+ // Ignored
+ } catch (IOException e) {
+ logger.log(Level.WARNING, "Could not read blocklist", e);
+ }
+ return "";
+ }
+
+ // From IoUtils.readFileAsString
+ private static String readFileAsString(String path) throws IOException {
+ return readFileAsBytes(path).toString("UTF-8");
+ }
+
+ // Based on IoUtils.readFileAsBytes
+ private static ByteArrayOutputStream readFileAsBytes(String path) throws IOException {
+ RandomAccessFile f = null;
+ try {
+ f = new RandomAccessFile(path, "r");
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream((int) f.length());
+ byte[] buffer = new byte[8192];
+ while (true) {
+ int byteCount = f.read(buffer);
+ if (byteCount == -1) {
+ return bytes;
+ }
+ bytes.write(buffer, 0, byteCount);
+ }
+ } finally {
+ closeQuietly(f);
+ }
+ }
+
+ // Base on IoUtils.closeQuietly
+ private static void closeQuietly(Closeable closeable) {
+ if (closeable != null) {
+ try {
+ closeable.close();
+ } catch (RuntimeException rethrown) {
+ throw rethrown;
+ } catch (Exception ignored) {
+ // Ignored
+ }
+ }
+ }
+
+ private static Set<BigInteger> readSerialBlockList(String path) {
+
+ /* Start out with a base set of known bad values.
+ *
+ * WARNING: Do not add short serials to this list!
+ *
+ * Since this currently doesn't compare the serial + issuer, you
+ * should only add serials that have enough entropy here. Short
+ * serials may inadvertently match a certificate that was issued
+ * not in compliance with the Baseline Requirements.
+ */
+ Set<BigInteger> bl = new HashSet<BigInteger>(Arrays.asList(
+ // From http://src.chromium.org/viewvc/chrome/trunk/src/net/base/x509_certificate.cc?revision=78748&view=markup
+ // Not a real certificate. For testing only.
+ new BigInteger("077a59bcd53459601ca6907267a6dd1c", 16),
+ new BigInteger("047ecbe9fca55f7bd09eae36e10cae1e", 16),
+ new BigInteger("d8f35f4eb7872b2dab0692e315382fb0", 16),
+ new BigInteger("b0b7133ed096f9b56fae91c874bd3ac0", 16),
+ new BigInteger("9239d5348f40d1695a745470e1f23f43", 16),
+ new BigInteger("e9028b9578e415dc1a710a2b88154447", 16),
+ new BigInteger("d7558fdaf5f1105bb213282b707729a3", 16),
+ new BigInteger("f5c86af36162f13a64f54f6dc9587c06", 16),
+ new BigInteger("392a434f0e07df1f8aa305de34e0c229", 16),
+ new BigInteger("3e75ced46b693021218830ae86a82a71", 16)
+ ));
+
+ // attempt to augment it with values taken from gservices
+ String serialBlocklist = readBlocklist(path);
+ if (!serialBlocklist.equals("")) {
+ for (String value : serialBlocklist.split(",", -1)) {
+ try {
+ bl.add(new BigInteger(value, 16));
+ } catch (NumberFormatException e) {
+ logger.log(Level.WARNING, "Tried to blacklist invalid serial number " + value, e);
+ }
+ }
+ }
+
+ // whether that succeeds or fails, send it on its merry way
+ return Collections.unmodifiableSet(bl);
+ }
+
+ private static Set<ByteString> readPublicKeyBlockList(String path) {
+
+ // start out with a base set of known bad values
+ Set<ByteString> bl = new HashSet<ByteString>(toByteStrings(
+ // Blocklist test cert for CTS. The cert and key can be found in
+ // src/test/resources/blocklist_test_ca.pem and
+ // src/test/resources/blocklist_test_ca_key.pem.
+ "bae78e6bed65a2bf60ddedde7fd91e825865e93d".getBytes(UTF_8),
+ // From http://src.chromium.org/viewvc/chrome/branches/782/src/net/base/x509_certificate.cc?r1=98750&r2=98749&pathrev=98750
+ // C=NL, O=DigiNotar, CN=DigiNotar Root CA/emailAddress=info@diginotar.nl
+ "410f36363258f30b347d12ce4863e433437806a8".getBytes(UTF_8),
+ // Subject: CN=DigiNotar Cyber CA
+ // Issuer: CN=GTE CyberTrust Global Root
+ "ba3e7bd38cd7e1e6b9cd4c219962e59d7a2f4e37".getBytes(UTF_8),
+ // Subject: CN=DigiNotar Services 1024 CA
+ // Issuer: CN=Entrust.net
+ "e23b8d105f87710a68d9248050ebefc627be4ca6".getBytes(UTF_8),
+ // Subject: CN=DigiNotar PKIoverheid CA Organisatie - G2
+ // Issuer: CN=Staat der Nederlanden Organisatie CA - G2
+ "7b2e16bc39bcd72b456e9f055d1de615b74945db".getBytes(UTF_8),
+ // Subject: CN=DigiNotar PKIoverheid CA Overheid en Bedrijven
+ // Issuer: CN=Staat der Nederlanden Overheid CA
+ "e8f91200c65cee16e039b9f883841661635f81c5".getBytes(UTF_8),
+ // From http://src.chromium.org/viewvc/chrome?view=rev&revision=108479
+ // Subject: O=Digicert Sdn. Bhd.
+ // Issuer: CN=GTE CyberTrust Global Root
+ "0129bcd5b448ae8d2496d1c3e19723919088e152".getBytes(UTF_8),
+ // Subject: CN=e-islem.kktcmerkezbankasi.org/emailAddress=ileti@kktcmerkezbankasi.org
+ // Issuer: CN=T\xC3\x9CRKTRUST Elektronik Sunucu Sertifikas\xC4\xB1 Hizmetleri
+ "5f3ab33d55007054bc5e3e5553cd8d8465d77c61".getBytes(UTF_8),
+ // Subject: CN=*.EGO.GOV.TR 93
+ // Issuer: CN=T\xC3\x9CRKTRUST Elektronik Sunucu Sertifikas\xC4\xB1 Hizmetleri
+ "783333c9687df63377efceddd82efa9101913e8e".getBytes(UTF_8),
+ // Subject: Subject: C=FR, O=DG Tr\xC3\xA9sor, CN=AC DG Tr\xC3\xA9sor SSL
+ // Issuer: C=FR, O=DGTPE, CN=AC DGTPE Signature Authentification
+ "3ecf4bbbe46096d514bb539bb913d77aa4ef31bf".getBytes(UTF_8)
+ ));
+
+ // attempt to augment it with values taken from gservices
+ String pubkeyBlocklist = readBlocklist(path);
+ if (!pubkeyBlocklist.equals("")) {
+ for (String value : pubkeyBlocklist.split(",", -1)) {
+ value = value.trim();
+ if (isPubkeyHash(value)) {
+ bl.add(new ByteString(value.getBytes(UTF_8)));
+ } else {
+ logger.log(Level.WARNING, "Tried to blocklist invalid pubkey " + value);
+ }
+ }
+ }
+
+ return bl;
+ }
+
+ @Override
+ public boolean isPublicKeyBlockListed(PublicKey publicKey) {
+ byte[] encoded = publicKey.getEncoded();
+ MessageDigest md;
+ try {
+ md = MessageDigest.getInstance("SHA1");
+ } catch (GeneralSecurityException e) {
+ logger.log(Level.SEVERE, "Unable to get SHA1 MessageDigest", e);
+ return false;
+ }
+ byte[] out = toHex(md.digest(encoded));
+ for (ByteString blocklisted : pubkeyBlocklist) {
+ if (Arrays.equals(blocklisted.bytes, out)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static final byte[] HEX_TABLE = { (byte) '0', (byte) '1', (byte) '2', (byte) '3',
+ (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'a',
+ (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f'};
+
+ private static byte[] toHex(byte[] in) {
+ byte[] out = new byte[in.length * 2];
+ int outIndex = 0;
+ for (int i = 0; i < in.length; i++) {
+ int value = in[i] & 0xff;
+ out[outIndex++] = HEX_TABLE[value >> 4];
+ out[outIndex++] = HEX_TABLE[value & 0xf];
+ }
+ return out;
+ }
+
+ @Override
+ public boolean isSerialNumberBlockListed(BigInteger serial) {
+ return serialBlocklist.contains(serial);
+ }
+
+ private static List<ByteString> toByteStrings(byte[]... allBytes) {
+ List<ByteString> byteStrings = new ArrayList<>(allBytes.length + 1);
+ for (byte[] bytes : allBytes) {
+ byteStrings.add(new ByteString(bytes));
+ }
+ return byteStrings;
+ }
+
+ private static class ByteString {
+ final byte[] bytes;
+
+ public ByteString(byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof ByteString)) {
+ return false;
+ }
+
+ ByteString other = (ByteString) o;
+ return Arrays.equals(bytes, other.bytes);
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(bytes);
+ }
+ }
+}
diff --git a/repackaged/platform/src/main/java/com/android/org/conscrypt/Hex.java b/repackaged/platform/src/main/java/com/android/org/conscrypt/Hex.java
new file mode 100644
index 0000000..cadbf44
--- /dev/null
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/Hex.java
@@ -0,0 +1,54 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2013 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.
+ */
+
+package com.android.org.conscrypt;
+
+/**
+ * Helper class for dealing with hexadecimal strings.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+// public for testing by TrustedCertificateStoreTest
+// TODO(nathanmittler): Move to InternalUtil?
+public final class Hex {
+ private Hex() {}
+
+ private final static char[] DIGITS = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+ public static String bytesToHexString(byte[] bytes) {
+ char[] buf = new char[bytes.length * 2];
+ int c = 0;
+ for (byte b : bytes) {
+ buf[c++] = DIGITS[(b >> 4) & 0xf];
+ buf[c++] = DIGITS[b & 0xf];
+ }
+ return new String(buf);
+ }
+
+ public static String intToHexString(int i, int minWidth) {
+ int bufLen = 8; // Max number of hex digits in an int
+ char[] buf = new char[bufLen];
+ int cursor = bufLen;
+
+ do {
+ buf[--cursor] = DIGITS[i & 0xf];
+ } while ((i >>>= 4) != 0 || (bufLen - cursor < minWidth));
+
+ return new String(buf, cursor, bufLen - cursor);
+ }
+}
diff --git a/repackaged/platform/src/main/java/com/android/org/conscrypt/InternalUtil.java b/repackaged/platform/src/main/java/com/android/org/conscrypt/InternalUtil.java
new file mode 100644
index 0000000..bf3f043
--- /dev/null
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/InternalUtil.java
@@ -0,0 +1,48 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.InputStream;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+
+/**
+ * Helper to initialize the JNI libraries. This version runs when compiled
+ * as part of the platform.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class InternalUtil {
+ public static PublicKey logKeyToPublicKey(byte[] logKey)
+ throws NoSuchAlgorithmException {
+ try {
+ return new OpenSSLKey(NativeCrypto.EVP_parse_public_key(logKey)).getPublicKey();
+ } catch (ParsingException e) {
+ throw new NoSuchAlgorithmException(e);
+ }
+ }
+
+ public static PublicKey readPublicKeyPem(InputStream pem) throws InvalidKeyException, NoSuchAlgorithmException {
+ return OpenSSLKey.fromPublicKeyPemInputStream(pem).getPublicKey();
+ }
+
+ private InternalUtil() {
+ }
+}
diff --git a/repackaged/platform/src/main/java/com/android/org/conscrypt/JSSEProvider.java b/repackaged/platform/src/main/java/com/android/org/conscrypt/JSSEProvider.java
new file mode 100644
index 0000000..d4e2d4a
--- /dev/null
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/JSSEProvider.java
@@ -0,0 +1,57 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.security.Provider;
+
+/**
+ * JSSE Provider implementation.
+ *
+ * The current JSSE provider implementation uses the following
+ * crypto algorithms:
+ *
+ * Algorithms that MUST be provided by crypto provider:
+ * Mac HmacMD5
+ * Mac HmacSHA1
+ * MessageDigest MD5
+ * MessageDigest SHA-1
+ * CertificateFactory X509
+ *
+ * Trust manager implementation requires:
+ * CertPathValidator PKIX
+ * CertificateFactory X509
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class JSSEProvider extends Provider {
+
+ private static final long serialVersionUID = 3075686092260669675L;
+
+ public JSSEProvider() {
+ super("HarmonyJSSE", 1.0, "Harmony JSSE Provider");
+
+ put("KeyManagerFactory.PKIX", KeyManagerFactoryImpl.class.getName());
+ put("Alg.Alias.KeyManagerFactory.X509", "PKIX");
+
+ put("TrustManagerFactory.PKIX", TrustManagerFactoryImpl.class.getName());
+ put("Alg.Alias.TrustManagerFactory.X509", "PKIX");
+
+ put("KeyStore.AndroidCAStore", TrustedCertificateKeyStoreSpi.class.getName());
+ }
+}
diff --git a/repackaged/platform/src/main/java/com/android/org/conscrypt/NativeCryptoJni.java b/repackaged/platform/src/main/java/com/android/org/conscrypt/NativeCryptoJni.java
new file mode 100644
index 0000000..254b45c
--- /dev/null
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/NativeCryptoJni.java
@@ -0,0 +1,31 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2015 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.
+ */
+
+package com.android.org.conscrypt;
+
+/**
+ * Helper to initialize the JNI libraries. This version runs when compiled
+ * as part of the platform.
+ */
+class NativeCryptoJni {
+ public static void init() {
+ System.loadLibrary("javacrypto");
+ }
+
+ private NativeCryptoJni() {
+ }
+}
diff --git a/repackaged/platform/src/main/java/com/android/org/conscrypt/Platform.java b/repackaged/platform/src/main/java/com/android/org/conscrypt/Platform.java
new file mode 100644
index 0000000..e43e2f3
--- /dev/null
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/Platform.java
@@ -0,0 +1,570 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2013 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static android.system.OsConstants.SOL_SOCKET;
+import static android.system.OsConstants.SO_SNDTIMEO;
+import static com.android.org.conscrypt.metrics.Source.SOURCE_MAINLINE;
+
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructTimeval;
+import com.android.org.conscrypt.ct.CTLogStore;
+import com.android.org.conscrypt.ct.CTLogStoreImpl;
+import com.android.org.conscrypt.ct.CTPolicy;
+import com.android.org.conscrypt.ct.CTPolicyImpl;
+import com.android.org.conscrypt.metrics.CipherSuite;
+import com.android.org.conscrypt.metrics.ConscryptStatsLog;
+import com.android.org.conscrypt.metrics.Protocol;
+import dalvik.system.BlockGuard;
+import dalvik.system.CloseGuard;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.lang.System;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketImpl;
+import java.security.AlgorithmParameters;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIMatcher;
+import javax.net.ssl.SNIServerName;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.StandardConstants;
+import javax.net.ssl.X509ExtendedTrustManager;
+import javax.net.ssl.X509TrustManager;
+import libcore.net.NetworkSecurityPolicy;
+import sun.security.x509.AlgorithmId;
+
+final class Platform {
+ private static class NoPreloadHolder { public static final Platform MAPPER = new Platform(); }
+
+ /**
+ * Runs all the setup for the platform that only needs to run once.
+ */
+ public static void setup() {
+ NoPreloadHolder.MAPPER.ping();
+ }
+
+ /**
+ * Just a placeholder to make sure the class is initialized.
+ */
+ private void ping() {}
+
+ private Platform() {}
+
+ /**
+ * Default name used in the {@link java.security.Security JCE system} by {@code OpenSSLProvider}
+ * if the default constructor is used.
+ */
+ // @VisibleForTesting - used by CTS
+ public static String getDefaultProviderName() {
+ return "AndroidOpenSSL";
+ }
+
+ static boolean provideTrustManagerByDefault() {
+ return false;
+ }
+
+ static FileDescriptor getFileDescriptor(Socket s) {
+ return s.getFileDescriptor$();
+ }
+
+ static FileDescriptor getFileDescriptorFromSSLSocket(AbstractConscryptSocket socket) {
+ try {
+ Field f_impl = Socket.class.getDeclaredField("impl");
+ f_impl.setAccessible(true);
+ Object socketImpl = f_impl.get(socket);
+ Field f_fd = SocketImpl.class.getDeclaredField("fd");
+ f_fd.setAccessible(true);
+ return (FileDescriptor) f_fd.get(socketImpl);
+ } catch (Exception e) {
+ throw new RuntimeException("Can't get FileDescriptor from socket", e);
+ }
+ }
+
+ static String getCurveName(ECParameterSpec spec) {
+ return spec.getCurveName();
+ }
+
+ static void setCurveName(ECParameterSpec spec, String curveName) {
+ spec.setCurveName(curveName);
+ }
+
+ static void setSocketWriteTimeout(Socket s, long timeoutMillis) throws SocketException {
+ StructTimeval tv = StructTimeval.fromMillis(timeoutMillis);
+ try {
+ Os.setsockoptTimeval(s.getFileDescriptor$(), SOL_SOCKET, SO_SNDTIMEO, tv);
+ } catch (ErrnoException errnoException) {
+ // Equivalent to errnoException.rethrowAsSocketException() but that causes
+ // lint issues on AOSP.
+ SocketException exception = new SocketException(errnoException.getMessage());
+ exception.addSuppressed(errnoException);
+ throw exception;
+ }
+ }
+
+ static void setSSLParameters(
+ SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) {
+ impl.setEndpointIdentificationAlgorithm(params.getEndpointIdentificationAlgorithm());
+ impl.setUseCipherSuitesOrder(params.getUseCipherSuitesOrder());
+ List<SNIServerName> serverNames = params.getServerNames();
+ if (serverNames != null) {
+ for (SNIServerName serverName : serverNames) {
+ if (serverName.getType() == StandardConstants.SNI_HOST_NAME) {
+ socket.setHostname(((SNIHostName) serverName).getAsciiName());
+ break;
+ }
+ }
+ }
+ impl.setApplicationProtocols(params.getApplicationProtocols());
+ }
+
+ static void getSSLParameters(
+ SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) {
+ params.setEndpointIdentificationAlgorithm(impl.getEndpointIdentificationAlgorithm());
+ params.setUseCipherSuitesOrder(impl.getUseCipherSuitesOrder());
+ if (impl.getUseSni() && AddressUtils.isValidSniHostname(socket.getHostname())) {
+ params.setServerNames(Collections.<SNIServerName>singletonList(
+ new SNIHostName(socket.getHostname())));
+ }
+ params.setApplicationProtocols(impl.getApplicationProtocols());
+ }
+
+ static void setSSLParameters(
+ SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) {
+ impl.setEndpointIdentificationAlgorithm(params.getEndpointIdentificationAlgorithm());
+ impl.setUseCipherSuitesOrder(params.getUseCipherSuitesOrder());
+ List<SNIServerName> serverNames = params.getServerNames();
+ if (serverNames != null) {
+ for (SNIServerName serverName : serverNames) {
+ if (serverName.getType() == StandardConstants.SNI_HOST_NAME) {
+ engine.setHostname(((SNIHostName) serverName).getAsciiName());
+ break;
+ }
+ }
+ }
+ impl.setApplicationProtocols(params.getApplicationProtocols());
+ }
+
+ static void getSSLParameters(
+ SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) {
+ params.setEndpointIdentificationAlgorithm(impl.getEndpointIdentificationAlgorithm());
+ params.setUseCipherSuitesOrder(impl.getUseCipherSuitesOrder());
+ if (impl.getUseSni() && AddressUtils.isValidSniHostname(engine.getHostname())) {
+ params.setServerNames(Collections.<SNIServerName>singletonList(
+ new SNIHostName(engine.getHostname())));
+ }
+ params.setApplicationProtocols(impl.getApplicationProtocols());
+ }
+
+ /**
+ * Helper function to unify calls to the different names used for each function taking a
+ * Socket, SSLEngine, or String (legacy Android).
+ */
+ private static boolean checkTrusted(String methodName, X509TrustManager tm,
+ X509Certificate[] chain, String authType, Class<?> argumentClass,
+ Object argumentInstance) throws CertificateException {
+ // Use duck-typing to try and call the hostname-aware method if available.
+ try {
+ Method method = tm.getClass().getMethod(
+ methodName, X509Certificate[].class, String.class, argumentClass);
+ method.invoke(tm, chain, authType, argumentInstance);
+ return true;
+ } catch (NoSuchMethodException | IllegalAccessException ignored) {
+ } catch (InvocationTargetException e) {
+ if (e.getCause() instanceof CertificateException) {
+ throw(CertificateException) e.getCause();
+ }
+ throw new RuntimeException(e.getCause());
+ }
+ return false;
+ }
+
+ static void checkClientTrusted(X509TrustManager tm, X509Certificate[] chain, String authType,
+ AbstractConscryptSocket socket) throws CertificateException {
+ if (tm instanceof X509ExtendedTrustManager) {
+ X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm;
+ x509etm.checkClientTrusted(chain, authType, socket);
+ } else if (!checkTrusted("checkClientTrusted", tm, chain, authType, Socket.class, socket)
+ && !checkTrusted("checkClientTrusted", tm, chain, authType, String.class,
+ socket.getHandshakeSession().getPeerHost())) {
+ tm.checkClientTrusted(chain, authType);
+ }
+ }
+
+ static void checkServerTrusted(X509TrustManager tm, X509Certificate[] chain, String authType,
+ AbstractConscryptSocket socket) throws CertificateException {
+ if (tm instanceof X509ExtendedTrustManager) {
+ X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm;
+ x509etm.checkServerTrusted(chain, authType, socket);
+ } else if (!checkTrusted("checkServerTrusted", tm, chain, authType, Socket.class, socket)
+ && !checkTrusted("checkServerTrusted", tm, chain, authType, String.class,
+ socket.getHandshakeSession().getPeerHost())) {
+ tm.checkServerTrusted(chain, authType);
+ }
+ }
+
+ static void checkClientTrusted(X509TrustManager tm, X509Certificate[] chain, String authType,
+ ConscryptEngine engine) throws CertificateException {
+ if (tm instanceof X509ExtendedTrustManager) {
+ X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm;
+ x509etm.checkClientTrusted(chain, authType, engine);
+ } else if (!checkTrusted("checkClientTrusted", tm, chain, authType, SSLEngine.class, engine)
+ && !checkTrusted("checkClientTrusted", tm, chain, authType, String.class,
+ engine.getHandshakeSession().getPeerHost())) {
+ tm.checkClientTrusted(chain, authType);
+ }
+ }
+
+ static void checkServerTrusted(X509TrustManager tm, X509Certificate[] chain, String authType,
+ ConscryptEngine engine) throws CertificateException {
+ if (tm instanceof X509ExtendedTrustManager) {
+ X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm;
+ x509etm.checkServerTrusted(chain, authType, engine);
+ } else if (!checkTrusted("checkServerTrusted", tm, chain, authType, SSLEngine.class, engine)
+ && !checkTrusted("checkServerTrusted", tm, chain, authType, String.class,
+ engine.getHandshakeSession().getPeerHost())) {
+ tm.checkServerTrusted(chain, authType);
+ }
+ }
+
+ /**
+ * Wraps an old AndroidOpenSSL key instance. This is not needed on platform
+ * builds since we didn't backport, so return null.
+ */
+ static OpenSSLKey wrapRsaKey(PrivateKey key) {
+ return null;
+ }
+
+ /**
+ * Logs to the system EventLog system.
+ */
+ static void logEvent(String message) {
+ try {
+ Class processClass = Class.forName("android.os.Process");
+ Object processInstance = processClass.newInstance();
+ Method myUidMethod = processClass.getMethod("myUid", (Class[]) null);
+ int uid = (Integer) myUidMethod.invoke(processInstance);
+
+ Class eventLogClass = Class.forName("android.util.EventLog");
+ Object eventLogInstance = eventLogClass.newInstance();
+ Method writeEventMethod = eventLogClass.getMethod(
+ "writeEvent", new Class[] {Integer.TYPE, Object[].class});
+ writeEventMethod.invoke(eventLogInstance, 0x534e4554 /* SNET */,
+ new Object[] {"conscrypt", uid, message});
+ } catch (Exception e) {
+ // Do not log and fail silently
+ }
+ }
+
+ static SSLEngine wrapEngine(ConscryptEngine engine) {
+ return new Java8EngineWrapper(engine);
+ }
+
+ static SSLEngine unwrapEngine(SSLEngine engine) {
+ return Java8EngineWrapper.getDelegate(engine);
+ }
+
+ static ConscryptEngineSocket createEngineSocket(SSLParametersImpl sslParameters)
+ throws IOException {
+ return new Java8EngineSocket(sslParameters);
+ }
+
+ static ConscryptEngineSocket createEngineSocket(String hostname, int port,
+ SSLParametersImpl sslParameters) throws IOException {
+ return new Java8EngineSocket(hostname, port, sslParameters);
+ }
+
+ static ConscryptEngineSocket createEngineSocket(InetAddress address, int port,
+ SSLParametersImpl sslParameters) throws IOException {
+ return new Java8EngineSocket(address, port, sslParameters);
+ }
+
+ static ConscryptEngineSocket createEngineSocket(String hostname, int port,
+ InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters)
+ throws IOException {
+ return new Java8EngineSocket(hostname, port, clientAddress, clientPort, sslParameters);
+ }
+
+ static ConscryptEngineSocket createEngineSocket(InetAddress address, int port,
+ InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters)
+ throws IOException {
+ return new Java8EngineSocket(address, port, clientAddress, clientPort, sslParameters);
+ }
+
+ static ConscryptEngineSocket createEngineSocket(Socket socket, String hostname, int port,
+ boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
+ return new Java8EngineSocket(socket, hostname, port, autoClose, sslParameters);
+ }
+
+ static ConscryptFileDescriptorSocket createFileDescriptorSocket(SSLParametersImpl sslParameters)
+ throws IOException {
+ return new Java8FileDescriptorSocket(sslParameters);
+ }
+
+ static ConscryptFileDescriptorSocket createFileDescriptorSocket(String hostname, int port,
+ SSLParametersImpl sslParameters) throws IOException {
+ return new Java8FileDescriptorSocket(hostname, port, sslParameters);
+ }
+
+ static ConscryptFileDescriptorSocket createFileDescriptorSocket(InetAddress address, int port,
+ SSLParametersImpl sslParameters) throws IOException {
+ return new Java8FileDescriptorSocket(address, port, sslParameters);
+ }
+
+ static ConscryptFileDescriptorSocket createFileDescriptorSocket(String hostname, int port,
+ InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters)
+ throws IOException {
+ return new Java8FileDescriptorSocket(
+ hostname, port, clientAddress, clientPort, sslParameters);
+ }
+
+ static ConscryptFileDescriptorSocket createFileDescriptorSocket(InetAddress address, int port,
+ InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters)
+ throws IOException {
+ return new Java8FileDescriptorSocket(
+ address, port, clientAddress, clientPort, sslParameters);
+ }
+
+ static ConscryptFileDescriptorSocket createFileDescriptorSocket(Socket socket, String hostname,
+ int port, boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
+ return new Java8FileDescriptorSocket(socket, hostname, port, autoClose, sslParameters);
+ }
+
+ /**
+ * Wrap the SocketFactory with the platform wrapper if needed for compatability.
+ * For the platform-bundled library we never need to wrap.
+ */
+ static SSLSocketFactory wrapSocketFactoryIfNeeded(OpenSSLSocketFactoryImpl factory) {
+ return factory;
+ }
+
+ /**
+ * Convert from platform's GCMParameterSpec to our internal version.
+ */
+ static GCMParameters fromGCMParameterSpec(AlgorithmParameterSpec params) {
+ if (params instanceof GCMParameterSpec) {
+ GCMParameterSpec gcmParams = (GCMParameterSpec) params;
+ return new GCMParameters(gcmParams.getTLen(), gcmParams.getIV());
+ }
+ return null;
+ }
+
+ /**
+ * Convert from an opaque AlgorithmParameters to the platform's GCMParameterSpec.
+ */
+ static AlgorithmParameterSpec fromGCMParameters(AlgorithmParameters params) {
+ try {
+ return params.getParameterSpec(GCMParameterSpec.class);
+ } catch (InvalidParameterSpecException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Creates a platform version of {@code GCMParameterSpec}.
+ */
+ static AlgorithmParameterSpec toGCMParameterSpec(int tagLenInBits, byte[] iv) {
+ return new GCMParameterSpec(tagLenInBits, iv);
+ }
+
+ /*
+ * CloseGuard functions.
+ */
+
+ static CloseGuard closeGuardGet() {
+ return CloseGuard.get();
+ }
+
+ static void closeGuardOpen(Object guardObj, String message) {
+ CloseGuard guard = (CloseGuard) guardObj;
+ guard.open(message);
+ }
+
+ static void closeGuardClose(Object guardObj) {
+ CloseGuard guard = (CloseGuard) guardObj;
+ guard.close();
+ }
+
+ static void closeGuardWarnIfOpen(Object guardObj) {
+ CloseGuard guard = (CloseGuard) guardObj;
+ guard.warnIfOpen();
+ }
+
+ /*
+ * BlockGuard functions.
+ */
+
+ static void blockGuardOnNetwork() {
+ BlockGuard.getThreadPolicy().onNetwork();
+ }
+
+ /**
+ * OID to Algorithm Name mapping.
+ */
+ static String oidToAlgorithmName(String oid) {
+ try {
+ return AlgorithmId.get(oid).getName();
+ } catch (NoSuchAlgorithmException e) {
+ return oid;
+ }
+ }
+
+ /**
+ * Provides extended capabilities for the session if supported by the platform.
+ */
+ static SSLSession wrapSSLSession(ExternalSession sslSession) {
+ return new Java8ExtendedSSLSession(sslSession);
+ }
+
+ public static String getOriginalHostNameFromInetAddress(InetAddress addr) {
+ try {
+ Method getHolder = InetAddress.class.getDeclaredMethod("holder");
+ getHolder.setAccessible(true);
+
+ Method getOriginalHostName = Class.forName("java.net.InetAddress$InetAddressHolder")
+ .getDeclaredMethod("getOriginalHostName");
+ getOriginalHostName.setAccessible(true);
+
+ String originalHostName = (String) getOriginalHostName.invoke(getHolder.invoke(addr));
+ if (originalHostName == null) {
+ return addr.getHostAddress();
+ }
+ return originalHostName;
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException("Failed to get originalHostName", e);
+ } catch (ClassNotFoundException ignore) {
+ // passthrough and return addr.getHostAddress()
+ } catch (IllegalAccessException ignore) {
+ } catch (NoSuchMethodException ignore) {
+ }
+ return addr.getHostAddress();
+ }
+
+ /*
+ * Pre-Java-7 backward compatibility.
+ */
+
+ static String getHostStringFromInetSocketAddress(InetSocketAddress addr) {
+ return addr.getHostString();
+ }
+
+ // The platform always has X509ExtendedTrustManager
+ static boolean supportsX509ExtendedTrustManager() {
+ return true;
+ }
+
+ static boolean isCTVerificationRequired(String hostname) {
+ return NetworkSecurityPolicy.getInstance().isCertificateTransparencyVerificationRequired(
+ hostname);
+ }
+
+ static boolean supportsConscryptCertStore() {
+ return true;
+ }
+
+ static KeyStore getDefaultCertKeyStore() throws KeyStoreException {
+ KeyStore keyStore = KeyStore.getInstance("AndroidCAStore");
+ try {
+ keyStore.load(null, null);
+ } catch (IOException | CertificateException | NoSuchAlgorithmException e) {
+ throw new KeyStoreException(e);
+ }
+ return keyStore;
+ }
+
+ static ConscryptCertStore newDefaultCertStore() {
+ return new TrustedCertificateStore();
+ }
+
+ static CertBlocklist newDefaultBlocklist() {
+ return CertBlocklistImpl.getDefault();
+ }
+
+ static CTLogStore newDefaultLogStore() {
+ return new CTLogStoreImpl();
+ }
+
+ static CTPolicy newDefaultPolicy(CTLogStore logStore) {
+ return new CTPolicyImpl(logStore, 2);
+ }
+
+ static boolean serverNamePermitted(SSLParametersImpl parameters, String serverName) {
+ Collection<SNIMatcher> sniMatchers = parameters.getSNIMatchers();
+ if (sniMatchers == null || sniMatchers.isEmpty()) {
+ return true;
+ }
+
+ SNIHostName hostname = new SNIHostName(serverName);
+ for (SNIMatcher m : sniMatchers) {
+ boolean match = m.matches(hostname);
+ if (match) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static ConscryptHostnameVerifier getDefaultHostnameVerifier() {
+ return Conscrypt.wrapHostnameVerifier(HttpsURLConnection.getDefaultHostnameVerifier());
+ }
+
+ /**
+ * Returns milliseconds elapsed since boot, including time spent in sleep.
+ * @return long number of milliseconds elapsed since boot
+ */
+ static long getMillisSinceBoot() {
+ return System.currentTimeMillis();
+ }
+
+ static void countTlsHandshake(
+ boolean success, String protocol, String cipherSuite, long durationLong) {
+ Protocol proto = Protocol.forName(protocol);
+ CipherSuite suite = CipherSuite.forName(cipherSuite);
+ int duration = (int) durationLong;
+
+ ConscryptStatsLog.write(ConscryptStatsLog.TLS_HANDSHAKE_REPORTED, success, proto.getId(),
+ suite.getId(), duration, SOURCE_MAINLINE);
+ }
+
+ public static boolean isJavaxCertificateSupported() {
+ return true;
+ }
+}
diff --git a/repackaged/platform/src/main/java/com/android/org/conscrypt/TEST_MAPPING b/repackaged/platform/src/main/java/com/android/org/conscrypt/TEST_MAPPING
new file mode 100644
index 0000000..04c4062
--- /dev/null
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "external/conscrypt/repackaged/common/src/main/java/com/android/org/conscrypt"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/repackaged/platform/src/main/java/com/android/org/conscrypt/TrustedCertificateKeyStoreSpi.java b/repackaged/platform/src/main/java/com/android/org/conscrypt/TrustedCertificateKeyStoreSpi.java
new file mode 100644
index 0000000..6bfdbbd
--- /dev/null
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/TrustedCertificateKeyStoreSpi.java
@@ -0,0 +1,132 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2011 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.Key;
+import java.security.KeyStoreSpi;
+import java.security.cert.Certificate;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+
+/**
+ * A KeyStoreSpi wrapper for the TrustedCertificateStore.
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class TrustedCertificateKeyStoreSpi extends KeyStoreSpi {
+
+ private final TrustedCertificateStore store = new TrustedCertificateStore();
+
+ @Override
+ public Key engineGetKey(String alias, char[] password) {
+ if (alias == null) {
+ throw new NullPointerException("alias == null");
+ }
+ return null;
+ }
+
+ @Override
+ public Certificate[] engineGetCertificateChain(String alias) {
+ if (alias == null) {
+ throw new NullPointerException("alias == null");
+ }
+ return null;
+ }
+
+ @Override
+ public Certificate engineGetCertificate(String alias) {
+ return store.getCertificate(alias);
+ }
+
+ @Override
+ public Date engineGetCreationDate(String alias) {
+ return store.getCreationDate(alias);
+ }
+
+ @Override
+ public void engineSetKeyEntry(
+ String alias, Key key, char[] password, Certificate[] chain) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void engineSetCertificateEntry(String alias, Certificate cert) {
+ if (alias == null) {
+ throw new NullPointerException("alias == null");
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void engineDeleteEntry(String alias) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Enumeration<String> engineAliases() {
+ return Collections.enumeration(store.aliases());
+ }
+
+ @Override
+ public boolean engineContainsAlias(String alias) {
+ return store.containsAlias(alias);
+ }
+
+ @Override
+ public int engineSize() {
+ return store.aliases().size();
+ }
+
+ @Override
+ public boolean engineIsKeyEntry(String alias) {
+ if (alias == null) {
+ throw new NullPointerException("alias == null");
+ }
+ return false;
+ }
+
+ @Override
+ public boolean engineIsCertificateEntry(String alias) {
+ return engineContainsAlias(alias);
+ }
+
+ @Override
+ public String engineGetCertificateAlias(Certificate c) {
+ return store.getCertificateAlias(c);
+ }
+
+ @Override
+ public void engineStore(OutputStream stream, char[] password) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void engineLoad(InputStream stream, char[] password) {
+ if (stream != null) {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/repackaged/platform/src/main/java/com/android/org/conscrypt/TrustedCertificateStore.java b/repackaged/platform/src/main/java/com/android/org/conscrypt/TrustedCertificateStore.java
new file mode 100644
index 0000000..fbbcc25
--- /dev/null
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/TrustedCertificateStore.java
@@ -0,0 +1,707 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2011 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.
+ */
+
+package com.android.org.conscrypt;
+
+import com.android.org.conscrypt.io.IoUtils;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * A source for trusted root certificate authority (CA) certificates
+ * supporting an immutable system CA directory along with mutable
+ * directories allowing the user addition of custom CAs and user
+ * removal of system CAs. This store supports the {@code
+ * TrustedCertificateKeyStoreSpi} wrapper to allow a traditional
+ * KeyStore interface for use with {@link
+ * javax.net.ssl.TrustManagerFactory.init}.
+ *
+ * <p>The CAs are accessed via {@code KeyStore} style aliases. Aliases
+ * are made up of a prefix identifying the source ("system:" vs
+ * "user:") and a suffix based on the OpenSSL X509_NAME_hash_old
+ * function of the CA's subject name. For example, the system CA for
+ * "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification
+ * Authority" could be represented as "system:7651b327.0". By using
+ * the subject hash, operations such as {@link #getCertificateAlias
+ * getCertificateAlias} can be implemented efficiently without
+ * scanning the entire store.
+ *
+ * <p>In addition to supporting the {@code
+ * TrustedCertificateKeyStoreSpi} implementation, {@code
+ * TrustedCertificateStore} also provides the additional public
+ * method {@link #findIssuer} to allow efficient lookup operations
+ * for CAs again based on the file naming convention.
+ *
+ * <p>The KeyChainService users the {@link installCertificate} and
+ * {@link #deleteCertificateEntry} to install user CAs as well as
+ * delete those user CAs as well as system CAs. The deletion of system
+ * CAs is performed by placing an exact copy of that CA in the deleted
+ * directory. Such deletions are intended to persist across upgrades
+ * but not intended to mask a CA with a matching name or public key
+ * but is otherwise reissued in a system update. Reinstalling a
+ * deleted system certificate simply removes the copy from the deleted
+ * directory, reenabling the original in the system directory.
+ *
+ * <p>Note that the default mutable directory is created by init via
+ * configuration in the system/core/rootdir/init.rc file. The
+ * directive "mkdir /data/misc/keychain 0775 system system"
+ * ensures that its owner and group are the system uid and system
+ * gid and that it is world readable but only writable by the system
+ * user.
+ * @hide This class is not part of the Android public SDK API
+ */
+@libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+@Internal
+public class TrustedCertificateStore implements ConscryptCertStore {
+ private static String PREFIX_SYSTEM = "system:";
+ private static final String PREFIX_USER = "user:";
+
+ public static final boolean isSystem(String alias) {
+ return alias.startsWith(PREFIX_SYSTEM);
+ }
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public static final boolean isUser(String alias) {
+ return alias.startsWith(PREFIX_USER);
+ }
+
+ private static class PreloadHolder {
+ private static File defaultCaCertsSystemDir;
+ private static File defaultCaCertsAddedDir;
+ private static File defaultCaCertsDeletedDir;
+
+ static {
+ String ANDROID_ROOT = System.getenv("ANDROID_ROOT");
+ String ANDROID_DATA = System.getenv("ANDROID_DATA");
+ File updatableDir = new File("/apex/com.android.conscrypt/cacerts");
+ if ((System.getProperty("system.certs.enabled") != null)
+ && (System.getProperty("system.certs.enabled")).equals("true")) {
+ defaultCaCertsSystemDir = new File(ANDROID_ROOT + "/etc/security/cacerts");
+ } else if (updatableDir.exists() && !(updatableDir.list().length == 0)) {
+ defaultCaCertsSystemDir = updatableDir;
+ } else {
+ defaultCaCertsSystemDir = new File(ANDROID_ROOT + "/etc/security/cacerts");
+ }
+ setDefaultUserDirectory(new File(ANDROID_DATA + "/misc/keychain"));
+ }
+ }
+
+ private static final CertificateFactory CERT_FACTORY;
+ static {
+ try {
+ CERT_FACTORY = CertificateFactory.getInstance("X509");
+ } catch (CertificateException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public static void setDefaultUserDirectory(File root) {
+ PreloadHolder.defaultCaCertsAddedDir = new File(root, "cacerts-added");
+ PreloadHolder.defaultCaCertsDeletedDir = new File(root, "cacerts-removed");
+ }
+
+ private final File systemDir;
+ private final File addedDir;
+ private final File deletedDir;
+
+ @android.compat.annotation.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public TrustedCertificateStore() {
+ this(PreloadHolder.defaultCaCertsSystemDir, PreloadHolder.defaultCaCertsAddedDir,
+ PreloadHolder.defaultCaCertsDeletedDir);
+ }
+
+ public TrustedCertificateStore(File baseDir) {
+ this(baseDir, PreloadHolder.defaultCaCertsAddedDir, PreloadHolder.defaultCaCertsDeletedDir);
+ }
+
+ public TrustedCertificateStore(File systemDir, File addedDir, File deletedDir) {
+ this.systemDir = systemDir;
+ this.addedDir = addedDir;
+ this.deletedDir = deletedDir;
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public Certificate getCertificate(String alias) {
+ return getCertificate(alias, false);
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public Certificate getCertificate(String alias, boolean includeDeletedSystem) {
+ File file = fileForAlias(alias);
+ if (file == null || (isUser(alias) && isTombstone(file))) {
+ return null;
+ }
+ X509Certificate cert = readCertificate(file);
+ if (cert == null || (isSystem(alias)
+ && !includeDeletedSystem
+ && isDeletedSystemCertificate(cert))) {
+ // skip malformed certs as well as deleted system ones
+ return null;
+ }
+ return cert;
+ }
+
+ private File fileForAlias(String alias) {
+ if (alias == null) {
+ throw new NullPointerException("alias == null");
+ }
+ File file;
+ if (isSystem(alias)) {
+ file = new File(systemDir, alias.substring(PREFIX_SYSTEM.length()));
+ } else if (isUser(alias)) {
+ file = new File(addedDir, alias.substring(PREFIX_USER.length()));
+ } else {
+ return null;
+ }
+ if (!file.exists() || isTombstone(file)) {
+ // silently elide tombstones
+ return null;
+ }
+ return file;
+ }
+
+ private boolean isTombstone(File file) {
+ return file.length() == 0;
+ }
+
+ private X509Certificate readCertificate(File file) {
+ if (!file.isFile()) {
+ return null;
+ }
+ InputStream is = null;
+ try {
+ is = new BufferedInputStream(new FileInputStream(file));
+ return (X509Certificate) CERT_FACTORY.generateCertificate(is);
+ } catch (IOException e) {
+ return null;
+ } catch (CertificateException e) {
+ // reading a cert while its being installed can lead to this.
+ // just pretend like its not available yet.
+ return null;
+ } finally {
+ IoUtils.closeQuietly(is);
+ }
+ }
+
+ private void writeCertificate(File file, X509Certificate cert)
+ throws IOException, CertificateException {
+ File dir = file.getParentFile();
+ dir.mkdirs();
+ dir.setReadable(true, false);
+ dir.setExecutable(true, false);
+ OutputStream os = null;
+ try {
+ os = new FileOutputStream(file);
+ os.write(cert.getEncoded());
+ } finally {
+ IoUtils.closeQuietly(os);
+ }
+ file.setReadable(true, false);
+ }
+
+ private boolean isDeletedSystemCertificate(X509Certificate x) {
+ return getCertificateFile(deletedDir, x).exists();
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ @SuppressWarnings("JdkObsolete") // Used in public API TrustedCertificateKeyStoreSpi
+ public Date getCreationDate(String alias) {
+ // containsAlias check ensures the later fileForAlias result
+ // was not a deleted system cert.
+ if (!containsAlias(alias)) {
+ return null;
+ }
+ File file = fileForAlias(alias);
+ if (file == null) {
+ return null;
+ }
+ long time = file.lastModified();
+ if (time == 0) {
+ time = 1672531200L; // Jan 1st, 2023
+ }
+ return new Date(time);
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public Set<String> aliases() {
+ Set<String> result = new HashSet<String>();
+ addAliases(result, PREFIX_USER, addedDir);
+ addAliases(result, PREFIX_SYSTEM, systemDir);
+ return result;
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public Set<String> userAliases() {
+ Set<String> result = new HashSet<String>();
+ addAliases(result, PREFIX_USER, addedDir);
+ return result;
+ }
+
+ private void addAliases(Set<String> result, String prefix, File dir) {
+ String[] files = dir.list();
+ if (files == null) {
+ return;
+ }
+ for (String filename : files) {
+ String alias = prefix + filename;
+ if (containsAlias(alias)) {
+ result.add(alias);
+ }
+ }
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public Set<String> allSystemAliases() {
+ Set<String> result = new HashSet<String>();
+ String[] files = systemDir.list();
+ if (files == null) {
+ return result;
+ }
+ for (String filename : files) {
+ String alias = PREFIX_SYSTEM + filename;
+ if (containsAlias(alias, true)) {
+ result.add(alias);
+ }
+ }
+ return result;
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public boolean containsAlias(String alias) {
+ return containsAlias(alias, false);
+ }
+
+ private boolean containsAlias(String alias, boolean includeDeletedSystem) {
+ return getCertificate(alias, includeDeletedSystem) != null;
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public String getCertificateAlias(Certificate c) {
+ return getCertificateAlias(c, false);
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public String getCertificateAlias(Certificate c, boolean includeDeletedSystem) {
+ if (c == null || !(c instanceof X509Certificate)) {
+ return null;
+ }
+ X509Certificate x = (X509Certificate) c;
+ File user = getCertificateFile(addedDir, x);
+ if (user.exists()) {
+ return PREFIX_USER + user.getName();
+ }
+ if (!includeDeletedSystem && isDeletedSystemCertificate(x)) {
+ return null;
+ }
+ File system = getCertificateFile(systemDir, x);
+ if (system.exists()) {
+ return PREFIX_SYSTEM + system.getName();
+ }
+ return null;
+ }
+
+ /**
+ * Returns true to indicate that the certificate was added by the
+ * user, false otherwise.
+ */
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public boolean isUserAddedCertificate(X509Certificate cert) {
+ return getCertificateFile(addedDir, cert).exists();
+ }
+
+ /**
+ * Returns a File for where the certificate is found if it exists
+ * or where it should be installed if it does not exist. The
+ * caller can disambiguate these cases by calling {@code
+ * File.exists()} on the result.
+ *
+ * @VisibleForTesting
+ */
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public File getCertificateFile(File dir, final X509Certificate x) {
+ // compare X509Certificate.getEncoded values
+ CertSelector selector = new CertSelector() {
+ @Override
+ public boolean match(X509Certificate cert) {
+ return cert.equals(x);
+ }
+ };
+ return findCert(dir, x.getSubjectX500Principal(), selector, File.class);
+ }
+
+ /**
+ * This non-{@code KeyStoreSpi} public interface is used by {@code
+ * TrustManagerImpl} to locate a CA certificate with the same name
+ * and public key as the provided {@code X509Certificate}. We
+ * match on the name and public key and not the entire certificate
+ * since a CA may be reissued with the same name and PublicKey but
+ * with other differences (for example when switching signature
+ * from md2WithRSAEncryption to SHA1withRSA)
+ */
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ @Override
+ public X509Certificate getTrustAnchor(final X509Certificate c) {
+ // compare X509Certificate.getPublicKey values
+ CertSelector selector = new CertSelector() {
+ @Override
+ public boolean match(X509Certificate ca) {
+ return ca.getPublicKey().equals(c.getPublicKey());
+ }
+ };
+ X509Certificate user = findCert(addedDir,
+ c.getSubjectX500Principal(),
+ selector,
+ X509Certificate.class);
+ if (user != null) {
+ return user;
+ }
+ X509Certificate system = findCert(systemDir,
+ c.getSubjectX500Principal(),
+ selector,
+ X509Certificate.class);
+ if (system != null && !isDeletedSystemCertificate(system)) {
+ return system;
+ }
+ return null;
+ }
+
+ /**
+ * This non-{@code KeyStoreSpi} public interface is used by {@code
+ * TrustManagerImpl} to locate the CA certificate that signed the
+ * provided {@code X509Certificate}.
+ */
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public X509Certificate findIssuer(final X509Certificate c) {
+ // match on verified issuer of Certificate
+ CertSelector selector = new CertSelector() {
+ @Override
+ public boolean match(X509Certificate ca) {
+ try {
+ c.verify(ca.getPublicKey());
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ };
+ X500Principal issuer = c.getIssuerX500Principal();
+ X509Certificate user = findCert(addedDir, issuer, selector, X509Certificate.class);
+ if (user != null) {
+ return user;
+ }
+ X509Certificate system = findCert(systemDir, issuer, selector, X509Certificate.class);
+ if (system != null && !isDeletedSystemCertificate(system)) {
+ return system;
+ }
+ return null;
+ }
+
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ @Override
+ public Set<X509Certificate> findAllIssuers(final X509Certificate c) {
+ Set<X509Certificate> issuers = null;
+ CertSelector selector = new CertSelector() {
+ @Override
+ public boolean match(X509Certificate ca) {
+ try {
+ c.verify(ca.getPublicKey());
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ };
+ X500Principal issuer = c.getIssuerX500Principal();
+ Set<X509Certificate> userAddedCerts = findCertSet(addedDir, issuer, selector);
+ if (userAddedCerts != null) {
+ issuers = userAddedCerts;
+ }
+ selector = new CertSelector() {
+ @Override
+ public boolean match(X509Certificate ca) {
+ try {
+ if (isDeletedSystemCertificate(ca)) {
+ return false;
+ }
+ c.verify(ca.getPublicKey());
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ };
+ Set<X509Certificate> systemCerts = findCertSet(systemDir, issuer, selector);
+ if (systemCerts != null) {
+ if (issuers != null) {
+ issuers.addAll(systemCerts);
+ } else {
+ issuers = systemCerts;
+ }
+ }
+ return (issuers != null) ? issuers : Collections.<X509Certificate>emptySet();
+ }
+
+ private static boolean isSelfIssuedCertificate(OpenSSLX509Certificate cert) {
+ final long ctx = cert.getContext();
+ return NativeCrypto.X509_check_issued(ctx, cert, ctx, cert) == 0;
+ }
+
+ /**
+ * Converts the {@code cert} to the internal OpenSSL X.509 format so we can
+ * run {@link NativeCrypto} methods on it.
+ */
+ private static OpenSSLX509Certificate convertToOpenSSLIfNeeded(X509Certificate cert)
+ throws CertificateException {
+ if (cert == null) {
+ return null;
+ }
+
+ if (cert instanceof OpenSSLX509Certificate) {
+ return (OpenSSLX509Certificate) cert;
+ }
+
+ try {
+ return OpenSSLX509Certificate.fromX509Der(cert.getEncoded());
+ } catch (Exception e) {
+ throw new CertificateException(e);
+ }
+ }
+
+ /**
+ * Attempt to build a certificate chain from the supplied {@code leaf}
+ * argument through the chain of issuers as high up as known. If the chain
+ * can't be completed, the most complete chain available will be returned.
+ * This means that a list with only the {@code leaf} certificate is returned
+ * if no issuer certificates could be found.
+ *
+ * @throws CertificateException if there was a problem parsing the
+ * certificates
+ */
+ @android.compat.annotation.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public List<X509Certificate> getCertificateChain(X509Certificate leaf)
+ throws CertificateException {
+ final LinkedHashSet<OpenSSLX509Certificate> chain
+ = new LinkedHashSet<OpenSSLX509Certificate>();
+ OpenSSLX509Certificate cert = convertToOpenSSLIfNeeded(leaf);
+ chain.add(cert);
+
+ while (true) {
+ if (isSelfIssuedCertificate(cert)) {
+ break;
+ }
+ cert = convertToOpenSSLIfNeeded(findIssuer(cert));
+ if (cert == null || chain.contains(cert)) {
+ break;
+ }
+ chain.add(cert);
+ }
+
+ return new ArrayList<X509Certificate>(chain);
+ }
+
+ // like java.security.cert.CertSelector but with X509Certificate and without cloning
+ private static interface CertSelector {
+ public boolean match(X509Certificate cert);
+ }
+
+ @SuppressWarnings("unchecked")
+ private Set<X509Certificate> findCertSet(
+ File dir, X500Principal subject, CertSelector selector) {
+ return (Set<X509Certificate>) findCert(dir, subject, selector, Set.class);
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T> T findCert(
+ File dir, X500Principal subject, CertSelector selector, Class<T> desiredReturnType) {
+ Set<X509Certificate> certs = null;
+ String hash = hash(subject);
+ for (int index = 0; true; index++) {
+ File file = file(dir, hash, index);
+ if (!file.isFile()) {
+ // could not find a match, no file exists, bail
+ if (desiredReturnType == Boolean.class) {
+ return (T) Boolean.FALSE;
+ }
+ if (desiredReturnType == File.class) {
+ // we return file so that caller that wants to
+ // write knows what the next available has
+ // location is
+ return (T) file;
+ }
+ if (desiredReturnType == Set.class) {
+ return (T) certs;
+ }
+ return null;
+ }
+ if (isTombstone(file)) {
+ continue;
+ }
+ X509Certificate cert = readCertificate(file);
+ if (cert == null) {
+ // skip problem certificates
+ continue;
+ }
+ if (selector.match(cert)) {
+ if (desiredReturnType == X509Certificate.class) {
+ return (T) cert;
+ } else if (desiredReturnType == Boolean.class) {
+ return (T) Boolean.TRUE;
+ } else if (desiredReturnType == File.class) {
+ return (T) file;
+ } else if (desiredReturnType == Set.class) {
+ if (certs == null) {
+ certs = new HashSet<X509Certificate>();
+ }
+ certs.add((X509Certificate) cert);
+ } else {
+ throw new AssertionError();
+ }
+ }
+ }
+ }
+
+ private String hash(X500Principal name) {
+ int hash = NativeCrypto.X509_NAME_hash_old(name);
+ return Hex.intToHexString(hash, 8);
+ }
+
+ private File file(File dir, String hash, int index) {
+ return new File(dir, hash + '.' + index);
+ }
+
+ /**
+ * This non-{@code KeyStoreSpi} public interface is used by the
+ * {@code KeyChainService} to install new CA certificates. It
+ * silently ignores the certificate if it already exists in the
+ * store.
+ */
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public void installCertificate(X509Certificate cert) throws IOException, CertificateException {
+ if (cert == null) {
+ throw new NullPointerException("cert == null");
+ }
+ File system = getCertificateFile(systemDir, cert);
+ if (system.exists()) {
+ File deleted = getCertificateFile(deletedDir, cert);
+ if (deleted.exists()) {
+ // we have a system cert that was marked deleted.
+ // remove the deleted marker to expose the original
+ if (!deleted.delete()) {
+ throw new IOException("Could not remove " + deleted);
+ }
+ return;
+ }
+ // otherwise we just have a dup of an existing system cert.
+ // return taking no further action.
+ return;
+ }
+ File user = getCertificateFile(addedDir, cert);
+ if (user.exists()) {
+ // we have an already installed user cert, bail.
+ return;
+ }
+ // install the user cert
+ writeCertificate(user, cert);
+ }
+
+ /**
+ * This could be considered the implementation of {@code
+ * TrustedCertificateKeyStoreSpi.engineDeleteEntry} but we
+ * consider {@code TrustedCertificateKeyStoreSpi} to be read
+ * only. Instead, this is used by the {@code KeyChainService} to
+ * delete CA certificates.
+ */
+ @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
+ public void deleteCertificateEntry(String alias) throws IOException, CertificateException {
+ if (alias == null) {
+ return;
+ }
+ File file = fileForAlias(alias);
+ if (file == null) {
+ return;
+ }
+ if (isSystem(alias)) {
+ X509Certificate cert = readCertificate(file);
+ if (cert == null) {
+ // skip problem certificates
+ return;
+ }
+ File deleted = getCertificateFile(deletedDir, cert);
+ if (deleted.exists()) {
+ // already deleted system certificate
+ return;
+ }
+ // write copy of system cert to marked as deleted
+ writeCertificate(deleted, cert);
+ return;
+ }
+ if (isUser(alias)) {
+ // truncate the file to make a tombstone by opening and closing.
+ // we need ensure that we don't leave a gap before a valid cert.
+ new FileOutputStream(file).close();
+ removeUnnecessaryTombstones(alias);
+ return;
+ }
+ // non-existant user cert, nothing to delete
+ }
+
+ private void removeUnnecessaryTombstones(String alias) throws IOException {
+ if (!isUser(alias)) {
+ throw new AssertionError(alias);
+ }
+ int dotIndex = alias.lastIndexOf('.');
+ if (dotIndex == -1) {
+ throw new AssertionError(alias);
+ }
+
+ String hash = alias.substring(PREFIX_USER.length(), dotIndex);
+ int lastTombstoneIndex = Integer.parseInt(alias.substring(dotIndex + 1));
+
+ if (file(addedDir, hash, lastTombstoneIndex + 1).exists()) {
+ return;
+ }
+ while (lastTombstoneIndex >= 0) {
+ File file = file(addedDir, hash, lastTombstoneIndex);
+ if (!isTombstone(file)) {
+ break;
+ }
+ if (!file.delete()) {
+ throw new IOException("Could not remove " + file);
+ }
+ lastTombstoneIndex--;
+ }
+ }
+}
diff --git a/repackaged/platform/src/main/java/com/android/org/conscrypt/ct/CTLogStoreImpl.java b/repackaged/platform/src/main/java/com/android/org/conscrypt/ct/CTLogStoreImpl.java
new file mode 100644
index 0000000..d34b683
--- /dev/null
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/ct/CTLogStoreImpl.java
@@ -0,0 +1,263 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt.ct;
+
+import com.android.org.conscrypt.Internal;
+import com.android.org.conscrypt.InternalUtil;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Scanner;
+import java.util.Set;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class CTLogStoreImpl implements CTLogStore {
+ private static final Charset US_ASCII = StandardCharsets.US_ASCII;
+
+ /**
+ * Thrown when parsing of a log file fails.
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class InvalidLogFileException extends Exception {
+ public InvalidLogFileException() {
+ }
+
+ public InvalidLogFileException(String message) {
+ super(message);
+ }
+
+ public InvalidLogFileException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public InvalidLogFileException(Throwable cause) {
+ super(cause);
+ }
+ }
+
+ private static final File defaultUserLogDir;
+ private static final File defaultSystemLogDir;
+ // Lazy loaded by CTLogStoreImpl()
+ private static volatile CTLogInfo[] defaultFallbackLogs = null;
+ static {
+ String ANDROID_DATA = System.getenv("ANDROID_DATA");
+ String ANDROID_ROOT = System.getenv("ANDROID_ROOT");
+ defaultUserLogDir = new File(ANDROID_DATA + "/misc/keychain/trusted_ct_logs/current/");
+ defaultSystemLogDir = new File(ANDROID_ROOT + "/etc/security/ct_known_logs/");
+ }
+
+ private final File userLogDir;
+ private final File systemLogDir;
+ private final CTLogInfo[] fallbackLogs;
+
+ private final HashMap<ByteBuffer, CTLogInfo> logCache = new HashMap<>();
+ private final Set<ByteBuffer> missingLogCache =
+ Collections.synchronizedSet(new HashSet<ByteBuffer>());
+
+ public CTLogStoreImpl() {
+ this(defaultUserLogDir,
+ defaultSystemLogDir,
+ getDefaultFallbackLogs());
+ }
+
+ public CTLogStoreImpl(File userLogDir, File systemLogDir, CTLogInfo[] fallbackLogs) {
+ this.userLogDir = userLogDir;
+ this.systemLogDir = systemLogDir;
+ this.fallbackLogs = fallbackLogs;
+ }
+
+ @Override
+ public CTLogInfo getKnownLog(byte[] logId) {
+ ByteBuffer buf = ByteBuffer.wrap(logId);
+ CTLogInfo log = logCache.get(buf);
+ if (log != null) {
+ return log;
+ }
+ if (missingLogCache.contains(buf)) {
+ return null;
+ }
+
+ log = findKnownLog(logId);
+ if (log != null) {
+ logCache.put(buf, log);
+ } else {
+ missingLogCache.add(buf);
+ }
+
+ return log;
+ }
+
+ private CTLogInfo findKnownLog(byte[] logId) {
+ String filename = hexEncode(logId);
+ try {
+ return loadLog(new File(userLogDir, filename));
+ } catch (InvalidLogFileException e) {
+ return null;
+ } catch (FileNotFoundException e) {
+ // Ignored
+ }
+
+ try {
+ return loadLog(new File(systemLogDir, filename));
+ } catch (InvalidLogFileException e) {
+ return null;
+ } catch (FileNotFoundException e) {
+ // Ignored
+ }
+
+ // If the updateable logs dont exist then use the fallback logs.
+ if (!userLogDir.exists()) {
+ for (CTLogInfo log: fallbackLogs) {
+ if (Arrays.equals(logId, log.getID())) {
+ return log;
+ }
+ }
+ }
+ return null;
+ }
+
+ public static CTLogInfo[] getDefaultFallbackLogs() {
+ CTLogInfo[] result = defaultFallbackLogs;
+ if (result == null) {
+ // single-check idiom
+ defaultFallbackLogs = result = createDefaultFallbackLogs();
+ }
+ return result;
+ }
+
+ private static CTLogInfo[] createDefaultFallbackLogs() {
+ CTLogInfo[] logs = new CTLogInfo[KnownLogs.LOG_COUNT];
+ for (int i = 0; i < KnownLogs.LOG_COUNT; i++) {
+ try {
+ PublicKey key = InternalUtil.logKeyToPublicKey(KnownLogs.LOG_KEYS[i]);
+
+ logs[i] = new CTLogInfo(key,
+ KnownLogs.LOG_DESCRIPTIONS[i],
+ KnownLogs.LOG_URLS[i]);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ defaultFallbackLogs = logs;
+ return logs;
+ }
+
+ /**
+ * Load a CTLogInfo from a file.
+ * @throws FileNotFoundException if the file does not exist
+ * @throws InvalidLogFileException if the file could not be parsed properly
+ * @return a CTLogInfo or null if the file is empty
+ */
+ public static CTLogInfo loadLog(File file) throws FileNotFoundException,
+ InvalidLogFileException {
+ return loadLog(new FileInputStream(file));
+ }
+
+ /**
+ * Load a CTLogInfo from a textual representation. Closes {@code input} upon completion
+ * of loading.
+ *
+ * @throws InvalidLogFileException if the input could not be parsed properly
+ * @return a CTLogInfo or null if the input is empty
+ */
+ public static CTLogInfo loadLog(InputStream input) throws InvalidLogFileException {
+ final Scanner scan = new Scanner(input, "UTF-8");
+ scan.useDelimiter("\n");
+
+ String description = null;
+ String url = null;
+ String key = null;
+ try {
+ // If the scanner can't even read one token then the file must be empty/blank
+ if (!scan.hasNext()) {
+ return null;
+ }
+
+ while (scan.hasNext()) {
+ String[] parts = scan.next().split(":", 2);
+ if (parts.length < 2) {
+ continue;
+ }
+
+ String name = parts[0];
+ String value = parts[1];
+ switch (name) {
+ case "description":
+ description = value;
+ break;
+ case "url":
+ url = value;
+ break;
+ case "key":
+ key = value;
+ break;
+ }
+ }
+ } finally {
+ scan.close();
+ }
+
+ if (description == null || url == null || key == null) {
+ throw new InvalidLogFileException("Missing one of 'description', 'url' or 'key'");
+ }
+
+ PublicKey pubkey;
+ try {
+ pubkey = InternalUtil.readPublicKeyPem(new ByteArrayInputStream(
+ ("-----BEGIN PUBLIC KEY-----\n" +
+ key + "\n" +
+ "-----END PUBLIC KEY-----").getBytes(US_ASCII)));
+ } catch (InvalidKeyException e) {
+ throw new InvalidLogFileException(e);
+ } catch (NoSuchAlgorithmException e) {
+ throw new InvalidLogFileException(e);
+ }
+
+ return new CTLogInfo(pubkey, description, url);
+ }
+
+ private final static char[] HEX_DIGITS = new char[] {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+
+ private static String hexEncode(byte[] data) {
+ StringBuilder sb = new StringBuilder(data.length * 2);
+ for (byte b: data) {
+ sb.append(HEX_DIGITS[(b >> 4) & 0x0f]);
+ sb.append(HEX_DIGITS[b & 0x0f]);
+ }
+ return sb.toString();
+ }
+}
diff --git a/repackaged/platform/src/main/java/com/android/org/conscrypt/ct/CTPolicyImpl.java b/repackaged/platform/src/main/java/com/android/org/conscrypt/ct/CTPolicyImpl.java
new file mode 100644
index 0000000..aa22b95
--- /dev/null
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/ct/CTPolicyImpl.java
@@ -0,0 +1,51 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt.ct;
+
+import java.security.cert.X509Certificate;
+import java.util.HashSet;
+import java.util.Set;
+import com.android.org.conscrypt.Internal;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class CTPolicyImpl implements CTPolicy {
+ private final CTLogStore logStore;
+ private final int minimumLogCount;
+
+ public CTPolicyImpl(CTLogStore logStore, int minimumLogCount) {
+ this.logStore = logStore;
+ this.minimumLogCount = minimumLogCount;
+ }
+
+ @Override
+ public boolean doesResultConformToPolicy(CTVerificationResult result, String hostname,
+ X509Certificate[] chain) {
+ Set<CTLogInfo> logSet = new HashSet<>();
+ for (VerifiedSCT verifiedSCT: result.getValidSCTs()) {
+ CTLogInfo log = logStore.getKnownLog(verifiedSCT.sct.getLogID());
+ if (log != null) {
+ logSet.add(log);
+ }
+ }
+
+ return logSet.size() >= minimumLogCount;
+ }
+}
diff --git a/repackaged/platform/src/main/java/com/android/org/conscrypt/ct/KnownLogs.java b/repackaged/platform/src/main/java/com/android/org/conscrypt/ct/KnownLogs.java
new file mode 100644
index 0000000..7d6dca1
--- /dev/null
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/ct/KnownLogs.java
@@ -0,0 +1,138 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+/* This file is generated by print_log_list.py
+ * https://github.com/google/certificate-transparency/blob/master/python/utilities/log_list/print_log_list.py */
+
+package com.android.org.conscrypt.ct;
+
+import com.android.org.conscrypt.Internal;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public final class KnownLogs {
+ public static final int LOG_COUNT = 8;
+ public static final String[] LOG_DESCRIPTIONS = new String[] {
+ "Google 'Pilot' log",
+ "Google 'Aviator' log",
+ "DigiCert Log Server",
+ "Google 'Rocketeer' log",
+ "Certly.IO log",
+ "Izenpe log",
+ "Symantec log",
+ "Venafi log",
+ };
+ public static final String[] LOG_URLS = new String[] {
+ "ct.googleapis.com/pilot",
+ "ct.googleapis.com/aviator",
+ "ct1.digicert-ct.com/log",
+ "ct.googleapis.com/rocketeer",
+ "log.certly.io",
+ "ct.izenpe.com",
+ "ct.ws.symantec.com",
+ "ctlog.api.venafi.com",
+ };
+ public static final byte[][] LOG_KEYS = new byte[][] {
+ // Google 'Pilot' log
+ new byte[] {
+ 48, 89, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 8, 42, -122, 72,
+ -50, 61, 3, 1, 7, 3, 66, 0, 4, 125, -88, 75, 18, 41, -128, -93, 61, -83,
+ -45, 90, 119, -72, -52, -30, -120, -77, -91, -3, -15, -45, 12, -51, 24,
+ 12, -24, 65, 70, -24, -127, 1, 27, 21, -31, 75, -15, 27, 98, -35, 54, 10,
+ 8, 24, -70, -19, 11, 53, -124, -48, -98, 64, 60, 45, -98, -101, -126,
+ 101, -67, 31, 4, 16, 65, 76, -96
+ },
+ // Google 'Aviator' log
+ new byte[] {
+ 48, 89, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 8, 42, -122, 72,
+ -50, 61, 3, 1, 7, 3, 66, 0, 4, -41, -12, -52, 105, -78, -28, 14, -112,
+ -93, -118, -22, 90, 112, 9, 79, -17, 19, 98, -48, -115, 73, 96, -1, 27,
+ 64, 80, 7, 12, 109, 113, -122, -38, 37, 73, -115, 101, -31, 8, 13, 71,
+ 52, 107, -67, 39, -68, -106, 33, 62, 52, -11, -121, 118, 49, -79, 127,
+ 29, -55, -123, 59, 13, -9, 31, 63, -23
+ },
+ // DigiCert Log Server
+ new byte[] {
+ 48, 89, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 8, 42, -122, 72,
+ -50, 61, 3, 1, 7, 3, 66, 0, 4, 2, 70, -59, -66, 27, -69, -126, 64, 22,
+ -24, -63, -46, -84, 25, 105, 19, 89, -8, -8, 112, -123, 70, 64, -71, 56,
+ -80, 35, -126, -88, 100, 76, 127, -65, -69, 52, -97, 74, 95, 40, -118,
+ -49, 25, -60, 0, -10, 54, 6, -109, 101, -19, 76, -11, -87, 33, 98, 90,
+ -40, -111, -21, 56, 36, 64, -84, -24
+ },
+ // Google 'Rocketeer' log
+ new byte[] {
+ 48, 89, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 8, 42, -122, 72,
+ -50, 61, 3, 1, 7, 3, 66, 0, 4, 32, 91, 24, -56, 60, -63, -117, -77, 49,
+ 8, 0, -65, -96, -112, 87, 43, -73, 71, -116, 111, -75, 104, -80, -114,
+ -112, 120, -23, -96, 115, -22, 79, 40, 33, 46, -100, -64, -12, 22, 27,
+ -86, -7, -43, -41, -87, -128, -61, 78, 47, 82, 60, -104, 1, 37, 70, 36,
+ 37, 40, 35, 119, 45, 5, -62, 64, 122
+ },
+ // Certly.IO log
+ new byte[] {
+ 48, 89, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 8, 42, -122, 72,
+ -50, 61, 3, 1, 7, 3, 66, 0, 4, 11, 35, -53, -123, 98, -104, 97, 72, 4,
+ 115, -21, 84, 93, -13, -48, 7, -116, 45, 25, 45, -116, 54, -11, -21,
+ -113, 1, 66, 10, 124, -104, 38, 39, -63, -75, -35, -110, -109, -80, -82,
+ -8, -101, 61, 12, -40, 76, 78, 29, -7, 21, -5, 71, 104, 123, -70, 102,
+ -73, 37, -100, -48, 74, -62, 102, -37, 72
+ },
+ // Izenpe log
+ new byte[] {
+ 48, 89, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 8, 42, -122, 72,
+ -50, 61, 3, 1, 7, 3, 66, 0, 4, 39, 100, 57, 12, 45, -36, 80, 24, -8, 33,
+ 0, -94, 14, -19, 44, -22, 62, 117, -70, -97, -109, 100, 9, 0, 17, -60,
+ 17, 23, -85, 92, -49, 15, 116, -84, -75, -105, -112, -109, 0, 91, -72,
+ -21, -9, 39, 61, -39, -78, 10, -127, 95, 47, 13, 117, 56, -108, 55, -103,
+ 30, -10, 7, 118, -32, -18, -66
+ },
+ // Symantec log
+ new byte[] {
+ 48, 89, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 8, 42, -122, 72,
+ -50, 61, 3, 1, 7, 3, 66, 0, 4, -106, -22, -84, 28, 70, 12, 27, 85, -36,
+ 13, -4, -75, -108, 39, 70, 87, 66, 112, 58, 105, 24, -30, -65, 59, -60,
+ -37, -85, -96, -12, -74, 108, -64, 83, 63, 77, 66, 16, 51, -16, 88, -105,
+ -113, 107, -66, 114, -12, 42, -20, 28, 66, -86, 3, 47, 26, 126, 40, 53,
+ 118, -103, 8, 61, 33, 20, -122
+ },
+ // Venafi log
+ new byte[] {
+ 48, -126, 1, 34, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0,
+ 3, -126, 1, 15, 0, 48, -126, 1, 10, 2, -126, 1, 1, 0, -94, 90, 72, 31,
+ 23, 82, -107, 53, -53, -93, 91, 58, 31, 83, -126, 118, -108, -93, -1,
+ -128, -14, 28, 55, 60, -64, -79, -67, -63, 89, -117, -85, 45, 101, -109,
+ -41, -13, -32, 4, -43, -102, 111, -65, -42, 35, 118, 54, 79, 35, -103,
+ -53, 84, 40, -83, -116, 21, 75, 101, 89, 118, 65, 74, -100, -90, -9, -77,
+ 59, 126, -79, -91, 73, -92, 23, 81, 108, -128, -36, 42, -112, 80, 75,
+ -120, 36, -23, -91, 18, 50, -109, 4, 72, -112, 2, -6, 95, 14, 48, -121,
+ -114, 85, 118, 5, -18, 42, 76, -50, -93, 106, 105, 9, 110, 37, -83, -126,
+ 118, 15, -124, -110, -6, 56, -42, -122, 78, 36, -113, -101, -80, 114,
+ -53, -98, -30, 107, 63, -31, 109, -55, 37, 117, 35, -120, -95, 24, 88, 6,
+ 35, 51, 120, -38, 0, -48, 56, -111, 103, -46, -90, 125, 39, -105, 103,
+ 90, -63, -13, 47, 23, -26, -22, -46, 91, -24, -127, -51, -3, -110, 104,
+ -25, -13, 6, -16, -23, 114, -124, -18, 1, -91, -79, -40, 51, -38, -50,
+ -125, -91, -37, -57, -49, -42, 22, 126, -112, 117, 24, -65, 22, -36, 50,
+ 59, 109, -115, -85, -126, 23, 31, -119, 32, -115, 29, -102, -26, 77, 35,
+ 8, -33, 120, 111, -58, 5, -65, 95, -82, -108, -105, -37, 95, 100, -44,
+ -18, 22, -117, -93, -124, 108, 113, 43, -15, -85, 127, 93, 13, 50, -18,
+ 4, -30, -112, -20, 65, -97, -5, 57, -63, 2, 3, 1, 0, 1
+ },
+ };
+}
diff --git a/repackaged/platform/src/main/java/com/android/org/conscrypt/ct/TEST_MAPPING b/repackaged/platform/src/main/java/com/android/org/conscrypt/ct/TEST_MAPPING
new file mode 100644
index 0000000..34120cb
--- /dev/null
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/ct/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "external/conscrypt/repackaged/common/src/main/java/com/android/org/conscrypt/ct"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/repackaged/platform/src/test/java/com/android/org/conscrypt/CertBlocklistTest.java b/repackaged/platform/src/test/java/com/android/org/conscrypt/CertBlocklistTest.java
new file mode 100644
index 0000000..c970f22
--- /dev/null
+++ b/repackaged/platform/src/test/java/com/android/org/conscrypt/CertBlocklistTest.java
@@ -0,0 +1,127 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import javax.net.ssl.X509TrustManager;
+import junit.framework.TestCase;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CertBlocklistTest extends TestCase {
+
+ private static final String BLOCKLIST_CA = "test_blocklist_ca.pem";
+ private static final String BLOCKLISTED_CHAIN = "blocklist_test_chain.pem";
+ private static final String BLOCKLIST_FALLBACK_VALID_CA = "blocklist_test_valid_ca.pem";
+ private static final String BLOCKLISTED_VALID_CHAIN = "blocklist_test_valid_chain.pem";
+
+ /**
+ * Ensure that the test blocklisted CA is actually blocklisted by default.
+ */
+ public void testBlocklistedPublicKey() throws Exception {
+ X509Certificate blocklistedCa = loadCertificate(BLOCKLIST_CA);
+ CertBlocklist blocklist = CertBlocklistImpl.getDefault();
+ assertTrue(blocklist.isPublicKeyBlockListed(blocklistedCa.getPublicKey()));
+ }
+
+ /**
+ * Check that the blocklisted CA is rejected even if it used as a root of trust
+ */
+ public void testBlocklistedCaUntrusted() throws Exception {
+ X509Certificate blocklistedCa = loadCertificate(BLOCKLIST_CA);
+ assertUntrusted(new X509Certificate[] {blocklistedCa}, getTrustManager(blocklistedCa));
+ }
+
+ /**
+ * Check that a chain that is rooted in a blocklisted trusted CA is rejected.
+ */
+ public void testBlocklistedRootOfTrust() throws Exception {
+ // Chain is leaf -> blocklisted
+ X509Certificate[] chain = loadCertificates(BLOCKLISTED_CHAIN);
+ X509Certificate blocklistedCa = loadCertificate(BLOCKLIST_CA);
+ assertUntrusted(chain, getTrustManager(blocklistedCa));
+ }
+
+ /** Test that the path building correctly routes around a blocklisted cert where there are
+ * other valid paths available. This prevents breakage where a cert was cross signed by a
+ * blocklisted CA but is still valid due to also being cross signed by CAs that remain trusted.
+ * Path:
+ *
+ * leaf -> intermediate -> blocklisted_ca
+ * \
+ * -------> trusted_ca
+ */
+ public void testBlocklistedIntermediateFallback() throws Exception {
+ X509Certificate[] chain = loadCertificates(BLOCKLISTED_VALID_CHAIN);
+ X509Certificate blocklistedCa = loadCertificate(BLOCKLIST_CA);
+ X509Certificate validCa = loadCertificate(BLOCKLIST_FALLBACK_VALID_CA);
+ assertTrusted(chain, getTrustManager(blocklistedCa, validCa));
+ // Check that without the trusted_ca the chain is invalid (since it only chains to a
+ // blocklisted ca)
+ assertUntrusted(chain, getTrustManager(blocklistedCa));
+ }
+
+ private static X509Certificate loadCertificate(String file) throws Exception {
+ return loadCertificates(file)[0];
+ }
+
+ private static X509Certificate[] loadCertificates(String file) throws Exception {
+ CertificateFactory factory = CertificateFactory.getInstance("X.509");
+ try (InputStream is = TestUtils.openTestFile(file)) {
+ Collection<? extends Certificate> collection = factory.generateCertificates(is);
+ is.close();
+ X509Certificate[] certs = new X509Certificate[collection.size()];
+ int i = 0;
+ for (Certificate cert : collection) {
+ certs[i++] = (X509Certificate) cert;
+ }
+ return certs;
+ }
+ }
+
+ private static TrustManagerImpl getTrustManager(X509Certificate... trustedCas)
+ throws Exception {
+ KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ ks.load(null);
+ int i = 0;
+ for (X509Certificate ca : trustedCas) {
+ ks.setCertificateEntry(String.valueOf(i++), ca);
+ }
+ return new TrustManagerImpl(ks);
+ }
+
+ private static void assertTrusted(X509Certificate[] certs, X509TrustManager tm)
+ throws Exception {
+ tm.checkServerTrusted(certs, "RSA");
+ }
+
+ private static void assertUntrusted(X509Certificate[] certs, X509TrustManager tm) {
+ try {
+ tm.checkServerTrusted(certs, "RSA");
+ fail();
+ } catch (CertificateException expected) {
+ }
+ }
+}
diff --git a/repackaged/platform/src/test/java/com/android/org/conscrypt/TrustedCertificateStoreTest.java b/repackaged/platform/src/test/java/com/android/org/conscrypt/TrustedCertificateStoreTest.java
new file mode 100644
index 0000000..79c920f
--- /dev/null
+++ b/repackaged/platform/src/test/java/com/android/org/conscrypt/TrustedCertificateStoreTest.java
@@ -0,0 +1,1051 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2011 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.
+ */
+
+package com.android.org.conscrypt;
+
+import com.android.org.conscrypt.java.security.TestKeyStore;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.KeyStore;
+import java.security.KeyStore.PrivateKeyEntry;
+import java.security.KeyStore.TrustedCertificateEntry;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import javax.security.auth.x500.X500Principal;
+import junit.framework.TestCase;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@SuppressWarnings("unused")
+@RunWith(Parameterized.class)
+public class TrustedCertificateStoreTest extends TestCase {
+ private static final Random tempFileRandom = new Random();
+
+ private static File dirTest;
+ private static File dirSystem;
+ private static File dirAdded;
+ private static File dirDeleted;
+
+ private static X509Certificate CA1;
+ private static X509Certificate CA2;
+
+ private static KeyStore.PrivateKeyEntry PRIVATE;
+ private static X509Certificate[] CHAIN;
+
+ private static X509Certificate CA3_WITH_CA1_SUBJECT;
+ private static String ALIAS_SYSTEM_CA1;
+ private static String ALIAS_SYSTEM_CA2;
+ private static String ALIAS_USER_CA1;
+ private static String ALIAS_USER_CA2;
+
+ private static String ALIAS_SYSTEM_CHAIN0;
+ private static String ALIAS_SYSTEM_CHAIN1;
+ private static String ALIAS_SYSTEM_CHAIN2;
+ private static String ALIAS_USER_CHAIN0;
+ private static String ALIAS_USER_CHAIN1;
+ private static String ALIAS_USER_CHAIN2;
+
+ private static String ALIAS_SYSTEM_CA3;
+ private static String ALIAS_SYSTEM_CA3_COLLISION;
+ private static String ALIAS_USER_CA3;
+ private static String ALIAS_USER_CA3_COLLISION;
+
+ private static X509Certificate CERTLOOP_EE;
+ private static X509Certificate CERTLOOP_CA1;
+ private static X509Certificate CERTLOOP_CA2;
+ private static String ALIAS_USER_CERTLOOP_EE;
+ private static String ALIAS_USER_CERTLOOP_CA1;
+ private static String ALIAS_USER_CERTLOOP_CA2;
+
+ private static X509Certificate MULTIPLE_ISSUERS_CA1;
+ private static X509Certificate MULTIPLE_ISSUERS_CA1_CROSS;
+ private static X509Certificate MULTIPLE_ISSUERS_CA2;
+ private static X509Certificate MULTIPLE_ISSUERS_EE;
+ private static String ALIAS_MULTIPLE_ISSUERS_CA1;
+ private static String ALIAS_MULTIPLE_ISSUERS_CA1_CROSS;
+ private static String ALIAS_MULTIPLE_ISSUERS_CA2;
+ private static String ALIAS_MULTIPLE_ISSUERS_EE;
+
+ private static X509Certificate getCa1() {
+ initCerts();
+ return CA1;
+ }
+ private static X509Certificate getCa2() {
+ initCerts();
+ return CA2;
+ }
+
+ private static KeyStore.PrivateKeyEntry getPrivate() {
+ initCerts();
+ return PRIVATE;
+ }
+ private static X509Certificate[] getChain() {
+ initCerts();
+ return CHAIN;
+ }
+
+ private static X509Certificate getCa3WithCa1Subject() {
+ initCerts();
+ return CA3_WITH_CA1_SUBJECT;
+ }
+
+ private static String getAliasSystemCa1() {
+ initCerts();
+ return ALIAS_SYSTEM_CA1;
+ }
+ private static String getAliasSystemCa2() {
+ initCerts();
+ return ALIAS_SYSTEM_CA2;
+ }
+ private static String getAliasUserCa1() {
+ initCerts();
+ return ALIAS_USER_CA1;
+ }
+ private static String getAliasUserCa2() {
+ initCerts();
+ return ALIAS_USER_CA2;
+ }
+
+ private static String getAliasSystemChain0() {
+ initCerts();
+ return ALIAS_SYSTEM_CHAIN0;
+ }
+ private static String getAliasSystemChain1() {
+ initCerts();
+ return ALIAS_SYSTEM_CHAIN1;
+ }
+ private static String getAliasSystemChain2() {
+ initCerts();
+ return ALIAS_SYSTEM_CHAIN2;
+ }
+ private static String getAliasUserChain0() {
+ initCerts();
+ return ALIAS_USER_CHAIN0;
+ }
+ private static String getAliasUserChain1() {
+ initCerts();
+ return ALIAS_USER_CHAIN1;
+ }
+ private static String getAliasUserChain2() {
+ initCerts();
+ return ALIAS_USER_CHAIN2;
+ }
+
+ private static String getAliasSystemCa3() {
+ initCerts();
+ return ALIAS_SYSTEM_CA3;
+ }
+ private static String getAliasSystemCa3Collision() {
+ initCerts();
+ return ALIAS_SYSTEM_CA3_COLLISION;
+ }
+ private static String getAliasUserCa3() {
+ initCerts();
+ return ALIAS_USER_CA3;
+ }
+ private static String getAliasUserCa3Collision() {
+ initCerts();
+ return ALIAS_USER_CA3_COLLISION;
+ }
+ private static X509Certificate getCertLoopEe() {
+ initCerts();
+ return CERTLOOP_EE;
+ }
+ private static X509Certificate getCertLoopCa1() {
+ initCerts();
+ return CERTLOOP_CA1;
+ }
+ private static X509Certificate getCertLoopCa2() {
+ initCerts();
+ return CERTLOOP_CA2;
+ }
+ private static String getAliasCertLoopEe() {
+ initCerts();
+ return ALIAS_USER_CERTLOOP_EE;
+ }
+ private static String getAliasCertLoopCa1() {
+ initCerts();
+ return ALIAS_USER_CERTLOOP_CA1;
+ }
+ private static String getAliasCertLoopCa2() {
+ initCerts();
+ return ALIAS_USER_CERTLOOP_CA2;
+ }
+ private static String getAliasMultipleIssuersCa1() {
+ initCerts();
+ return ALIAS_MULTIPLE_ISSUERS_CA1;
+ }
+ private static String getAliasMultipleIssuersCa2() {
+ initCerts();
+ return ALIAS_MULTIPLE_ISSUERS_CA2;
+ }
+ private static String getAliasMultipleIssuersCa1Cross() {
+ initCerts();
+ return ALIAS_MULTIPLE_ISSUERS_CA1_CROSS;
+ }
+ private static String getAliasMultipleIssuersEe() {
+ initCerts();
+ return ALIAS_MULTIPLE_ISSUERS_EE;
+ }
+ private static X509Certificate getMultipleIssuersCa1() {
+ initCerts();
+ return MULTIPLE_ISSUERS_CA1;
+ }
+ private static X509Certificate getMultipleIssuersCa2() {
+ initCerts();
+ return MULTIPLE_ISSUERS_CA2;
+ }
+ private static X509Certificate getMultipleIssuersCa1Cross() {
+ initCerts();
+ return MULTIPLE_ISSUERS_CA1_CROSS;
+ }
+ private static X509Certificate getMultipleIssuersEe() {
+ initCerts();
+ return MULTIPLE_ISSUERS_EE;
+ }
+
+ /**
+ * Lazily create shared test certificates.
+ */
+ private static synchronized void initCerts() {
+ if (CA1 != null) {
+ return;
+ }
+ try {
+ CA1 = TestKeyStore.getClient().getRootCertificate("RSA");
+ CA2 = TestKeyStore.getClientCA2().getRootCertificate("RSA");
+ PRIVATE = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
+ CHAIN = (X509Certificate[]) PRIVATE.getCertificateChain();
+ CA3_WITH_CA1_SUBJECT = new TestKeyStore.Builder()
+ .aliasPrefix("unused")
+ .subject(CA1.getSubjectX500Principal())
+ .ca(true)
+ .build().getRootCertificate("RSA");
+
+
+ ALIAS_SYSTEM_CA1 = alias(false, CA1, 0);
+ ALIAS_SYSTEM_CA2 = alias(false, CA2, 0);
+ ALIAS_USER_CA1 = alias(true, CA1, 0);
+ ALIAS_USER_CA2 = alias(true, CA2, 0);
+
+ ALIAS_SYSTEM_CHAIN0 = alias(false, getChain()[0], 0);
+ ALIAS_SYSTEM_CHAIN1 = alias(false, getChain()[1], 0);
+ ALIAS_SYSTEM_CHAIN2 = alias(false, getChain()[2], 0);
+ ALIAS_USER_CHAIN0 = alias(true, getChain()[0], 0);
+ ALIAS_USER_CHAIN1 = alias(true, getChain()[1], 0);
+ ALIAS_USER_CHAIN2 = alias(true, getChain()[2], 0);
+
+ ALIAS_SYSTEM_CA3 = alias(false, CA3_WITH_CA1_SUBJECT, 0);
+ ALIAS_SYSTEM_CA3_COLLISION = alias(false, CA3_WITH_CA1_SUBJECT, 1);
+ ALIAS_USER_CA3 = alias(true, CA3_WITH_CA1_SUBJECT, 0);
+ ALIAS_USER_CA3_COLLISION = alias(true, CA3_WITH_CA1_SUBJECT, 1);
+
+ /*
+ * The construction below is to build a certificate chain that has a loop
+ * in it:
+ *
+ * EE ---> CA1 ---> CA2 ---+
+ * ^ |
+ * | |
+ * +--------------+
+ */
+ TestKeyStore certLoopTempCa1 = new TestKeyStore.Builder()
+ .keyAlgorithms("RSA")
+ .aliasPrefix("certloop-ca1")
+ .subject("CN=certloop-ca1")
+ .ca(true)
+ .build();
+ Certificate certLoopTempCaCert1 = ((TrustedCertificateEntry) certLoopTempCa1
+ .getEntryByAlias("certloop-ca1-public-RSA")).getTrustedCertificate();
+ PrivateKeyEntry certLoopCaKey1 = (PrivateKeyEntry) certLoopTempCa1
+ .getEntryByAlias("certloop-ca1-private-RSA");
+
+ TestKeyStore certLoopCa2 = new TestKeyStore.Builder()
+ .keyAlgorithms("RSA")
+ .aliasPrefix("certloop-ca2")
+ .subject("CN=certloop-ca2")
+ .rootCa(certLoopTempCaCert1)
+ .signer(certLoopCaKey1)
+ .ca(true)
+ .build();
+ CERTLOOP_CA2 = (X509Certificate) ((TrustedCertificateEntry) certLoopCa2
+ .getEntryByAlias("certloop-ca2-public-RSA")).getTrustedCertificate();
+ ALIAS_USER_CERTLOOP_CA2 = alias(true, CERTLOOP_CA2, 0);
+ PrivateKeyEntry certLoopCaKey2 = (PrivateKeyEntry) certLoopCa2
+ .getEntryByAlias("certloop-ca2-private-RSA");
+
+ TestKeyStore certLoopCa1 = new TestKeyStore.Builder()
+ .keyAlgorithms("RSA")
+ .aliasPrefix("certloop-ca1")
+ .subject("CN=certloop-ca1")
+ .privateEntry(certLoopCaKey1)
+ .rootCa(CERTLOOP_CA2)
+ .signer(certLoopCaKey2)
+ .ca(true)
+ .build();
+ CERTLOOP_CA1 = (X509Certificate) ((TrustedCertificateEntry) certLoopCa1
+ .getEntryByAlias("certloop-ca1-public-RSA")).getTrustedCertificate();
+ ALIAS_USER_CERTLOOP_CA1 = alias(true, CERTLOOP_CA1, 0);
+
+ TestKeyStore certLoopEe = new TestKeyStore.Builder()
+ .keyAlgorithms("RSA")
+ .aliasPrefix("certloop-ee")
+ .subject("CN=certloop-ee")
+ .rootCa(CERTLOOP_CA1)
+ .signer(certLoopCaKey1)
+ .build();
+ CERTLOOP_EE = (X509Certificate) ((TrustedCertificateEntry) certLoopEe
+ .getEntryByAlias("certloop-ee-public-RSA")).getTrustedCertificate();
+ ALIAS_USER_CERTLOOP_EE = alias(true, CERTLOOP_EE, 0);
+
+ /*
+ * The construction below creates a certificate with multiple possible issuer certs.
+ *
+ * EE ----> CA1 ---> CA2
+ *
+ * Where CA1 also exists in a self-issued form.
+ */
+ TestKeyStore multipleIssuersCa1 = new TestKeyStore.Builder()
+ .keyAlgorithms("RSA")
+ .aliasPrefix("multiple-issuers-ca1")
+ .subject("CN=multiple-issuers-ca1")
+ .ca(true)
+ .build();
+ MULTIPLE_ISSUERS_CA1 = (X509Certificate) ((TrustedCertificateEntry) multipleIssuersCa1
+ .getEntryByAlias("multiple-issuers-ca1-public-RSA")).getTrustedCertificate();
+ ALIAS_MULTIPLE_ISSUERS_CA1 = alias(false, MULTIPLE_ISSUERS_CA1, 0);
+ PrivateKeyEntry multipleIssuersCa1Key = (PrivateKeyEntry) multipleIssuersCa1
+ .getEntryByAlias("multiple-issuers-ca1-private-RSA");
+
+ TestKeyStore multipleIssuersCa2 = new TestKeyStore.Builder()
+ .keyAlgorithms("RSA")
+ .aliasPrefix("multiple-issuers-ca2")
+ .subject("CN=multiple-issuers-ca2")
+ .ca(true)
+ .build();
+ MULTIPLE_ISSUERS_CA2 = (X509Certificate) ((TrustedCertificateEntry) multipleIssuersCa2
+ .getEntryByAlias("multiple-issuers-ca2-public-RSA")).getTrustedCertificate();
+ ALIAS_MULTIPLE_ISSUERS_CA2 = alias(false, MULTIPLE_ISSUERS_CA2, 0);
+ PrivateKeyEntry multipleIssuersCa2Key = (PrivateKeyEntry) multipleIssuersCa2
+ .getEntryByAlias("multiple-issuers-ca2-private-RSA");
+
+ TestKeyStore multipleIssuersCa1SignedByCa2 = new TestKeyStore.Builder()
+ .keyAlgorithms("RSA")
+ .aliasPrefix("multiple-issuers-ca1")
+ .subject("CN=multiple-issuers-ca1")
+ .privateEntry(multipleIssuersCa1Key)
+ .rootCa(MULTIPLE_ISSUERS_CA2)
+ .signer(multipleIssuersCa2Key)
+ .ca(true)
+ .build();
+ MULTIPLE_ISSUERS_CA1_CROSS =
+ (X509Certificate) ((TrustedCertificateEntry) multipleIssuersCa1SignedByCa2
+ .getEntryByAlias("multiple-issuers-ca1-public-RSA"))
+ .getTrustedCertificate();
+ ALIAS_MULTIPLE_ISSUERS_CA1_CROSS = alias(false, MULTIPLE_ISSUERS_CA1_CROSS, 1);
+
+ TestKeyStore multipleIssuersEe = new TestKeyStore.Builder()
+ .keyAlgorithms("RSA")
+ .aliasPrefix("multiple-issuers-ee")
+ .subject("CN=multiple-issuers-ee")
+ .rootCa(MULTIPLE_ISSUERS_CA1)
+ .signer(multipleIssuersCa1Key)
+ .build();
+ MULTIPLE_ISSUERS_EE = (X509Certificate) ((TrustedCertificateEntry) multipleIssuersEe
+ .getEntryByAlias("multiple-issuers-ee-public-RSA")).getTrustedCertificate();
+ ALIAS_MULTIPLE_ISSUERS_EE = alias(false, MULTIPLE_ISSUERS_EE, 0);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Parameters(name = "{0}")
+ public static Object[] data() {
+ return new Object[] {"true", "false"};
+ }
+
+ @Parameter public String mApexCertsEnabled;
+
+ private TrustedCertificateStore store;
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ dirTest = Files.createTempDirectory("cert-store-test").toFile();
+ dirSystem = new File(dirTest, "system");
+ dirAdded = new File(dirTest, "added");
+ dirDeleted = new File(dirTest, "removed");
+ setupStore();
+ }
+
+ private void setupStore() {
+ dirSystem.mkdirs();
+ cleanStore();
+ createStore();
+ }
+
+ private void createStore() {
+ System.setProperty("system.certs.enabled", mApexCertsEnabled);
+ store = new TrustedCertificateStore(dirSystem, dirAdded, dirDeleted);
+ }
+
+ @After
+ @Override
+ public void tearDown() {
+ cleanStore();
+ }
+
+ private void cleanStore() {
+ for (File dir : new File[] { dirSystem, dirAdded, dirDeleted, dirTest }) {
+ File[] files = dir.listFiles();
+ if (files == null) {
+ continue;
+ }
+ for (File file : files) {
+ assertTrue("Should delete " + file.getPath(), file.delete());
+ }
+ }
+ store = null;
+ }
+
+ private void resetStore() {
+ cleanStore();
+ setupStore();
+ }
+
+ @Test
+ public void testEmptyDirectories() throws Exception {
+ assertEmpty();
+ }
+
+ @Test
+ public void testOneSystemOneDeleted() throws Exception {
+ install(getCa1(), getAliasSystemCa1());
+ store.deleteCertificateEntry(getAliasSystemCa1());
+ assertEmpty();
+ assertDeleted(getCa1(), getAliasSystemCa1());
+ }
+
+ @Test
+ public void testTwoSystemTwoDeleted() throws Exception {
+ install(getCa1(), getAliasSystemCa1());
+ store.deleteCertificateEntry(getAliasSystemCa1());
+ install(getCa2(), getAliasSystemCa2());
+ store.deleteCertificateEntry(getAliasSystemCa2());
+ assertEmpty();
+ assertDeleted(getCa1(), getAliasSystemCa1());
+ assertDeleted(getCa2(), getAliasSystemCa2());
+ }
+
+ @Test
+ public void testPartialFileIsIgnored() throws Exception {
+ File file = file(getAliasSystemCa1());
+ file.getParentFile().mkdirs();
+ OutputStream os = new FileOutputStream(file);
+ os.write(0);
+ os.close();
+ assertTrue(file.exists());
+ assertEmpty();
+ assertTrue(file.exists());
+ }
+
+ private void assertEmpty() throws Exception {
+ try {
+ store.getCertificate(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ assertNull(store.getCertificate(""));
+
+ try {
+ store.getCreationDate(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ assertNull(store.getCreationDate(""));
+
+ Set<String> s = store.aliases();
+ assertNotNull(s);
+ assertTrue(s.isEmpty());
+ assertAliases();
+
+ Set<String> u = store.userAliases();
+ assertNotNull(u);
+ assertTrue(u.isEmpty());
+
+ try {
+ store.containsAlias(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ assertFalse(store.containsAlias(""));
+
+ assertNull(store.getCertificateAlias(null));
+ assertNull(store.getCertificateAlias(getCa1()));
+
+ try {
+ store.getTrustAnchor(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ assertNull(store.getTrustAnchor(getCa1()));
+
+ try {
+ store.findIssuer(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ assertNull(store.findIssuer(getCa1()));
+
+ try {
+ store.installCertificate(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ store.deleteCertificateEntry(null);
+ store.deleteCertificateEntry("");
+
+ String[] userFiles = dirAdded.list();
+ assertTrue(userFiles == null || userFiles.length == 0);
+ }
+
+ @Test
+ public void testTwoSystem() throws Exception {
+ testTwo(getCa1(), getAliasSystemCa1(),
+ getCa2(), getAliasSystemCa2());
+ }
+
+ @Test
+ public void testTwoUser() throws Exception {
+ testTwo(getCa1(), getAliasUserCa1(),
+ getCa2(), getAliasUserCa2());
+ }
+
+ @Test
+ public void testOneSystemOneUser() throws Exception {
+ testTwo(getCa1(), getAliasSystemCa1(),
+ getCa2(), getAliasUserCa2());
+ }
+
+ @Test
+ public void testTwoSystemSameSubject() throws Exception {
+ testTwo(getCa1(), getAliasSystemCa1(),
+ getCa3WithCa1Subject(), getAliasSystemCa3Collision());
+ }
+
+ @Test
+ public void testTwoUserSameSubject() throws Exception {
+ testTwo(getCa1(), getAliasUserCa1(),
+ getCa3WithCa1Subject(), getAliasUserCa3Collision());
+
+ store.deleteCertificateEntry(getAliasUserCa1());
+ assertDeleted(getCa1(), getAliasUserCa1());
+ assertTombstone(getAliasUserCa1());
+ assertRootCa(getCa3WithCa1Subject(), getAliasUserCa3Collision());
+ assertAliases(getAliasUserCa3Collision());
+
+ store.deleteCertificateEntry(getAliasUserCa3Collision());
+ assertDeleted(getCa3WithCa1Subject(), getAliasUserCa3Collision());
+ assertNoTombstone(getAliasUserCa3Collision());
+ assertNoTombstone(getAliasUserCa1());
+ assertEmpty();
+ }
+
+ @Test
+ public void testOneSystemOneUserSameSubject() throws Exception {
+ testTwo(getCa1(), getAliasSystemCa1(),
+ getCa3WithCa1Subject(), getAliasUserCa3());
+ testTwo(getCa1(), getAliasUserCa1(),
+ getCa3WithCa1Subject(), getAliasSystemCa3());
+ }
+
+ private void testTwo(X509Certificate x1, String alias1,
+ X509Certificate x2, String alias2) {
+ install(x1, alias1);
+ install(x2, alias2);
+ assertRootCa(x1, alias1);
+ assertRootCa(x2, alias2);
+ assertAliases(alias1, alias2);
+ }
+
+ @Test
+ public void testOneSystemOneUserOneDeleted() throws Exception {
+ install(getCa1(), getAliasSystemCa1());
+ store.installCertificate(getCa2());
+ store.deleteCertificateEntry(getAliasSystemCa1());
+ assertDeleted(getCa1(), getAliasSystemCa1());
+ assertRootCa(getCa2(), getAliasUserCa2());
+ assertAliases(getAliasUserCa2());
+ }
+
+ @Test
+ public void testOneSystemOneUserOneDeletedSameSubject() throws Exception {
+ install(getCa1(), getAliasSystemCa1());
+ store.installCertificate(getCa3WithCa1Subject());
+ store.deleteCertificateEntry(getAliasSystemCa1());
+ assertDeleted(getCa1(), getAliasSystemCa1());
+ assertRootCa(getCa3WithCa1Subject(), getAliasUserCa3());
+ assertAliases(getAliasUserCa3());
+ }
+
+ @Test
+ public void testUserMaskingSystem() throws Exception {
+ install(getCa1(), getAliasSystemCa1());
+ install(getCa1(), getAliasUserCa1());
+ assertMasked(getCa1(), getAliasSystemCa1());
+ assertRootCa(getCa1(), getAliasUserCa1());
+ assertAliases(getAliasSystemCa1(), getAliasUserCa1());
+ }
+
+ @Test
+ public void testChain() throws Exception {
+ testChain(getAliasSystemChain1(), getAliasSystemChain2());
+ testChain(getAliasSystemChain1(), getAliasUserChain2());
+ testChain(getAliasUserChain1(), getAliasSystemCa1());
+ testChain(getAliasUserChain1(), getAliasUserChain2());
+ }
+
+ private void testChain(String alias1, String alias2) throws Exception {
+ install(getChain()[1], alias1);
+ install(getChain()[2], alias2);
+ assertIntermediateCa(getChain()[1], alias1);
+ assertRootCa(getChain()[2], alias2);
+ assertAliases(alias1, alias2);
+ assertEquals(getChain()[2], store.findIssuer(getChain()[1]));
+ assertEquals(getChain()[1], store.findIssuer(getChain()[0]));
+
+ X509Certificate[] expected = getChain();
+ List<X509Certificate> actualList = store.getCertificateChain(expected[0]);
+
+ assertEquals("Generated CA list should be same length", expected.length, actualList.size());
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals("Chain value should be the same for position " + i, expected[i],
+ actualList.get(i));
+ }
+ resetStore();
+ }
+
+ @Test
+ public void testMissingSystemDirectory() throws Exception {
+ cleanStore();
+ createStore();
+ assertEmpty();
+ }
+
+ @Test
+ public void testWithExistingUserDirectories() throws Exception {
+ dirAdded.mkdirs();
+ dirDeleted.mkdirs();
+ install(getCa1(), getAliasSystemCa1());
+ assertRootCa(getCa1(), getAliasSystemCa1());
+ assertAliases(getAliasSystemCa1());
+ }
+
+ @Test
+ public void testIsTrustAnchorWithReissuedgetCa() throws Exception {
+ PublicKey publicKey = getPrivate().getCertificate().getPublicKey();
+ PrivateKey privateKey = getPrivate().getPrivateKey();
+ String name = "CN=CA4";
+ X509Certificate ca1 = TestKeyStore.createCa(publicKey, privateKey, name);
+ Thread.sleep(1 * 1000); // wait to ensure CAs vary by expiration
+ X509Certificate ca2 = TestKeyStore.createCa(publicKey, privateKey, name);
+ assertFalse(ca1.equals(ca2));
+
+ String systemAlias = alias(false, ca1, 0);
+ install(ca1, systemAlias);
+ assertRootCa(ca1, systemAlias);
+ assertEquals(ca1, store.getTrustAnchor(ca2));
+ assertEquals(ca1, store.findIssuer(ca2));
+ resetStore();
+
+ String userAlias = alias(true, ca1, 0);
+ store.installCertificate(ca1);
+ assertRootCa(ca1, userAlias);
+ assertNotNull(store.getTrustAnchor(ca2));
+ assertEquals(ca1, store.findIssuer(ca2));
+ resetStore();
+ }
+
+ @Test
+ public void testInstallEmpty() throws Exception {
+ store.installCertificate(getCa1());
+ assertRootCa(getCa1(), getAliasUserCa1());
+ assertAliases(getAliasUserCa1());
+
+ // reinstalling should not change anything
+ store.installCertificate(getCa1());
+ assertRootCa(getCa1(), getAliasUserCa1());
+ assertAliases(getAliasUserCa1());
+ }
+
+ @Test
+ public void testInstallEmptySystemExists() throws Exception {
+ install(getCa1(), getAliasSystemCa1());
+ assertRootCa(getCa1(), getAliasSystemCa1());
+ assertAliases(getAliasSystemCa1());
+
+ // reinstalling should not affect system CA
+ store.installCertificate(getCa1());
+ assertRootCa(getCa1(), getAliasSystemCa1());
+ assertAliases(getAliasSystemCa1());
+ }
+
+ @Test
+ public void testInstallEmptyDeletedSystemExists() throws Exception {
+ install(getCa1(), getAliasSystemCa1());
+ store.deleteCertificateEntry(getAliasSystemCa1());
+ assertEmpty();
+ assertDeleted(getCa1(), getAliasSystemCa1());
+
+ // installing should restore deleted system CA
+ store.installCertificate(getCa1());
+ assertRootCa(getCa1(), getAliasSystemCa1());
+ assertAliases(getAliasSystemCa1());
+ }
+
+ @Test
+ public void testDeleteEmpty() throws Exception {
+ store.deleteCertificateEntry(getAliasSystemCa1());
+ assertEmpty();
+ assertDeleted(getCa1(), getAliasSystemCa1());
+ }
+
+ @Test
+ public void testDeleteUser() throws Exception {
+ store.installCertificate(getCa1());
+ assertRootCa(getCa1(), getAliasUserCa1());
+ assertAliases(getAliasUserCa1());
+
+ store.deleteCertificateEntry(getAliasUserCa1());
+ assertEmpty();
+ assertDeleted(getCa1(), getAliasUserCa1());
+ assertNoTombstone(getAliasUserCa1());
+ }
+
+ @Test
+ public void testDeleteSystem() throws Exception {
+ install(getCa1(), getAliasSystemCa1());
+ assertRootCa(getCa1(), getAliasSystemCa1());
+ assertAliases(getAliasSystemCa1());
+
+ store.deleteCertificateEntry(getAliasSystemCa1());
+ assertEmpty();
+ assertDeleted(getCa1(), getAliasSystemCa1());
+
+ // deleting again should not change anything
+ store.deleteCertificateEntry(getAliasSystemCa1());
+ assertEmpty();
+ assertDeleted(getCa1(), getAliasSystemCa1());
+ }
+
+ @Test
+ public void testGetLoopedCert() throws Exception {
+ install(getCertLoopEe(), getAliasCertLoopEe());
+ install(getCertLoopCa1(), getAliasCertLoopCa1());
+ install(getCertLoopCa2(), getAliasCertLoopCa2());
+
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Future<List<X509Certificate>> future = executor
+ .submit(new Callable<List<X509Certificate>>() {
+ @Override
+ public List<X509Certificate> call() throws Exception {
+ return store.getCertificateChain(getCertLoopEe());
+ }
+ });
+ executor.shutdown();
+ final List<X509Certificate> certs;
+ try {
+ certs = future.get(10, TimeUnit.SECONDS);
+ } catch (TimeoutException e) {
+ fail("Could not finish building chain; possibly confused by loops");
+ return; // Not actually reached.
+ }
+ assertEquals(3, certs.size());
+ assertEquals(getCertLoopEe(), certs.get(0));
+ assertEquals(getCertLoopCa1(), certs.get(1));
+ assertEquals(getCertLoopCa2(), certs.get(2));
+ }
+
+ @Test
+ public void testIsUserAddedCertificate() throws Exception {
+ assertFalse(store.isUserAddedCertificate(getCa1()));
+ assertFalse(store.isUserAddedCertificate(getCa2()));
+ install(getCa1(), getAliasSystemCa1());
+ assertFalse(store.isUserAddedCertificate(getCa1()));
+ assertFalse(store.isUserAddedCertificate(getCa2()));
+ install(getCa1(), getAliasUserCa1());
+ assertTrue(store.isUserAddedCertificate(getCa1()));
+ assertFalse(store.isUserAddedCertificate(getCa2()));
+ install(getCa2(), getAliasUserCa2());
+ assertTrue(store.isUserAddedCertificate(getCa1()));
+ assertTrue(store.isUserAddedCertificate(getCa2()));
+ store.deleteCertificateEntry(getAliasUserCa1());
+ assertFalse(store.isUserAddedCertificate(getCa1()));
+ assertTrue(store.isUserAddedCertificate(getCa2()));
+ store.deleteCertificateEntry(getAliasUserCa2());
+ assertFalse(store.isUserAddedCertificate(getCa1()));
+ assertFalse(store.isUserAddedCertificate(getCa2()));
+ }
+
+ @Test
+ public void testSystemCaCertsUseCorrectFileNames() throws Exception {
+ File dir = new File(System.getenv("ANDROID_ROOT") + "/etc/security/cacerts");
+ useCorrectFileNamesTest(dir);
+ }
+
+ @Test
+ public void testSystemCaCertsUseCorrectFileNamesUpdatable() throws Exception {
+ File dir = new File("/apex/com.android.conscrypt/cacerts");
+ useCorrectFileNamesTest(dir);
+ }
+
+ private void useCorrectFileNamesTest(File dir) throws Exception {
+ TrustedCertificateStore store = new TrustedCertificateStore(dir.getAbsoluteFile());
+
+ // Assert that all the certificates in the system cacerts directory are stored in files with
+ // expected names.
+ CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
+ assertTrue(dir.exists());
+ int systemCertFileCount = 0;
+ for (File actualFile : listFilesNoNull(dir)) {
+ if (!actualFile.isFile()) {
+ continue;
+ }
+ systemCertFileCount++;
+ X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(
+ new ByteArrayInputStream(readFully(actualFile)));
+
+ File expectedFile = store.getCertificateFile(dir, cert);
+ assertEquals("Updatable certificate stored in the wrong file",
+ expectedFile.getAbsolutePath(), actualFile.getAbsolutePath());
+
+ // The two statements below indirectly assert that the certificate can be looked up
+ // from a file (hopefully the same one as the expectedFile above). As opposed to
+ // getCertificateFile above, these are the actual methods used when verifying chain of
+ // trust. Thus, we assert that they work as expected for all system certificates.
+ assertNotNull("Issuer certificate not found for updatable certificate " + actualFile,
+ store.findIssuer(cert));
+ assertNotNull("Trust anchor not found for updatable certificate " + actualFile,
+ store.getTrustAnchor(cert));
+ }
+
+ assertTrue(systemCertFileCount > 0);
+ // Assert that all files corresponding to all system certs/aliases known to the store are
+ // present.
+ int systemCertAliasCount = 0;
+ for (String alias : store.aliases()) {
+ if (!TrustedCertificateStore.isSystem(alias)) {
+ continue;
+ }
+ systemCertAliasCount++;
+ // Checking that the certificate is stored in a file is extraneous given the current
+ // implementation of the class under test. We do it just in case the implementation
+ // changes.
+ X509Certificate cert = (X509Certificate) store.getCertificate(alias);
+ File expectedFile = store.getCertificateFile(dir, cert);
+ if (!expectedFile.isFile()) {
+ fail("Missing certificate file for alias " + alias
+ + ": " + expectedFile.getAbsolutePath());
+ }
+ }
+
+ assertEquals("Number of system cert files and aliases doesn't match",
+ systemCertFileCount, systemCertAliasCount);
+ }
+
+ @Test
+ public void testMultipleIssuers() throws Exception {
+ Set<X509Certificate> result;
+ install(getMultipleIssuersCa1(), getAliasMultipleIssuersCa1());
+ result = store.findAllIssuers(getMultipleIssuersEe());
+ assertEquals("Unexpected number of issuers found", 1, result.size());
+ assertTrue("findAllIssuers does not contain expected issuer",
+ result.contains(getMultipleIssuersCa1()));
+ install(getMultipleIssuersCa1Cross(), getAliasMultipleIssuersCa1Cross());
+ result = store.findAllIssuers(getMultipleIssuersEe());
+ assertEquals("findAllIssuers did not return all issuers", 2, result.size());
+ assertTrue("findAllIssuers does not contain CA1",
+ result.contains(getMultipleIssuersCa1()));
+ assertTrue("findAllIssuers does not contain CA1 signed by CA2",
+ result.contains(getMultipleIssuersCa1Cross()));
+ }
+
+ private static File[] listFilesNoNull(File dir) {
+ File[] files = dir.listFiles();
+ return (files != null) ? files : new File[0];
+ }
+
+ private static byte[] readFully(File file) throws IOException {
+ InputStream in = null;
+ try {
+ in = new FileInputStream(file);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ byte[] buf = new byte[16384];
+ int chunkSize;
+ while ((chunkSize = in.read(buf)) != -1) {
+ out.write(buf, 0, chunkSize);
+ }
+ return out.toByteArray();
+ } finally {
+ if (in != null) {
+ in.close();
+ }
+ }
+ }
+
+ private void assertRootCa(X509Certificate x, String alias) {
+ assertIntermediateCa(x, alias);
+ assertEquals(x, store.findIssuer(x));
+ }
+
+ @SuppressWarnings("JdkObsolete") // Date is used in public API TrustedCertificateKeyStoreSpi
+ private void assertTrusted(X509Certificate x, String alias) {
+ assertEquals(x, store.getCertificate(alias));
+ assertEquals(file(alias).lastModified(), store.getCreationDate(alias).getTime());
+ assertTrue(store.containsAlias(alias));
+ assertEquals(x, store.getTrustAnchor(x));
+ }
+
+ private void assertIntermediateCa(X509Certificate x, String alias) {
+ assertTrusted(x, alias);
+ assertEquals(alias, store.getCertificateAlias(x));
+ }
+
+ private void assertMasked(X509Certificate x, String alias) {
+ assertTrusted(x, alias);
+ assertFalse(alias.equals(store.getCertificateAlias(x)));
+ }
+
+ private void assertDeleted(X509Certificate x, String alias) {
+ assertNull(store.getCertificate(alias));
+ assertFalse(store.containsAlias(alias));
+ assertNull(store.getCertificateAlias(x));
+ assertNull(store.getTrustAnchor(x));
+ assertEquals(store.allSystemAliases().contains(alias),
+ store.getCertificate(alias, true) != null);
+ }
+
+ private void assertTombstone(String alias) {
+ assertTrue(TrustedCertificateStore.isUser(alias));
+ File file = file(alias);
+ assertTrue(file.exists());
+ assertEquals(0, file.length());
+ }
+
+ private void assertNoTombstone(String alias) {
+ assertTrue(TrustedCertificateStore.isUser(alias));
+ assertFalse(file(alias).exists());
+ }
+
+ private void assertAliases(String... aliases) {
+ Set<String> expected = new HashSet<String>(Arrays.asList(aliases));
+ Set<String> actual = new HashSet<String>();
+ for (String alias : store.aliases()) {
+ boolean system = TrustedCertificateStore.isSystem(alias);
+ boolean user = TrustedCertificateStore.isUser(alias);
+ if (system || user) {
+ assertEquals(system, store.allSystemAliases().contains(alias));
+ assertEquals(user, store.userAliases().contains(alias));
+ actual.add(alias);
+ } else {
+ throw new AssertionError(alias);
+ }
+ }
+ assertEquals(expected, actual);
+ }
+
+ /**
+ * format a certificate alias
+ */
+ private static String alias(boolean user, X509Certificate x, int index) {
+ String prefix = user ? "user:" : "system:";
+
+ X500Principal subject = x.getSubjectX500Principal();
+ int intHash = NativeCrypto.X509_NAME_hash_old(subject);
+ String strHash = Hex.intToHexString(intHash, 8);
+
+ return prefix + strHash + '.' + index;
+ }
+
+ /**
+ * Install certificate under specified alias
+ */
+ private void install(X509Certificate x, String alias) {
+ try {
+ File file = file(alias);
+ file.getParentFile().mkdirs();
+ OutputStream out = new FileOutputStream(file);
+ out.write(x.getEncoded());
+ out.close();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Compute file for an alias
+ */
+ private File file(String alias) {
+ File dir;
+ if (TrustedCertificateStore.isSystem(alias)) {
+ dir = dirSystem;
+ } else if (TrustedCertificateStore.isUser(alias)) {
+ dir = dirAdded;
+ } else {
+ throw new IllegalArgumentException(alias);
+ }
+
+ int index = alias.lastIndexOf(":");
+ if (index == -1) {
+ throw new IllegalArgumentException(alias);
+ }
+ String filename = alias.substring(index+1);
+
+ return new File(dir, filename);
+ }
+}
diff --git a/repackaged/platform/src/test/java/com/android/org/conscrypt/ct/CTLogStoreImplTest.java b/repackaged/platform/src/test/java/com/android/org/conscrypt/ct/CTLogStoreImplTest.java
new file mode 100644
index 0000000..c7e6efa
--- /dev/null
+++ b/repackaged/platform/src/test/java/com/android/org/conscrypt/ct/CTLogStoreImplTest.java
@@ -0,0 +1,208 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt.ct;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.android.org.conscrypt.InternalUtil;
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.security.PublicKey;
+import junit.framework.TestCase;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CTLogStoreImplTest extends TestCase {
+ private static final String[] LOG_KEYS = new String[] {
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmXg8sUUzwBYaWrRb+V0IopzQ6o3U" +
+ "yEJ04r5ZrRXGdpYM8K+hB0pXrGRLI0eeWz+3skXrS0IO83AhA3GpRL6s6w==",
+
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAErEULmlBnX9L/+AK20hLYzPMFozYx" +
+ "pP0Wm1ylqGkPEwuDKn9DSpNSOym49SN77BLGuAXu9twOW/qT+ddIYVBEIw==",
+
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEP6PGcXmjlyCBz2ZFUuUjrgbZLaEF" +
+ "gfLUkt2cEqlSbb4vTuB6WWmgC9h0L6PN6JF0CPcajpBKGlTI15242a8d4g==",
+
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAER3qB0NADsP1szXxe4EagrD/ryPVh" +
+ "Y/azWbKyXcK12zhXnO8WH2U4QROVUMctFXLflIzw0EivdRN9t7UH1Od30w==",
+
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEY0ww9JqeJvzVtKNTPVb3JZa7s0ZV" +
+ "duH3PpshpMS5XVoPRSjSQCph6f3HjUcM3c4N2hpa8OFbrFFy37ttUrgD+A=="
+ };
+ private static final String[] LOG_FILENAMES = new String[] {
+ "df1c2ec11500945247a96168325ddc5c7959e8f7c6d388fc002e0bbd3f74d764",
+ "84f8ae3f613b13407a75fa2893b93ab03b18d86c455fe7c241ae020033216446",
+ "89baa01a445100009d8f9a238947115b30702275aafee675a7d94b6b09287619",
+ "57456bffe268e49a190dce4318456034c2b4958f3c0201bed5a366737d1e74ca",
+ "896c898ced4b8e6547fa351266caae4ca304f1c1ec2b623c2ee259c5452147b0"
+ };
+
+ private static final CTLogInfo[] LOGS;
+ private static final String[] LOGS_SERIALIZED;
+
+ static {
+ try {
+ int logCount = LOG_KEYS.length;
+ LOGS = new CTLogInfo[logCount];
+ LOGS_SERIALIZED = new String[logCount];
+ for (int i = 0; i < logCount; i++) {
+ PublicKey key = InternalUtil.readPublicKeyPem(new ByteArrayInputStream(
+ ("-----BEGIN PUBLIC KEY-----\n" + LOG_KEYS[i] + "\n"
+ + "-----END PUBLIC KEY-----\n")
+ .getBytes(StandardCharsets.US_ASCII)));
+ String description = String.format("Test Log %d", i);
+ String url = String.format("log%d.example.com", i);
+ LOGS[i] = new CTLogInfo(key, description, url);
+ LOGS_SERIALIZED[i] = String.format("description:%s\nurl:%s\nkey:%s",
+ description, url, LOG_KEYS[i]);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /* CTLogStoreImpl loads the list of logs lazily when they are first needed
+ * to avoid any overhead when CT is disabled.
+ * This test simply forces the logs to be loaded to make sure it doesn't
+ * fail, as all of the other tests use a different log store.
+ */
+ public void test_getDefaultFallbackLogs() {
+ CTLogInfo[] knownLogs = CTLogStoreImpl.getDefaultFallbackLogs();
+ assertEquals(KnownLogs.LOG_COUNT, knownLogs.length);
+ }
+
+ public void test_loadLog() throws Exception {
+ CTLogInfo log = CTLogStoreImpl.loadLog(
+ new ByteArrayInputStream(LOGS_SERIALIZED[0].getBytes(StandardCharsets.US_ASCII)));
+ assertEquals(LOGS[0], log);
+
+ File testFile = writeFile(LOGS_SERIALIZED[0]);
+ log = CTLogStoreImpl.loadLog(testFile);
+ assertEquals(LOGS[0], log);
+
+ // Empty log file, used to mask fallback logs
+ assertEquals(null, CTLogStoreImpl.loadLog(new ByteArrayInputStream(new byte[0])));
+ try {
+ CTLogStoreImpl.loadLog(
+ new ByteArrayInputStream("randomgarbage".getBytes(StandardCharsets.US_ASCII)));
+ fail("InvalidLogFileException not thrown");
+ } catch (CTLogStoreImpl.InvalidLogFileException e) {}
+
+ try {
+ CTLogStoreImpl.loadLog(new File("/nonexistent"));
+ fail("FileNotFoundException not thrown");
+ } catch (FileNotFoundException e) {}
+ }
+
+ public void test_getKnownLog() throws Exception {
+ File userDir = createTempDirectory();
+ userDir.deleteOnExit();
+
+ File systemDir = createTempDirectory();
+ systemDir.deleteOnExit();
+
+ CTLogInfo[] fallback = new CTLogInfo[] { LOGS[2], LOGS[3] };
+
+ CTLogStore store = new CTLogStoreImpl(userDir, systemDir, fallback);
+
+ /* Add logs 0 and 1 to the user and system directories respectively
+ * Log 2 & 3 are part of the fallbacks
+ * But mask log 3 with an empty file in the user directory.
+ * Log 4 is not in the store
+ */
+ File log0File = new File(userDir, LOG_FILENAMES[0]);
+ File log1File = new File(systemDir, LOG_FILENAMES[1]);
+ File log3File = new File(userDir, LOG_FILENAMES[3]);
+ File log4File = new File(userDir, LOG_FILENAMES[4]);
+
+ writeFile(log0File, LOGS_SERIALIZED[0]);
+ writeFile(log1File, LOGS_SERIALIZED[1]);
+ writeFile(log3File, "");
+
+ // Logs 01 are present, log 2 is in the fallback and unused, log 3 is present but masked,
+ // log 4 is missing
+ assertEquals(LOGS[0], store.getKnownLog(LOGS[0].getID()));
+ assertEquals(LOGS[1], store.getKnownLog(LOGS[1].getID()));
+ // Fallback logs are not used if the userDir is present.
+ assertEquals(null, store.getKnownLog(LOGS[2].getID()));
+ assertEquals(null, store.getKnownLog(LOGS[3].getID()));
+ assertEquals(null, store.getKnownLog(LOGS[4].getID()));
+
+ /* Test whether CTLogStoreImpl caches properly
+ * Modify the files on the disk, the result of the store should not change
+ * Delete log 0, mask log 1, add log 4
+ */
+ log0File.delete();
+ writeFile(log1File, "");
+ writeFile(log4File, LOGS_SERIALIZED[4]);
+
+ assertEquals(LOGS[0], store.getKnownLog(LOGS[0].getID()));
+ assertEquals(LOGS[1], store.getKnownLog(LOGS[1].getID()));
+ assertEquals(null, store.getKnownLog(LOGS[4].getID()));
+
+ // Test that fallback logs are used when the userDir doesn't exist.
+ File doesntExist = new File("/doesnt/exist/");
+ store = new CTLogStoreImpl(doesntExist, doesntExist, fallback);
+ assertEquals(LOGS[2], store.getKnownLog(LOGS[2].getID()));
+ assertEquals(LOGS[3], store.getKnownLog(LOGS[3].getID()));
+ }
+
+ /**
+ * Create a temporary file and write to it.
+ * The file will be deleted on exit.
+ * @param contents The data to be written to the file
+ * @return A reference to the temporary file
+ */
+ private File writeFile(String contents) throws IOException {
+ File file = File.createTempFile("test", null);
+ file.deleteOnExit();
+ writeFile(file, contents);
+ return file;
+ }
+
+ private static void writeFile(File file, String contents) throws FileNotFoundException {
+ PrintWriter writer = new PrintWriter(
+ new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), UTF_8)),
+ false);
+ try {
+ writer.write(contents);
+ } finally {
+ writer.close();
+ }
+ }
+
+ /*
+ * This is NOT safe, as another process could create a file between delete() and mkdir()
+ * It should be fine for tests though
+ */
+ private static File createTempDirectory() throws IOException {
+ File folder = File.createTempFile("test", "");
+ folder.delete();
+ folder.mkdir();
+ return folder;
+ }
+}
+
diff --git a/repackaged/platform/src/test/java/com/android/org/conscrypt/metrics/MetricsTest.java b/repackaged/platform/src/test/java/com/android/org/conscrypt/metrics/MetricsTest.java
new file mode 100644
index 0000000..57bb8f7
--- /dev/null
+++ b/repackaged/platform/src/test/java/com/android/org/conscrypt/metrics/MetricsTest.java
@@ -0,0 +1,86 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package com.android.org.conscrypt.metrics;
+
+import static org.junit.Assert.assertEquals;
+
+import android.util.StatsEvent;
+import com.android.org.conscrypt.TestUtils;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class MetricsTest {
+ public static final int TLS_HANDSHAKE_REPORTED = 317;
+
+ // Tests that ReflexiveEvent produces the same event as framework's.
+ @Test
+ @Ignore // Ignore on CTS 12 only: b/259508875
+ public void test_reflexiveEvent() throws Exception {
+ TestUtils.assumeStatsLogAvailable();
+
+ StatsEvent frameworkStatsEvent = StatsEvent.newBuilder()
+ .setAtomId(TLS_HANDSHAKE_REPORTED)
+ .writeBoolean(false)
+ .writeInt(1) // protocol
+ .writeInt(2) // cipher suite
+ .writeInt(100) // duration
+ .writeInt(3) // source
+ .usePooledBuffer()
+ .build();
+
+ ReflexiveStatsEvent reflexiveStatsEvent =
+ ReflexiveStatsEvent.buildEvent(TLS_HANDSHAKE_REPORTED, false, 1, 2, 100, 3);
+ StatsEvent constructedEvent = (StatsEvent) reflexiveStatsEvent.getStatsEvent();
+
+ // TODO(nikitai): Figure out how to use hidden (@hide) getters from StatsEvent
+ // to eliminate the use of reflection
+ int fid = (Integer) frameworkStatsEvent.getClass()
+ .getMethod("getAtomId")
+ .invoke(frameworkStatsEvent);
+ int cid = (Integer) constructedEvent.getClass()
+ .getMethod("getAtomId")
+ .invoke(constructedEvent);
+ assertEquals(fid, cid);
+
+ int fnb = (Integer) frameworkStatsEvent.getClass()
+ .getMethod("getNumBytes")
+ .invoke(frameworkStatsEvent);
+ int cnb = (Integer) constructedEvent.getClass()
+ .getMethod("getNumBytes")
+ .invoke(constructedEvent);
+ assertEquals(fnb, cnb);
+
+ byte[] fbytes = (byte[]) frameworkStatsEvent.getClass()
+ .getMethod("getBytes")
+ .invoke(frameworkStatsEvent);
+ byte[] cbytes =
+ (byte[]) constructedEvent.getClass().getMethod("getBytes").invoke(constructedEvent);
+ for (int i = 0; i < fnb; i++) {
+ // skip encoded timestamp (bytes 1-8)
+ if (i < 1 || i > 8) {
+ assertEquals(fbytes[i], cbytes[i]);
+ }
+ }
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/ChannelType.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/ChannelType.java
new file mode 100644
index 0000000..a1a77c1
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/ChannelType.java
@@ -0,0 +1,132 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2017 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.
+ */
+package com.android.org.conscrypt;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import javax.net.ServerSocketFactory;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * The type of socket to be wrapped by the Conscrypt socket.
+ * @hide This class is not part of the Android public SDK API
+ */
+@SuppressWarnings("unused")
+public enum ChannelType {
+ NONE {
+ @Override
+ SSLSocket newClientSocket(SSLSocketFactory factory, InetAddress address, int port)
+ throws IOException {
+ return clientMode(factory.createSocket(address, port));
+ }
+
+ @Override
+ ServerSocket newServerSocket(SSLServerSocketFactory factory) throws IOException {
+ return factory.createServerSocket(0, 50, InetAddress.getLoopbackAddress());
+ }
+
+ @Override
+ SSLSocket accept(ServerSocket socket, SSLSocketFactory unused) throws IOException {
+ return serverMode(socket.accept());
+ }
+ },
+ NO_CHANNEL {
+ @Override
+ SSLSocket newClientSocket(SSLSocketFactory factory, InetAddress address, int port)
+ throws IOException {
+ Socket wrapped = new Socket(address, port);
+ assertNull(wrapped.getChannel());
+
+ return clientMode(factory.createSocket(wrapped, address.getHostName(), port, true));
+ }
+
+ @Override
+ ServerSocket newServerSocket(SSLServerSocketFactory unused) throws IOException {
+ return ServerSocketFactory.getDefault().createServerSocket(
+ 0, 50, InetAddress.getLoopbackAddress());
+ }
+
+ @Override
+ SSLSocket accept(ServerSocket serverSocket, SSLSocketFactory factory) throws IOException {
+ assertFalse(serverSocket instanceof SSLServerSocket);
+ Socket wrapped = serverSocket.accept();
+ assertNull(wrapped.getChannel());
+
+ return serverMode(factory.createSocket(
+ wrapped, wrapped.getInetAddress().getHostAddress(), wrapped.getPort(), true));
+ }
+ },
+ CHANNEL {
+ @Override
+ SSLSocket newClientSocket(SSLSocketFactory factory, InetAddress address, int port)
+ throws IOException {
+ Socket wrapped = SocketChannel.open(new InetSocketAddress(address, port)).socket();
+ return clientMode(factory.createSocket(wrapped, address.getHostName(), port, true));
+ }
+
+ @Override
+ ServerSocket newServerSocket(SSLServerSocketFactory unused) throws IOException {
+ return ServerSocketChannel.open()
+ .bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0))
+ .socket();
+ }
+
+ @Override
+ SSLSocket accept(ServerSocket serverSocket, SSLSocketFactory factory) throws IOException {
+ assertFalse(serverSocket instanceof SSLServerSocket);
+ ServerSocketChannel serverChannel = serverSocket.getChannel();
+
+ // Just loop until the accept completes.
+ SocketChannel channel;
+ do {
+ channel = serverChannel.accept();
+ } while (channel == null);
+
+ Socket wrapped = channel.socket();
+ return serverMode(factory.createSocket(
+ wrapped, wrapped.getInetAddress().getHostAddress(), wrapped.getPort(), true));
+ }
+ };
+
+ abstract SSLSocket newClientSocket(SSLSocketFactory factory, InetAddress address, int port)
+ throws IOException;
+ abstract ServerSocket newServerSocket(SSLServerSocketFactory factory) throws IOException;
+ abstract SSLSocket accept(ServerSocket socket, SSLSocketFactory factory) throws IOException;
+
+ private static SSLSocket clientMode(Socket socket) {
+ SSLSocket sslSocket = (SSLSocket) socket;
+ sslSocket.setUseClientMode(true);
+ return sslSocket;
+ }
+
+ private static SSLSocket serverMode(Socket socket) {
+ SSLSocket sslSocket = (SSLSocket) socket;
+ sslSocket.setUseClientMode(false);
+ return sslSocket;
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/MethodFilter.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/MethodFilter.java
new file mode 100644
index 0000000..680abd7
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/MethodFilter.java
@@ -0,0 +1,201 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt;
+
+import static org.junit.Assert.assertTrue;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Predicate;
+
+
+/**
+ * Test support class for filtering collections of {@link Method}. Each filter is a list of
+ * predicates which must all be true for a Method in order for it to be included it the output.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class MethodFilter {
+ private final String name;
+ private final CompoundMethodPredicate predicates = new CompoundMethodPredicate();
+ private int expectedSize = 0;
+
+ public MethodFilter(String name) {
+ this.name = name;
+ }
+
+ public List<Method> filter(Iterable<Method> input) {
+ List<Method> result = new ArrayList<>();
+ for (Method method : input) {
+ if (predicates.test(method)) {
+ result.add(method);
+ }
+ }
+ if (expectedSize != 0) {
+ assertTrue(String.format("Filter %s only returned %d methods, expected at least %d",
+ name, result.size(), expectedSize), result.size() >= expectedSize);
+ }
+ return result;
+ }
+
+ /** Returns a new {@link Builder} */
+ public static Builder newBuilder(String name) {
+ return new Builder(name);
+ }
+
+ /** Returns a filter which selects only methods named in {@code methodNames} */
+ public static MethodFilter nameFilter(String name, String... methodNames) {
+ return newBuilder(name)
+ .named(methodNames)
+ .expectSize(methodNames.length)
+ .build();
+ }
+
+ private void addPredicate(Predicate<Method> predicate) {
+ predicates.add(predicate);
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class Builder {
+ private final MethodFilter filter;
+
+ private Builder(String name) {
+ filter = new MethodFilter(name);
+ }
+
+ /** Method's simple name must start with {@code prefix}. */
+ public Builder hasPrefix(String prefix) {
+ filter.addPredicate(new MethodNamePrefixPredicate(prefix));
+ return this;
+ }
+
+ /** Argument at {@code position} must be one of the supplied {@code classes}. */
+ public Builder hasArg(int position, Class<?>... classes) {
+ filter.addPredicate(new MethodArgPredicate(position, classes));
+ return this;
+ }
+
+ /** Method must take exactly {@code length} args. */
+ public Builder hasArgLength(int length) {
+ filter.addPredicate(new MethodArgLengthPredicate(length));
+ return this;
+ }
+
+ /* Method must take one or more arguments, i.e. not void. */
+ public Builder takesArguments() {
+ filter.addPredicate(new MethodArgLengthPredicate(0).negate());
+ return this;
+ }
+
+ /** Method's simple name is in the list of {@code names} provided. */
+ public Builder named(String... names) {
+ filter.addPredicate(new MethodNamePredicate(names));
+ return this;
+ }
+
+ /** Method's simple name is NOT in the list of {@code names} provided. */
+ public Builder except(String... names) {
+ filter.addPredicate(new MethodNamePredicate(names).negate());
+ return this;
+ }
+
+ /** Expect at least {@code size} matching methods when filtering, otherwise filter()
+ * will throw {@code AssertionError} */
+ public Builder expectSize(int size) {
+ filter.expectedSize = size;
+ return this;
+ }
+
+ public MethodFilter build() {
+ return filter;
+ }
+ }
+
+ // Implements Builder.hasPrefix()
+ private static class MethodNamePrefixPredicate implements Predicate<Method> {
+ private final String prefix;
+
+ public MethodNamePrefixPredicate(String prefix) {
+ this.prefix = prefix;
+ }
+
+ @Override
+ public boolean test(Method method) {
+ return method.getName().startsWith(prefix);
+ }
+ }
+
+ // Implements Builder.named()
+ private static class MethodNamePredicate implements Predicate<Method> {
+ private final List<String> names;
+
+ public MethodNamePredicate(String... names) {
+ this.names = Arrays.asList(names);
+ }
+
+ @Override
+ public boolean test(Method method) {
+ return names.contains(method.getName());
+ }
+ }
+
+ // Implements Builder.hasArg()
+ private static class MethodArgPredicate implements Predicate<Method> {
+ private final int position;
+ private final List<Class<?>> allowedClasses;
+
+ public MethodArgPredicate(int position, Class<?>... classes) {
+ this.position = position;
+ allowedClasses = Arrays.asList(classes);
+ }
+
+ @Override
+ public boolean test(Method method) {
+ Class<?>[] argTypes = method.getParameterTypes();
+ if (argTypes.length > position) {
+ for (Class<?> c : allowedClasses) {
+ if (argTypes[position] == c) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }
+
+ // Implements Builder.hasArgLength()
+ private static class MethodArgLengthPredicate implements Predicate<Method> {
+ private final int length;
+
+ public MethodArgLengthPredicate(int length) {
+ this.length = length;
+ }
+
+ @Override
+ public boolean test(Method method) {
+ return method.getParameterCount() == length;
+ }
+ }
+
+ // A Predicate which contains a list of sub-Predicates, all of which must be true
+ // for this one to be true.
+ private static class CompoundMethodPredicate implements Predicate<Method> {
+ private final List<Predicate<Method>> predicates = new ArrayList<>();
+
+ @Override
+ public boolean test(Method method) {
+ for (Predicate<Method> p : predicates) {
+ if (!p.test(method)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public void add(Predicate<Method> predicate) {
+ predicates.add(predicate);
+ }
+ }
+}
\ No newline at end of file
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/TestUtils.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/TestUtils.java
new file mode 100644
index 0000000..afd6ef9
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/TestUtils.java
@@ -0,0 +1,814 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.org.conscrypt;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+import com.android.org.conscrypt.java.security.StandardNames;
+import com.android.org.conscrypt.java.security.TestKeyStore;
+import com.android.org.conscrypt.testing.Streams;
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.Signature;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Random;
+import java.util.Set;
+import java.util.function.Predicate;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.junit.Assume;
+
+/**
+ * Utility methods to support testing.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class TestUtils {
+ public static final Charset UTF_8 = StandardCharsets.UTF_8;
+ private static final String PROTOCOL_TLS_V1_3 = "TLSv1.3";
+ private static final String PROTOCOL_TLS_V1_2 = "TLSv1.2";
+ private static final String PROTOCOL_TLS_V1_1 = "TLSv1.1";
+ // For interop testing we need a JDK Provider that can do TLS 1.2 as 1.x may be disabled
+ // in Conscrypt and 1.3 does not (yet) handle interoperability with the JDK Provider.
+ private static final String[] DESIRED_JDK_PROTOCOLS = new String[] {PROTOCOL_TLS_V1_2};
+ private static final Provider JDK_PROVIDER = getNonConscryptTlsProvider();
+ private static final byte[] CHARS =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".getBytes(UTF_8);
+ private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocateDirect(0);
+
+ static final String TEST_CIPHER = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256";
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public enum BufferType {
+ HEAP {
+ @Override
+ ByteBuffer newBuffer(int size) {
+ return ByteBuffer.allocate(size);
+ }
+ },
+ DIRECT {
+ @Override
+ ByteBuffer newBuffer(int size) {
+ return ByteBuffer.allocateDirect(size);
+ }
+ };
+ private static final Random random = new Random(System.currentTimeMillis());
+ abstract ByteBuffer newBuffer(int size);
+
+ public ByteBuffer[] newRandomBuffers(int... sizes) {
+ int numBuffers = sizes.length;
+ ByteBuffer[] result = new ByteBuffer[numBuffers];
+ for (int i = 0; i < numBuffers; i++) {
+ result[i] = newRandomBuffer(sizes[i]);
+ }
+ return result;
+ }
+
+ public ByteBuffer newRandomBuffer(int size) {
+ byte[] data = new byte[size];
+ random.nextBytes(data);
+ ByteBuffer buffer = newBuffer(size);
+ buffer.put(data);
+ buffer.flip();
+ return buffer;
+ }
+ }
+
+ private TestUtils() {}
+
+ private static Provider getNonConscryptTlsProvider() {
+ for (String protocol : DESIRED_JDK_PROTOCOLS) {
+ for (Provider p : Security.getProviders()) {
+ if (!p.getClass().getPackage().getName().contains("conscrypt")
+ && hasSslContext(p, protocol)) {
+ return p;
+ }
+ }
+ }
+ return new BouncyCastleProvider();
+ }
+
+ private static boolean hasSslContext(Provider p, String protocol) {
+ return p.get("SSLContext." + protocol) != null;
+ }
+
+ static Provider getJdkProvider() {
+ return JDK_PROVIDER;
+ }
+
+ public static boolean isClassAvailable(String classname) {
+ try {
+ Class.forName(classname);
+ return true;
+ } catch (ClassNotFoundException ignore) {
+ // Ignored
+ }
+ return false;
+ }
+
+ private static void assumeClassAvailable(String classname) {
+ Assume.assumeTrue("Skipping test: " + classname + " unavailable",
+ isClassAvailable(classname));
+ }
+
+ public static void assumeSNIHostnameAvailable() {
+ assumeClassAvailable("javax.net.ssl.SNIHostName");
+ }
+
+ public static void assumeExtendedTrustManagerAvailable() {
+ assumeClassAvailable("javax.net.ssl.X509ExtendedTrustManager");
+ }
+
+ public static void assumeStatsLogAvailable() {
+ assumeClassAvailable("android.util.StatsEvent");
+ }
+
+ public static void assumeSetEndpointIdentificationAlgorithmAvailable() {
+ boolean supported = false;
+ try {
+ SSLParameters.class.getMethod("setEndpointIdentificationAlgorithm", String.class);
+ supported = true;
+ } catch (NoSuchMethodException ignore) {
+ // Ignored
+ }
+ Assume.assumeTrue("Skipping test: "
+ + "SSLParameters.setEndpointIdentificationAlgorithm unavailable", supported);
+ }
+
+ public static void assumeAEADAvailable() {
+ assumeClassAvailable("javax.crypto.AEADBadTagException");
+ }
+
+ private static boolean isAndroid() {
+ try {
+ Class.forName("android.app.Application", false, ClassLoader.getSystemClassLoader());
+ return true;
+ } catch (Throwable ignored) {
+ // Failed to load the class uniquely available in Android.
+ return false;
+ }
+ }
+
+ public static void assumeAndroid() {
+ Assume.assumeTrue(isAndroid());
+ }
+
+ public static void assumeAllowsUnsignedCrypto() {
+ // The Oracle JRE disallows loading crypto providers from unsigned jars
+ Assume.assumeTrue(isAndroid()
+ || !System.getProperty("java.vm.name").contains("HotSpot"));
+ }
+
+ public static void assumeSHA2WithDSAAvailable() {
+ boolean available;
+ try {
+ Signature.getInstance("SHA256withDSA");
+ available = true;
+ } catch (NoSuchAlgorithmException e) {
+ available = false;
+ }
+ Assume.assumeTrue("SHA2 with DSA signatures not available", available);
+ }
+
+ public static InetAddress getLoopbackAddress() {
+ try {
+ Method method = InetAddress.class.getMethod("getLoopbackAddress");
+ return (InetAddress) method.invoke(null);
+ } catch (Exception ignore) {
+ // Ignored.
+ }
+ try {
+ return InetAddress.getLocalHost();
+ } catch (UnknownHostException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static Provider getConscryptProvider() {
+ try {
+ String defaultName = (String) conscryptClass("Platform")
+ .getDeclaredMethod("getDefaultProviderName")
+ .invoke(null);
+ Constructor<?> c =
+ conscryptClass("OpenSSLProvider")
+ .getDeclaredConstructor(String.class, Boolean.TYPE, String.class);
+
+ if (!isClassAvailable("javax.net.ssl.X509ExtendedTrustManager")) {
+ return (Provider) c.newInstance(defaultName, false, "TLSv1.3");
+ } else {
+ return (Provider) c.newInstance(defaultName, true, "TLSv1.3");
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static synchronized void installConscryptAsDefaultProvider() {
+ Provider conscryptProvider = getConscryptProvider();
+ Provider[] providers = Security.getProviders();
+ if (providers.length == 0 || !providers[0].equals(conscryptProvider)) {
+ Security.insertProviderAt(conscryptProvider, 1);
+ }
+ }
+
+ public static InputStream openTestFile(String name) throws FileNotFoundException {
+ InputStream is = TestUtils.class.getResourceAsStream("/" + name);
+ if (is == null) {
+ throw new FileNotFoundException(name);
+ }
+ return is;
+ }
+
+ public static byte[] readTestFile(String name) throws IOException {
+ return Streams.readFully(openTestFile(name));
+ }
+
+ public static PublicKey readPublicKeyPemFile(String name)
+ throws InvalidKeySpecException, NoSuchAlgorithmException, IOException {
+ String keyData = new String(readTestFile(name), StandardCharsets.US_ASCII);
+ keyData = keyData.replace("-----BEGIN PUBLIC KEY-----", "");
+ keyData = keyData.replace("-----END PUBLIC KEY-----", "");
+ keyData = keyData.replace("\r", "");
+ keyData = keyData.replace("\n", "");
+ return KeyFactory.getInstance("EC").generatePublic(
+ new X509EncodedKeySpec(decodeBase64(keyData)));
+ }
+
+ public static List<String[]> readCsvResource(String resourceName) throws IOException {
+ InputStream stream = openTestFile(resourceName);
+ List<String[]> lines = new ArrayList<>();
+ try (BufferedReader reader =
+ new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (line.isEmpty() || line.startsWith("#")) {
+ continue;
+ }
+ lines.add(line.split(",", -1));
+ }
+ }
+ return lines;
+ }
+
+ /**
+ * Looks up the conscrypt class for the given simple name (i.e. no package prefix).
+ */
+ public static Class<?> conscryptClass(String simpleName) throws ClassNotFoundException {
+ ClassNotFoundException ex = null;
+ for (String packageName : new String[] {"com.android.org.conscrypt", "com.android.com.android.org.conscrypt"}) {
+ String name = packageName + "." + simpleName;
+ try {
+ return Class.forName(name);
+ } catch (ClassNotFoundException e) {
+ ex = e;
+ }
+ }
+ throw ex;
+ }
+
+ static SSLSocketFactory setUseEngineSocket(
+ SSLSocketFactory conscryptFactory, boolean useEngineSocket) {
+ try {
+ Class<?> clazz = conscryptClass("Conscrypt");
+ Method method =
+ clazz.getMethod("setUseEngineSocket", SSLSocketFactory.class, boolean.class);
+ method.invoke(null, conscryptFactory, useEngineSocket);
+ return conscryptFactory;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static SSLServerSocketFactory setUseEngineSocket(
+ SSLServerSocketFactory conscryptFactory, boolean useEngineSocket) {
+ try {
+ Class<?> clazz = conscryptClass("Conscrypt");
+ Method method = clazz.getMethod(
+ "setUseEngineSocket", SSLServerSocketFactory.class, boolean.class);
+ method.invoke(null, conscryptFactory, useEngineSocket);
+ return conscryptFactory;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static boolean getUseEngineSocketByDefault() {
+ try {
+ boolean sfDefault =
+ getBooleanField("OpenSSLSocketFactoryImpl", "useEngineSocketByDefault");
+ boolean ssfDefault =
+ getBooleanField("OpenSSLServerSocketFactoryImpl", "useEngineSocketByDefault");
+ if (sfDefault != ssfDefault) {
+ throw new IllegalStateException("Socket factory and server socket factory must\n"
+ + "use the same default implementation during testing");
+ }
+ return sfDefault;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static boolean getBooleanField(String className, String fieldName) throws Exception {
+ Class<?> clazz = conscryptClass(className);
+ Field field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ return field.getBoolean(null);
+ }
+
+ public static void setUseSessionTickets(SSLSocket socket, boolean useTickets) {
+ try {
+ Class<?> clazz = conscryptClass("Conscrypt");
+ Method method = clazz.getMethod("setUseSessionTickets", SSLSocket.class, boolean.class);
+ method.invoke(null, socket, useTickets);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static SSLContext newContext(Provider provider) {
+ try {
+ return SSLContext.getInstance("TLS", provider);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static String highestCommonProtocol() {
+ String[] common = getCommonProtocolSuites();
+ Arrays.sort(common);
+ return common[common.length - 1];
+ }
+
+ public static String[] getCommonProtocolSuites() {
+ SSLContext jdkContext = newClientSslContext(getJdkProvider());
+ SSLContext conscryptContext = newClientSslContext(getConscryptProvider());
+ // No point building a Set here due to small list sizes.
+ List<String> conscryptProtocols = getSupportedProtocols(conscryptContext);
+ Predicate<String> predicate = p
+ -> conscryptProtocols.contains(p)
+ // TODO(prb): Certificate auth fails when connecting Conscrypt and JDK's TLS 1.3.
+ && !p.equals(PROTOCOL_TLS_V1_3);
+ return getSupportedProtocols(jdkContext, predicate);
+ }
+
+ public static String[] getCommonCipherSuites() {
+ SSLContext jdkContext = newClientSslContext(getJdkProvider());
+ SSLContext conscryptContext = newClientSslContext(getConscryptProvider());
+ Set<String> conscryptCiphers = new HashSet<>(getSupportedCiphers(conscryptContext));
+ Predicate<String> predicate = c -> isTlsCipherSuite(c) && conscryptCiphers.contains(c);
+ return getSupportedCiphers(jdkContext, predicate);
+ }
+
+ public static List<String> getSupportedCiphers(SSLContext ctx) {
+ return Arrays.asList(ctx.getDefaultSSLParameters().getCipherSuites());
+ }
+
+ public static String[] getSupportedCiphers(SSLContext ctx, Predicate<String> predicate) {
+ return Arrays.stream(ctx.getDefaultSSLParameters().getCipherSuites())
+ .filter(predicate)
+ .toArray(String[] ::new);
+ }
+
+ public static List<String> getSupportedProtocols(SSLContext ctx) {
+ return Arrays.asList(ctx.getDefaultSSLParameters().getProtocols());
+ }
+
+ public static String[] getSupportedProtocols(SSLContext ctx, Predicate<String> predicate) {
+ return Arrays.stream(ctx.getDefaultSSLParameters().getProtocols())
+ .filter(predicate)
+ .toArray(String[] ::new);
+ }
+
+ private static boolean isTlsCipherSuite(String cipher) {
+ return !cipher.startsWith("SSL_") && !cipher.startsWith("TLS_EMPTY")
+ && !cipher.contains("_RC4_");
+ }
+
+ public static void assumeTlsV11Enabled(SSLContext context) {
+ Assume.assumeTrue(getSupportedProtocols(context).contains(PROTOCOL_TLS_V1_1));
+ }
+
+ /**
+ * Picks a port that is not used right at this moment.
+ * Warning: Not thread safe. May see "BindException: Address already in use: bind" if using the
+ * returned port to create a new server socket when other threads/processes are concurrently
+ * creating new sockets without a specific port.
+ */
+ public static int pickUnusedPort() {
+ try {
+ ServerSocket serverSocket = new ServerSocket(0);
+ int port = serverSocket.getLocalPort();
+ serverSocket.close();
+ return port;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Creates a text message of the given length.
+ */
+ public static byte[] newTextMessage(int length) {
+ byte[] msg = new byte[length];
+ for (int msgIndex = 0; msgIndex < length;) {
+ int remaining = length - msgIndex;
+ int numChars = Math.min(remaining, CHARS.length);
+ System.arraycopy(CHARS, 0, msg, msgIndex, numChars);
+ msgIndex += numChars;
+ }
+ return msg;
+ }
+
+ static SSLContext newClientSslContext(Provider provider) {
+ SSLContext context = newContext(provider);
+ return initClientSslContext(context);
+ }
+
+ static SSLContext newServerSslContext(Provider provider) {
+ SSLContext context = newContext(provider);
+ return initServerSslContext(context);
+ }
+
+ /**
+ * Initializes the given client-side {@code context} with a default cert.
+ */
+ public static SSLContext initClientSslContext(SSLContext context) {
+ return initSslContext(context, TestKeyStore.getClient());
+ }
+
+ /**
+ * Initializes the given server-side {@code context} with the given cert chain and private key.
+ */
+ public static SSLContext initServerSslContext(SSLContext context) {
+ return initSslContext(context, TestKeyStore.getServer());
+ }
+
+ /**
+ * Initializes the given {@code context} from the {@code keyStore}.
+ */
+ static SSLContext initSslContext(SSLContext context, TestKeyStore keyStore) {
+ try {
+ context.init(keyStore.keyManagers, keyStore.trustManagers, null);
+ return context;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Performs the initial TLS handshake between the two {@link SSLEngine} instances.
+ */
+ public static void doEngineHandshake(SSLEngine clientEngine, SSLEngine serverEngine,
+ ByteBuffer clientAppBuffer, ByteBuffer clientPacketBuffer, ByteBuffer serverAppBuffer,
+ ByteBuffer serverPacketBuffer, boolean beginHandshake) throws SSLException {
+ if (beginHandshake) {
+ clientEngine.beginHandshake();
+ serverEngine.beginHandshake();
+ }
+
+ SSLEngineResult clientResult;
+ SSLEngineResult serverResult;
+
+ boolean clientHandshakeFinished = false;
+ boolean serverHandshakeFinished = false;
+
+ do {
+ int cTOsPos = clientPacketBuffer.position();
+ int sTOcPos = serverPacketBuffer.position();
+
+ clientResult = clientEngine.wrap(EMPTY_BUFFER, clientPacketBuffer);
+ runDelegatedTasks(clientResult, clientEngine);
+ serverResult = serverEngine.wrap(EMPTY_BUFFER, serverPacketBuffer);
+ runDelegatedTasks(serverResult, serverEngine);
+
+ // Verify that the consumed and produced number match what is in the buffers now.
+ assertEquals(0, clientResult.bytesConsumed());
+ assertEquals(0, serverResult.bytesConsumed());
+ assertEquals(clientPacketBuffer.position() - cTOsPos, clientResult.bytesProduced());
+ assertEquals(serverPacketBuffer.position() - sTOcPos, serverResult.bytesProduced());
+
+ clientPacketBuffer.flip();
+ serverPacketBuffer.flip();
+
+ // Verify that we only had one SSLEngineResult.HandshakeStatus.FINISHED
+ if (isHandshakeFinished(clientResult)) {
+ assertFalse(clientHandshakeFinished);
+ clientHandshakeFinished = true;
+ }
+ if (isHandshakeFinished(serverResult)) {
+ assertFalse(serverHandshakeFinished);
+ serverHandshakeFinished = true;
+ }
+
+ cTOsPos = clientPacketBuffer.position();
+ sTOcPos = serverPacketBuffer.position();
+
+ int clientAppReadBufferPos = clientAppBuffer.position();
+ int serverAppReadBufferPos = serverAppBuffer.position();
+
+ clientResult = clientEngine.unwrap(serverPacketBuffer, clientAppBuffer);
+ runDelegatedTasks(clientResult, clientEngine);
+ serverResult = serverEngine.unwrap(clientPacketBuffer, serverAppBuffer);
+ runDelegatedTasks(serverResult, serverEngine);
+
+ // Verify that the consumed and produced number match what is in the buffers now.
+ assertEquals(serverPacketBuffer.position() - sTOcPos, clientResult.bytesConsumed());
+ assertEquals(clientPacketBuffer.position() - cTOsPos, serverResult.bytesConsumed());
+ assertEquals(clientAppBuffer.position() - clientAppReadBufferPos,
+ clientResult.bytesProduced());
+ assertEquals(serverAppBuffer.position() - serverAppReadBufferPos,
+ serverResult.bytesProduced());
+
+ clientPacketBuffer.compact();
+ serverPacketBuffer.compact();
+
+ // Verify that we only had one SSLEngineResult.HandshakeStatus.FINISHED
+ if (isHandshakeFinished(clientResult)) {
+ assertFalse(clientHandshakeFinished);
+ clientHandshakeFinished = true;
+ }
+ if (isHandshakeFinished(serverResult)) {
+ assertFalse(serverHandshakeFinished);
+ serverHandshakeFinished = true;
+ }
+ } while (!clientHandshakeFinished || !serverHandshakeFinished);
+ }
+
+ private static boolean isHandshakeFinished(SSLEngineResult result) {
+ return result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED;
+ }
+
+ private static void runDelegatedTasks(SSLEngineResult result, SSLEngine engine) {
+ if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) {
+ for (;;) {
+ Runnable task = engine.getDelegatedTask();
+ if (task == null) {
+ break;
+ }
+ task.run();
+ }
+ }
+ }
+
+ public static String pickArbitraryNonTls13Suite(String[] cipherSuites) {
+ return pickArbitraryNonTls13Suite(Arrays.asList(cipherSuites));
+ }
+
+ public static String pickArbitraryNonTls13Suite(Iterable<String> cipherSuites) {
+ for (String cipherSuite : cipherSuites) {
+ if (!StandardNames.CIPHER_SUITES_TLS13.contains(cipherSuite)) {
+ return cipherSuite;
+ }
+ }
+ fail("No non-TLSv1.3 cipher suite available.");
+ return null;
+ }
+
+ /**
+ * Decodes the provided hexadecimal string into a byte array. Odd-length inputs
+ * are not allowed.
+ *
+ * Throws an {@code IllegalArgumentException} if the input is malformed.
+ */
+ public static byte[] decodeHex(String encoded) throws IllegalArgumentException {
+ return decodeHex(encoded.toCharArray());
+ }
+
+ /**
+ * Decodes the provided hexadecimal string into a byte array. If {@code allowSingleChar}
+ * is {@code true} odd-length inputs are allowed and the first character is interpreted
+ * as the lower bits of the first result byte.
+ *
+ * Throws an {@code IllegalArgumentException} if the input is malformed.
+ */
+ public static byte[] decodeHex(String encoded, boolean allowSingleChar) throws IllegalArgumentException {
+ return decodeHex(encoded.toCharArray(), allowSingleChar);
+ }
+
+ /**
+ * Decodes the provided hexadecimal string into a byte array. Odd-length inputs
+ * are not allowed.
+ *
+ * Throws an {@code IllegalArgumentException} if the input is malformed.
+ */
+ public static byte[] decodeHex(char[] encoded) throws IllegalArgumentException {
+ return decodeHex(encoded, false);
+ }
+
+ /**
+ * Decodes the provided hexadecimal string into a byte array. If {@code allowSingleChar}
+ * is {@code true} odd-length inputs are allowed and the first character is interpreted
+ * as the lower bits of the first result byte.
+ *
+ * Throws an {@code IllegalArgumentException} if the input is malformed.
+ */
+ public static byte[] decodeHex(char[] encoded, boolean allowSingleChar) throws IllegalArgumentException {
+ int resultLengthBytes = (encoded.length + 1) / 2;
+ byte[] result = new byte[resultLengthBytes];
+
+ int resultOffset = 0;
+ int i = 0;
+ if (allowSingleChar) {
+ if ((encoded.length % 2) != 0) {
+ // Odd number of digits -- the first digit is the lower 4 bits of the first result byte.
+ result[resultOffset++] = (byte) toDigit(encoded, i);
+ i++;
+ }
+ } else {
+ if ((encoded.length % 2) != 0) {
+ throw new IllegalArgumentException("Invalid input length: " + encoded.length);
+ }
+ }
+
+ for (int len = encoded.length; i < len; i += 2) {
+ result[resultOffset++] = (byte) ((toDigit(encoded, i) << 4) | toDigit(encoded, i + 1));
+ }
+
+ return result;
+ }
+
+ private static int toDigit(char[] str, int offset) throws IllegalArgumentException {
+ // NOTE: that this isn't really a code point in the traditional sense, since we're
+ // just rejecting surrogate pairs outright.
+ int pseudoCodePoint = str[offset];
+
+ if ('0' <= pseudoCodePoint && pseudoCodePoint <= '9') {
+ return pseudoCodePoint - '0';
+ } else if ('a' <= pseudoCodePoint && pseudoCodePoint <= 'f') {
+ return 10 + (pseudoCodePoint - 'a');
+ } else if ('A' <= pseudoCodePoint && pseudoCodePoint <= 'F') {
+ return 10 + (pseudoCodePoint - 'A');
+ }
+
+ throw new IllegalArgumentException("Illegal char: " + str[offset] +
+ " at offset " + offset);
+ }
+
+ private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray();
+
+ public static String encodeHex(byte[] data) {
+ char[] hex = new char[data.length * 2];
+ for (int i = 0; i < data.length; i++) {
+ int value = data[i] & 0xff;
+ hex[2 * i] = HEX_CHARS[value >>> 4];
+ hex[2 * i + 1] = HEX_CHARS[value & 0x0f];
+ }
+ return new String(hex);
+ }
+
+ private static final String BASE64_ALPHABET =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ public static String encodeBase64(byte[] data) {
+ // Base64 was introduced in Java 8, so if it's not available we can use a hacky
+ // solution that works in previous versions
+ if (isClassAvailable("java.util.Base64")) {
+ return Base64.getEncoder().encodeToString(data);
+ } else {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < data.length; i += 3) {
+ int padding = (i + 2 < data.length) ? 0 : (i + 3 - data.length);
+ byte b1 = data[i];
+ byte b2 = padding >= 2 ? 0 : data[i+1];
+ byte b3 = padding >= 1 ? 0 : data[i+2];
+
+ char c1 = BASE64_ALPHABET.charAt((b1 & 0xFF) >>> 2);
+ char c2 = BASE64_ALPHABET.charAt(((b1 & 0x03) << 4) | ((b2 & 0xFF) >>> 4));
+ char c3 = BASE64_ALPHABET.charAt(((b2 & 0x0F) << 2) | ((b3 & 0xFF) >>> 6));
+ char c4 = BASE64_ALPHABET.charAt(b3 & 0x3F);
+
+ if (padding >= 1) {
+ c4 = '=';
+ }
+ if (padding >= 2) {
+ c3 = '=';
+ }
+ builder.append(c1).append(c2).append(c3).append(c4);
+ }
+ return builder.toString();
+ }
+ }
+
+ public static byte[] decodeBase64(String data) {
+ // Base64 was introduced in Java 8, so if it's not available we can use a hacky
+ // solution that works in previous versions
+ if (isClassAvailable("java.util.Base64")) {
+ return Base64.getDecoder().decode(data);
+ } else {
+ while (data.endsWith("=")) {
+ data = data.substring(0, data.length() - 1);
+ }
+ int padding = (data.length() % 4 == 0) ? 0 : 4 - (data.length() % 4);
+ byte[] output = new byte[((data.length() - 1) / 4) * 3 + 3 - padding];
+ int outputindex = 0;
+ for (int i = 0; i < data.length(); i += 4) {
+ char c1 = data.charAt(i);
+ char c2 = data.charAt(i+1);
+ char c3 = (i+2 < data.length()) ? data.charAt(i+2) : 'A';
+ char c4 = (i+3 < data.length()) ? data.charAt(i+3) : 'A';
+
+ byte b1 = (byte)
+ (BASE64_ALPHABET.indexOf(c1) << 2 | BASE64_ALPHABET.indexOf(c2) >>> 4);
+ byte b2 = (byte)
+ ((BASE64_ALPHABET.indexOf(c2) & 0x0F) << 4 | BASE64_ALPHABET.indexOf(c3) >>> 2);
+ byte b3 = (byte)
+ ((BASE64_ALPHABET.indexOf(c3) & 0x03) << 6 | BASE64_ALPHABET.indexOf(c4));
+
+ output[outputindex++] = b1;
+ if (outputindex < output.length) {
+ output[outputindex++] = b2;
+ }
+ if (outputindex < output.length) {
+ output[outputindex++] = b3;
+ }
+ }
+ return output;
+ }
+ }
+
+ public static boolean isJavaVersion(int version) {
+ return javaVersion() >= version;
+ }
+
+ private static int javaVersion() {
+ String[] v = System.getProperty("java.specification.version", "1.6").split("\\.", -1);
+ if ("1".equals(v[0])) {
+ return Integer.parseInt(v[1]);
+ }
+ return Integer.parseInt(v[0]);
+ }
+
+ public static void assumeJava8() {
+ Assume.assumeTrue("Require Java 8: " + javaVersion(), isJavaVersion(8));
+ }
+
+ public static void assumeEngineSocket() {
+ Assume.assumeTrue(getUseEngineSocketByDefault());
+ }
+
+ public static String osName() {
+ return System.getProperty("os.name").toLowerCase(Locale.US).replaceAll("[^a-z0-9]+", "");
+ }
+
+ public static boolean isLinux() {
+ return osName().startsWith("linux");
+ }
+
+ public static boolean isWindows() {
+ return osName().startsWith("windows");
+ }
+
+ public static boolean isOsx() {
+ String name = osName();
+ return name.startsWith("macosx") || name.startsWith("osx");
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/VeryBasicHttpServer.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/VeryBasicHttpServer.java
new file mode 100644
index 0000000..12f19b4
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/VeryBasicHttpServer.java
@@ -0,0 +1,262 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2023 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.
+ */
+
+package com.android.org.conscrypt;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.Callable;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSocket;
+import com.android.org.conscrypt.javax.net.ssl.TestSSLContext;
+
+/**
+ * Very basic http server. Literally just enough to do some HTTP 1.1 in order
+ * to test URL connection functionality with the ability to inject faults.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class VeryBasicHttpServer {
+ private final TestSSLContext context = TestSSLContext.create();
+ private final ServerSocket tlsSocket = context.serverSocket;
+ private final ServerSocket plainSocket = new ServerSocket(0);
+
+
+ public VeryBasicHttpServer() throws IOException {
+ }
+
+ public String getTlsHostname() {
+ return context.host.getHostName();
+ }
+
+ public int getTlsPort() {
+ return tlsSocket.getLocalPort();
+ }
+
+ public String getPlainHostname() {
+ return plainSocket.getInetAddress().getHostName();
+ }
+
+ public int getPlainPort() {
+ return plainSocket.getLocalPort();
+ }
+
+ public void runInternal(Op op) throws Exception {
+ ServerSocket listenSocket = op.useTls() ? tlsSocket : plainSocket;
+ Socket connection = listenSocket.accept();
+ if (connection instanceof SSLSocket) {
+ ((SSLSocket) connection).setUseClientMode(false);
+ }
+ long delay = op.getPostAcceptDelay();
+ if (delay > 0) {
+ Thread.sleep(delay);
+ }
+
+ if (op.closeBeforeRead()) {
+ connection.close();
+ return;
+ }
+
+ Request request = readRequest(connection);
+ process(request, op);
+ connection.close();
+ }
+
+ public Callable<Void> run(Op op) {
+ return () -> {
+ runInternal(op);
+ return null;
+ };
+ }
+
+ public Op.Builder opBuilder() {
+ return Op.newBuilder();
+ }
+
+ void process(Request request, Op op) throws Exception {
+ String data = op.content.get(request.path);
+ if (data == null) {
+ request.sendStatus(404, request.protocol, "Not found: " + request.path);
+ request.endHeaders();
+ } else {
+ request.sendStatus(200, request.protocol, "OK");
+ request.sendHeader("Content-type", "text/plain");
+ request.sendHeader("Content-Length", data.length());
+ request.endHeaders();
+ request.sendString(data);
+ }
+ }
+
+ private Request readRequest(Socket socket) throws Exception {
+ Request request = new Request();
+ request.outputStream = socket.getOutputStream();
+
+ BufferedReader reader = new BufferedReader(
+ new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
+ String line = reader.readLine();
+ String[] words = line.split("\\s+");
+ checkCondition("Expected 3 words", words.length == 3);
+ request.command = words[0];
+ request.path = words[1];
+ request.protocol = words[2];
+
+ while (true) {
+ line = reader.readLine();
+ Objects.requireNonNull(line);
+ if (line.isEmpty()) {
+ break;
+ }
+ int separator = line.indexOf(": ");
+ checkCondition("Parse error", separator > 0);
+ String key = line.substring(0, separator);
+ String value = line.substring(separator + 2);
+ request.headers.put(key, value);
+ }
+ return request;
+ }
+
+ public void checkCondition(String message, boolean condition) {
+ if (!condition) {
+ throw new IllegalStateException(message);
+ }
+ }
+
+ public HttpsURLConnection tlsConnection(String filePart) throws Exception {
+ URL url = new URL("https", getTlsHostname(), getTlsPort(), filePart);
+ HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
+ connection.setSSLSocketFactory(context.clientContext.getSocketFactory());
+ return connection;
+ }
+
+ public HttpURLConnection plainConnection(String filePart) throws Exception {
+ URL url = new URL("http", getPlainHostname(), getPlainPort(), filePart);
+ return (HttpURLConnection) url.openConnection();
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class Op {
+ private final Map<String, String> content;
+ private final long postAcceptDelay;
+ private final boolean useTls;
+ private final boolean closeBeforeRead;
+
+ Op(Map<String, String> content, long postAcceptDelay,
+ boolean useTls, boolean closeBeforeRead) {
+ this.content = content;
+ this.postAcceptDelay = postAcceptDelay;
+ this.useTls = useTls;
+ this.closeBeforeRead = closeBeforeRead;
+ }
+
+ public long getPostAcceptDelay() {
+ return postAcceptDelay;
+ }
+
+ public boolean useTls() {
+ return useTls;
+ }
+
+ public boolean closeBeforeRead() {
+ return closeBeforeRead;
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class Builder {
+ private final Map<String, String> content = new HashMap<>();
+ private long postAcceptDelay = 0;
+ private boolean useTls = true;
+ private boolean closeBeforeRead = false;
+
+ private Builder() {}
+
+ public Builder content(String path, String data) {
+ this.content.put(path, data);
+ return this;
+ }
+
+ public Builder postAcceptDelay(long postAcceptDelay) {
+ this.postAcceptDelay = postAcceptDelay;
+ return this;
+ }
+
+ public Builder noTls() {
+ useTls = false;
+ return this;
+ }
+
+ public Builder closeBeforeRead() {
+ this.closeBeforeRead = true;
+ return this;
+ }
+
+ public Op build() {
+ return new Op(content, postAcceptDelay, useTls, closeBeforeRead);
+ }
+ }
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+ }
+
+ private static class Request {
+ public String command;
+ public String protocol;
+ public String path;
+ public Map<String, String> headers = new HashMap<>();
+ public OutputStream outputStream;
+
+ @Override
+ public String toString() {
+ return String.format("cmd=%s proto=%s path=%s headers=%s",
+ command, protocol, path, headers.toString());
+ }
+
+ public void sendStatus(int result, String proto, String extra) throws Exception {
+ String resultString = java.lang.String.format("%s %d %s\r\n", proto, result, extra);
+ outputStream.write(resultString.getBytes(StandardCharsets.UTF_8));
+ }
+
+ public void sendString (String string) throws Exception {
+ outputStream.write(string.getBytes(StandardCharsets.UTF_8));
+ }
+
+ public void endHeaders() throws Exception {
+ sendString("\r\n");
+ }
+
+ public void sendHeader(String key, String value) throws Exception {
+ sendString(key + ": " + value + "\r\n");
+ }
+
+ public void sendHeader(String key, Integer value) throws Exception {
+ sendHeader(key, value.toString());
+ }
+ }
+}
\ No newline at end of file
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AbstractAlgorithmParameterGeneratorTest.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AbstractAlgorithmParameterGeneratorTest.java
new file mode 100644
index 0000000..cdbd7e8
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AbstractAlgorithmParameterGeneratorTest.java
@@ -0,0 +1,47 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import org.junit.Test;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class AbstractAlgorithmParameterGeneratorTest {
+
+ private final String algorithmName;
+ private final TestHelper<AlgorithmParameters> helper;
+
+ protected AbstractAlgorithmParameterGeneratorTest(String algorithmName, TestHelper<AlgorithmParameters> helper) {
+ this.algorithmName = algorithmName;
+ this.helper = helper;
+ }
+
+ @Test
+ public void testAlgorithmParameterGenerator() throws Exception {
+ AlgorithmParameterGenerator generator = AlgorithmParameterGenerator.getInstance(algorithmName);
+ generator.init(1024);
+
+ AlgorithmParameters parameters = generator.generateParameters();
+ assertNotNull("generated parameters are null", parameters);
+ helper.test(parameters);
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AbstractAlgorithmParametersTest.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AbstractAlgorithmParametersTest.java
new file mode 100644
index 0000000..9f2ea86
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AbstractAlgorithmParametersTest.java
@@ -0,0 +1,45 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import java.security.AlgorithmParameters;
+import java.security.spec.AlgorithmParameterSpec;
+import org.junit.Test;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class AbstractAlgorithmParametersTest {
+
+ private final String algorithmName;
+ private final TestHelper<AlgorithmParameters> helper;
+ private final AlgorithmParameterSpec parameterData;
+
+ public AbstractAlgorithmParametersTest(String algorithmName,
+ TestHelper<AlgorithmParameters> helper, AlgorithmParameterSpec parameterData) {
+ this.algorithmName = algorithmName;
+ this.helper = helper;
+ this.parameterData = parameterData;
+ }
+
+ @Test
+ public void testAlgorithmParameters() throws Exception {
+ AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance(algorithmName);
+ algorithmParameters.init(parameterData);
+ helper.test(algorithmParameters);
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AbstractKeyFactoryTest.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AbstractKeyFactoryTest.java
new file mode 100644
index 0000000..319b198
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AbstractKeyFactoryTest.java
@@ -0,0 +1,111 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.Test;
+import tests.util.ServiceTester;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class AbstractKeyFactoryTest<PublicKeySpec extends KeySpec, PrivateKeySpec extends KeySpec> {
+ protected final String algorithmName;
+ private final Class<PublicKeySpec> publicKeySpecClass;
+ private final Class<PrivateKeySpec> privateKeySpecClass;
+
+ protected AbstractKeyFactoryTest(String algorithmName, Class<PublicKeySpec> publicKeySpecClass,
+ Class<PrivateKeySpec> privateKeySpecClass) {
+ this.algorithmName = algorithmName;
+ this.publicKeySpecClass = publicKeySpecClass;
+ this.privateKeySpecClass = privateKeySpecClass;
+ }
+
+ @Test
+ public void testKeyFactory() throws Exception {
+ customizeTester(ServiceTester.test("KeyFactory")
+ .withAlgorithm(algorithmName)
+ // On OpenJDK 7, the SunPKCS11-NSS provider sometimes doesn't accept
+ // keys created by other providers in getKeySpec(), so it fails some
+ // of the tests.
+ .skipProvider("SunPKCS11-NSS")
+ // Android Keystore's KeyFactory must be initialized with its own
+ // classes, it can't use the standard init() calls
+ .skipProvider("AndroidKeyStore"))
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p, String algorithm) throws Exception {
+ final KeyFactory factory = KeyFactory.getInstance(algorithm, p);
+
+ for (KeyPair pair : getKeys()) {
+ final PrivateKeySpec privateKeySpec =
+ factory.getKeySpec(pair.getPrivate(), privateKeySpecClass);
+ PrivateKey privateKey = factory.generatePrivate(privateKeySpec);
+ final PublicKeySpec publicKeySpec =
+ factory.getKeySpec(pair.getPublic(), publicKeySpecClass);
+ PublicKey publicKey = factory.generatePublic(publicKeySpec);
+ check(new KeyPair(publicKey, privateKey));
+
+ // Test that keys from any other KeyFactory can be translated into
+ // working keys from this KeyFactory
+ customizeTester(ServiceTester.test("KeyFactory")
+ .withAlgorithm(algorithmName)
+ .skipProvider(p.getName())
+ .skipProvider("SunPKCS11-NSS")
+ .skipProvider("AndroidKeyStore"))
+ .run(new ServiceTester.Test() {
+ @Override
+ public void test(Provider p2, String algorithm)
+ throws Exception {
+ KeyFactory factory2 =
+ KeyFactory.getInstance(algorithm, p2);
+ PrivateKey privateKey2 =
+ factory2.generatePrivate(privateKeySpec);
+ PublicKey publicKey2 =
+ factory2.generatePublic(publicKeySpec);
+
+ check(new KeyPair(
+ (PublicKey) factory.translateKey(publicKey2),
+ (PrivateKey) factory.translateKey(
+ privateKey2)));
+ }
+ });
+ }
+ }
+ });
+ }
+
+ protected ServiceTester customizeTester(ServiceTester tester) {
+ return tester;
+ }
+
+ protected void check(KeyPair keyPair) throws Exception {}
+
+ protected List<KeyPair> getKeys() throws NoSuchAlgorithmException, InvalidKeySpecException {
+ return Arrays.asList(new KeyPair(
+ DefaultKeys.getPublicKey(algorithmName), DefaultKeys.getPrivateKey(algorithmName)));
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AbstractKeyPairGeneratorTest.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AbstractKeyPairGeneratorTest.java
new file mode 100644
index 0000000..105bd48
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AbstractKeyPairGeneratorTest.java
@@ -0,0 +1,63 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2008 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.
+ */
+
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class AbstractKeyPairGeneratorTest {
+
+ private final String algorithmName;
+ private final TestHelper<KeyPair> helper;
+
+ private KeyPairGenerator generator;
+
+ protected AbstractKeyPairGeneratorTest(String algorithmName, TestHelper<KeyPair> helper) {
+ this.algorithmName = algorithmName;
+ this.helper = helper;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ generator = KeyPairGenerator.getInstance(algorithmName);
+ }
+
+ protected int getKeySize() {
+ return 1024;
+ }
+
+ @Test
+ public void testKeyPairGenerator() throws Exception {
+ generator.initialize(getKeySize());
+
+ KeyPair keyPair = generator.generateKeyPair();
+
+ assertNotNull("no keypair generated", keyPair);
+ assertNotNull("no public key generated", keyPair.getPublic());
+ assertNotNull("no private key generated", keyPair.getPrivate());
+
+ helper.test(keyPair);
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AlgorithmParameterAsymmetricHelper.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AlgorithmParameterAsymmetricHelper.java
new file mode 100644
index 0000000..bbc6bd4
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AlgorithmParameterAsymmetricHelper.java
@@ -0,0 +1,60 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertTrue;
+
+import java.security.AlgorithmParameters;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.util.Arrays;
+import javax.crypto.Cipher;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AlgorithmParameterAsymmetricHelper extends TestHelper<AlgorithmParameters> {
+
+ private static final String plainData = "some data to encrypt and decrypt";
+ private final String algorithmName;
+
+ public AlgorithmParameterAsymmetricHelper(String algorithmName) {
+ this.algorithmName = algorithmName;
+ }
+
+ private String baseName() {
+ return algorithmName.contains("/")
+ ? algorithmName.substring(0, algorithmName.indexOf('/'))
+ : algorithmName;
+ }
+
+ @Override
+ public void test(AlgorithmParameters parameters) throws Exception {
+ KeyPairGenerator generator = KeyPairGenerator.getInstance(baseName());
+ generator.initialize(1024);
+ KeyPair keyPair = generator.generateKeyPair();
+
+ Cipher cipher = Cipher.getInstance(algorithmName);
+ cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic(), parameters);
+ byte[] bs = cipher.doFinal(plainData.getBytes("UTF-8"));
+
+ cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate(), parameters);
+ byte[] decrypted = cipher.doFinal(bs);
+ assertTrue(Arrays.equals(plainData.getBytes("UTF-8"), decrypted));
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AlgorithmParameterKeyAgreementHelper.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AlgorithmParameterKeyAgreementHelper.java
new file mode 100644
index 0000000..5eba48e
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AlgorithmParameterKeyAgreementHelper.java
@@ -0,0 +1,49 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.security.AlgorithmParameters;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import javax.crypto.KeyAgreement;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AlgorithmParameterKeyAgreementHelper extends TestHelper<AlgorithmParameters> {
+
+ private final String algorithmName;
+
+ public AlgorithmParameterKeyAgreementHelper(String algorithmName) {
+ this.algorithmName = algorithmName;
+ }
+
+ @Override
+ public void test(AlgorithmParameters parameters) throws Exception {
+ KeyPairGenerator generator = KeyPairGenerator.getInstance(algorithmName);
+ generator.initialize(1024);
+
+ KeyPair keyPair = generator.generateKeyPair();
+ KeyAgreement keyAgreement = KeyAgreement.getInstance(algorithmName);
+ keyAgreement.init(keyPair.getPrivate());
+ keyAgreement.doPhase(keyPair.getPublic(), true);
+ assertNotNull("generated secret is null", keyAgreement.generateSecret());
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AlgorithmParameterSignatureHelper.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AlgorithmParameterSignatureHelper.java
new file mode 100644
index 0000000..1c45cdf
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AlgorithmParameterSignatureHelper.java
@@ -0,0 +1,69 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertTrue;
+
+import java.security.AlgorithmParameters;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.Signature;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AlgorithmParameterSignatureHelper<T extends AlgorithmParameterSpec>
+ extends TestHelper<AlgorithmParameters> {
+
+ private final String algorithmName;
+ private final String keyPairAlgorithmName;
+ private final String plainData = "some data do sign and verify";
+ private final Class<T> parameterSpecClass;
+
+ public AlgorithmParameterSignatureHelper(String algorithmName, Class<T> parameterSpecCla1ss) {
+ this.algorithmName = algorithmName;
+ this.keyPairAlgorithmName = algorithmName;
+ this.parameterSpecClass = parameterSpecCla1ss;
+ }
+
+ public AlgorithmParameterSignatureHelper(
+ String algorithmName, String keyPairAlgorithmName, Class<T> parameterSpecCla1ss) {
+ this.algorithmName = algorithmName;
+ this.keyPairAlgorithmName = keyPairAlgorithmName;
+ this.parameterSpecClass = parameterSpecCla1ss;
+ }
+
+ @Override
+ public void test(AlgorithmParameters parameters) throws Exception {
+ Signature signature = Signature.getInstance(algorithmName);
+ T parameterSpec = parameters.getParameterSpec(parameterSpecClass);
+ KeyPairGenerator generator = KeyPairGenerator.getInstance(keyPairAlgorithmName);
+
+ generator.initialize(parameterSpec);
+ KeyPair keyPair = generator.genKeyPair();
+
+ signature.initSign(keyPair.getPrivate());
+ signature.update(plainData.getBytes("UTF-8"));
+ byte[] signed = signature.sign();
+
+ signature.initVerify(keyPair.getPublic());
+ signature.update(plainData.getBytes("UTF-8"));
+ assertTrue("signature should verify", signature.verify(signed));
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AlgorithmParameterSymmetricHelper.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AlgorithmParameterSymmetricHelper.java
new file mode 100644
index 0000000..8791ecb
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AlgorithmParameterSymmetricHelper.java
@@ -0,0 +1,69 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertTrue;
+
+import java.security.AlgorithmParameters;
+import java.security.Key;
+import java.util.Arrays;
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AlgorithmParameterSymmetricHelper extends TestHelper<AlgorithmParameters> {
+
+ private static final String plainData = "some data to encrypt and decrypt";
+ private final String algorithmName;
+ private final int keySize;
+ private String blockmode;
+
+ public AlgorithmParameterSymmetricHelper(String algorithmName, int keySize) {
+ this.algorithmName = algorithmName;
+ this.keySize = keySize;
+ }
+
+ public AlgorithmParameterSymmetricHelper(String algorithmName, String blockmode, int keySize) {
+ this(algorithmName, keySize);
+ this.blockmode = blockmode;
+ }
+
+ @Override
+ public void test(AlgorithmParameters parameters) throws Exception {
+ KeyGenerator generator = KeyGenerator.getInstance(algorithmName);
+ generator.init(keySize);
+
+ Key key = generator.generateKey();
+ String transformation = algorithmName;
+ if (blockmode != null)
+ {
+ transformation += "/" + blockmode;
+ }
+
+ Cipher cipher = Cipher.getInstance(transformation);
+ cipher.init(Cipher.ENCRYPT_MODE, key, parameters);
+ byte[] bs = cipher.doFinal(plainData.getBytes("UTF-8"));
+
+ cipher.init(Cipher.DECRYPT_MODE, key, parameters);
+ byte[] decrypted = cipher.doFinal(bs);
+
+ assertTrue(Arrays.equals(plainData.getBytes("UTF-8"), decrypted));
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/CipherAsymmetricCryptHelper.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/CipherAsymmetricCryptHelper.java
new file mode 100644
index 0000000..049f609
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/CipherAsymmetricCryptHelper.java
@@ -0,0 +1,39 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt.java.security;
+
+import java.security.KeyPair;
+import javax.crypto.Cipher;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CipherAsymmetricCryptHelper extends CipherHelper<KeyPair> {
+
+ private static final String plainData = "some data to encrypt and decrypt test";
+
+ public CipherAsymmetricCryptHelper(String algorithmName) {
+ super(algorithmName, plainData, Cipher.ENCRYPT_MODE,
+ Cipher.DECRYPT_MODE);
+ }
+
+ @Override
+ public void test(KeyPair keyPair) throws Exception {
+ test(keyPair.getPrivate(), keyPair.getPublic());
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/CipherHelper.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/CipherHelper.java
new file mode 100644
index 0000000..29eb63a
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/CipherHelper.java
@@ -0,0 +1,54 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertEquals;
+
+import java.nio.charset.StandardCharsets;
+import java.security.Key;
+import javax.crypto.Cipher;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class CipherHelper<T> extends TestHelper<T> {
+
+ private final String algorithmName;
+ private final String plainData;
+ private final int mode1;
+ private final int mode2;
+
+ protected CipherHelper(String algorithmName, String plainData, int mode1, int mode2) {
+ this.algorithmName = algorithmName;
+ this.plainData = plainData;
+ this.mode1 = mode1;
+ this.mode2 = mode2;
+ }
+
+ public void test(Key encryptKey, Key decryptKey) throws Exception {
+ Cipher cipher = Cipher.getInstance(algorithmName);
+ cipher.init(mode1, encryptKey);
+ byte[] encrypted = cipher.doFinal(plainData.getBytes(StandardCharsets.UTF_8));
+
+ cipher.init(mode2, decryptKey);
+ byte[] decrypted = cipher.doFinal(encrypted);
+ String decryptedString = new String(decrypted, StandardCharsets.UTF_8);
+
+ assertEquals("transformed data does not match", plainData, decryptedString);
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/CpuFeatures.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/CpuFeatures.java
new file mode 100644
index 0000000..553a714
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/CpuFeatures.java
@@ -0,0 +1,155 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright 2016 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.
+ */
+
+package com.android.org.conscrypt.java.security;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CpuFeatures {
+ private CpuFeatures() {}
+
+ public static boolean isAESHardwareAccelerated() {
+ List<String> features = getListFromCpuinfo("Features");
+ if (features != null && features.contains("aes")) {
+ return true;
+ }
+
+ List<String> flags = getListFromCpuinfo("flags");
+ if (flags != null && flags.contains("aes")) {
+ return true;
+ }
+
+ features = getCpuFeaturesMac();
+ if (features != null && features.contains("aes")) {
+ return true;
+ }
+
+ // If we're in an emulated ABI, Conscrypt's NativeCrypto might bridge to
+ // a library that has accelerated AES instructions. See if Conscrypt
+ // detects that condition.
+ Class<?> nativeCrypto = findNativeCrypto();
+ if (nativeCrypto != null) {
+ try {
+ Method EVP_has_aes_hardware =
+ nativeCrypto.getDeclaredMethod("EVP_has_aes_hardware");
+ EVP_has_aes_hardware.setAccessible(true);
+ return ((Integer) EVP_has_aes_hardware.invoke(null)) == 1;
+ } catch (NoSuchMethodException ignored) {
+ // Ignored
+ } catch (SecurityException ignored) {
+ // Ignored
+ } catch (IllegalAccessException ignored) {
+ // Ignored
+ } catch (IllegalArgumentException ignored) {
+ // Ignored
+ } catch (InvocationTargetException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ return false;
+ }
+
+ private static Class<?> findNativeCrypto() {
+ for (String packageName : new String[]{"com.android.com.android.org.conscrypt", "com.android.org.conscrypt"}) {
+ String name = packageName + ".NativeCrypto";
+ try {
+ return Class.forName(name);
+ } catch (ClassNotFoundException e) {
+ // Try the next one.
+ }
+ }
+ return null;
+ }
+
+ private static String getFieldFromCpuinfo(String field) {
+ try {
+ @SuppressWarnings("DefaultCharset")
+ BufferedReader br = new BufferedReader(new FileReader("/proc/cpuinfo"));
+ Pattern p = Pattern.compile(field + "\\s*:\\s*(.*)");
+
+ try {
+ String line;
+ while ((line = br.readLine()) != null) {
+ Matcher m = p.matcher(line);
+ if (m.matches()) {
+ return m.group(1);
+ }
+ }
+ } finally {
+ br.close();
+ }
+ } catch (IOException ignored) {
+ // Ignored.
+ }
+
+ return null;
+ }
+
+ private static List<String> getListFromCpuinfo(String fieldName) {
+ String features = getFieldFromCpuinfo(fieldName);
+ if (features == null)
+ return null;
+
+ return Arrays.asList(features.split("\\s"));
+ }
+
+ private static List<String> getCpuFeaturesMac() {
+ try {
+ StringBuilder output = new StringBuilder();
+ Process proc = Runtime.getRuntime().exec("sysctl -a");
+ if (proc.waitFor() == 0) {
+ BufferedReader reader =
+ new BufferedReader(new InputStreamReader(proc.getInputStream(), UTF_8));
+
+ final String linePrefix = "machdep.cpu.features:";
+
+ String line;
+ while ((line = reader.readLine()) != null) {
+ line = line.toLowerCase();
+ if (line.startsWith(linePrefix)) {
+ // Strip the line prefix from the results.
+ output.append(line.substring(linePrefix.length())).append(' ');
+ }
+ }
+ if (output.length() > 0) {
+ String outputString = output.toString();
+ String[] parts = outputString.split("\\s+");
+ return Arrays.asList(parts);
+ }
+ }
+ } catch (Exception ignored) {
+ // Ignored.
+ }
+
+ return null;
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/DefaultKeys.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/DefaultKeys.java
new file mode 100644
index 0000000..0ce676f
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/DefaultKeys.java
@@ -0,0 +1,319 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+package com.android.org.conscrypt.java.security;
+
+import com.android.org.conscrypt.TestUtils;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DefaultKeys {
+ private static final byte[] RSA_private = new byte[] {
+ (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x75, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x30, (byte) 0x0D, (byte) 0x06, (byte) 0x09, (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D,
+ (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x82, (byte) 0x02, (byte) 0x5F, (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x5B, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02,
+ (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x99, (byte) 0xA5, (byte) 0x96, (byte) 0x72, (byte) 0xAE, (byte) 0xBB, (byte) 0x59, (byte) 0x36, (byte) 0xA8, (byte) 0x12, (byte) 0x17, (byte) 0x05, (byte) 0x4C, (byte) 0x63,
+ (byte) 0x9E, (byte) 0xB8, (byte) 0x85, (byte) 0xD4, (byte) 0x2D, (byte) 0x71, (byte) 0xD7, (byte) 0x29, (byte) 0xB9, (byte) 0x05, (byte) 0x0F, (byte) 0xB4, (byte) 0x57, (byte) 0xFB, (byte) 0xD3, (byte) 0x95, (byte) 0x5C,
+ (byte) 0x21, (byte) 0xEC, (byte) 0xB5, (byte) 0xEB, (byte) 0x67, (byte) 0xA2, (byte) 0x4F, (byte) 0xC1, (byte) 0x93, (byte) 0xEF, (byte) 0x96, (byte) 0x41, (byte) 0x05, (byte) 0x3D, (byte) 0xC5, (byte) 0x3E, (byte) 0x04,
+ (byte) 0x4D, (byte) 0xC6, (byte) 0xCF, (byte) 0x32, (byte) 0x7C, (byte) 0x1F, (byte) 0x66, (byte) 0xA3, (byte) 0xC5, (byte) 0x27, (byte) 0x79, (byte) 0xEC, (byte) 0x2E, (byte) 0x67, (byte) 0xFA, (byte) 0x19, (byte) 0x5B,
+ (byte) 0xE3, (byte) 0xB1, (byte) 0x69, (byte) 0xDA, (byte) 0x63, (byte) 0xBC, (byte) 0xDA, (byte) 0xD3, (byte) 0xBB, (byte) 0xAD, (byte) 0x8C, (byte) 0x38, (byte) 0x7B, (byte) 0x4A, (byte) 0x9C, (byte) 0xD4, (byte) 0x4D,
+ (byte) 0xD2, (byte) 0x33, (byte) 0xB7, (byte) 0x4E, (byte) 0x04, (byte) 0xB6, (byte) 0xDF, (byte) 0x62, (byte) 0x55, (byte) 0x48, (byte) 0x5C, (byte) 0x94, (byte) 0x02, (byte) 0xF7, (byte) 0x84, (byte) 0xE6, (byte) 0x9B,
+ (byte) 0x57, (byte) 0xFF, (byte) 0x17, (byte) 0x2A, (byte) 0xA1, (byte) 0x74, (byte) 0x8D, (byte) 0x07, (byte) 0xD8, (byte) 0xCE, (byte) 0xF7, (byte) 0x0B, (byte) 0x59, (byte) 0xFB, (byte) 0x13, (byte) 0x6E, (byte) 0xF1,
+ (byte) 0xC3, (byte) 0xAB, (byte) 0x3E, (byte) 0x72, (byte) 0x1B, (byte) 0x62, (byte) 0x09, (byte) 0xE8, (byte) 0xD8, (byte) 0x41, (byte) 0x69, (byte) 0xE1, (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01,
+ (byte) 0x02, (byte) 0x81, (byte) 0x80, (byte) 0x57, (byte) 0xD6, (byte) 0x1C, (byte) 0x2E, (byte) 0x2F, (byte) 0xCA, (byte) 0x16, (byte) 0xF4, (byte) 0x72, (byte) 0x1C, (byte) 0xF5, (byte) 0x60, (byte) 0x28, (byte) 0x0D,
+ (byte) 0x83, (byte) 0x7D, (byte) 0x85, (byte) 0xB4, (byte) 0x88, (byte) 0xCE, (byte) 0x5D, (byte) 0xED, (byte) 0x12, (byte) 0x42, (byte) 0xDC, (byte) 0x79, (byte) 0x83, (byte) 0x1B, (byte) 0x0A, (byte) 0x18, (byte) 0x86,
+ (byte) 0xF5, (byte) 0x35, (byte) 0xF7, (byte) 0xC2, (byte) 0x3E, (byte) 0x1A, (byte) 0xC2, (byte) 0x71, (byte) 0xAD, (byte) 0xFA, (byte) 0xF7, (byte) 0xF0, (byte) 0xEF, (byte) 0xE8, (byte) 0x22, (byte) 0x4C, (byte) 0x93,
+ (byte) 0xF5, (byte) 0x4A, (byte) 0xC4, (byte) 0xC4, (byte) 0xDD, (byte) 0xC4, (byte) 0xAD, (byte) 0xCE, (byte) 0xCE, (byte) 0x35, (byte) 0x05, (byte) 0x34, (byte) 0x8A, (byte) 0x4B, (byte) 0x12, (byte) 0xE4, (byte) 0x69,
+ (byte) 0xE6, (byte) 0xDA, (byte) 0x07, (byte) 0x1A, (byte) 0x77, (byte) 0x5C, (byte) 0xA7, (byte) 0x21, (byte) 0x41, (byte) 0x89, (byte) 0x8C, (byte) 0x95, (byte) 0x6A, (byte) 0x5D, (byte) 0x9C, (byte) 0x3C, (byte) 0xAE,
+ (byte) 0xC3, (byte) 0xE4, (byte) 0x64, (byte) 0x54, (byte) 0xDA, (byte) 0xFB, (byte) 0xBA, (byte) 0xA6, (byte) 0xE5, (byte) 0x8A, (byte) 0x7F, (byte) 0xFA, (byte) 0x1A, (byte) 0x3F, (byte) 0x9B, (byte) 0xAB, (byte) 0xDA,
+ (byte) 0x3D, (byte) 0x3B, (byte) 0x43, (byte) 0xF0, (byte) 0x0C, (byte) 0x06, (byte) 0x57, (byte) 0x43, (byte) 0x45, (byte) 0xEE, (byte) 0x8C, (byte) 0x27, (byte) 0x05, (byte) 0xAF, (byte) 0xCD, (byte) 0x5A, (byte) 0x47,
+ (byte) 0xB9, (byte) 0xEA, (byte) 0xD9, (byte) 0xAA, (byte) 0x66, (byte) 0xDB, (byte) 0xE3, (byte) 0xDC, (byte) 0x54, (byte) 0x47, (byte) 0x60, (byte) 0x01, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xED, (byte) 0xE9,
+ (byte) 0xBD, (byte) 0xD5, (byte) 0x02, (byte) 0x6D, (byte) 0x44, (byte) 0x0E, (byte) 0x3F, (byte) 0x74, (byte) 0x0C, (byte) 0x45, (byte) 0x54, (byte) 0x88, (byte) 0xFE, (byte) 0x5C, (byte) 0xFC, (byte) 0xF2, (byte) 0x31,
+ (byte) 0x7B, (byte) 0xAF, (byte) 0x15, (byte) 0x77, (byte) 0x7A, (byte) 0xDC, (byte) 0xC6, (byte) 0x9E, (byte) 0x7E, (byte) 0xC1, (byte) 0xCA, (byte) 0x84, (byte) 0xC7, (byte) 0x4B, (byte) 0xC4, (byte) 0x41, (byte) 0xE1,
+ (byte) 0x85, (byte) 0xE4, (byte) 0x5A, (byte) 0xA7, (byte) 0x3D, (byte) 0x54, (byte) 0x87, (byte) 0x0D, (byte) 0x7A, (byte) 0xC5, (byte) 0x47, (byte) 0x5C, (byte) 0xF2, (byte) 0xAD, (byte) 0x14, (byte) 0x4D, (byte) 0x63,
+ (byte) 0xB0, (byte) 0xDC, (byte) 0x34, (byte) 0xB5, (byte) 0xDA, (byte) 0x17, (byte) 0x0D, (byte) 0x4E, (byte) 0x2B, (byte) 0x9E, (byte) 0x81, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xA5, (byte) 0x53, (byte) 0xDB,
+ (byte) 0xD8, (byte) 0x28, (byte) 0x57, (byte) 0x65, (byte) 0x2B, (byte) 0xFA, (byte) 0xF2, (byte) 0x21, (byte) 0xB8, (byte) 0x60, (byte) 0xAE, (byte) 0x43, (byte) 0x4B, (byte) 0x51, (byte) 0x85, (byte) 0xCB, (byte) 0xDA,
+ (byte) 0x89, (byte) 0x5A, (byte) 0x7D, (byte) 0x05, (byte) 0xDA, (byte) 0xFC, (byte) 0xAF, (byte) 0x46, (byte) 0x86, (byte) 0xBC, (byte) 0x3F, (byte) 0xD1, (byte) 0xEA, (byte) 0xA4, (byte) 0x56, (byte) 0xA3, (byte) 0xE6,
+ (byte) 0xD4, (byte) 0xA2, (byte) 0x08, (byte) 0x93, (byte) 0x63, (byte) 0x21, (byte) 0x0E, (byte) 0xC5, (byte) 0x3C, (byte) 0x97, (byte) 0x7E, (byte) 0x71, (byte) 0x0B, (byte) 0x79, (byte) 0xF8, (byte) 0x60, (byte) 0x73,
+ (byte) 0xD1, (byte) 0xF9, (byte) 0xD4, (byte) 0x66, (byte) 0x29, (byte) 0x7D, (byte) 0xDC, (byte) 0x22, (byte) 0xDB, (byte) 0x61, (byte) 0x02, (byte) 0x40, (byte) 0x5D, (byte) 0x3D, (byte) 0xEF, (byte) 0x85, (byte) 0x4D,
+ (byte) 0x27, (byte) 0x2F, (byte) 0xB5, (byte) 0xF9, (byte) 0xCE, (byte) 0x6C, (byte) 0x84, (byte) 0xBB, (byte) 0x85, (byte) 0xD9, (byte) 0x52, (byte) 0xEE, (byte) 0x5B, (byte) 0xA9, (byte) 0x63, (byte) 0x15, (byte) 0x12,
+ (byte) 0x6F, (byte) 0xBA, (byte) 0x3A, (byte) 0x4E, (byte) 0xA9, (byte) 0x8D, (byte) 0x7A, (byte) 0x3B, (byte) 0xF9, (byte) 0xDF, (byte) 0xF5, (byte) 0xE4, (byte) 0xDC, (byte) 0x01, (byte) 0x1C, (byte) 0x2D, (byte) 0x8C,
+ (byte) 0x0D, (byte) 0xE1, (byte) 0x6E, (byte) 0x80, (byte) 0x63, (byte) 0x9B, (byte) 0x0B, (byte) 0x38, (byte) 0x55, (byte) 0xC8, (byte) 0x52, (byte) 0x67, (byte) 0x13, (byte) 0x91, (byte) 0x8F, (byte) 0x9E, (byte) 0x2E,
+ (byte) 0x16, (byte) 0x5B, (byte) 0x7C, (byte) 0x0F, (byte) 0x5D, (byte) 0xE4, (byte) 0xA0, (byte) 0x81, (byte) 0x02, (byte) 0x40, (byte) 0x20, (byte) 0x12, (byte) 0x11, (byte) 0x5E, (byte) 0x70, (byte) 0x0C, (byte) 0xEC,
+ (byte) 0x02, (byte) 0x49, (byte) 0x0E, (byte) 0xB9, (byte) 0x3D, (byte) 0xD3, (byte) 0xFB, (byte) 0x59, (byte) 0xF0, (byte) 0x7D, (byte) 0x62, (byte) 0xEF, (byte) 0xF5, (byte) 0x77, (byte) 0x99, (byte) 0x87, (byte) 0x11,
+ (byte) 0x20, (byte) 0xB6, (byte) 0xCD, (byte) 0xA5, (byte) 0x67, (byte) 0xB3, (byte) 0x92, (byte) 0xC9, (byte) 0xBC, (byte) 0xB3, (byte) 0x9E, (byte) 0x5E, (byte) 0xF3, (byte) 0x03, (byte) 0x22, (byte) 0x5F, (byte) 0x79,
+ (byte) 0x7F, (byte) 0xCC, (byte) 0x44, (byte) 0xDA, (byte) 0x3B, (byte) 0xF3, (byte) 0xC3, (byte) 0x42, (byte) 0x58, (byte) 0x90, (byte) 0x93, (byte) 0x7E, (byte) 0xDA, (byte) 0x58, (byte) 0xCC, (byte) 0x16, (byte) 0xC8,
+ (byte) 0xAE, (byte) 0x99, (byte) 0xCC, (byte) 0x9F, (byte) 0x32, (byte) 0x61, (byte) 0x02, (byte) 0x40, (byte) 0x02, (byte) 0x29, (byte) 0xDB, (byte) 0x00, (byte) 0x0F, (byte) 0x0A, (byte) 0x17, (byte) 0x33, (byte) 0x7E,
+ (byte) 0xC5, (byte) 0xEC, (byte) 0x21, (byte) 0x47, (byte) 0x65, (byte) 0xDC, (byte) 0xE5, (byte) 0xC2, (byte) 0x0D, (byte) 0x42, (byte) 0x28, (byte) 0xE1, (byte) 0x17, (byte) 0x1A, (byte) 0x00, (byte) 0xBD, (byte) 0xBE,
+ (byte) 0x1C, (byte) 0x7D, (byte) 0xCA, (byte) 0x93, (byte) 0x67, (byte) 0x8F, (byte) 0x28, (byte) 0xB7, (byte) 0x60, (byte) 0x8E, (byte) 0xF0, (byte) 0x5D, (byte) 0xCD, (byte) 0xFA, (byte) 0xDD, (byte) 0x6B, (byte) 0x72,
+ (byte) 0xF7, (byte) 0x48, (byte) 0xD9, (byte) 0x3C, (byte) 0x40, (byte) 0x7C, (byte) 0xB0, (byte) 0xD7, (byte) 0x58, (byte) 0xC2, (byte) 0x53, (byte) 0xAD, (byte) 0x04, (byte) 0xF6, (byte) 0x0B, (byte) 0x35, (byte) 0x51,
+ (byte) 0x45, (byte) 0xB9, (byte) 0x4F, (byte) 0x49 };
+ private static final byte[] RSA_public = new byte[] {
+ (byte) 0x30, (byte) 0x81, (byte) 0x9F, (byte) 0x30, (byte) 0x0D, (byte) 0x06, (byte) 0x09, (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05,
+ (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x8D, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x99, (byte) 0xA5, (byte) 0x96, (byte) 0x72, (byte) 0xAE,
+ (byte) 0xBB, (byte) 0x59, (byte) 0x36, (byte) 0xA8, (byte) 0x12, (byte) 0x17, (byte) 0x05, (byte) 0x4C, (byte) 0x63, (byte) 0x9E, (byte) 0xB8, (byte) 0x85, (byte) 0xD4, (byte) 0x2D, (byte) 0x71, (byte) 0xD7, (byte) 0x29,
+ (byte) 0xB9, (byte) 0x05, (byte) 0x0F, (byte) 0xB4, (byte) 0x57, (byte) 0xFB, (byte) 0xD3, (byte) 0x95, (byte) 0x5C, (byte) 0x21, (byte) 0xEC, (byte) 0xB5, (byte) 0xEB, (byte) 0x67, (byte) 0xA2, (byte) 0x4F, (byte) 0xC1,
+ (byte) 0x93, (byte) 0xEF, (byte) 0x96, (byte) 0x41, (byte) 0x05, (byte) 0x3D, (byte) 0xC5, (byte) 0x3E, (byte) 0x04, (byte) 0x4D, (byte) 0xC6, (byte) 0xCF, (byte) 0x32, (byte) 0x7C, (byte) 0x1F, (byte) 0x66, (byte) 0xA3,
+ (byte) 0xC5, (byte) 0x27, (byte) 0x79, (byte) 0xEC, (byte) 0x2E, (byte) 0x67, (byte) 0xFA, (byte) 0x19, (byte) 0x5B, (byte) 0xE3, (byte) 0xB1, (byte) 0x69, (byte) 0xDA, (byte) 0x63, (byte) 0xBC, (byte) 0xDA, (byte) 0xD3,
+ (byte) 0xBB, (byte) 0xAD, (byte) 0x8C, (byte) 0x38, (byte) 0x7B, (byte) 0x4A, (byte) 0x9C, (byte) 0xD4, (byte) 0x4D, (byte) 0xD2, (byte) 0x33, (byte) 0xB7, (byte) 0x4E, (byte) 0x04, (byte) 0xB6, (byte) 0xDF, (byte) 0x62,
+ (byte) 0x55, (byte) 0x48, (byte) 0x5C, (byte) 0x94, (byte) 0x02, (byte) 0xF7, (byte) 0x84, (byte) 0xE6, (byte) 0x9B, (byte) 0x57, (byte) 0xFF, (byte) 0x17, (byte) 0x2A, (byte) 0xA1, (byte) 0x74, (byte) 0x8D, (byte) 0x07,
+ (byte) 0xD8, (byte) 0xCE, (byte) 0xF7, (byte) 0x0B, (byte) 0x59, (byte) 0xFB, (byte) 0x13, (byte) 0x6E, (byte) 0xF1, (byte) 0xC3, (byte) 0xAB, (byte) 0x3E, (byte) 0x72, (byte) 0x1B, (byte) 0x62, (byte) 0x09, (byte) 0xE8,
+ (byte) 0xD8, (byte) 0x41, (byte) 0x69, (byte) 0xE1, (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01 };
+ private static final byte[] DSA_private = new byte[] {
+ (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x4B, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x2C, (byte) 0x06, (byte) 0x07, (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0xCE,
+ (byte) 0x38, (byte) 0x04, (byte) 0x01, (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x1F, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xFD, (byte) 0x7F, (byte) 0x53, (byte) 0x81, (byte) 0x1D, (byte) 0x75,
+ (byte) 0x12, (byte) 0x29, (byte) 0x52, (byte) 0xDF, (byte) 0x4A, (byte) 0x9C, (byte) 0x2E, (byte) 0xEC, (byte) 0xE4, (byte) 0xE7, (byte) 0xF6, (byte) 0x11, (byte) 0xB7, (byte) 0x52, (byte) 0x3C, (byte) 0xEF, (byte) 0x44,
+ (byte) 0x00, (byte) 0xC3, (byte) 0x1E, (byte) 0x3F, (byte) 0x80, (byte) 0xB6, (byte) 0x51, (byte) 0x26, (byte) 0x69, (byte) 0x45, (byte) 0x5D, (byte) 0x40, (byte) 0x22, (byte) 0x51, (byte) 0xFB, (byte) 0x59, (byte) 0x3D,
+ (byte) 0x8D, (byte) 0x58, (byte) 0xFA, (byte) 0xBF, (byte) 0xC5, (byte) 0xF5, (byte) 0xBA, (byte) 0x30, (byte) 0xF6, (byte) 0xCB, (byte) 0x9B, (byte) 0x55, (byte) 0x6C, (byte) 0xD7, (byte) 0x81, (byte) 0x3B, (byte) 0x80,
+ (byte) 0x1D, (byte) 0x34, (byte) 0x6F, (byte) 0xF2, (byte) 0x66, (byte) 0x60, (byte) 0xB7, (byte) 0x6B, (byte) 0x99, (byte) 0x50, (byte) 0xA5, (byte) 0xA4, (byte) 0x9F, (byte) 0x9F, (byte) 0xE8, (byte) 0x04, (byte) 0x7B,
+ (byte) 0x10, (byte) 0x22, (byte) 0xC2, (byte) 0x4F, (byte) 0xBB, (byte) 0xA9, (byte) 0xD7, (byte) 0xFE, (byte) 0xB7, (byte) 0xC6, (byte) 0x1B, (byte) 0xF8, (byte) 0x3B, (byte) 0x57, (byte) 0xE7, (byte) 0xC6, (byte) 0xA8,
+ (byte) 0xA6, (byte) 0x15, (byte) 0x0F, (byte) 0x04, (byte) 0xFB, (byte) 0x83, (byte) 0xF6, (byte) 0xD3, (byte) 0xC5, (byte) 0x1E, (byte) 0xC3, (byte) 0x02, (byte) 0x35, (byte) 0x54, (byte) 0x13, (byte) 0x5A, (byte) 0x16,
+ (byte) 0x91, (byte) 0x32, (byte) 0xF6, (byte) 0x75, (byte) 0xF3, (byte) 0xAE, (byte) 0x2B, (byte) 0x61, (byte) 0xD7, (byte) 0x2A, (byte) 0xEF, (byte) 0xF2, (byte) 0x22, (byte) 0x03, (byte) 0x19, (byte) 0x9D, (byte) 0xD1,
+ (byte) 0x48, (byte) 0x01, (byte) 0xC7, (byte) 0x02, (byte) 0x15, (byte) 0x00, (byte) 0x97, (byte) 0x60, (byte) 0x50, (byte) 0x8F, (byte) 0x15, (byte) 0x23, (byte) 0x0B, (byte) 0xCC, (byte) 0xB2, (byte) 0x92, (byte) 0xB9,
+ (byte) 0x82, (byte) 0xA2, (byte) 0xEB, (byte) 0x84, (byte) 0x0B, (byte) 0xF0, (byte) 0x58, (byte) 0x1C, (byte) 0xF5, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xF7, (byte) 0xE1, (byte) 0xA0, (byte) 0x85,
+ (byte) 0xD6, (byte) 0x9B, (byte) 0x3D, (byte) 0xDE, (byte) 0xCB, (byte) 0xBC, (byte) 0xAB, (byte) 0x5C, (byte) 0x36, (byte) 0xB8, (byte) 0x57, (byte) 0xB9, (byte) 0x79, (byte) 0x94, (byte) 0xAF, (byte) 0xBB, (byte) 0xFA,
+ (byte) 0x3A, (byte) 0xEA, (byte) 0x82, (byte) 0xF9, (byte) 0x57, (byte) 0x4C, (byte) 0x0B, (byte) 0x3D, (byte) 0x07, (byte) 0x82, (byte) 0x67, (byte) 0x51, (byte) 0x59, (byte) 0x57, (byte) 0x8E, (byte) 0xBA, (byte) 0xD4,
+ (byte) 0x59, (byte) 0x4F, (byte) 0xE6, (byte) 0x71, (byte) 0x07, (byte) 0x10, (byte) 0x81, (byte) 0x80, (byte) 0xB4, (byte) 0x49, (byte) 0x16, (byte) 0x71, (byte) 0x23, (byte) 0xE8, (byte) 0x4C, (byte) 0x28, (byte) 0x16,
+ (byte) 0x13, (byte) 0xB7, (byte) 0xCF, (byte) 0x09, (byte) 0x32, (byte) 0x8C, (byte) 0xC8, (byte) 0xA6, (byte) 0xE1, (byte) 0x3C, (byte) 0x16, (byte) 0x7A, (byte) 0x8B, (byte) 0x54, (byte) 0x7C, (byte) 0x8D, (byte) 0x28,
+ (byte) 0xE0, (byte) 0xA3, (byte) 0xAE, (byte) 0x1E, (byte) 0x2B, (byte) 0xB3, (byte) 0xA6, (byte) 0x75, (byte) 0x91, (byte) 0x6E, (byte) 0xA3, (byte) 0x7F, (byte) 0x0B, (byte) 0xFA, (byte) 0x21, (byte) 0x35, (byte) 0x62,
+ (byte) 0xF1, (byte) 0xFB, (byte) 0x62, (byte) 0x7A, (byte) 0x01, (byte) 0x24, (byte) 0x3B, (byte) 0xCC, (byte) 0xA4, (byte) 0xF1, (byte) 0xBE, (byte) 0xA8, (byte) 0x51, (byte) 0x90, (byte) 0x89, (byte) 0xA8, (byte) 0x83,
+ (byte) 0xDF, (byte) 0xE1, (byte) 0x5A, (byte) 0xE5, (byte) 0x9F, (byte) 0x06, (byte) 0x92, (byte) 0x8B, (byte) 0x66, (byte) 0x5E, (byte) 0x80, (byte) 0x7B, (byte) 0x55, (byte) 0x25, (byte) 0x64, (byte) 0x01, (byte) 0x4C,
+ (byte) 0x3B, (byte) 0xFE, (byte) 0xCF, (byte) 0x49, (byte) 0x2A, (byte) 0x04, (byte) 0x16, (byte) 0x02, (byte) 0x14, (byte) 0x0E, (byte) 0x90, (byte) 0xB7, (byte) 0x92, (byte) 0x01, (byte) 0x98, (byte) 0xCD, (byte) 0x85,
+ (byte) 0x87, (byte) 0x77, (byte) 0x2F, (byte) 0xB4, (byte) 0x31, (byte) 0xFD, (byte) 0xDE, (byte) 0xFA, (byte) 0x08, (byte) 0x6D, (byte) 0x0C, (byte) 0xE3 };
+ private static final byte[] DSA_public = new byte[] {
+ (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0xB8, (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x2C, (byte) 0x06, (byte) 0x07, (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0xCE, (byte) 0x38, (byte) 0x04, (byte) 0x01,
+ (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x1F, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xFD, (byte) 0x7F, (byte) 0x53, (byte) 0x81, (byte) 0x1D, (byte) 0x75, (byte) 0x12, (byte) 0x29, (byte) 0x52,
+ (byte) 0xDF, (byte) 0x4A, (byte) 0x9C, (byte) 0x2E, (byte) 0xEC, (byte) 0xE4, (byte) 0xE7, (byte) 0xF6, (byte) 0x11, (byte) 0xB7, (byte) 0x52, (byte) 0x3C, (byte) 0xEF, (byte) 0x44, (byte) 0x00, (byte) 0xC3, (byte) 0x1E,
+ (byte) 0x3F, (byte) 0x80, (byte) 0xB6, (byte) 0x51, (byte) 0x26, (byte) 0x69, (byte) 0x45, (byte) 0x5D, (byte) 0x40, (byte) 0x22, (byte) 0x51, (byte) 0xFB, (byte) 0x59, (byte) 0x3D, (byte) 0x8D, (byte) 0x58, (byte) 0xFA,
+ (byte) 0xBF, (byte) 0xC5, (byte) 0xF5, (byte) 0xBA, (byte) 0x30, (byte) 0xF6, (byte) 0xCB, (byte) 0x9B, (byte) 0x55, (byte) 0x6C, (byte) 0xD7, (byte) 0x81, (byte) 0x3B, (byte) 0x80, (byte) 0x1D, (byte) 0x34, (byte) 0x6F,
+ (byte) 0xF2, (byte) 0x66, (byte) 0x60, (byte) 0xB7, (byte) 0x6B, (byte) 0x99, (byte) 0x50, (byte) 0xA5, (byte) 0xA4, (byte) 0x9F, (byte) 0x9F, (byte) 0xE8, (byte) 0x04, (byte) 0x7B, (byte) 0x10, (byte) 0x22, (byte) 0xC2,
+ (byte) 0x4F, (byte) 0xBB, (byte) 0xA9, (byte) 0xD7, (byte) 0xFE, (byte) 0xB7, (byte) 0xC6, (byte) 0x1B, (byte) 0xF8, (byte) 0x3B, (byte) 0x57, (byte) 0xE7, (byte) 0xC6, (byte) 0xA8, (byte) 0xA6, (byte) 0x15, (byte) 0x0F,
+ (byte) 0x04, (byte) 0xFB, (byte) 0x83, (byte) 0xF6, (byte) 0xD3, (byte) 0xC5, (byte) 0x1E, (byte) 0xC3, (byte) 0x02, (byte) 0x35, (byte) 0x54, (byte) 0x13, (byte) 0x5A, (byte) 0x16, (byte) 0x91, (byte) 0x32, (byte) 0xF6,
+ (byte) 0x75, (byte) 0xF3, (byte) 0xAE, (byte) 0x2B, (byte) 0x61, (byte) 0xD7, (byte) 0x2A, (byte) 0xEF, (byte) 0xF2, (byte) 0x22, (byte) 0x03, (byte) 0x19, (byte) 0x9D, (byte) 0xD1, (byte) 0x48, (byte) 0x01, (byte) 0xC7,
+ (byte) 0x02, (byte) 0x15, (byte) 0x00, (byte) 0x97, (byte) 0x60, (byte) 0x50, (byte) 0x8F, (byte) 0x15, (byte) 0x23, (byte) 0x0B, (byte) 0xCC, (byte) 0xB2, (byte) 0x92, (byte) 0xB9, (byte) 0x82, (byte) 0xA2, (byte) 0xEB,
+ (byte) 0x84, (byte) 0x0B, (byte) 0xF0, (byte) 0x58, (byte) 0x1C, (byte) 0xF5, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xF7, (byte) 0xE1, (byte) 0xA0, (byte) 0x85, (byte) 0xD6, (byte) 0x9B, (byte) 0x3D,
+ (byte) 0xDE, (byte) 0xCB, (byte) 0xBC, (byte) 0xAB, (byte) 0x5C, (byte) 0x36, (byte) 0xB8, (byte) 0x57, (byte) 0xB9, (byte) 0x79, (byte) 0x94, (byte) 0xAF, (byte) 0xBB, (byte) 0xFA, (byte) 0x3A, (byte) 0xEA, (byte) 0x82,
+ (byte) 0xF9, (byte) 0x57, (byte) 0x4C, (byte) 0x0B, (byte) 0x3D, (byte) 0x07, (byte) 0x82, (byte) 0x67, (byte) 0x51, (byte) 0x59, (byte) 0x57, (byte) 0x8E, (byte) 0xBA, (byte) 0xD4, (byte) 0x59, (byte) 0x4F, (byte) 0xE6,
+ (byte) 0x71, (byte) 0x07, (byte) 0x10, (byte) 0x81, (byte) 0x80, (byte) 0xB4, (byte) 0x49, (byte) 0x16, (byte) 0x71, (byte) 0x23, (byte) 0xE8, (byte) 0x4C, (byte) 0x28, (byte) 0x16, (byte) 0x13, (byte) 0xB7, (byte) 0xCF,
+ (byte) 0x09, (byte) 0x32, (byte) 0x8C, (byte) 0xC8, (byte) 0xA6, (byte) 0xE1, (byte) 0x3C, (byte) 0x16, (byte) 0x7A, (byte) 0x8B, (byte) 0x54, (byte) 0x7C, (byte) 0x8D, (byte) 0x28, (byte) 0xE0, (byte) 0xA3, (byte) 0xAE,
+ (byte) 0x1E, (byte) 0x2B, (byte) 0xB3, (byte) 0xA6, (byte) 0x75, (byte) 0x91, (byte) 0x6E, (byte) 0xA3, (byte) 0x7F, (byte) 0x0B, (byte) 0xFA, (byte) 0x21, (byte) 0x35, (byte) 0x62, (byte) 0xF1, (byte) 0xFB, (byte) 0x62,
+ (byte) 0x7A, (byte) 0x01, (byte) 0x24, (byte) 0x3B, (byte) 0xCC, (byte) 0xA4, (byte) 0xF1, (byte) 0xBE, (byte) 0xA8, (byte) 0x51, (byte) 0x90, (byte) 0x89, (byte) 0xA8, (byte) 0x83, (byte) 0xDF, (byte) 0xE1, (byte) 0x5A,
+ (byte) 0xE5, (byte) 0x9F, (byte) 0x06, (byte) 0x92, (byte) 0x8B, (byte) 0x66, (byte) 0x5E, (byte) 0x80, (byte) 0x7B, (byte) 0x55, (byte) 0x25, (byte) 0x64, (byte) 0x01, (byte) 0x4C, (byte) 0x3B, (byte) 0xFE, (byte) 0xCF,
+ (byte) 0x49, (byte) 0x2A, (byte) 0x03, (byte) 0x81, (byte) 0x85, (byte) 0x00, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x98, (byte) 0x33, (byte) 0x90, (byte) 0x14, (byte) 0x79, (byte) 0xC7, (byte) 0xC8,
+ (byte) 0x57, (byte) 0xE1, (byte) 0x82, (byte) 0x53, (byte) 0x5B, (byte) 0x6E, (byte) 0x01, (byte) 0x07, (byte) 0x1E, (byte) 0xA5, (byte) 0x98, (byte) 0xC4, (byte) 0x57, (byte) 0x5D, (byte) 0x23, (byte) 0xAB, (byte) 0x72,
+ (byte) 0x9A, (byte) 0xB3, (byte) 0x2F, (byte) 0x39, (byte) 0xCB, (byte) 0xC5, (byte) 0xD0, (byte) 0x97, (byte) 0xD5, (byte) 0x62, (byte) 0x8C, (byte) 0xD9, (byte) 0xE6, (byte) 0xE2, (byte) 0x05, (byte) 0xC6, (byte) 0x05,
+ (byte) 0x71, (byte) 0x16, (byte) 0xE3, (byte) 0xE8, (byte) 0x04, (byte) 0xE8, (byte) 0x46, (byte) 0x12, (byte) 0x0C, (byte) 0xF8, (byte) 0xFC, (byte) 0x8E, (byte) 0x15, (byte) 0x26, (byte) 0x32, (byte) 0xF7, (byte) 0x8C,
+ (byte) 0x04, (byte) 0x3B, (byte) 0x53, (byte) 0x68, (byte) 0x9A, (byte) 0xA3, (byte) 0xB7, (byte) 0x4D, (byte) 0x13, (byte) 0x40, (byte) 0x0F, (byte) 0xBE, (byte) 0x03, (byte) 0x87, (byte) 0xD8, (byte) 0xF1, (byte) 0xFE,
+ (byte) 0x4B, (byte) 0xF5, (byte) 0x44, (byte) 0x19, (byte) 0x29, (byte) 0xBB, (byte) 0x0D, (byte) 0x0C, (byte) 0x52, (byte) 0xC6, (byte) 0x84, (byte) 0x33, (byte) 0x62, (byte) 0x73, (byte) 0x5D, (byte) 0x03, (byte) 0xFF,
+ (byte) 0x6F, (byte) 0x0A, (byte) 0x5A, (byte) 0xF3, (byte) 0x9E, (byte) 0x52, (byte) 0xF2, (byte) 0xC2, (byte) 0xC8, (byte) 0x00, (byte) 0x52, (byte) 0xC7, (byte) 0x75, (byte) 0xA4, (byte) 0xFD, (byte) 0x71, (byte) 0x2D,
+ (byte) 0x7B, (byte) 0x7A, (byte) 0x31, (byte) 0x27, (byte) 0x6E, (byte) 0xAC, (byte) 0xB6, (byte) 0x40, (byte) 0x14, (byte) 0x4E, (byte) 0xB4, (byte) 0xBB, (byte) 0xB1, (byte) 0x51, (byte) 0x63, (byte) 0x29, (byte) 0x81,
+ (byte) 0x06, (byte) 0xF9 };
+ private static final byte[] DH_private = new byte[] {
+ (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0xA8, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x1B, (byte) 0x06, (byte) 0x09, (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86,
+ (byte) 0xF7, (byte) 0x0D, (byte) 0x01, (byte) 0x03, (byte) 0x01, (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x0C, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xFD, (byte) 0x7F, (byte) 0x53, (byte) 0x81,
+ (byte) 0x1D, (byte) 0x75, (byte) 0x12, (byte) 0x29, (byte) 0x52, (byte) 0xDF, (byte) 0x4A, (byte) 0x9C, (byte) 0x2E, (byte) 0xEC, (byte) 0xE4, (byte) 0xE7, (byte) 0xF6, (byte) 0x11, (byte) 0xB7, (byte) 0x52, (byte) 0x3C,
+ (byte) 0xEF, (byte) 0x44, (byte) 0x00, (byte) 0xC3, (byte) 0x1E, (byte) 0x3F, (byte) 0x80, (byte) 0xB6, (byte) 0x51, (byte) 0x26, (byte) 0x69, (byte) 0x45, (byte) 0x5D, (byte) 0x40, (byte) 0x22, (byte) 0x51, (byte) 0xFB,
+ (byte) 0x59, (byte) 0x3D, (byte) 0x8D, (byte) 0x58, (byte) 0xFA, (byte) 0xBF, (byte) 0xC5, (byte) 0xF5, (byte) 0xBA, (byte) 0x30, (byte) 0xF6, (byte) 0xCB, (byte) 0x9B, (byte) 0x55, (byte) 0x6C, (byte) 0xD7, (byte) 0x81,
+ (byte) 0x3B, (byte) 0x80, (byte) 0x1D, (byte) 0x34, (byte) 0x6F, (byte) 0xF2, (byte) 0x66, (byte) 0x60, (byte) 0xB7, (byte) 0x6B, (byte) 0x99, (byte) 0x50, (byte) 0xA5, (byte) 0xA4, (byte) 0x9F, (byte) 0x9F, (byte) 0xE8,
+ (byte) 0x04, (byte) 0x7B, (byte) 0x10, (byte) 0x22, (byte) 0xC2, (byte) 0x4F, (byte) 0xBB, (byte) 0xA9, (byte) 0xD7, (byte) 0xFE, (byte) 0xB7, (byte) 0xC6, (byte) 0x1B, (byte) 0xF8, (byte) 0x3B, (byte) 0x57, (byte) 0xE7,
+ (byte) 0xC6, (byte) 0xA8, (byte) 0xA6, (byte) 0x15, (byte) 0x0F, (byte) 0x04, (byte) 0xFB, (byte) 0x83, (byte) 0xF6, (byte) 0xD3, (byte) 0xC5, (byte) 0x1E, (byte) 0xC3, (byte) 0x02, (byte) 0x35, (byte) 0x54, (byte) 0x13,
+ (byte) 0x5A, (byte) 0x16, (byte) 0x91, (byte) 0x32, (byte) 0xF6, (byte) 0x75, (byte) 0xF3, (byte) 0xAE, (byte) 0x2B, (byte) 0x61, (byte) 0xD7, (byte) 0x2A, (byte) 0xEF, (byte) 0xF2, (byte) 0x22, (byte) 0x03, (byte) 0x19,
+ (byte) 0x9D, (byte) 0xD1, (byte) 0x48, (byte) 0x01, (byte) 0xC7, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xF7, (byte) 0xE1, (byte) 0xA0, (byte) 0x85, (byte) 0xD6, (byte) 0x9B, (byte) 0x3D, (byte) 0xDE,
+ (byte) 0xCB, (byte) 0xBC, (byte) 0xAB, (byte) 0x5C, (byte) 0x36, (byte) 0xB8, (byte) 0x57, (byte) 0xB9, (byte) 0x79, (byte) 0x94, (byte) 0xAF, (byte) 0xBB, (byte) 0xFA, (byte) 0x3A, (byte) 0xEA, (byte) 0x82, (byte) 0xF9,
+ (byte) 0x57, (byte) 0x4C, (byte) 0x0B, (byte) 0x3D, (byte) 0x07, (byte) 0x82, (byte) 0x67, (byte) 0x51, (byte) 0x59, (byte) 0x57, (byte) 0x8E, (byte) 0xBA, (byte) 0xD4, (byte) 0x59, (byte) 0x4F, (byte) 0xE6, (byte) 0x71,
+ (byte) 0x07, (byte) 0x10, (byte) 0x81, (byte) 0x80, (byte) 0xB4, (byte) 0x49, (byte) 0x16, (byte) 0x71, (byte) 0x23, (byte) 0xE8, (byte) 0x4C, (byte) 0x28, (byte) 0x16, (byte) 0x13, (byte) 0xB7, (byte) 0xCF, (byte) 0x09,
+ (byte) 0x32, (byte) 0x8C, (byte) 0xC8, (byte) 0xA6, (byte) 0xE1, (byte) 0x3C, (byte) 0x16, (byte) 0x7A, (byte) 0x8B, (byte) 0x54, (byte) 0x7C, (byte) 0x8D, (byte) 0x28, (byte) 0xE0, (byte) 0xA3, (byte) 0xAE, (byte) 0x1E,
+ (byte) 0x2B, (byte) 0xB3, (byte) 0xA6, (byte) 0x75, (byte) 0x91, (byte) 0x6E, (byte) 0xA3, (byte) 0x7F, (byte) 0x0B, (byte) 0xFA, (byte) 0x21, (byte) 0x35, (byte) 0x62, (byte) 0xF1, (byte) 0xFB, (byte) 0x62, (byte) 0x7A,
+ (byte) 0x01, (byte) 0x24, (byte) 0x3B, (byte) 0xCC, (byte) 0xA4, (byte) 0xF1, (byte) 0xBE, (byte) 0xA8, (byte) 0x51, (byte) 0x90, (byte) 0x89, (byte) 0xA8, (byte) 0x83, (byte) 0xDF, (byte) 0xE1, (byte) 0x5A, (byte) 0xE5,
+ (byte) 0x9F, (byte) 0x06, (byte) 0x92, (byte) 0x8B, (byte) 0x66, (byte) 0x5E, (byte) 0x80, (byte) 0x7B, (byte) 0x55, (byte) 0x25, (byte) 0x64, (byte) 0x01, (byte) 0x4C, (byte) 0x3B, (byte) 0xFE, (byte) 0xCF, (byte) 0x49,
+ (byte) 0x2A, (byte) 0x02, (byte) 0x02, (byte) 0x03, (byte) 0xFE, (byte) 0x04, (byte) 0x81, (byte) 0x83, (byte) 0x02, (byte) 0x81, (byte) 0x80, (byte) 0x35, (byte) 0xFE, (byte) 0x44, (byte) 0x0A, (byte) 0xA3, (byte) 0xA0,
+ (byte) 0xCB, (byte) 0x52, (byte) 0xC2, (byte) 0x32, (byte) 0xCA, (byte) 0x38, (byte) 0x1F, (byte) 0x18, (byte) 0xEB, (byte) 0x27, (byte) 0x6E, (byte) 0x77, (byte) 0x25, (byte) 0x40, (byte) 0x1F, (byte) 0x64, (byte) 0x5D,
+ (byte) 0x4B, (byte) 0x59, (byte) 0x41, (byte) 0xB6, (byte) 0xCB, (byte) 0xDF, (byte) 0x73, (byte) 0xE0, (byte) 0x01, (byte) 0x5A, (byte) 0x79, (byte) 0x0D, (byte) 0x8D, (byte) 0x08, (byte) 0xE6, (byte) 0x7F, (byte) 0x86,
+ (byte) 0x58, (byte) 0xCF, (byte) 0x7F, (byte) 0x4B, (byte) 0x2E, (byte) 0xDB, (byte) 0x4C, (byte) 0xDF, (byte) 0x75, (byte) 0xB5, (byte) 0x16, (byte) 0xC4, (byte) 0xA9, (byte) 0x49, (byte) 0xEE, (byte) 0x00, (byte) 0x56,
+ (byte) 0xA0, (byte) 0x60, (byte) 0x08, (byte) 0x8E, (byte) 0x0D, (byte) 0xC7, (byte) 0xC9, (byte) 0x45, (byte) 0x0C, (byte) 0x5D, (byte) 0xB7, (byte) 0x4C, (byte) 0xC4, (byte) 0x7E, (byte) 0xAB, (byte) 0x1F, (byte) 0xEA,
+ (byte) 0xCF, (byte) 0x08, (byte) 0x6D, (byte) 0x05, (byte) 0xA1, (byte) 0x7F, (byte) 0x63, (byte) 0x6F, (byte) 0xB3, (byte) 0x91, (byte) 0xA3, (byte) 0xE1, (byte) 0xB0, (byte) 0x36, (byte) 0x02, (byte) 0x3F, (byte) 0x55,
+ (byte) 0x71, (byte) 0x38, (byte) 0x37, (byte) 0x9A, (byte) 0x19, (byte) 0xA3, (byte) 0xAF, (byte) 0xC8, (byte) 0xD5, (byte) 0x22, (byte) 0xDD, (byte) 0x00, (byte) 0x81, (byte) 0x19, (byte) 0xB6, (byte) 0x3C, (byte) 0x5F,
+ (byte) 0xD9, (byte) 0xDF, (byte) 0xFD, (byte) 0x58, (byte) 0xB1, (byte) 0xE6, (byte) 0xD1, (byte) 0xD2, (byte) 0x58, (byte) 0xEF, (byte) 0x44, (byte) 0x6E, (byte) 0x66, (byte) 0x92, (byte) 0x1E, (byte) 0x30, (byte) 0x0B,
+ (byte) 0x90, (byte) 0x8E, (byte) 0x29 };
+ private static final byte[] DH_public = new byte[] {
+ (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0xA7, (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x1B, (byte) 0x06, (byte) 0x09, (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01,
+ (byte) 0x03, (byte) 0x01, (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x0C, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xFD, (byte) 0x7F, (byte) 0x53, (byte) 0x81, (byte) 0x1D, (byte) 0x75, (byte) 0x12,
+ (byte) 0x29, (byte) 0x52, (byte) 0xDF, (byte) 0x4A, (byte) 0x9C, (byte) 0x2E, (byte) 0xEC, (byte) 0xE4, (byte) 0xE7, (byte) 0xF6, (byte) 0x11, (byte) 0xB7, (byte) 0x52, (byte) 0x3C, (byte) 0xEF, (byte) 0x44, (byte) 0x00,
+ (byte) 0xC3, (byte) 0x1E, (byte) 0x3F, (byte) 0x80, (byte) 0xB6, (byte) 0x51, (byte) 0x26, (byte) 0x69, (byte) 0x45, (byte) 0x5D, (byte) 0x40, (byte) 0x22, (byte) 0x51, (byte) 0xFB, (byte) 0x59, (byte) 0x3D, (byte) 0x8D,
+ (byte) 0x58, (byte) 0xFA, (byte) 0xBF, (byte) 0xC5, (byte) 0xF5, (byte) 0xBA, (byte) 0x30, (byte) 0xF6, (byte) 0xCB, (byte) 0x9B, (byte) 0x55, (byte) 0x6C, (byte) 0xD7, (byte) 0x81, (byte) 0x3B, (byte) 0x80, (byte) 0x1D,
+ (byte) 0x34, (byte) 0x6F, (byte) 0xF2, (byte) 0x66, (byte) 0x60, (byte) 0xB7, (byte) 0x6B, (byte) 0x99, (byte) 0x50, (byte) 0xA5, (byte) 0xA4, (byte) 0x9F, (byte) 0x9F, (byte) 0xE8, (byte) 0x04, (byte) 0x7B, (byte) 0x10,
+ (byte) 0x22, (byte) 0xC2, (byte) 0x4F, (byte) 0xBB, (byte) 0xA9, (byte) 0xD7, (byte) 0xFE, (byte) 0xB7, (byte) 0xC6, (byte) 0x1B, (byte) 0xF8, (byte) 0x3B, (byte) 0x57, (byte) 0xE7, (byte) 0xC6, (byte) 0xA8, (byte) 0xA6,
+ (byte) 0x15, (byte) 0x0F, (byte) 0x04, (byte) 0xFB, (byte) 0x83, (byte) 0xF6, (byte) 0xD3, (byte) 0xC5, (byte) 0x1E, (byte) 0xC3, (byte) 0x02, (byte) 0x35, (byte) 0x54, (byte) 0x13, (byte) 0x5A, (byte) 0x16, (byte) 0x91,
+ (byte) 0x32, (byte) 0xF6, (byte) 0x75, (byte) 0xF3, (byte) 0xAE, (byte) 0x2B, (byte) 0x61, (byte) 0xD7, (byte) 0x2A, (byte) 0xEF, (byte) 0xF2, (byte) 0x22, (byte) 0x03, (byte) 0x19, (byte) 0x9D, (byte) 0xD1, (byte) 0x48,
+ (byte) 0x01, (byte) 0xC7, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xF7, (byte) 0xE1, (byte) 0xA0, (byte) 0x85, (byte) 0xD6, (byte) 0x9B, (byte) 0x3D, (byte) 0xDE, (byte) 0xCB, (byte) 0xBC, (byte) 0xAB,
+ (byte) 0x5C, (byte) 0x36, (byte) 0xB8, (byte) 0x57, (byte) 0xB9, (byte) 0x79, (byte) 0x94, (byte) 0xAF, (byte) 0xBB, (byte) 0xFA, (byte) 0x3A, (byte) 0xEA, (byte) 0x82, (byte) 0xF9, (byte) 0x57, (byte) 0x4C, (byte) 0x0B,
+ (byte) 0x3D, (byte) 0x07, (byte) 0x82, (byte) 0x67, (byte) 0x51, (byte) 0x59, (byte) 0x57, (byte) 0x8E, (byte) 0xBA, (byte) 0xD4, (byte) 0x59, (byte) 0x4F, (byte) 0xE6, (byte) 0x71, (byte) 0x07, (byte) 0x10, (byte) 0x81,
+ (byte) 0x80, (byte) 0xB4, (byte) 0x49, (byte) 0x16, (byte) 0x71, (byte) 0x23, (byte) 0xE8, (byte) 0x4C, (byte) 0x28, (byte) 0x16, (byte) 0x13, (byte) 0xB7, (byte) 0xCF, (byte) 0x09, (byte) 0x32, (byte) 0x8C, (byte) 0xC8,
+ (byte) 0xA6, (byte) 0xE1, (byte) 0x3C, (byte) 0x16, (byte) 0x7A, (byte) 0x8B, (byte) 0x54, (byte) 0x7C, (byte) 0x8D, (byte) 0x28, (byte) 0xE0, (byte) 0xA3, (byte) 0xAE, (byte) 0x1E, (byte) 0x2B, (byte) 0xB3, (byte) 0xA6,
+ (byte) 0x75, (byte) 0x91, (byte) 0x6E, (byte) 0xA3, (byte) 0x7F, (byte) 0x0B, (byte) 0xFA, (byte) 0x21, (byte) 0x35, (byte) 0x62, (byte) 0xF1, (byte) 0xFB, (byte) 0x62, (byte) 0x7A, (byte) 0x01, (byte) 0x24, (byte) 0x3B,
+ (byte) 0xCC, (byte) 0xA4, (byte) 0xF1, (byte) 0xBE, (byte) 0xA8, (byte) 0x51, (byte) 0x90, (byte) 0x89, (byte) 0xA8, (byte) 0x83, (byte) 0xDF, (byte) 0xE1, (byte) 0x5A, (byte) 0xE5, (byte) 0x9F, (byte) 0x06, (byte) 0x92,
+ (byte) 0x8B, (byte) 0x66, (byte) 0x5E, (byte) 0x80, (byte) 0x7B, (byte) 0x55, (byte) 0x25, (byte) 0x64, (byte) 0x01, (byte) 0x4C, (byte) 0x3B, (byte) 0xFE, (byte) 0xCF, (byte) 0x49, (byte) 0x2A, (byte) 0x02, (byte) 0x02,
+ (byte) 0x03, (byte) 0xFE, (byte) 0x03, (byte) 0x81, (byte) 0x85, (byte) 0x00, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xD4, (byte) 0xC2, (byte) 0xC2, (byte) 0x84, (byte) 0xEB, (byte) 0xEC, (byte) 0xB6,
+ (byte) 0xF1, (byte) 0x29, (byte) 0x2B, (byte) 0xAB, (byte) 0x8F, (byte) 0xC1, (byte) 0x48, (byte) 0x4C, (byte) 0x47, (byte) 0xCE, (byte) 0x0B, (byte) 0x97, (byte) 0x4C, (byte) 0xFC, (byte) 0x27, (byte) 0x10, (byte) 0x0A,
+ (byte) 0x5F, (byte) 0x3E, (byte) 0xE6, (byte) 0xF9, (byte) 0x9B, (byte) 0x15, (byte) 0xDF, (byte) 0x83, (byte) 0x01, (byte) 0xFA, (byte) 0x69, (byte) 0x57, (byte) 0xEC, (byte) 0x6B, (byte) 0x68, (byte) 0xC7, (byte) 0x96,
+ (byte) 0x33, (byte) 0x98, (byte) 0xA4, (byte) 0xB0, (byte) 0xA3, (byte) 0x18, (byte) 0x01, (byte) 0x66, (byte) 0x7A, (byte) 0x4A, (byte) 0xF3, (byte) 0x3C, (byte) 0xD9, (byte) 0x2A, (byte) 0x48, (byte) 0xFD, (byte) 0x3A,
+ (byte) 0x31, (byte) 0xFC, (byte) 0x97, (byte) 0x52, (byte) 0x36, (byte) 0x20, (byte) 0x0E, (byte) 0x69, (byte) 0xB6, (byte) 0x32, (byte) 0x8B, (byte) 0x4E, (byte) 0xDA, (byte) 0x8B, (byte) 0x04, (byte) 0x88, (byte) 0xF8,
+ (byte) 0x30, (byte) 0xA9, (byte) 0x65, (byte) 0x68, (byte) 0x47, (byte) 0xBB, (byte) 0xA1, (byte) 0xF6, (byte) 0xD6, (byte) 0x18, (byte) 0x11, (byte) 0x48, (byte) 0x8D, (byte) 0x8F, (byte) 0x4B, (byte) 0xC1, (byte) 0xE1,
+ (byte) 0xA4, (byte) 0x43, (byte) 0x83, (byte) 0x1F, (byte) 0x6B, (byte) 0x6D, (byte) 0xEE, (byte) 0xA7, (byte) 0xA3, (byte) 0x5F, (byte) 0xD2, (byte) 0x95, (byte) 0x09, (byte) 0xD4, (byte) 0xEA, (byte) 0x85, (byte) 0x0C,
+ (byte) 0xA5, (byte) 0xC9, (byte) 0x93, (byte) 0xCE, (byte) 0xC1, (byte) 0x1D, (byte) 0x30, (byte) 0x73, (byte) 0xA3, (byte) 0xE1, (byte) 0x69, (byte) 0xA8, (byte) 0x11, (byte) 0x98, (byte) 0x78, (byte) 0xF3, (byte) 0xF9,
+ (byte) 0x8F, (byte) 0x04 };
+
+ private static final byte[] EC_private = TestUtils.decodeBase64(
+ "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgXbi5zGvh/MoXidykzJKs1yEbrN99"
+ + "/A3bQy1bMNQR/c2hRANCAAQqgfCMR3JAG/JhR386L6bTmo7XTd1B0oHCPaqPP5+YLzL5wY"
+ + "AbDExaCdzXEljDvrupjn1HfqjZNCVAc0j13QIM");
+ private static final byte[] EC_public = TestUtils.decodeBase64(
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKoHwjEdyQBvyYUd/Oi+m05qO103dQdKBwj2qjz+f"
+ + "mC8y+cGAGwxMWgnc1xJYw767qY59R36o2TQlQHNI9d0CDA==");
+
+ private static final byte[] X25519_private = new byte[] {
+ (byte) 0x30,
+ (byte) 0x2e,
+ (byte) 0x02,
+ (byte) 0x01,
+ (byte) 0x00,
+ (byte) 0x30,
+ (byte) 0x05,
+ (byte) 0x06,
+ (byte) 0x03,
+ (byte) 0x2b,
+ (byte) 0x65,
+ (byte) 0x6e,
+ (byte) 0x04,
+ (byte) 0x22,
+ (byte) 0x04,
+ (byte) 0x20,
+ (byte) 0xa5,
+ (byte) 0x46,
+ (byte) 0xe3,
+ (byte) 0x6b,
+ (byte) 0xf0,
+ (byte) 0x52,
+ (byte) 0x7c,
+ (byte) 0x9d,
+ (byte) 0x3b,
+ (byte) 0x16,
+ (byte) 0x15,
+ (byte) 0x4b,
+ (byte) 0x82,
+ (byte) 0x46,
+ (byte) 0x5e,
+ (byte) 0xdd,
+ (byte) 0x62,
+ (byte) 0x14,
+ (byte) 0x4c,
+ (byte) 0x0a,
+ (byte) 0xc1,
+ (byte) 0xfc,
+ (byte) 0x5a,
+ (byte) 0x18,
+ (byte) 0x50,
+ (byte) 0x6a,
+ (byte) 0x22,
+ (byte) 0x44,
+ (byte) 0xba,
+ (byte) 0x44,
+ (byte) 0x9a,
+ (byte) 0xc4,
+ };
+
+ private static final byte[] X25519_public = new byte[] {
+ (byte) 0x30,
+ (byte) 0x2a,
+ (byte) 0x30,
+ (byte) 0x05,
+ (byte) 0x06,
+ (byte) 0x03,
+ (byte) 0x2b,
+ (byte) 0x65,
+ (byte) 0x6e,
+ (byte) 0x03,
+ (byte) 0x21,
+ (byte) 0x00,
+ (byte) 0xe6,
+ (byte) 0xdb,
+ (byte) 0x68,
+ (byte) 0x67,
+ (byte) 0x58,
+ (byte) 0x30,
+ (byte) 0x30,
+ (byte) 0xdb,
+ (byte) 0x35,
+ (byte) 0x94,
+ (byte) 0xc1,
+ (byte) 0xa4,
+ (byte) 0x24,
+ (byte) 0xb1,
+ (byte) 0x5f,
+ (byte) 0x7c,
+ (byte) 0x72,
+ (byte) 0x66,
+ (byte) 0x24,
+ (byte) 0xec,
+ (byte) 0x26,
+ (byte) 0xb3,
+ (byte) 0x35,
+ (byte) 0x3b,
+ (byte) 0x10,
+ (byte) 0xa9,
+ (byte) 0x03,
+ (byte) 0xa6,
+ (byte) 0xd0,
+ (byte) 0xab,
+ (byte) 0x1c,
+ (byte) 0x4c,
+ };
+
+ private static final HashMap<String, KeySpec> keys = new HashMap<String, KeySpec>();
+ static {
+ keys.put("DH_public", new X509EncodedKeySpec(DH_public));
+ keys.put("DH_private", new PKCS8EncodedKeySpec(DH_private));
+ keys.put("DSA_public", new X509EncodedKeySpec(DSA_public));
+ keys.put("DSA_private", new PKCS8EncodedKeySpec(DSA_private));
+ keys.put("RSA_public", new X509EncodedKeySpec(RSA_public));
+ keys.put("RSA_private", new PKCS8EncodedKeySpec(RSA_private));
+ keys.put("EC_public", new X509EncodedKeySpec(EC_public));
+ keys.put("EC_private", new PKCS8EncodedKeySpec(EC_private));
+ keys.put("XDH_public", new X509EncodedKeySpec(X25519_public));
+ keys.put("XDH_private", new PKCS8EncodedKeySpec(X25519_private));
+ }
+
+ public static PrivateKey getPrivateKey(String algorithmName) throws NoSuchAlgorithmException, InvalidKeySpecException
+ {
+ KeyFactory factory = KeyFactory.getInstance(algorithmName);
+ return factory.generatePrivate(keys.get(algorithmName + "_private"));
+ }
+
+ public static PublicKey getPublicKey(String algorithmName) throws NoSuchAlgorithmException, InvalidKeySpecException
+ {
+ KeyFactory factory = KeyFactory.getInstance(algorithmName);
+ return factory.generatePublic(keys.get(algorithmName + "_public"));
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/KeyAgreementHelper.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/KeyAgreementHelper.java
new file mode 100644
index 0000000..7580aea
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/KeyAgreementHelper.java
@@ -0,0 +1,48 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import javax.crypto.KeyAgreement;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class KeyAgreementHelper extends TestHelper<KeyPair> {
+
+ private final String algorithmName;
+
+ public KeyAgreementHelper(String algorithmName) {
+ this.algorithmName = algorithmName;
+ }
+
+ @Override public void test(KeyPair keyPair) throws Exception {
+ test(keyPair.getPrivate(), keyPair.getPublic());
+ }
+
+ void test(PrivateKey encryptKey, PublicKey decryptKey) throws Exception {
+ KeyAgreement keyAgreement = KeyAgreement.getInstance(algorithmName);
+ keyAgreement.init(encryptKey);
+ keyAgreement.doPhase(decryptKey, true);
+ assertNotNull("generated secret is null", keyAgreement.generateSecret());
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/SignatureHelper.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/SignatureHelper.java
new file mode 100644
index 0000000..9717a58
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/SignatureHelper.java
@@ -0,0 +1,54 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertTrue;
+
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SignatureHelper extends TestHelper<KeyPair> {
+
+ private final String algorithmName;
+ private final String plainData = "some data do sign and verify";
+
+ public SignatureHelper(String algorithmName) {
+ this.algorithmName = algorithmName;
+ }
+
+ @Override
+ public void test(KeyPair keyPair) throws Exception {
+ test(keyPair.getPrivate(), keyPair.getPublic());
+ }
+
+ public void test(PrivateKey encryptKey, PublicKey decryptKey) throws Exception {
+ Signature signature = Signature.getInstance(algorithmName);
+ signature.initSign(encryptKey);
+ signature.update(plainData.getBytes("UTF-8"));
+ byte[] signed = signature.sign();
+
+ signature.initVerify(decryptKey);
+ signature.update(plainData.getBytes("UTF-8"));
+ assertTrue("signature could not be verified", signature.verify(signed));
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/StandardNames.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/StandardNames.java
new file mode 100644
index 0000000..e0cb275
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/StandardNames.java
@@ -0,0 +1,491 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * This class defines expected string names for protocols, key types,
+ * client and server auth types, cipher suites.
+ *
+ * Initially based on "Appendix A: Standard Names" of
+ * <a href="http://java.sun.com/j2se/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#AppA">
+ * Java ™ Secure Socket Extension (JSSE) Reference Guide
+ * for the Java ™ 2 Platform Standard Edition 5
+ * </a>.
+ *
+ * Updated based on the
+ * <a href="http://download.java.net/jdk8/docs/technotes/guides/security/SunProviders.html">
+ * Java ™ Cryptography Architecture Oracle Providers Documentation
+ * for Java ™ Platform Standard Edition 7
+ * </a>.
+ * See also the
+ * <a href="http://download.java.net/jdk8/docs/technotes/guides/security/StandardNames.html">
+ * Java ™ Cryptography Architecture Standard Algorithm Name Documentation
+ * </a>.
+ *
+ * Further updates based on the
+ * <a href=http://java.sun.com/javase/6/docs/technotes/guides/security/p11guide.html">
+ * Java ™ PKCS#11 Reference Guide
+ * </a>.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class StandardNames {
+ public static final boolean IS_RI =
+ !"Dalvik Core Library".equals(System.getProperty("java.specification.name"));
+ public static final String JSSE_PROVIDER_NAME = IS_RI ? "Conscrypt" : "AndroidOpenSSL";
+
+ public static final String KEY_MANAGER_FACTORY_DEFAULT = IS_RI ? "SunX509" : "PKIX";
+ public static final String TRUST_MANAGER_FACTORY_DEFAULT = "PKIX";
+
+ public static final String KEY_STORE_ALGORITHM = IS_RI ? "JKS" : "BKS";
+
+ public static final boolean IS_15_OR_UP = majorVersionFromJavaSpecificationVersion() >= 15;
+
+ private static int majorVersionFromJavaSpecificationVersion() {
+ return majorVersion(System.getProperty("java.specification.version", "1.6"));
+ }
+
+ private static int majorVersion(final String javaSpecVersion) {
+ final String[] components = javaSpecVersion.split("\\.", -1);
+ final int[] version = new int[components.length];
+ for (int i = 0; i < components.length; i++) {
+ version[i] = Integer.parseInt(components[i]);
+ }
+
+ if (version[0] == 1) {
+ assertTrue(version[1] >= 6);
+ return version[1];
+ } else {
+ return version[0];
+ }
+ }
+
+ /**
+ * RFC 5746's Signaling Cipher Suite Value to indicate a request for secure renegotiation
+ */
+ public static final String CIPHER_SUITE_SECURE_RENEGOTIATION =
+ "TLS_EMPTY_RENEGOTIATION_INFO_SCSV";
+
+ /**
+ * From https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00 it is a
+ * signaling cipher suite value (SCSV) to indicate that this request is a
+ * protocol fallback (e.g., TLS 1.0 -> SSL 3.0) because the server didn't respond
+ * to the first request.
+ */
+ public static final String CIPHER_SUITE_FALLBACK = "TLS_FALLBACK_SCSV";
+
+ private static final HashMap<String, HashSet<String>> CIPHER_MODES =
+ new HashMap<String, HashSet<String>>();
+
+ private static final HashMap<String, HashSet<String>> CIPHER_PADDINGS =
+ new HashMap<String, HashSet<String>>();
+
+ private static final HashMap<String, String[]> SSL_CONTEXT_PROTOCOLS_ENABLED =
+ new HashMap<String, String[]>();
+
+ private static void provideCipherModes(String algorithm, String newModes[]) {
+ HashSet<String> modes = CIPHER_MODES.get(algorithm);
+ if (modes == null) {
+ modes = new HashSet<String>();
+ CIPHER_MODES.put(algorithm, modes);
+ }
+ modes.addAll(Arrays.asList(newModes));
+ }
+ private static void provideCipherPaddings(String algorithm, String newPaddings[]) {
+ HashSet<String> paddings = CIPHER_PADDINGS.get(algorithm);
+ if (paddings == null) {
+ paddings = new HashSet<String>();
+ CIPHER_PADDINGS.put(algorithm, paddings);
+ }
+ paddings.addAll(Arrays.asList(newPaddings));
+ }
+ private static void provideSslContextEnabledProtocols(
+ String algorithm, TLSVersion minimum, TLSVersion maximum) {
+ if (minimum.ordinal() > maximum.ordinal()) {
+ throw new RuntimeException("TLS version: minimum > maximum");
+ }
+ int versionsLength = maximum.ordinal() - minimum.ordinal() + 1;
+ String[] versionNames = new String[versionsLength];
+ for (int i = 0; i < versionsLength; i++) {
+ versionNames[i] = TLSVersion.values()[i + minimum.ordinal()].name;
+ }
+ SSL_CONTEXT_PROTOCOLS_ENABLED.put(algorithm, versionNames);
+ }
+ static {
+ // TODO: provideCipherModes and provideCipherPaddings for other Ciphers
+ provideCipherModes("AES", new String[] {"CBC", "CFB", "CTR", "CTS", "ECB", "OFB"});
+ provideCipherPaddings("AES", new String[] {"NoPadding", "PKCS5Padding"});
+ // TODO: None?
+ provideCipherModes("RSA", new String[] {"ECB"});
+ // TODO: OAEPPadding
+ provideCipherPaddings("RSA", new String[] {"NoPadding", "PKCS1Padding"});
+
+ // Fixups for dalvik
+ if (!IS_RI) {
+ provideCipherPaddings("AES", new String[] {"PKCS7Padding"});
+ }
+
+ provideSslContextEnabledProtocols("TLS", TLSVersion.TLSv1, TLSVersion.TLSv13);
+ provideSslContextEnabledProtocols("TLSv1", TLSVersion.TLSv1, TLSVersion.TLSv12);
+ provideSslContextEnabledProtocols("TLSv1.1", TLSVersion.TLSv1, TLSVersion.TLSv12);
+ provideSslContextEnabledProtocols("TLSv1.2", TLSVersion.TLSv1, TLSVersion.TLSv12);
+ provideSslContextEnabledProtocols("TLSv1.3", TLSVersion.TLSv1, TLSVersion.TLSv13);
+ provideSslContextEnabledProtocols("Default", TLSVersion.TLSv1, TLSVersion.TLSv13);
+ }
+
+ public static final String SSL_CONTEXT_PROTOCOLS_DEFAULT = "Default";
+ public static final Set<String> SSL_CONTEXT_PROTOCOLS = new HashSet<String>(
+ Arrays.asList(SSL_CONTEXT_PROTOCOLS_DEFAULT, "TLS", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"));
+ public static final Set<String> SSL_CONTEXT_PROTOCOLS_WITH_DEFAULT_CONFIG = new HashSet<String>(
+ Arrays.asList(SSL_CONTEXT_PROTOCOLS_DEFAULT, "TLS", "TLSv1.3"));
+ // Deprecated TLS protocols... May or may not be present or enabled.
+ public static final Set<String> SSL_CONTEXT_PROTOCOLS_DEPRECATED =
+ new HashSet<>(Arrays.asList("TLSv1", "TLSv1.1"));
+
+ public static final Set<String> KEY_TYPES = new HashSet<String>(
+ Arrays.asList("RSA", "DSA", "DH_RSA", "DH_DSA", "EC", "EC_EC", "EC_RSA"));
+ static {
+ if (IS_RI) {
+ // DH_* are specified by standard names, but do not seem to be supported by RI
+ KEY_TYPES.remove("DH_RSA");
+ KEY_TYPES.remove("DH_DSA");
+ }
+ }
+
+ public static final Set<String> SSL_SOCKET_PROTOCOLS =
+ new HashSet<String>(Arrays.asList("TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"));
+
+ private enum TLSVersion {
+ SSLv3("SSLv3"),
+ TLSv1("TLSv1"),
+ TLSv11("TLSv1.1"),
+ TLSv12("TLSv1.2"),
+ TLSv13("TLSv1.3"),
+ ;
+
+ private final String name;
+
+ TLSVersion(String name) {
+ this.name = name;
+ }
+ }
+
+ /**
+ * Valid values for X509TrustManager.checkClientTrusted authType,
+ * either the algorithm of the public key or UNKNOWN.
+ */
+ public static final Set<String> CLIENT_AUTH_TYPES =
+ new HashSet<String>(Arrays.asList("RSA", "DSA", "EC", "UNKNOWN"));
+
+ /**
+ * Valid values for X509TrustManager.checkServerTrusted authType,
+ * either key exchange algorithm part of the cipher suite, UNKNOWN,
+ * or GENERIC (for TLS 1.3 cipher suites that don't imply a specific
+ * key exchange method).
+ */
+ public static final Set<String> SERVER_AUTH_TYPES = new HashSet<String>(Arrays.asList("DHE_DSS",
+ "DHE_DSS_EXPORT", "DHE_RSA", "DHE_RSA_EXPORT", "DH_DSS_EXPORT", "DH_RSA_EXPORT",
+ "DH_anon", "DH_anon_EXPORT", "KRB5", "KRB5_EXPORT", "RSA", "RSA_EXPORT",
+ "RSA_EXPORT1024", "ECDH_ECDSA", "ECDH_RSA", "ECDHE_ECDSA", "ECDHE_RSA", "UNKNOWN",
+ "GENERIC"));
+
+ public static final String CIPHER_SUITE_INVALID = "SSL_NULL_WITH_NULL_NULL";
+
+ private static final Set<String> CIPHER_SUITES = new LinkedHashSet<String>();
+
+ private static void addOpenSsl(String cipherSuite) {
+ CIPHER_SUITES.add(cipherSuite);
+ }
+
+ static {
+ addOpenSsl("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA");
+ addOpenSsl("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA");
+ addOpenSsl("TLS_RSA_WITH_AES_256_CBC_SHA");
+ addOpenSsl("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA");
+ addOpenSsl("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");
+ addOpenSsl("TLS_RSA_WITH_AES_128_CBC_SHA");
+ addOpenSsl("SSL_RSA_WITH_3DES_EDE_CBC_SHA");
+
+ // TLSv1.2 cipher suites
+ addOpenSsl("TLS_RSA_WITH_AES_128_GCM_SHA256");
+ addOpenSsl("TLS_RSA_WITH_AES_256_GCM_SHA384");
+ addOpenSsl("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256");
+ addOpenSsl("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384");
+ addOpenSsl("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256");
+ addOpenSsl("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384");
+ addOpenSsl("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256");
+ addOpenSsl("TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256");
+
+ // Pre-Shared Key (PSK) cipher suites
+ addOpenSsl("TLS_PSK_WITH_AES_128_CBC_SHA");
+ addOpenSsl("TLS_PSK_WITH_AES_256_CBC_SHA");
+ addOpenSsl("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA");
+ addOpenSsl("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA");
+ addOpenSsl("TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256");
+
+ // TLS 1.3 cipher suites
+ addOpenSsl("TLS_AES_128_GCM_SHA256");
+ addOpenSsl("TLS_AES_256_GCM_SHA384");
+ addOpenSsl("TLS_CHACHA20_POLY1305_SHA256");
+
+ // RFC 5746's Signaling Cipher Suite Value to indicate a request for secure renegotiation
+ addOpenSsl(CIPHER_SUITE_SECURE_RENEGOTIATION);
+
+ // From https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00 to indicate
+ // TLS fallback request
+ addOpenSsl(CIPHER_SUITE_FALLBACK);
+ }
+
+ /**
+ * Cipher suites that are not negotiated when TLSv1.2 is selected on the RI.
+ */
+ public static final List<String> CIPHER_SUITES_OBSOLETE_TLS12 = Arrays.asList(
+ "SSL_RSA_WITH_DES_CBC_SHA",
+ "SSL_DHE_RSA_WITH_DES_CBC_SHA",
+ "SSL_DHE_DSS_WITH_DES_CBC_SHA",
+ "SSL_DH_anon_WITH_DES_CBC_SHA",
+ "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
+ "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
+ "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
+ "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
+ "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
+ "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA");
+
+ /**
+ * Cipher suites that are only supported with TLS 1.3.
+ */
+ public static final List<String> CIPHER_SUITES_TLS13 = Arrays.asList(
+ "TLS_AES_128_GCM_SHA256",
+ "TLS_AES_256_GCM_SHA384",
+ "TLS_CHACHA20_POLY1305_SHA256");
+
+ // NOTE: This list needs to be kept in sync with Javadoc of javax.net.ssl.SSLSocket and
+ // javax.net.ssl.SSLEngine.
+ private static final List<String> CIPHER_SUITES_AES_HARDWARE = Arrays.asList(
+ "TLS_AES_128_GCM_SHA256",
+ "TLS_AES_256_GCM_SHA384",
+ "TLS_CHACHA20_POLY1305_SHA256",
+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
+ "TLS_RSA_WITH_AES_128_GCM_SHA256",
+ "TLS_RSA_WITH_AES_256_GCM_SHA384",
+ "TLS_RSA_WITH_AES_128_CBC_SHA",
+ "TLS_RSA_WITH_AES_256_CBC_SHA",
+ CIPHER_SUITE_SECURE_RENEGOTIATION);
+
+ // NOTE: This list needs to be kept in sync with Javadoc of javax.net.ssl.SSLSocket and
+ // javax.net.ssl.SSLEngine.
+ private static final List<String> CIPHER_SUITES_SOFTWARE = Arrays.asList(
+ "TLS_AES_128_GCM_SHA256",
+ "TLS_AES_256_GCM_SHA384",
+ "TLS_CHACHA20_POLY1305_SHA256",
+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
+ "TLS_RSA_WITH_AES_128_GCM_SHA256",
+ "TLS_RSA_WITH_AES_256_GCM_SHA384",
+ "TLS_RSA_WITH_AES_128_CBC_SHA",
+ "TLS_RSA_WITH_AES_256_CBC_SHA",
+ CIPHER_SUITE_SECURE_RENEGOTIATION);
+
+ // NOTE: This list needs to be kept in sync with Javadoc of javax.net.ssl.SSLSocket and
+ // javax.net.ssl.SSLEngine.
+ public static final List<String> CIPHER_SUITES_DEFAULT = CpuFeatures.isAESHardwareAccelerated()
+ ? CIPHER_SUITES_AES_HARDWARE
+ : CIPHER_SUITES_SOFTWARE;
+
+ // NOTE: This list needs to be kept in sync with Javadoc of javax.net.ssl.SSLSocket and
+ // javax.net.ssl.SSLEngine.
+ public static final List<String> CIPHER_SUITES_DEFAULT_PSK = Arrays.asList(
+ "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256",
+ "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA",
+ "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA",
+ "TLS_PSK_WITH_AES_128_CBC_SHA",
+ "TLS_PSK_WITH_AES_256_CBC_SHA");
+
+ // Should be updated to match BoringSSL's defaults when they change.
+ // https://boringssl.googlesource.com/boringssl/+/master/ssl/t1_lib.cc#289
+ private static final List<String> ELLIPTIC_CURVES_DEFAULT =
+ Arrays.asList("x25519 (29)", "secp256r1 (23)", "secp384r1 (24)");
+
+ /**
+ * Asserts that the cipher suites array is non-null and that it
+ * all of its contents are cipher suites known to this
+ * implementation. As a convenience, returns any unenabled cipher
+ * suites in a test for those that want to verify separately that
+ * all cipher suites were included.
+ */
+ private static Set<String> assertValidCipherSuites(
+ Set<String> expected, String[] cipherSuites) {
+ assertNotNull(cipherSuites);
+ assertTrue(cipherSuites.length != 0);
+
+ // Make sure all cipherSuites names are expected
+ HashSet<String> remainingCipherSuites = new HashSet<String>(expected);
+ HashSet<String> unknownCipherSuites = new HashSet<String>();
+ for (String cipherSuite : cipherSuites) {
+ boolean removed = remainingCipherSuites.remove(cipherSuite);
+ if (!removed) {
+ unknownCipherSuites.add(cipherSuite);
+ }
+ }
+ assertEquals("Unknown cipher suites", Collections.EMPTY_SET, unknownCipherSuites);
+ return remainingCipherSuites;
+ }
+
+ /**
+ * After using assertValidCipherSuites on cipherSuites,
+ * assertSupportedCipherSuites additionally verifies that all
+ * supported cipher suites where in the input array.
+ */
+ private static void assertSupportedCipherSuites(Set<String> expected, String[] cipherSuites) {
+ Set<String> remainingCipherSuites = assertValidCipherSuites(expected, cipherSuites);
+ assertEquals("Missing cipher suites", Collections.EMPTY_SET, remainingCipherSuites);
+ assertEquals(expected.size(), cipherSuites.length);
+ }
+
+ /**
+ * Asserts that the protocols array is non-null and that it all of
+ * its contents are protocols known to this implementation. As a
+ * convenience, returns any unenabled protocols in a test for
+ * those that want to verify separately that all protocols were
+ * included.
+ */
+ private static Set<String> assertValidProtocols(Set<String> expected, String[] protocols) {
+ assertNotNull(protocols);
+ assertTrue(protocols.length != 0);
+
+ // Make sure all protocols names are expected
+ HashSet<String> remainingProtocols = new HashSet<String>(expected);
+ HashSet<String> unknownProtocols = new HashSet<String>();
+ for (String protocol : protocols) {
+ if (!remainingProtocols.remove(protocol)) {
+ unknownProtocols.add(protocol);
+ }
+ }
+ assertEquals("Unknown protocols", Collections.EMPTY_SET, unknownProtocols);
+ return remainingProtocols;
+ }
+
+ /**
+ * After using assertValidProtocols on protocols,
+ * assertSupportedProtocols additionally verifies that all
+ * supported protocols where in the input array.
+ */
+ private static void assertSupportedProtocols(Set<String> valid, String[] protocols) {
+ Set<String> remainingProtocols = assertValidProtocols(valid, protocols);
+
+ // TODO(prb) Temporarily ignore TLSv1.x: See comment for assertSSLContextEnabledProtocols()
+ remainingProtocols.removeAll(SSL_CONTEXT_PROTOCOLS_DEPRECATED);
+
+ assertEquals("Missing protocols", Collections.EMPTY_SET, remainingProtocols);
+ }
+
+ /**
+ * Asserts that the provided list of protocols matches the supported list of protocols.
+ */
+ public static void assertSupportedProtocols(String[] protocols) {
+ assertSupportedProtocols(SSL_SOCKET_PROTOCOLS, protocols);
+ }
+
+ /**
+ * Assert that the provided list of cipher suites contains only the supported cipher suites.
+ */
+ public static void assertValidCipherSuites(String[] cipherSuites) {
+ assertValidCipherSuites(CIPHER_SUITES, cipherSuites);
+ }
+
+ /**
+ * Assert that the provided list of cipher suites matches the supported list.
+ */
+ public static void assertSupportedCipherSuites(String[] cipherSuites) {
+ assertSupportedCipherSuites(CIPHER_SUITES, cipherSuites);
+ }
+
+ /**
+ * Assert cipher suites match the default list in content and priority order and contain
+ * only cipher suites permitted by default.
+ */
+ public static void assertDefaultCipherSuites(String[] cipherSuites) {
+ assertValidCipherSuites(cipherSuites);
+
+ Set<String> expected = new TreeSet<String>(CIPHER_SUITES_DEFAULT);
+ Set<String> actual = new TreeSet<String>(Arrays.asList(cipherSuites));
+ assertEquals(expected, actual);
+ }
+
+ public static void assertDefaultEllipticCurves(String[] curves) {
+ assertEquals(ELLIPTIC_CURVES_DEFAULT, Arrays.asList(curves));
+ }
+
+ public static void assertSSLContextEnabledProtocols(String version, String[] protocols) {
+ Set<String> expected =
+ new HashSet<>(Arrays.asList(SSL_CONTEXT_PROTOCOLS_ENABLED.get(version)));
+ Set<String> actual = new HashSet<>(Arrays.asList(protocols));
+
+ // TODO(prb): Temporary measure - just ignore deprecated protocols. Allows
+ // testing on source trees where these have been disabled in unknown ways.
+ // Future work will provide a supported API for disabling protocols, but for
+ // now we need to work with what's in the field.
+ expected.removeAll(SSL_CONTEXT_PROTOCOLS_DEPRECATED);
+ actual.removeAll(SSL_CONTEXT_PROTOCOLS_DEPRECATED);
+
+ assertEquals("For protocol \"" + version + "\"", expected, actual);
+ }
+
+ /**
+ * Get all supported mode names for the given cipher.
+ */
+ public static Set<String> getModesForCipher(String cipher) {
+ return CIPHER_MODES.get(cipher);
+ }
+
+ /**
+ * Get all supported padding names for the given cipher.
+ */
+ public static Set<String> getPaddingsForCipher(String cipher) {
+ return CIPHER_PADDINGS.get(cipher);
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/TestHelper.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/TestHelper.java
new file mode 100644
index 0000000..92f3120
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/TestHelper.java
@@ -0,0 +1,25 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt.java.security;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class TestHelper<T> {
+ public abstract void test(T testObject) throws Exception;
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/TestKeyStore.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/TestKeyStore.java
new file mode 100644
index 0000000..aa150dd
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/TestKeyStore.java
@@ -0,0 +1,1159 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.java.security;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStore.PasswordProtection;
+import java.security.KeyStore.PrivateKeyEntry;
+import java.security.KeyStore.TrustedCertificateEntry;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.UnrecoverableEntryException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import javax.crypto.spec.DHParameterSpec;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.security.auth.x500.X500Principal;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.CRLReason;
+import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralNames;
+import org.bouncycastle.asn1.x509.GeneralSubtree;
+import org.bouncycastle.asn1.x509.KeyPurposeId;
+import org.bouncycastle.asn1.x509.KeyUsage;
+import org.bouncycastle.asn1.x509.NameConstraints;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.bouncycastle.cert.ocsp.BasicOCSPResp;
+import org.bouncycastle.cert.ocsp.BasicOCSPRespBuilder;
+import org.bouncycastle.cert.ocsp.CertificateID;
+import org.bouncycastle.cert.ocsp.CertificateStatus;
+import org.bouncycastle.cert.ocsp.OCSPResp;
+import org.bouncycastle.cert.ocsp.OCSPRespBuilder;
+import org.bouncycastle.cert.ocsp.RevokedStatus;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.DigestCalculatorProvider;
+import org.bouncycastle.operator.bc.BcDigestCalculatorProvider;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import com.android.org.conscrypt.javax.net.ssl.TestKeyManager;
+import com.android.org.conscrypt.javax.net.ssl.TestTrustManager;
+
+/**
+ * TestKeyStore is a convenience class for other tests that
+ * want a canned KeyStore with a variety of key pairs.
+ *
+ * Creating a key store is relatively slow, so a singleton instance is
+ * accessible via TestKeyStore.get().
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class TestKeyStore {
+ /** Size of DSA keys to generate for testing. */
+ private static final int DSA_KEY_SIZE_BITS = 1024;
+
+ /** Size of EC keys to generate for testing. */
+ private static final int EC_KEY_SIZE_BITS = 256;
+
+ /** Size of RSA keys to generate for testing. */
+ private static final int RSA_KEY_SIZE_BITS = 1024;
+
+ // Generated with: openssl dhparam -C 1024
+ private static final BigInteger DH_PARAMS_P = new BigInteger(1,
+ new byte[] {
+ (byte) 0xA2, (byte) 0x31, (byte) 0xB4, (byte) 0xB3, (byte) 0x6D, (byte) 0x9B,
+ (byte) 0x7E, (byte) 0xF4, (byte) 0xE7, (byte) 0x21, (byte) 0x51, (byte) 0x40,
+ (byte) 0xEB, (byte) 0xC6, (byte) 0xB6, (byte) 0xD6, (byte) 0x54, (byte) 0x56,
+ (byte) 0x72, (byte) 0xBE, (byte) 0x43, (byte) 0x18, (byte) 0x30, (byte) 0x5C,
+ (byte) 0x15, (byte) 0x5A, (byte) 0xF9, (byte) 0x19, (byte) 0x62, (byte) 0xAD,
+ (byte) 0xF4, (byte) 0x29, (byte) 0xCB, (byte) 0xC6, (byte) 0xF6, (byte) 0x64,
+ (byte) 0x0B, (byte) 0x9D, (byte) 0x23, (byte) 0x80, (byte) 0xF9, (byte) 0x5B,
+ (byte) 0x1C, (byte) 0x1C, (byte) 0x6A, (byte) 0xB4, (byte) 0xEA, (byte) 0xB9,
+ (byte) 0x80, (byte) 0x98, (byte) 0x8B, (byte) 0xAF, (byte) 0x15, (byte) 0xA8,
+ (byte) 0x5C, (byte) 0xC4, (byte) 0xB0, (byte) 0x41, (byte) 0x29, (byte) 0x66,
+ (byte) 0x9F, (byte) 0x9F, (byte) 0x1F, (byte) 0x88, (byte) 0x50, (byte) 0x97,
+ (byte) 0x38, (byte) 0x0B, (byte) 0x01, (byte) 0x16, (byte) 0xD6, (byte) 0x84,
+ (byte) 0x1D, (byte) 0x48, (byte) 0x6F, (byte) 0x7C, (byte) 0x06, (byte) 0x8C,
+ (byte) 0x6E, (byte) 0x68, (byte) 0xCD, (byte) 0x38, (byte) 0xE6, (byte) 0x22,
+ (byte) 0x30, (byte) 0x61, (byte) 0x37, (byte) 0x02, (byte) 0x3D, (byte) 0x47,
+ (byte) 0x62, (byte) 0xCE, (byte) 0xB9, (byte) 0x1A, (byte) 0x69, (byte) 0x9D,
+ (byte) 0xA1, (byte) 0x9F, (byte) 0x10, (byte) 0xA1, (byte) 0xAA, (byte) 0x70,
+ (byte) 0xF7, (byte) 0x27, (byte) 0x9C, (byte) 0xD4, (byte) 0xA5, (byte) 0x15,
+ (byte) 0xE2, (byte) 0x15, (byte) 0x0C, (byte) 0x20, (byte) 0x90, (byte) 0x08,
+ (byte) 0xB6, (byte) 0xF5, (byte) 0xDF, (byte) 0x1C, (byte) 0xCB, (byte) 0x82,
+ (byte) 0x6D, (byte) 0xC0, (byte) 0xE1, (byte) 0xBD, (byte) 0xCC, (byte) 0x4A,
+ (byte) 0x76, (byte) 0xE3,
+ });
+
+ // generator of 2
+ private static final BigInteger DH_PARAMS_G = BigInteger.valueOf(2);
+
+ private static TestKeyStore ROOT_CA;
+ private static TestKeyStore INTERMEDIATE_CA;
+ private static TestKeyStore INTERMEDIATE_CA_2;
+ private static TestKeyStore INTERMEDIATE_CA_EC;
+
+ private static TestKeyStore SERVER;
+ private static TestKeyStore SERVER_HOSTNAME;
+ private static TestKeyStore CLIENT;
+ private static TestKeyStore CLIENT_CERTIFICATE;
+ private static TestKeyStore CLIENT_EC_RSA_CERTIFICATE;
+ private static TestKeyStore CLIENT_EC_EC_CERTIFICATE;
+
+ private static TestKeyStore CLIENT_2;
+
+ static {
+ if (!StandardNames.IS_RI
+ && !BouncyCastleProvider.class.getName().startsWith("com.android")) {
+ // If we run outside of the Android system, we need to make sure
+ // that the BouncyCastleProvider's static field keyInfoConverters
+ // is initialized. This happens in the default constructor only.
+ new BouncyCastleProvider();
+ }
+ }
+
+ private static final byte[] LOCAL_HOST_ADDRESS = {127, 0, 0, 1};
+ private static final String LOCAL_HOST_NAME = "localhost";
+ private static final String LOCAL_HOST_NAME_IPV6 = "ip6-localhost";
+ public static final String CERT_HOSTNAME = "example.com";
+
+ public final KeyStore keyStore;
+ public final char[] storePassword;
+ public final char[] keyPassword;
+ public final KeyManager[] keyManagers;
+ public final TrustManager[] trustManagers;
+ public final TrustManager trustManager;
+
+ private TestKeyStore(KeyStore keyStore, char[] storePassword, char[] keyPassword) {
+ this.keyStore = keyStore;
+ this.storePassword = storePassword;
+ this.keyPassword = keyPassword;
+ this.keyManagers = createKeyManagers(keyStore, storePassword);
+ this.trustManagers = createTrustManagers(keyStore);
+ this.trustManager = trustManagers[0];
+ }
+
+ public static KeyManager[] createKeyManagers(KeyStore keyStore, char[] storePassword) {
+ try {
+ String kmfa = KeyManagerFactory.getDefaultAlgorithm();
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(kmfa);
+ kmf.init(keyStore, storePassword);
+ return TestKeyManager.wrap(kmf.getKeyManagers());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static TrustManager[] createTrustManagers(final KeyStore keyStore) {
+ try {
+ String tmfa = TrustManagerFactory.getDefaultAlgorithm();
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfa);
+ tmf.init(keyStore);
+ return TestTrustManager.wrap(tmf.getTrustManagers());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public TestKeyStore copy() {
+ return new TestKeyStore(keyStore, storePassword, keyPassword);
+ }
+
+ /**
+ * Lazily create shared test certificates.
+ */
+ private static synchronized void initCerts() {
+ if (ROOT_CA != null) {
+ return;
+ }
+ ROOT_CA = new Builder()
+ .aliasPrefix("RootCA")
+ .subject("CN=Test Root Certificate Authority")
+ .ca(true)
+ .certificateSerialNumber(BigInteger.valueOf(1))
+ .build();
+ INTERMEDIATE_CA_EC = new Builder()
+ .aliasPrefix("IntermediateCA-EC")
+ .keyAlgorithms("EC")
+ .subject("CN=Test Intermediate Certificate Authority ECDSA")
+ .ca(true)
+ .signer(ROOT_CA.getPrivateKey("RSA", "RSA"))
+ .rootCa(ROOT_CA.getRootCertificate("RSA"))
+ .certificateSerialNumber(BigInteger.valueOf(2))
+ .build();
+ INTERMEDIATE_CA = new Builder()
+ .aliasPrefix("IntermediateCA")
+ .subject("CN=Test Intermediate Certificate Authority")
+ .ca(true)
+ .signer(ROOT_CA.getPrivateKey("RSA", "RSA"))
+ .rootCa(ROOT_CA.getRootCertificate("RSA"))
+ .certificateSerialNumber(BigInteger.valueOf(2))
+ .build();
+ SERVER = new Builder()
+ .aliasPrefix("server")
+ .signer(INTERMEDIATE_CA.getPrivateKey("RSA", "RSA"))
+ .rootCa(INTERMEDIATE_CA.getRootCertificate("RSA"))
+ .addSubjectAltNameIpAddress(LOCAL_HOST_ADDRESS)
+ .certificateSerialNumber(BigInteger.valueOf(3))
+ .build();
+ SERVER_HOSTNAME = new Builder()
+ .aliasPrefix("server-hostname")
+ .signer(INTERMEDIATE_CA.getPrivateKey("RSA", "RSA"))
+ .rootCa(INTERMEDIATE_CA.getRootCertificate("RSA"))
+ .addSubjectAltNameDnsName(CERT_HOSTNAME)
+ .certificateSerialNumber(BigInteger.valueOf(4))
+ .build();
+ CLIENT = new TestKeyStore(createClient(INTERMEDIATE_CA.keyStore), null, null);
+ CLIENT_EC_RSA_CERTIFICATE = new Builder()
+ .aliasPrefix("client-ec")
+ .keyAlgorithms("EC")
+ .subject("emailAddress=test-ec@user")
+ .signer(INTERMEDIATE_CA.getPrivateKey("RSA", "RSA"))
+ .rootCa(INTERMEDIATE_CA.getRootCertificate("RSA"))
+ .build();
+ CLIENT_EC_EC_CERTIFICATE = new Builder()
+ .aliasPrefix("client-ec")
+ .keyAlgorithms("EC")
+ .subject("emailAddress=test-ec@user")
+ .signer(INTERMEDIATE_CA_EC.getPrivateKey("EC", "RSA"))
+ .rootCa(INTERMEDIATE_CA_EC.getRootCertificate("RSA"))
+ .build();
+ CLIENT_CERTIFICATE = new Builder()
+ .aliasPrefix("client")
+ .subject("emailAddress=test@user")
+ .signer(INTERMEDIATE_CA.getPrivateKey("RSA", "RSA"))
+ .rootCa(INTERMEDIATE_CA.getRootCertificate("RSA"))
+ .build();
+ TestKeyStore rootCa2 = new Builder()
+ .aliasPrefix("RootCA2")
+ .subject("CN=Test Root Certificate Authority 2")
+ .ca(true)
+ .build();
+ INTERMEDIATE_CA_2 = new Builder()
+ .aliasPrefix("IntermediateCA")
+ .subject("CN=Test Intermediate Certificate Authority")
+ .ca(true)
+ .signer(rootCa2.getPrivateKey("RSA", "RSA"))
+ .rootCa(rootCa2.getRootCertificate("RSA"))
+ .build();
+ CLIENT_2 = new TestKeyStore(createClient(rootCa2.keyStore), null, null);
+ }
+
+ /**
+ * Return an root CA that can be used to issue new certificates.
+ */
+ public static TestKeyStore getRootCa() {
+ initCerts();
+ return ROOT_CA;
+ }
+
+ /**
+ * Return an intermediate CA that can be used to issue new certificates.
+ */
+ public static TestKeyStore getIntermediateCa() {
+ initCerts();
+ return INTERMEDIATE_CA;
+ }
+
+ /**
+ * Return an intermediate CA that can be used to issue new certificates.
+ */
+ public static TestKeyStore getIntermediateCa2() {
+ initCerts();
+ return INTERMEDIATE_CA_2;
+ }
+
+ /**
+ * Return a server keystore with a matched RSA certificate and
+ * private key as well as a CA certificate.
+ */
+ public static TestKeyStore getServer() {
+ initCerts();
+ return SERVER;
+ }
+
+ /**
+ * Return a server keystore with a matched RSA certificate with SAN hostname and private key
+ * as well as a CA certificate.
+ */
+ public static TestKeyStore getServerHostname() {
+ initCerts();
+ return SERVER_HOSTNAME;
+ }
+
+ /**
+ * Return a keystore with a CA certificate
+ */
+ public static TestKeyStore getClient() {
+ initCerts();
+ return CLIENT;
+ }
+
+ /**
+ * Return a client keystore with a matched RSA certificate and
+ * private key as well as a CA certificate.
+ */
+ public static TestKeyStore getClientCertificate() {
+ initCerts();
+ return CLIENT_CERTIFICATE;
+ }
+
+ /**
+ * Return a client keystore with a matched RSA certificate and
+ * private key as well as a CA certificate.
+ */
+ public static TestKeyStore getClientEcRsaCertificate() {
+ initCerts();
+ return CLIENT_EC_RSA_CERTIFICATE;
+ }
+
+ /**
+ * Return a client keystore with a matched RSA certificate and
+ * private key as well as a CA certificate.
+ */
+ public static TestKeyStore getClientEcEcCertificate() {
+ initCerts();
+ return CLIENT_EC_EC_CERTIFICATE;
+ }
+
+ /**
+ * Return a keystore with a second CA certificate that does not
+ * trust the server certificate returned by getServer for negative
+ * testing.
+ */
+ public static TestKeyStore getClientCA2() {
+ initCerts();
+ return CLIENT_2;
+ }
+
+ /**
+ * Creates KeyStores containing the requested key types. Since key
+ * generation can be expensive, most tests should reuse the RSA-only
+ * singleton instance returned by TestKeyStore.get.
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class Builder {
+ private String[] keyAlgorithms = {"RSA"};
+ private char[] storePassword;
+ private char[] keyPassword;
+ private String aliasPrefix;
+ private X500Principal subject;
+ private int keyUsage;
+ private boolean ca;
+ private PrivateKeyEntry privateEntry;
+ private PrivateKeyEntry signer;
+ private Certificate rootCa;
+ private final List<KeyPurposeId> extendedKeyUsages = new ArrayList<KeyPurposeId>();
+ private final List<Boolean> criticalExtendedKeyUsages = new ArrayList<Boolean>();
+ private final List<GeneralName> subjectAltNames = new ArrayList<GeneralName>();
+ private final List<GeneralSubtree> permittedNameConstraints =
+ new ArrayList<GeneralSubtree>();
+ private final List<GeneralSubtree> excludedNameConstraints =
+ new ArrayList<GeneralSubtree>();
+ // Generated randomly if not set
+ private BigInteger certificateSerialNumber = null;
+
+ public Builder() {
+ }
+
+ /**
+ * Sets the requested key types to generate and include. The default is
+ * RSA only.
+ */
+ public Builder keyAlgorithms(String... keyAlgorithms) {
+ this.keyAlgorithms = keyAlgorithms;
+ return this;
+ }
+
+ /** A unique prefix to identify the key aliases */
+ public Builder aliasPrefix(String aliasPrefix) {
+ this.aliasPrefix = aliasPrefix;
+ return this;
+ }
+
+ /**
+ * Sets the subject common name. The default is the local host's
+ * canonical name.
+ */
+ public Builder subject(X500Principal subject) {
+ this.subject = subject;
+ return this;
+ }
+
+ public Builder subject(String commonName) {
+ return subject(new X500Principal(commonName));
+ }
+
+ /** {@link KeyUsage} bit mask for 2.5.29.15 extension */
+ public Builder keyUsage(int keyUsage) {
+ this.keyUsage = keyUsage;
+ return this;
+ }
+
+ /** true If the keys being created are for a CA */
+ public Builder ca(boolean ca) {
+ this.ca = ca;
+ return this;
+ }
+
+ /** a private key entry to use for the generation of the certificate */
+ public Builder privateEntry(PrivateKeyEntry privateEntry) {
+ this.privateEntry = privateEntry;
+ return this;
+ }
+
+ /** a private key entry to be used for signing, otherwise self-sign */
+ public Builder signer(PrivateKeyEntry signer) {
+ this.signer = signer;
+ return this;
+ }
+
+ /** a root CA to include in the final store */
+ public Builder rootCa(Certificate rootCa) {
+ this.rootCa = rootCa;
+ return this;
+ }
+
+ public Builder addExtendedKeyUsage(KeyPurposeId keyPurposeId, boolean critical) {
+ extendedKeyUsages.add(keyPurposeId);
+ criticalExtendedKeyUsages.add(critical);
+ return this;
+ }
+
+ public Builder addSubjectAltName(GeneralName generalName) {
+ subjectAltNames.add(generalName);
+ return this;
+ }
+
+ public Builder addSubjectAltNameDnsName(String dnsName) {
+ return addSubjectAltName(
+ new GeneralName(GeneralName.dNSName, dnsName));
+ }
+
+ public Builder addSubjectAltNameIpAddress(byte[] ipAddress) {
+ return addSubjectAltName(
+ new GeneralName(GeneralName.iPAddress, new DEROctetString(ipAddress)));
+ }
+
+ private Builder addNameConstraint(boolean permitted, GeneralName generalName) {
+ if (permitted) {
+ permittedNameConstraints.add(new GeneralSubtree(generalName));
+ } else {
+ excludedNameConstraints.add(new GeneralSubtree(generalName));
+ }
+ return this;
+ }
+
+ public Builder addNameConstraint(boolean permitted, byte[] ipAddress) {
+ return addNameConstraint(permitted,
+ new GeneralName(GeneralName.iPAddress, new DEROctetString(ipAddress)));
+ }
+
+ public Builder certificateSerialNumber(BigInteger certificateSerialNumber) {
+ this.certificateSerialNumber = certificateSerialNumber;
+ return this;
+ }
+
+ public TestKeyStore build() {
+ try {
+ if (StandardNames.IS_RI) {
+ // JKS does not allow null password
+ if (storePassword == null) {
+ storePassword = "password".toCharArray();
+ }
+ if (keyPassword == null) {
+ keyPassword = "password".toCharArray();
+ }
+ }
+
+ /*
+ * This is not implemented for other key types because the logic
+ * would be long to write and it's not needed currently.
+ */
+ if (privateEntry != null
+ && (keyAlgorithms.length != 1 || !"RSA".equals(keyAlgorithms[0]))) {
+ throw new IllegalStateException(
+ "Only reusing an existing key is implemented for RSA");
+ }
+
+ KeyStore keyStore = createKeyStore();
+ for (String keyAlgorithm : keyAlgorithms) {
+ String publicAlias = aliasPrefix + "-public-" + keyAlgorithm;
+ String privateAlias = aliasPrefix + "-private-" + keyAlgorithm;
+ if ((keyAlgorithm.equals("EC_RSA") || keyAlgorithm.equals("DH_RSA"))
+ && signer == null && rootCa == null) {
+ createKeys(keyStore, keyAlgorithm, publicAlias, privateAlias, null,
+ privateKey(keyStore, keyPassword, "RSA", "RSA"));
+ continue;
+ } else if (keyAlgorithm.equals("DH_DSA") && signer == null && rootCa == null) {
+ createKeys(keyStore, keyAlgorithm, publicAlias, privateAlias, null,
+ privateKey(keyStore, keyPassword, "DSA", "DSA"));
+ continue;
+ }
+ createKeys(keyStore, keyAlgorithm, publicAlias, privateAlias, privateEntry,
+ signer);
+ }
+ if (rootCa != null) {
+ keyStore.setCertificateEntry(
+ aliasPrefix + "-root-ca-" + rootCa.getPublicKey().getAlgorithm(),
+ rootCa);
+ }
+ return new TestKeyStore(keyStore, storePassword, keyPassword);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Add newly generated keys of a given key type to an existing
+ * KeyStore. The PrivateKey will be stored under the specified
+ * private alias name. The X509Certificate will be stored on the
+ * public alias name and have the given subject distinguished
+ * name.
+ *
+ * If a CA is provided, it will be used to sign the generated
+ * certificate and OCSP responses. Otherwise, the certificate
+ * will be self signed. The certificate will be valid for one
+ * day before and one day after the time of creation.
+ *
+ * Based on:
+ * org.bouncycastle.jce.provider.test.SigTest
+ * org.bouncycastle.jce.provider.test.CertTest
+ */
+ private KeyStore createKeys(KeyStore keyStore, String keyAlgorithm, String publicAlias,
+ String privateAlias, PrivateKeyEntry privateEntry, PrivateKeyEntry signer)
+ throws Exception {
+ PrivateKey caKey;
+ X509Certificate caCert;
+ X509Certificate[] caCertChain;
+ if (signer == null) {
+ caKey = null;
+ caCert = null;
+ caCertChain = null;
+ } else {
+ caKey = signer.getPrivateKey();
+ caCert = (X509Certificate) signer.getCertificate();
+ caCertChain = (X509Certificate[]) signer.getCertificateChain();
+ }
+
+ // Default to localhost if nothing was specified.
+ if (subject == null) {
+ subject = localhost();
+ addSubjectAltNameDnsName(LOCAL_HOST_NAME);
+ addSubjectAltNameDnsName(LOCAL_HOST_NAME_IPV6);
+ }
+
+ final PrivateKey privateKey;
+ final PublicKey publicKey;
+ X509Certificate x509c;
+ if (publicAlias == null && privateAlias == null) {
+ // don't want anything apparently
+ privateKey = null;
+ publicKey = null;
+ x509c = null;
+ } else {
+ if (privateEntry == null) {
+ // 1a.) we make the keys
+ int keySize = -1;
+ AlgorithmParameterSpec spec = null;
+ if (keyAlgorithm.equals("RSA")) {
+ keySize = RSA_KEY_SIZE_BITS;
+ } else if (keyAlgorithm.equals("DH_RSA")) {
+ spec = new DHParameterSpec(DH_PARAMS_P, DH_PARAMS_G);
+ keyAlgorithm = "DH";
+ } else if (keyAlgorithm.equals("DSA")) {
+ keySize = DSA_KEY_SIZE_BITS;
+ } else if (keyAlgorithm.equals("DH_DSA")) {
+ spec = new DHParameterSpec(DH_PARAMS_P, DH_PARAMS_G);
+ keyAlgorithm = "DH";
+ } else if (keyAlgorithm.equals("EC")) {
+ keySize = EC_KEY_SIZE_BITS;
+ } else if (keyAlgorithm.equals("EC_RSA")) {
+ keySize = EC_KEY_SIZE_BITS;
+ keyAlgorithm = "EC";
+ } else {
+ throw new IllegalArgumentException("Unknown key algorithm " + keyAlgorithm);
+ }
+
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyAlgorithm);
+ if (spec != null) {
+ kpg.initialize(spec);
+ } else if (keySize != -1) {
+ kpg.initialize(keySize);
+ } else {
+ throw new AssertionError(
+ "Must either have set algorithm parameters or key size!");
+ }
+
+ KeyPair kp = kpg.generateKeyPair();
+ privateKey = kp.getPrivate();
+ publicKey = kp.getPublic();
+ } else {
+ // 1b.) we use the previous keys
+ privateKey = privateEntry.getPrivateKey();
+ publicKey = privateEntry.getCertificate().getPublicKey();
+ }
+
+ // 2.) use keys to make certificate
+ X500Principal issuer =
+ ((caCert != null) ? caCert.getSubjectX500Principal() : subject);
+ PrivateKey signingKey = (caKey == null) ? privateKey : caKey;
+ x509c = createCertificate(publicKey, signingKey, subject, issuer, keyUsage, ca,
+ extendedKeyUsages, criticalExtendedKeyUsages, subjectAltNames,
+ permittedNameConstraints, excludedNameConstraints, certificateSerialNumber);
+ }
+
+ X509Certificate[] x509cc;
+ if (privateAlias == null) {
+ // don't need certificate chain
+ x509cc = null;
+ } else if (caCertChain == null) {
+ x509cc = new X509Certificate[] {x509c};
+ } else {
+ x509cc = new X509Certificate[caCertChain.length + 1];
+ x509cc[0] = x509c;
+ System.arraycopy(caCertChain, 0, x509cc, 1, caCertChain.length);
+ }
+
+ // 3.) put certificate and private key into the key store
+ if (privateAlias != null) {
+ keyStore.setKeyEntry(privateAlias, privateKey, keyPassword, x509cc);
+ }
+ if (publicAlias != null) {
+ keyStore.setCertificateEntry(publicAlias, x509c);
+ }
+ return keyStore;
+ }
+
+ private X500Principal localhost() {
+ return new X500Principal("CN=" + LOCAL_HOST_NAME);
+ }
+ }
+
+ public static X509Certificate createCa(
+ PublicKey publicKey, PrivateKey privateKey, String subject) {
+ try {
+ X500Principal principal = new X500Principal(subject);
+ return createCertificate(publicKey, privateKey, principal, principal, 0, true,
+ new ArrayList<KeyPurposeId>(), new ArrayList<Boolean>(),
+ new ArrayList<GeneralName>(), new ArrayList<GeneralSubtree>(),
+ new ArrayList<GeneralSubtree>(), null /* serialNumber, generated randomly */);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static X509Certificate createCertificate(PublicKey publicKey, PrivateKey privateKey,
+ X500Principal subject, X500Principal issuer, int keyUsage, boolean ca,
+ List<KeyPurposeId> extendedKeyUsages, List<Boolean> criticalExtendedKeyUsages,
+ List<GeneralName> subjectAltNames, List<GeneralSubtree> permittedNameConstraints,
+ List<GeneralSubtree> excludedNameConstraints, BigInteger serialNumber)
+ throws Exception {
+ // Note that there is no way to programmatically make a
+ // Certificate using java.* or javax.* APIs. The
+ // CertificateFactory interface assumes you want to read
+ // in a stream of bytes, typically the X.509 factory would
+ // allow ASN.1 DER encoded bytes and optionally some PEM
+ // formats. Here we use Bouncy Castle's
+ // X509V3CertificateGenerator and related classes.
+
+ long millisPerDay = 24 * 60 * 60 * 1000;
+ long now = System.currentTimeMillis();
+ Date start = new Date(now - millisPerDay);
+ Date end = new Date(now + millisPerDay);
+
+ String keyAlgorithm = privateKey.getAlgorithm();
+ String signatureAlgorithm;
+ if (keyAlgorithm.equals("RSA")) {
+ signatureAlgorithm = "sha256WithRSA";
+ } else if (keyAlgorithm.equals("DSA")) {
+ signatureAlgorithm = "sha256WithDSA";
+ } else if (keyAlgorithm.equals("EC")) {
+ signatureAlgorithm = "sha256WithECDSA";
+ } else if (keyAlgorithm.equals("EC_RSA")) {
+ signatureAlgorithm = "sha256WithRSA";
+ } else {
+ throw new IllegalArgumentException("Unknown key algorithm " + keyAlgorithm);
+ }
+
+ if (serialNumber == null) {
+ byte[] serialBytes = new byte[16];
+ new SecureRandom().nextBytes(serialBytes);
+ serialNumber = new BigInteger(1, serialBytes);
+ }
+
+ X509v3CertificateBuilder x509cg =
+ new X509v3CertificateBuilder(X500Name.getInstance(issuer.getEncoded()),
+ serialNumber, start, end, X500Name.getInstance(subject.getEncoded()),
+ SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));
+ if (keyUsage != 0) {
+ x509cg.addExtension(Extension.keyUsage, true, new KeyUsage(keyUsage));
+ }
+ if (ca) {
+ x509cg.addExtension(Extension.basicConstraints, true, new BasicConstraints(true));
+ }
+ for (int i = 0; i < extendedKeyUsages.size(); i++) {
+ KeyPurposeId keyPurposeId = extendedKeyUsages.get(i);
+ boolean critical = criticalExtendedKeyUsages.get(i);
+ x509cg.addExtension(
+ Extension.extendedKeyUsage, critical, new ExtendedKeyUsage(keyPurposeId));
+ }
+ if (!subjectAltNames.isEmpty()) {
+ x509cg.addExtension(Extension.subjectAlternativeName, false,
+ new GeneralNames(subjectAltNames.toArray(new GeneralName[0])).getEncoded());
+ }
+ if (!permittedNameConstraints.isEmpty() || !excludedNameConstraints.isEmpty()) {
+ x509cg.addExtension(Extension.nameConstraints, true,
+ new NameConstraints(
+ permittedNameConstraints.toArray(
+ new GeneralSubtree[permittedNameConstraints.size()]),
+ excludedNameConstraints.toArray(
+ new GeneralSubtree[excludedNameConstraints.size()])));
+ }
+
+ X509CertificateHolder x509holder =
+ x509cg.build(new JcaContentSignerBuilder(signatureAlgorithm).build(privateKey));
+ CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+ X509Certificate x509c = (X509Certificate) certFactory.generateCertificate(
+ new ByteArrayInputStream(x509holder.getEncoded()));
+ if (StandardNames.IS_RI) {
+ /*
+ * The RI can't handle the BC EC signature algorithm
+ * string of "ECDSA", since it expects "...WITHEC...",
+ * so convert from BC to RI X509Certificate
+ * implementation via bytes.
+ */
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ ByteArrayInputStream bais = new ByteArrayInputStream(x509c.getEncoded());
+ Certificate c = cf.generateCertificate(bais);
+ x509c = (X509Certificate) c;
+ }
+ return x509c;
+ }
+
+ /**
+ * Return the key algorithm for a possible compound algorithm
+ * identifier containing an underscore. If not underscore is
+ * present, the argument is returned unmodified. However for an
+ * algorithm such as EC_RSA, return EC.
+ */
+ public static String keyAlgorithm(String algorithm) {
+ int index = algorithm.indexOf('_');
+ if (index == -1) {
+ return algorithm;
+ }
+ return algorithm.substring(0, index);
+ }
+
+ /**
+ * Return the signature algorithm for a possible compound
+ * algorithm identifier containing an underscore. If not
+ * underscore is present, the argument is returned
+ * unmodified. However for an algorithm such as EC_RSA, return
+ * RSA.
+ */
+ public static String signatureAlgorithm(String algorithm) {
+ int index = algorithm.indexOf('_');
+ if (index == -1) {
+ return algorithm;
+ }
+ return algorithm.substring(index + 1, algorithm.length());
+ }
+
+ /**
+ * Create an empty KeyStore
+ */
+ public static KeyStore createKeyStore() {
+ try {
+ KeyStore keyStore = KeyStore.getInstance(StandardNames.KEY_STORE_ALGORITHM);
+ keyStore.load(null, null);
+ return keyStore;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Return the only private key in a TestKeyStore for the given
+ * algorithms. Throws IllegalStateException if there are are more
+ * or less than one.
+ */
+ public PrivateKeyEntry getPrivateKey(String keyAlgorithm, String signatureAlgorithm) {
+ return privateKey(keyStore, keyPassword, keyAlgorithm, signatureAlgorithm);
+ }
+
+ /**
+ * Return the only private key in a keystore for the given
+ * algorithms. Throws IllegalStateException if there are are more
+ * or less than one.
+ */
+ public static PrivateKeyEntry privateKey(
+ KeyStore keyStore, char[] keyPassword, String keyAlgorithm, String signatureAlgorithm) {
+ try {
+ PrivateKeyEntry found = null;
+ PasswordProtection password = new PasswordProtection(keyPassword);
+ for (String alias : Collections.list(keyStore.aliases())) {
+ if (!keyStore.entryInstanceOf(alias, PrivateKeyEntry.class)) {
+ continue;
+ }
+ PrivateKeyEntry privateKey = (PrivateKeyEntry) keyStore.getEntry(alias, password);
+ if (!privateKey.getPrivateKey().getAlgorithm().equals(keyAlgorithm)) {
+ continue;
+ }
+ X509Certificate certificate = (X509Certificate) privateKey.getCertificate();
+ if (!certificate.getSigAlgName().contains(signatureAlgorithm)) {
+ continue;
+ }
+ if (found != null) {
+ throw new IllegalStateException("KeyStore has more than one private key for"
+ + " keyAlgorithm: " + keyAlgorithm + " signatureAlgorithm: "
+ + signatureAlgorithm + "\nfirst: " + found.getPrivateKey()
+ + "\nsecond: " + privateKey.getPrivateKey());
+ }
+ found = privateKey;
+ }
+ if (found == null) {
+ throw new IllegalStateException("KeyStore contained no private key for"
+ + " keyAlgorithm: " + keyAlgorithm
+ + " signatureAlgorithm: " + signatureAlgorithm);
+ }
+ return found;
+ } catch (Exception e) {
+ throw new RuntimeException("Problem getting key for " + keyAlgorithm + " and signature "
+ + signatureAlgorithm,
+ e);
+ }
+ }
+
+ /**
+ * Return the issuing CA certificate of the given
+ * certificate. Throws IllegalStateException if there are are more
+ * or less than one.
+ */
+ public Certificate getIssuer(Certificate cert) throws Exception {
+ return issuer(keyStore, cert);
+ }
+
+ /**
+ * Return the issuing CA certificate of the given
+ * certificate. Throws IllegalStateException if there are are more
+ * or less than one.
+ */
+ public static Certificate issuer(KeyStore keyStore, Certificate c) throws Exception {
+ if (!(c instanceof X509Certificate)) {
+ throw new IllegalStateException("issuer requires an X509Certificate, found " + c);
+ }
+ X509Certificate cert = (X509Certificate) c;
+
+ Certificate found = null;
+ for (String alias : Collections.list(keyStore.aliases())) {
+ if (!keyStore.entryInstanceOf(alias, TrustedCertificateEntry.class)) {
+ continue;
+ }
+ TrustedCertificateEntry certificateEntry =
+ (TrustedCertificateEntry) keyStore.getEntry(alias, null);
+ Certificate certificate = certificateEntry.getTrustedCertificate();
+ if (!(certificate instanceof X509Certificate)) {
+ continue;
+ }
+ X509Certificate x = (X509Certificate) certificate;
+ if (!cert.getIssuerDN().equals(x.getSubjectDN())) {
+ continue;
+ }
+ if (found != null) {
+ throw new IllegalStateException("KeyStore has more than one issuing CA for " + cert
+ + "\nfirst: " + found + "\nsecond: " + certificate);
+ }
+ found = certificate;
+ }
+ if (found == null) {
+ throw new IllegalStateException("KeyStore contained no issuing CA for " + cert);
+ }
+ return found;
+ }
+
+ /**
+ * Return the only self-signed root certificate in a TestKeyStore
+ * for the given algorithm. Throws IllegalStateException if there
+ * are are more or less than one.
+ */
+ public X509Certificate getRootCertificate(String algorithm) {
+ return rootCertificate(keyStore, algorithm);
+ }
+
+ private static OCSPResp generateOCSPResponse(PrivateKeyEntry server, PrivateKeyEntry issuer,
+ CertificateStatus status) throws CertificateException {
+ try {
+ X509Certificate serverCertJca = (X509Certificate) server.getCertificate();
+ X509Certificate caCertJca = (X509Certificate) issuer.getCertificate();
+
+ X509CertificateHolder caCert = new JcaX509CertificateHolder(caCertJca);
+
+ DigestCalculatorProvider digCalcProv = new BcDigestCalculatorProvider();
+ BasicOCSPRespBuilder basicBuilder = new BasicOCSPRespBuilder(
+ SubjectPublicKeyInfo.getInstance(caCertJca.getPublicKey().getEncoded()),
+ digCalcProv.get(CertificateID.HASH_SHA1));
+
+ CertificateID certId = new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1),
+ caCert, serverCertJca.getSerialNumber());
+
+ basicBuilder.addResponse(certId, status);
+
+ BasicOCSPResp resp = basicBuilder.build(
+ new JcaContentSignerBuilder("SHA256withRSA").build(issuer.getPrivateKey()),
+ null, new Date());
+
+ OCSPRespBuilder builder = new OCSPRespBuilder();
+ return builder.build(OCSPRespBuilder.SUCCESSFUL, resp);
+ } catch (Exception e) {
+ throw new CertificateException("cannot generate OCSP response", e);
+ }
+ }
+
+ public static byte[] getOCSPResponseForGood(PrivateKeyEntry server, PrivateKeyEntry issuer)
+ throws CertificateException {
+ try {
+ return generateOCSPResponse(server, issuer, CertificateStatus.GOOD).getEncoded();
+ } catch (IOException e) {
+ throw new CertificateException(e);
+ }
+ }
+
+ public static byte[] getOCSPResponseForRevoked(PrivateKeyEntry server, PrivateKeyEntry issuer)
+ throws CertificateException {
+ try {
+ return generateOCSPResponse(
+ server, issuer, new RevokedStatus(new Date(), CRLReason.keyCompromise))
+ .getEncoded();
+ } catch (IOException e) {
+ throw new CertificateException(e);
+ }
+ }
+
+ /**
+ * Return the only self-signed root certificate in a keystore for
+ * the given algorithm. Throws IllegalStateException if there are
+ * are more or less than one.
+ */
+ public static X509Certificate rootCertificate(KeyStore keyStore, String algorithm) {
+ try {
+ X509Certificate found = null;
+ for (String alias : Collections.list(keyStore.aliases())) {
+ if (!keyStore.entryInstanceOf(alias, TrustedCertificateEntry.class)) {
+ continue;
+ }
+ TrustedCertificateEntry certificateEntry =
+ (TrustedCertificateEntry) keyStore.getEntry(alias, null);
+ Certificate certificate = certificateEntry.getTrustedCertificate();
+ if (!certificate.getPublicKey().getAlgorithm().equals(algorithm)) {
+ continue;
+ }
+ if (!(certificate instanceof X509Certificate)) {
+ continue;
+ }
+ X509Certificate x = (X509Certificate) certificate;
+ if (!x.getIssuerDN().equals(x.getSubjectDN())) {
+ continue;
+ }
+ if (found != null) {
+ throw new IllegalStateException("KeyStore has more than one root CA for "
+ + algorithm + "\nfirst: " + found + "\nsecond: " + certificate);
+ }
+ found = x;
+ }
+ if (found == null) {
+ throw new IllegalStateException("KeyStore contained no root CA for " + algorithm);
+ }
+ return found;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Return an {@code X509Certificate} that matches the given {@code alias}.
+ */
+ public KeyStore.Entry getEntryByAlias(String alias) {
+ return entryByAlias(keyStore, alias);
+ }
+
+ /**
+ * Finds an entry in the keystore by the given alias.
+ */
+ public static KeyStore.Entry entryByAlias(KeyStore keyStore, String alias) {
+ try {
+ return keyStore.getEntry(alias, null);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ } catch (UnrecoverableEntryException e) {
+ throw new RuntimeException(e);
+ } catch (KeyStoreException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Create a client key store that only contains self-signed certificates but no private keys
+ */
+ public static KeyStore createClient(KeyStore caKeyStore) {
+ KeyStore clientKeyStore = createKeyStore();
+ copySelfSignedCertificates(clientKeyStore, caKeyStore);
+ return clientKeyStore;
+ }
+
+ /**
+ * Copy self-signed certificates from one key store to another.
+ * Returns true if successful, false if no match found.
+ */
+ public static boolean copySelfSignedCertificates(KeyStore dst, KeyStore src) {
+ try {
+ boolean copied = false;
+ for (String alias : Collections.list(src.aliases())) {
+ if (!src.isCertificateEntry(alias)) {
+ continue;
+ }
+ X509Certificate cert = (X509Certificate) src.getCertificate(alias);
+ if (!cert.getSubjectDN().equals(cert.getIssuerDN())) {
+ continue;
+ }
+ dst.setCertificateEntry(alias, cert);
+ copied = true;
+ }
+ return copied;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Copy named certificates from one key store to another.
+ * Returns true if successful, false if no match found.
+ */
+ public static boolean copyCertificate(Principal subject, KeyStore dst, KeyStore src)
+ throws Exception {
+ for (String alias : Collections.list(src.aliases())) {
+ if (!src.isCertificateEntry(alias)) {
+ continue;
+ }
+ X509Certificate cert = (X509Certificate) src.getCertificate(alias);
+ if (!cert.getSubjectDN().equals(subject)) {
+ continue;
+ }
+ dst.setCertificateEntry(alias, cert);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Dump a key store for debugging.
+ */
+ public void dump(String context) throws KeyStoreException, NoSuchAlgorithmException {
+ dump(context, keyStore, keyPassword);
+ }
+
+ /**
+ * Dump a key store for debugging.
+ */
+ public static void dump(String context, KeyStore keyStore, char[] keyPassword)
+ throws KeyStoreException, NoSuchAlgorithmException {
+ PrintStream out = System.out;
+ out.println("context=" + context);
+ out.println("\tkeyStore=" + keyStore);
+ out.println("\tkeyStore.type=" + keyStore.getType());
+ out.println("\tkeyStore.provider=" + keyStore.getProvider());
+ out.println("\tkeyPassword=" + ((keyPassword == null) ? null : new String(keyPassword)));
+ out.println("\tsize=" + keyStore.size());
+ for (String alias : Collections.list(keyStore.aliases())) {
+ out.println("alias=" + alias);
+ out.println("\tcreationDate=" + keyStore.getCreationDate(alias));
+ if (keyStore.isCertificateEntry(alias)) {
+ out.println("\tcertificate:");
+ out.println("==========================================");
+ out.println(keyStore.getCertificate(alias));
+ out.println("==========================================");
+ continue;
+ }
+ if (keyStore.isKeyEntry(alias)) {
+ out.println("\tkey:");
+ out.println("==========================================");
+ String key;
+ try {
+ key = ("Key retrieved using password\n" + keyStore.getKey(alias, keyPassword));
+ } catch (UnrecoverableKeyException e1) {
+ try {
+ key = ("Key retrieved without password\n" + keyStore.getKey(alias, null));
+ } catch (UnrecoverableKeyException e2) {
+ key = "Key could not be retrieved";
+ }
+ }
+ out.println(key);
+ out.println("==========================================");
+ Certificate[] chain = keyStore.getCertificateChain(alias);
+ if (chain == null) {
+ out.println("No certificate chain associated with key");
+ out.println("==========================================");
+ } else {
+ for (int i = 0; i < chain.length; i++) {
+ out.println("Certificate chain element #" + i);
+ out.println(chain[i]);
+ out.println("==========================================");
+ }
+ }
+ continue;
+ }
+ out.println("\tunknown entry type");
+ }
+ }
+
+ public static void assertChainLength(Object[] chain) {
+ /*
+ * Note chain is Object[] to support both
+ * java.security.cert.X509Certificate and
+ * javax.security.cert.X509Certificate
+ */
+ assertEquals(3, chain.length);
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/FakeSSLSession.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/FakeSSLSession.java
new file mode 100644
index 0000000..a373c72
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/FakeSSLSession.java
@@ -0,0 +1,142 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import java.nio.charset.Charset;
+import java.security.Principal;
+import java.security.cert.Certificate;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class FakeSSLSession implements SSLSession {
+ private static final Charset UTF_8 = Charset.forName("UTF-8");
+ final String host;
+
+ public FakeSSLSession(String host) {
+ this.host = host;
+ }
+
+ @Override
+ public int getApplicationBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getCipherSuite() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getCreationTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte[] getId() {
+ return host.getBytes(UTF_8);
+ }
+
+ @Override
+ public long getLastAccessedTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getLocalCertificates() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getLocalPrincipal() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPacketBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public javax.security.cert.X509Certificate[] getPeerCertificateChain() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getPeerHost() {
+ return host;
+ }
+
+ @Override
+ public int getPeerPort() {
+ return 443;
+ }
+
+ @Override
+ public Principal getPeerPrincipal() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getProtocol() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SSLSessionContext getSessionContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void invalidate() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isValid() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putValue(String name, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/ForwardingX509ExtendedKeyManager.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/ForwardingX509ExtendedKeyManager.java
new file mode 100644
index 0000000..9ad3db5
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/ForwardingX509ExtendedKeyManager.java
@@ -0,0 +1,66 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2013 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.
+ */
+package com.android.org.conscrypt.javax.net.ssl;
+import java.net.Socket;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.X509ExtendedKeyManager;
+/**
+ * {@link X509ExtendedKeyManager} which delegates all calls to the provided
+ * {@code X509ExtendedKeyManager} instance.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ForwardingX509ExtendedKeyManager extends X509ExtendedKeyManager {
+ private final X509ExtendedKeyManager delegate;
+ public ForwardingX509ExtendedKeyManager(X509ExtendedKeyManager delegate) {
+ this.delegate = delegate;
+ }
+ @Override
+ public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
+ return delegate.chooseClientAlias(keyType, issuers, socket);
+ }
+ @Override
+ public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
+ return delegate.chooseServerAlias(keyType, issuers, socket);
+ }
+ @Override
+ public X509Certificate[] getCertificateChain(String alias) {
+ return delegate.getCertificateChain(alias);
+ }
+ @Override
+ public String[] getClientAliases(String keyType, Principal[] issuers) {
+ return delegate.getClientAliases(keyType, issuers);
+ }
+ @Override
+ public String[] getServerAliases(String keyType, Principal[] issuers) {
+ return delegate.getServerAliases(keyType, issuers);
+ }
+ @Override
+ public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) {
+ return delegate.chooseEngineClientAlias(keyType, issuers, engine);
+ }
+ @Override
+ public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) {
+ return delegate.chooseEngineServerAlias(keyType, issuers, engine);
+ }
+ @Override
+ public PrivateKey getPrivateKey(String alias) {
+ return delegate.getPrivateKey(alias);
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/PSKKeyManagerProxy.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/PSKKeyManagerProxy.java
new file mode 100644
index 0000000..d4275c6
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/PSKKeyManagerProxy.java
@@ -0,0 +1,97 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2014 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.
+ */
+package com.android.org.conscrypt.javax.net.ssl;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.Socket;
+import javax.crypto.SecretKey;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLEngine;
+import com.android.org.conscrypt.TestUtils;
+
+/**
+ * Reflection-based implementation of {@code PSKKeyManager} from Conscrypt on which these tests
+ * cannot depend directly.
+ */
+class PSKKeyManagerProxy implements InvocationHandler {
+ static KeyManager getConscryptPSKKeyManager(PSKKeyManagerProxy delegate) {
+ Class<?> pskKeyManagerInterface;
+ try {
+ pskKeyManagerInterface = TestUtils.conscryptClass("PSKKeyManager");
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ return (KeyManager) Proxy.newProxyInstance(
+ PSKKeyManagerProxy.class.getClassLoader(),
+ new Class<?>[] {pskKeyManagerInterface},
+ delegate);
+ }
+ @SuppressWarnings("unused")
+ protected SecretKey getKey(String identityHint, String identity, Socket socket) {
+ return null;
+ }
+ @SuppressWarnings("unused")
+ protected SecretKey getKey(String identityHint, String identity, SSLEngine engine) {
+ return null;
+ }
+ @SuppressWarnings("unused")
+ protected String chooseServerKeyIdentityHint(Socket socket) {
+ return null;
+ }
+ @SuppressWarnings("unused")
+ protected String chooseServerKeyIdentityHint(SSLEngine engine) {
+ return null;
+ }
+ @SuppressWarnings("unused")
+ protected String chooseClientKeyIdentity(String identityHint, Socket socket) {
+ return null;
+ }
+ @SuppressWarnings("unused")
+ protected String chooseClientKeyIdentity(String identityHint, SSLEngine engine) {
+ return null;
+ }
+ @Override
+ public final Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ String methodName = method.getName();
+ Class<?>[] parameterTypes = method.getParameterTypes();
+ boolean sslEngineVariant = (parameterTypes.length > 0)
+ && SSLEngine.class.equals(parameterTypes[parameterTypes.length - 1]);
+ if ("getKey".equals(methodName)) {
+ if (sslEngineVariant) {
+ return getKey((String) args[0], (String) args[1], (SSLEngine) args[2]);
+ } else {
+ return getKey((String) args[0], (String) args[1], (Socket) args[2]);
+ }
+ } else if ("chooseServerKeyIdentityHint".equals(methodName)) {
+ if (sslEngineVariant) {
+ return chooseServerKeyIdentityHint((SSLEngine) args[0]);
+ } else {
+ return chooseServerKeyIdentityHint((Socket) args[0]);
+ }
+ } else if ("chooseClientKeyIdentity".equals(methodName)) {
+ if (sslEngineVariant) {
+ return chooseClientKeyIdentity((String) args[0], (SSLEngine) args[1]);
+ } else {
+ return chooseClientKeyIdentity((String) args[0], (Socket) args[1]);
+ }
+ } else {
+ throw new IllegalArgumentException("Unexpected method: " + method);
+ }
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/RandomPrivateKeyX509ExtendedKeyManager.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/RandomPrivateKeyX509ExtendedKeyManager.java
new file mode 100644
index 0000000..efe5d6c
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/RandomPrivateKeyX509ExtendedKeyManager.java
@@ -0,0 +1,87 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2013 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.
+ */
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static org.junit.Assert.fail;
+
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
+import java.util.HashMap;
+import java.util.Map;
+import javax.net.ssl.X509ExtendedKeyManager;
+
+/**
+ * {@link X509ExtendedKeyManager} which forwards all calls to a delegate while substituting
+ * the returned private key with its own randomly generated keys of the same type (and parameters).
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RandomPrivateKeyX509ExtendedKeyManager extends ForwardingX509ExtendedKeyManager {
+ private final Map<String, PrivateKey> cachedKeys = new HashMap<String, PrivateKey>();
+ public RandomPrivateKeyX509ExtendedKeyManager(X509ExtendedKeyManager delegate) {
+ super(delegate);
+ }
+ @Override
+ public PrivateKey getPrivateKey(String alias) {
+ PrivateKey originalPrivateKey = super.getPrivateKey(alias);
+ if (originalPrivateKey == null) {
+ return null;
+ }
+ PrivateKey result;
+ String keyAlgorithm = originalPrivateKey.getAlgorithm();
+ try {
+ KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm);
+ if ("RSA".equals(keyAlgorithm)) {
+ RSAPrivateKeySpec originalKeySpec =
+ keyFactory.getKeySpec(originalPrivateKey, RSAPrivateKeySpec.class);
+ int keyLengthBits = originalKeySpec.getModulus().bitLength();
+ // Use a cache because RSA key generation is slow.
+ String cacheKey = keyAlgorithm + "-" + keyLengthBits;
+ result = cachedKeys.get(cacheKey);
+ if (result == null) {
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyAlgorithm);
+ keyPairGenerator.initialize(keyLengthBits);
+ result = keyPairGenerator.generateKeyPair().getPrivate();
+ cachedKeys.put(cacheKey, result);
+ }
+ } else if ("DSA".equals(keyAlgorithm)) {
+ DSAPrivateKeySpec originalKeySpec =
+ keyFactory.getKeySpec(originalPrivateKey, DSAPrivateKeySpec.class);
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyAlgorithm);
+ keyPairGenerator.initialize(new DSAParameterSpec(
+ originalKeySpec.getP(), originalKeySpec.getQ(), originalKeySpec.getG()));
+ result = keyPairGenerator.generateKeyPair().getPrivate();
+ } else if ("EC".equals(keyAlgorithm)) {
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyAlgorithm);
+ keyPairGenerator.initialize(((ECPrivateKey) originalPrivateKey).getParams());
+ result = keyPairGenerator.generateKeyPair().getPrivate();
+ } else {
+ fail("Unsupported key algorithm: " + originalPrivateKey.getAlgorithm());
+ result = null;
+ }
+ } catch (GeneralSecurityException e) {
+ fail("Failed to generate private key: " + e);
+ result = null;
+ }
+ return result;
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/SSLConfigurationAsserts.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/SSLConfigurationAsserts.java
new file mode 100644
index 0000000..a415292
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/SSLConfigurationAsserts.java
@@ -0,0 +1,236 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2013 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.
+ */
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import com.android.org.conscrypt.java.security.StandardNames;
+
+/**
+ * Assertions about the configuration of TLS/SSL primitives.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SSLConfigurationAsserts {
+ /** Hidden constructor to prevent instantiation. */
+ private SSLConfigurationAsserts() {}
+ /**
+ * Asserts that the provided {@link SSLContext} has the expected default configuration, and that
+ * {@link SSLSocketFactory}, {@link SSLServerSocketFactory}, {@link SSLSocket},
+ * {@link SSLServerSocket} and {@link SSLEngine} instances created from the context match the
+ * configuration.
+ */
+ public static void assertSSLContextDefaultConfiguration(SSLContext sslContext)
+ throws IOException {
+ SSLParameters defaultParameters = sslContext.getDefaultSSLParameters();
+ StandardNames.assertSSLContextEnabledProtocols(
+ sslContext.getProtocol(), defaultParameters.getProtocols());
+ StandardNames.assertDefaultCipherSuites(defaultParameters.getCipherSuites());
+ assertFalse(defaultParameters.getWantClientAuth());
+ assertFalse(defaultParameters.getNeedClientAuth());
+ SSLParameters supportedParameters = sslContext.getSupportedSSLParameters();
+ StandardNames.assertSupportedCipherSuites(supportedParameters.getCipherSuites());
+ StandardNames.assertSupportedProtocols(supportedParameters.getProtocols());
+ assertFalse(supportedParameters.getWantClientAuth());
+ assertFalse(supportedParameters.getNeedClientAuth());
+ assertContainsAll("Unsupported enabled cipher suites",
+ supportedParameters.getCipherSuites(), defaultParameters.getCipherSuites());
+ assertContainsAll("Unsupported enabled protocols", supportedParameters.getProtocols(),
+ defaultParameters.getProtocols());
+ assertSSLSocketFactoryConfigSameAsSSLContext(sslContext.getSocketFactory(), sslContext);
+ assertSSLServerSocketFactoryConfigSameAsSSLContext(
+ sslContext.getServerSocketFactory(), sslContext);
+ SSLEngine sslEngine = sslContext.createSSLEngine();
+ assertFalse(sslEngine.getUseClientMode());
+ assertSSLEngineConfigSameAsSSLContext(sslEngine, sslContext);
+ }
+ /**
+ * Asserts that the provided {@link SSLSocketFactory} has the expected default configuration and
+ * that {@link SSLSocket} instances created by the factory match the configuration.
+ */
+ public static void assertSSLSocketFactoryDefaultConfiguration(SSLSocketFactory sslSocketFactory)
+ throws Exception {
+ assertSSLSocketFactoryConfigSameAsSSLContext(sslSocketFactory, SSLContext.getDefault());
+ }
+ /**
+ * Asserts that {@link SSLSocketFactory}'s configuration matches {@code SSLContext}'s
+ * configuration, and that {@link SSLSocket} instances obtained from the factory match this
+ * configuration as well.
+ */
+ private static void assertSSLSocketFactoryConfigSameAsSSLContext(
+ SSLSocketFactory sslSocketFactory, SSLContext sslContext) throws IOException {
+ assertCipherSuitesEqual(sslContext.getDefaultSSLParameters().getCipherSuites(),
+ sslSocketFactory.getDefaultCipherSuites());
+ assertCipherSuitesEqual(sslContext.getSupportedSSLParameters().getCipherSuites(),
+ sslSocketFactory.getSupportedCipherSuites());
+ SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket();
+ try {
+ assertTrue(sslSocket.getUseClientMode());
+ assertTrue(sslSocket.getEnableSessionCreation());
+ assertSSLSocketConfigSameAsSSLContext(sslSocket, sslContext);
+ } finally {
+ sslSocket.close();
+ }
+ }
+ /**
+ * Asserts that the provided {@link SSLSocket} has the expected default configuration.
+ */
+ public static void assertSSLSocketDefaultConfiguration(SSLSocket sslSocket) throws Exception {
+ assertTrue(sslSocket.getUseClientMode());
+ assertTrue(sslSocket.getEnableSessionCreation());
+ assertSSLSocketConfigSameAsSSLContext(sslSocket, SSLContext.getDefault());
+ }
+ /**
+ * Asserts that {@link SSLSocket}'s configuration matches {@code SSLContext's} configuration.
+ */
+ private static void assertSSLSocketConfigSameAsSSLContext(
+ SSLSocket sslSocket, SSLContext sslContext) {
+ assertSSLParametersEqual(
+ sslSocket.getSSLParameters(), sslContext.getDefaultSSLParameters());
+ assertCipherSuitesEqual(sslSocket.getEnabledCipherSuites(),
+ sslContext.getDefaultSSLParameters().getCipherSuites());
+ assertProtocolsEqual(sslSocket.getEnabledProtocols(),
+ sslContext.getDefaultSSLParameters().getProtocols());
+ assertCipherSuitesEqual(sslSocket.getSupportedCipherSuites(),
+ sslContext.getSupportedSSLParameters().getCipherSuites());
+ assertProtocolsEqual(sslSocket.getSupportedProtocols(),
+ sslContext.getSupportedSSLParameters().getProtocols());
+ }
+ /**
+ * Asserts that the provided {@link SSLServerSocketFactory} has the expected default
+ * configuration, and that {@link SSLServerSocket} instances created by the factory match the
+ * configuration.
+ */
+ public static void assertSSLServerSocketFactoryDefaultConfiguration(
+ SSLServerSocketFactory sslServerSocketFactory) throws Exception {
+ assertSSLServerSocketFactoryConfigSameAsSSLContext(
+ sslServerSocketFactory, SSLContext.getDefault());
+ }
+ /**
+ * Asserts that {@link SSLServerSocketFactory}'s configuration matches {@code SSLContext}'s
+ * configuration, and that {@link SSLServerSocket} instances obtained from the factory match
+ * this
+ * configuration as well.
+ */
+ private static void assertSSLServerSocketFactoryConfigSameAsSSLContext(
+ SSLServerSocketFactory sslServerSocketFactory, SSLContext sslContext)
+ throws IOException {
+ assertCipherSuitesEqual(sslContext.getDefaultSSLParameters().getCipherSuites(),
+ sslServerSocketFactory.getDefaultCipherSuites());
+ assertCipherSuitesEqual(sslContext.getSupportedSSLParameters().getCipherSuites(),
+ sslServerSocketFactory.getSupportedCipherSuites());
+ SSLServerSocket sslServerSocket =
+ (SSLServerSocket) sslServerSocketFactory.createServerSocket();
+ try {
+ assertFalse(sslServerSocket.getUseClientMode());
+ assertTrue(sslServerSocket.getEnableSessionCreation());
+ assertSSLServerSocketConfigSameAsSSLContext(sslServerSocket, sslContext);
+ } finally {
+ sslServerSocket.close();
+ }
+ }
+ /**
+ * Asserts that the provided {@link SSLServerSocket} has the expected default configuration.
+ */
+ public static void assertSSLServerSocketDefaultConfiguration(SSLServerSocket sslServerSocket)
+ throws Exception {
+ assertFalse(sslServerSocket.getUseClientMode());
+ assertTrue(sslServerSocket.getEnableSessionCreation());
+ assertSSLServerSocketConfigSameAsSSLContext(sslServerSocket, SSLContext.getDefault());
+ // TODO: Check SSLParameters when supported by SSLServerSocket API
+ }
+ /**
+ * Asserts that {@link SSLServerSocket}'s configuration matches {@code SSLContext's}
+ * configuration.
+ */
+ private static void assertSSLServerSocketConfigSameAsSSLContext(
+ SSLServerSocket sslServerSocket, SSLContext sslContext) {
+ assertCipherSuitesEqual(sslServerSocket.getEnabledCipherSuites(),
+ sslContext.getDefaultSSLParameters().getCipherSuites());
+ assertProtocolsEqual(sslServerSocket.getEnabledProtocols(),
+ sslContext.getDefaultSSLParameters().getProtocols());
+ assertCipherSuitesEqual(sslServerSocket.getSupportedCipherSuites(),
+ sslContext.getSupportedSSLParameters().getCipherSuites());
+ assertProtocolsEqual(sslServerSocket.getSupportedProtocols(),
+ sslContext.getSupportedSSLParameters().getProtocols());
+ assertEquals(sslServerSocket.getNeedClientAuth(),
+ sslContext.getDefaultSSLParameters().getNeedClientAuth());
+ assertEquals(sslServerSocket.getWantClientAuth(),
+ sslContext.getDefaultSSLParameters().getWantClientAuth());
+ }
+ /**
+ * Asserts that the provided {@link SSLEngine} has the expected default configuration.
+ */
+ public static void assertSSLEngineDefaultConfiguration(SSLEngine sslEngine) throws Exception {
+ assertFalse(sslEngine.getUseClientMode());
+ assertTrue(sslEngine.getEnableSessionCreation());
+ assertSSLEngineConfigSameAsSSLContext(sslEngine, SSLContext.getDefault());
+ }
+ /**
+ * Asserts that {@link SSLEngine}'s configuration matches {@code SSLContext's} configuration.
+ */
+ private static void assertSSLEngineConfigSameAsSSLContext(
+ SSLEngine sslEngine, SSLContext sslContext) {
+ assertSSLParametersEqual(
+ sslEngine.getSSLParameters(), sslContext.getDefaultSSLParameters());
+ assertCipherSuitesEqual(sslEngine.getEnabledCipherSuites(),
+ sslContext.getDefaultSSLParameters().getCipherSuites());
+ assertProtocolsEqual(sslEngine.getEnabledProtocols(),
+ sslContext.getDefaultSSLParameters().getProtocols());
+ assertCipherSuitesEqual(sslEngine.getSupportedCipherSuites(),
+ sslContext.getSupportedSSLParameters().getCipherSuites());
+ assertProtocolsEqual(sslEngine.getSupportedProtocols(),
+ sslContext.getSupportedSSLParameters().getProtocols());
+ }
+ private static void assertSSLParametersEqual(SSLParameters expected, SSLParameters actual) {
+ assertCipherSuitesEqual(expected.getCipherSuites(), actual.getCipherSuites());
+ assertProtocolsEqual(expected.getProtocols(), actual.getProtocols());
+ assertEquals(expected.getNeedClientAuth(), actual.getNeedClientAuth());
+ assertEquals(expected.getWantClientAuth(), actual.getWantClientAuth());
+ }
+ private static void assertCipherSuitesEqual(String[] expected, String[] actual) {
+ assertEquals(Arrays.asList(expected), Arrays.asList(actual));
+ }
+ private static void assertProtocolsEqual(String[] expected, String[] actual) {
+ // IMPLEMENTATION NOTE: The order of protocols versions does not matter. Similarly, it only
+ // matters whether a protocol version is present or absent in the array. These arrays are
+ // supposed to represent sets of protocol versions. Thus, we treat them as such.
+ assertEquals(new HashSet<String>(Arrays.asList(expected)),
+ new HashSet<String>(Arrays.asList(actual)));
+ }
+ /**
+ * Asserts that the {@code container} contains all the {@code elements}.
+ */
+ private static void assertContainsAll(String message, String[] container, String[] elements) {
+ Set<String> elementsNotInContainer = new HashSet<String>(Arrays.asList(elements));
+ elementsNotInContainer.removeAll(Arrays.asList(container));
+ assertEquals(message, Collections.EMPTY_SET, elementsNotInContainer);
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestHostnameVerifier.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestHostnameVerifier.java
new file mode 100644
index 0000000..b2d5552
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestHostnameVerifier.java
@@ -0,0 +1,58 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt.javax.net.ssl;
+
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+
+/**
+ * This class implements the simplest possible HostnameVerifier.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class TestHostnameVerifier implements HostnameVerifier {
+ @Override
+ public boolean verify(String hostname, SSLSession sslSession) {
+ try {
+ return verify(hostname, (X509Certificate) sslSession.getPeerCertificates()[0]);
+ } catch (SSLException e) {
+ return false;
+ }
+ }
+
+ private boolean verify(String hostname, X509Certificate cert) {
+ for (String certHost : getHostnames(cert)) {
+ if (certHost.equals(hostname)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static final int DNS_NAME_TYPE = 2;
+
+ @SuppressWarnings("MixedMutabilityReturnType")
+ private static List<String> getHostnames(X509Certificate cert) {
+ List<String> result = new ArrayList<String>();
+ try {
+ Collection<List<?>> altNamePairs = cert.getSubjectAlternativeNames();
+ if (altNamePairs != null) {
+ for (List<?> altNamePair : altNamePairs) {
+ // altNames are returned as effectively Pair<Integer, String> instances,
+ // where the first member is the type of altName and the second is the name.
+ if (altNamePair.get(0).equals(DNS_NAME_TYPE)) {
+ result.add((String) altNamePair.get(1));
+ }
+ }
+ }
+ return result;
+ } catch (CertificateParsingException e) {
+ return Collections.emptyList();
+ }
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestKeyManager.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestKeyManager.java
new file mode 100644
index 0000000..10e2266
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestKeyManager.java
@@ -0,0 +1,213 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import java.io.PrintStream;
+import java.net.Socket;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.X509ExtendedKeyManager;
+import com.android.org.conscrypt.java.security.StandardNames;
+import com.android.org.conscrypt.testing.NullPrintStream;
+
+/**
+ * TestKeyManager is a simple proxy class that wraps an existing
+ * X509ExtendedKeyManager to provide debug logging and recording of
+ * values.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class TestKeyManager extends X509ExtendedKeyManager {
+ private static final boolean LOG = false;
+ private static final PrintStream out = LOG ? System.out : new NullPrintStream();
+
+ private final X509ExtendedKeyManager keyManager;
+
+ public static KeyManager[] wrap(KeyManager[] keyManagers) {
+ KeyManager[] result = keyManagers.clone();
+ for (int i = 0; i < result.length; i++) {
+ result[i] = wrap(result[i]);
+ }
+ return result;
+ }
+
+ public static KeyManager wrap(KeyManager keyManager) {
+ if (!(keyManager instanceof X509ExtendedKeyManager)) {
+ return keyManager;
+ }
+ return new TestKeyManager((X509ExtendedKeyManager) keyManager);
+ }
+
+ public TestKeyManager(X509ExtendedKeyManager keyManager) {
+ out.println("TestKeyManager.<init> keyManager=" + keyManager);
+ this.keyManager = keyManager;
+ }
+
+ @Override
+ public String chooseClientAlias(String[] keyTypes, Principal[] issuers, Socket socket) {
+ out.print("TestKeyManager.chooseClientAlias");
+ out.print(" | keyTypes: ");
+ for (String keyType : keyTypes) {
+ out.print(keyType);
+ out.print(' ');
+ }
+ dumpIssuers(issuers);
+ dumpSocket(socket);
+ assertKeyTypes(keyTypes);
+ return dumpAlias(keyManager.chooseClientAlias(keyTypes, issuers, socket));
+ }
+
+ private void assertKeyTypes(String[] keyTypes) {
+ for (String keyType : keyTypes) {
+ assertKeyType(keyType);
+ }
+ }
+
+ private void assertKeyType(String keyType) {
+ if (!StandardNames.KEY_TYPES.contains(keyType)) {
+ throw new AssertionError("Unexpected key type " + keyType);
+ }
+ }
+
+ @Override
+ public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
+ out.print("TestKeyManager.chooseServerAlias");
+ out.print(" | keyType: ");
+ out.print(keyType);
+ out.print(' ');
+ dumpIssuers(issuers);
+ dumpSocket(socket);
+ assertKeyType(keyType);
+ return dumpAlias(keyManager.chooseServerAlias(keyType, issuers, socket));
+ }
+
+ private void dumpSocket(Socket socket) {
+ out.print(" | socket: ");
+ out.print(String.valueOf(socket));
+ }
+
+ private void dumpIssuers(Principal[] issuers) {
+ out.print(" | issuers: ");
+ if (issuers == null) {
+ out.print("null");
+ return;
+ }
+ for (Principal issuer : issuers) {
+ out.print(issuer);
+ out.print(' ');
+ }
+ }
+
+ private String dumpAlias(String alias) {
+ out.print(" => ");
+ out.println(alias);
+ return alias;
+ }
+
+ @Override
+ public X509Certificate[] getCertificateChain(String alias) {
+ out.print("TestKeyManager.getCertificateChain");
+ out.print(" | alias: ");
+ out.print(alias);
+ return dumpCerts(keyManager.getCertificateChain(alias));
+ }
+
+ private X509Certificate[] dumpCerts(X509Certificate[] certs) {
+ out.print(" => ");
+ for (X509Certificate cert : certs) {
+ out.print(cert.getSubjectDN());
+ out.print(' ');
+ }
+ out.println();
+ return certs;
+ }
+
+ @Override
+ public String[] getClientAliases(String keyType, Principal[] issuers) {
+ out.print("TestKeyManager.getClientAliases");
+ out.print(" | keyType: ");
+ out.print(keyType);
+ dumpIssuers(issuers);
+ assertKeyType(keyType);
+ return dumpAliases(keyManager.getClientAliases(keyType, issuers));
+ }
+
+ @Override
+ public String[] getServerAliases(String keyType, Principal[] issuers) {
+ out.print("TestKeyManager.getServerAliases");
+ out.print(" | keyType: ");
+ out.print(keyType);
+ dumpIssuers(issuers);
+ assertKeyType(keyType);
+ return dumpAliases(keyManager.getServerAliases(keyType, issuers));
+ }
+
+ private String[] dumpAliases(String[] aliases) {
+ out.print(" => ");
+ for (String alias : aliases) {
+ out.print(alias);
+ out.print(' ');
+ }
+ out.println();
+ return aliases;
+ }
+
+ @Override
+ public PrivateKey getPrivateKey(String alias) {
+ out.print("TestKeyManager.getPrivateKey");
+ out.print(" | alias: ");
+ out.print(alias);
+ PrivateKey pk = keyManager.getPrivateKey(alias);
+ out.print(" => ");
+ out.println(String.valueOf(pk));
+ return pk;
+ }
+
+ @Override
+ public String chooseEngineClientAlias(String[] keyTypes, Principal[] issuers, SSLEngine e) {
+ out.print("TestKeyManager.chooseEngineClientAlias");
+ out.print(" | keyTypes: ");
+ for (String keyType : keyTypes) {
+ out.print(keyType);
+ out.print(' ');
+ }
+ dumpIssuers(issuers);
+ dumpEngine(e);
+ assertKeyTypes(keyTypes);
+ return dumpAlias(keyManager.chooseEngineClientAlias(keyTypes, issuers, e));
+ }
+
+ @Override
+ public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine e) {
+ out.print("TestKeyManager.chooseEngineServerAlias");
+ out.print(" | keyType: ");
+ out.print(keyType);
+ out.print(' ');
+ dumpIssuers(issuers);
+ dumpEngine(e);
+ assertKeyType(keyType);
+ return dumpAlias(keyManager.chooseEngineServerAlias(keyType, issuers, e));
+ }
+
+ private void dumpEngine(SSLEngine engine) {
+ out.print(" | engine: ");
+ out.print(String.valueOf(engine));
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestSSLContext.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestSSLContext.java
new file mode 100644
index 0000000..84f377b
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestSSLContext.java
@@ -0,0 +1,490 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.security.KeyStore;
+import java.security.Principal;
+import java.security.SecureRandom;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import com.android.org.conscrypt.TestUtils;
+import com.android.org.conscrypt.java.security.TestKeyStore;
+
+/**
+ * TestSSLContext is a convenience class for other tests that
+ * want a canned SSLContext and related state for testing so they
+ * don't have to duplicate the logic.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class TestSSLContext {
+ /**
+ * The Android SSLSocket and SSLServerSocket implementations are
+ * based on a version of OpenSSL which includes support for RFC
+ * 4507 session tickets. When using session tickets, the server
+ * does not need to keep a cache mapping session IDs to SSL
+ * sessions for reuse. Instead, the client presents the server
+ * with a session ticket it received from the server earlier,
+ * which is an SSL session encrypted by the server's secret
+ * key. Since in this case the server does not need to keep a
+ * cache, some tests may find different results depending on
+ * whether or not the session tickets are in use. These tests can
+ * use this function to determine if loopback SSL connections are
+ * expected to use session tickets and conditionalize their
+ * results appropriately.
+ */
+ public static boolean sslServerSocketSupportsSessionTickets() {
+ // Disabled session tickets for better compatability b/2682876
+ // return !IS_RI;
+ return true;
+ }
+ public final KeyStore clientKeyStore;
+ public final char[] clientStorePassword;
+ public final KeyStore serverKeyStore;
+ public final char[] serverStorePassword;
+ public final KeyManager[] clientKeyManagers;
+ public final KeyManager[] serverKeyManagers;
+ public final X509TrustManager clientTrustManager;
+ public final X509TrustManager serverTrustManager;
+ public final SSLContext clientContext;
+ public final SSLContext serverContext;
+ public final SSLServerSocket serverSocket;
+ public final InetAddress host;
+ public final int port;
+ /**
+ * Used for replacing the hostname in an InetSocketAddress object during
+ * serialization.
+ */
+ private static class HostnameRewritingObjectOutputStream extends ObjectOutputStream {
+ private final String hostname;
+ public HostnameRewritingObjectOutputStream(OutputStream out, String hostname)
+ throws IOException {
+ super(out);
+ this.hostname = hostname;
+ }
+ @Override
+ public PutField putFields() throws IOException {
+ return new PutFieldProxy(super.putFields(), hostname);
+ }
+ private static class PutFieldProxy extends ObjectOutputStream.PutField {
+ private final PutField delegate;
+ private final String hostname;
+ public PutFieldProxy(ObjectOutputStream.PutField delegate, String hostname) {
+ this.delegate = delegate;
+ this.hostname = hostname;
+ }
+ @Override
+ public void put(String name, boolean val) {
+ delegate.put(name, val);
+ }
+ @Override
+ public void put(String name, byte val) {
+ delegate.put(name, val);
+ }
+ @Override
+ public void put(String name, char val) {
+ delegate.put(name, val);
+ }
+ @Override
+ public void put(String name, short val) {
+ delegate.put(name, val);
+ }
+ @Override
+ public void put(String name, int val) {
+ delegate.put(name, val);
+ }
+ @Override
+ public void put(String name, long val) {
+ delegate.put(name, val);
+ }
+ @Override
+ public void put(String name, float val) {
+ delegate.put(name, val);
+ }
+ @Override
+ public void put(String name, double val) {
+ delegate.put(name, val);
+ }
+ @Override
+ public void put(String name, Object val) {
+ if ("hostname".equals(name)) {
+ delegate.put(name, hostname);
+ } else {
+ delegate.put(name, val);
+ }
+ }
+ @SuppressWarnings("deprecation")
+ @Override
+ public void write(ObjectOutput out) throws IOException {
+ delegate.write(out);
+ }
+ }
+ }
+ /**
+ * Creates an InetSocketAddress where the hostname points to an arbitrary
+ * hostname, but the address points to the loopback address. Useful for
+ * testing SNI where both "localhost" and IP addresses are not allowed.
+ */
+ public InetSocketAddress getLoopbackAsHostname(String hostname, int port)
+ throws IOException, ClassNotFoundException {
+ InetSocketAddress addr = new InetSocketAddress(TestUtils.getLoopbackAddress(), port);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ HostnameRewritingObjectOutputStream oos =
+ new HostnameRewritingObjectOutputStream(baos, hostname);
+ oos.writeObject(addr);
+ oos.close();
+ ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
+ return (InetSocketAddress) ois.readObject();
+ }
+ private TestSSLContext(KeyStore clientKeyStore, char[] clientStorePassword,
+ KeyStore serverKeyStore, char[] serverStorePassword, KeyManager[] clientKeyManagers,
+ KeyManager[] serverKeyManagers, X509TrustManager clientTrustManager,
+ X509TrustManager serverTrustManager, SSLContext clientContext,
+ SSLContext serverContext, SSLServerSocket serverSocket, InetAddress host, int port) {
+ this.clientKeyStore = clientKeyStore;
+ this.clientStorePassword = clientStorePassword;
+ this.serverKeyStore = serverKeyStore;
+ this.serverStorePassword = serverStorePassword;
+ this.clientKeyManagers = clientKeyManagers;
+ this.serverKeyManagers = serverKeyManagers;
+ this.clientTrustManager = clientTrustManager;
+ this.serverTrustManager = serverTrustManager;
+ this.clientContext = clientContext;
+ this.serverContext = serverContext;
+ this.serverSocket = serverSocket;
+ this.host = host;
+ this.port = port;
+ }
+ public void close() {
+ try {
+ serverSocket.close();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static final class Builder {
+ private TestKeyStore client;
+ private char[] clientStorePassword;
+ private TestKeyStore server;
+ private char[] serverStorePassword;
+ private KeyManager[] additionalClientKeyManagers;
+ private KeyManager[] additionalServerKeyManagers;
+ private TrustManager clientTrustManager;
+ private TrustManager serverTrustManager;
+ private SSLContext clientContext;
+ private SSLContext serverContext;
+ private String clientProtocol = "TLS";
+ private String serverProtocol = "TLS";
+ private int serverReceiveBufferSize;
+ private boolean useDefaults = true;
+
+ public Builder useDefaults(boolean useDefaults) {
+ this.useDefaults = useDefaults;
+ return this;
+ }
+
+ public Builder client(TestKeyStore client) {
+ this.client = client;
+ return this;
+ }
+
+ public Builder clientStorePassword(char[] clientStorePassword) {
+ this.clientStorePassword = clientStorePassword;
+ return this;
+ }
+
+ public Builder server(TestKeyStore server) {
+ this.server = server;
+ return this;
+ }
+
+ public Builder serverStorePassword(char[] serverStorePassword) {
+ this.serverStorePassword = serverStorePassword;
+ return this;
+ }
+
+ public Builder additionalClientKeyManagers(KeyManager[] additionalClientKeyManagers) {
+ this.additionalClientKeyManagers = additionalClientKeyManagers;
+ return this;
+ }
+
+ public Builder additionalServerKeyManagers(KeyManager[] additionalServerKeyManagers) {
+ this.additionalServerKeyManagers = additionalServerKeyManagers;
+ return this;
+ }
+
+ public Builder clientTrustManager(TrustManager clientTrustManager) {
+ this.clientTrustManager = clientTrustManager;
+ return this;
+ }
+
+ public Builder serverTrustManager(TrustManager serverTrustManager) {
+ this.serverTrustManager = serverTrustManager;
+ return this;
+ }
+
+ public Builder clientContext(SSLContext clientContext) {
+ this.clientContext = clientContext;
+ return this;
+ }
+
+ public Builder serverContext(SSLContext serverContext) {
+ this.serverContext = serverContext;
+ return this;
+ }
+
+ public Builder clientProtocol(String clientProtocol) {
+ this.clientProtocol = clientProtocol;
+ return this;
+ }
+
+ public Builder serverProtocol(String serverProtocol) {
+ this.serverProtocol = serverProtocol;
+ return this;
+ }
+
+ public Builder serverReceiveBufferSize(int serverReceiveBufferSize) {
+ this.serverReceiveBufferSize = serverReceiveBufferSize;
+ return this;
+ }
+
+ TestSSLContext build() {
+ // Get the current values for all the things.
+ TestKeyStore client = this.client;
+ TestKeyStore server = this.server;
+ char[] clientStorePassword = this.clientStorePassword;
+ char[] serverStorePassword = this.serverStorePassword;
+ KeyManager[] clientKeyManagers = client != null ? client.keyManagers : null;
+ KeyManager[] serverKeyManagers = server != null ? server.keyManagers : null;
+ TrustManager clientTrustManager = this.clientTrustManager;
+ TrustManager serverTrustManager = this.serverTrustManager;
+ SSLContext clientContext = this.clientContext;
+ SSLContext serverContext = this.serverContext;
+
+ // Apply default values if configured to do so.
+ if (useDefaults) {
+ client = client != null ? client : TestKeyStore.getClient();
+ server = server != null ? server : TestKeyStore.getServer();
+ clientStorePassword =
+ clientStorePassword != null ? clientStorePassword : client.storePassword;
+ serverStorePassword =
+ serverStorePassword != null ? serverStorePassword : server.storePassword;
+ clientKeyManagers =
+ clientKeyManagers != null ? clientKeyManagers : client.keyManagers;
+ serverKeyManagers =
+ serverKeyManagers != null ? serverKeyManagers : server.keyManagers;
+ clientKeyManagers = concat(clientKeyManagers, additionalClientKeyManagers);
+ serverKeyManagers = concat(serverKeyManagers, additionalServerKeyManagers);
+ clientTrustManager =
+ clientTrustManager != null ? clientTrustManager : client.trustManagers[0];
+ serverTrustManager =
+ serverTrustManager != null ? serverTrustManager : server.trustManagers[0];
+
+ clientContext = clientContext != null
+ ? clientContext
+ : createSSLContext(clientProtocol, clientKeyManagers,
+ new TrustManager[] {clientTrustManager});
+ serverContext = serverContext != null
+ ? serverContext
+ : createSSLContext(serverProtocol, serverKeyManagers,
+ new TrustManager[] {serverTrustManager});
+ }
+
+ // Create the context.
+ try {
+ SSLServerSocket serverSocket =
+ (SSLServerSocket) serverContext.getServerSocketFactory()
+ .createServerSocket();
+ if (serverReceiveBufferSize > 0) {
+ // The TCP spec says that this should occur before listen.
+ serverSocket.setReceiveBufferSize(serverReceiveBufferSize);
+ }
+ InetAddress host = TestUtils.getLoopbackAddress();
+ serverSocket.bind(new InetSocketAddress(host, 0));
+ int port = serverSocket.getLocalPort();
+ return new TestSSLContext(client != null ? client.keyStore : null,
+ clientStorePassword, server != null ? server.keyStore : null,
+ serverStorePassword, clientKeyManagers, serverKeyManagers,
+ (X509TrustManager) clientTrustManager,
+ (X509TrustManager) serverTrustManager, clientContext, serverContext,
+ serverSocket, host, port);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Usual TestSSLContext creation method, creates underlying
+ * SSLContext with certificate and key as well as SSLServerSocket
+ * listening provided host and port.
+ */
+ public static TestSSLContext create() {
+ return new Builder().build();
+ }
+
+ /**
+ * TestSSLContext creation method that allows separate creation of server key store
+ */
+ public static TestSSLContext create(TestKeyStore client, TestKeyStore server) {
+ return new Builder().client(client).server(server).build();
+ }
+ /**
+ * Create a SSLContext with a KeyManager using the private key and
+ * certificate chain from the given KeyStore and a TrustManager
+ * using the certificates authorities from the same KeyStore.
+ */
+ public static SSLContext createSSLContext(final String protocol, final KeyManager[] keyManagers,
+ final TrustManager[] trustManagers) {
+ try {
+ SSLContext context = SSLContext.getInstance(protocol);
+ context.init(keyManagers, trustManagers, new SecureRandom());
+ return context;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ public static void assertCertificateInKeyStore(Principal principal, KeyStore keyStore)
+ throws Exception {
+ String subjectName = principal.getName();
+ boolean found = false;
+ for (String alias : Collections.list(keyStore.aliases())) {
+ if (!keyStore.isCertificateEntry(alias)) {
+ continue;
+ }
+ X509Certificate keyStoreCertificate = (X509Certificate) keyStore.getCertificate(alias);
+ if (subjectName.equals(keyStoreCertificate.getSubjectDN().getName())) {
+ found = true;
+ break;
+ }
+ }
+ assertTrue(found);
+ }
+ public static void assertCertificateInKeyStore(Certificate certificate, KeyStore keyStore)
+ throws Exception {
+ boolean found = false;
+ for (String alias : Collections.list(keyStore.aliases())) {
+ if (!keyStore.isCertificateEntry(alias)) {
+ continue;
+ }
+ Certificate keyStoreCertificate = keyStore.getCertificate(alias);
+ if (certificate.equals(keyStoreCertificate)) {
+ found = true;
+ break;
+ }
+ }
+ assertTrue(found);
+ }
+ public static void assertServerCertificateChain(
+ X509TrustManager trustManager, Certificate[] serverChain) throws CertificateException {
+ X509Certificate[] chain = (X509Certificate[]) serverChain;
+ trustManager.checkServerTrusted(chain, chain[0].getPublicKey().getAlgorithm());
+ }
+ public static void assertClientCertificateChain(
+ X509TrustManager trustManager, Certificate[] clientChain) throws CertificateException {
+ X509Certificate[] chain = (X509Certificate[]) clientChain;
+ trustManager.checkClientTrusted(chain, chain[0].getPublicKey().getAlgorithm());
+ }
+ /**
+ * Returns an SSLSocketFactory that calls setWantClientAuth and
+ * setNeedClientAuth as specified on all returned sockets.
+ */
+ public static SSLSocketFactory clientAuth(
+ final SSLSocketFactory sf, final boolean want, final boolean need) {
+ return new SSLSocketFactory() {
+ private SSLSocket set(Socket socket) {
+ SSLSocket s = (SSLSocket) socket;
+ s.setWantClientAuth(want);
+ s.setNeedClientAuth(need);
+ return s;
+ }
+ @Override
+ public Socket createSocket(String host, int port) throws IOException {
+ return set(sf.createSocket(host, port));
+ }
+ @Override
+ public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
+ throws IOException {
+ return set(sf.createSocket(host, port, localHost, localPort));
+ }
+ @Override
+ public Socket createSocket(InetAddress host, int port) throws IOException {
+ return set(sf.createSocket(host, port));
+ }
+ @Override
+ public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
+ int localPort) throws IOException {
+ return set(sf.createSocket(address, port));
+ }
+ @Override
+ public String[] getDefaultCipherSuites() {
+ return sf.getDefaultCipherSuites();
+ }
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return sf.getSupportedCipherSuites();
+ }
+ @Override
+ public Socket createSocket(Socket s, String host, int port, boolean autoClose)
+ throws IOException {
+ return set(sf.createSocket(s, host, port, autoClose));
+ }
+ };
+ }
+ private static KeyManager[] concat(KeyManager[] a, KeyManager[] b) {
+ if ((a == null) || (a.length == 0)) {
+ return b;
+ }
+ if ((b == null) || (b.length == 0)) {
+ return a;
+ }
+ KeyManager[] result = new KeyManager[a.length + b.length];
+ System.arraycopy(a, 0, result, 0, a.length);
+ System.arraycopy(b, 0, result, a.length, b.length);
+ return result;
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestSSLEnginePair.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestSSLEnginePair.java
new file mode 100644
index 0000000..a2906d3
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestSSLEnginePair.java
@@ -0,0 +1,232 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+
+/**
+ * TestSSLEnginePair is a convenience class for other tests that want
+ * a pair of connected and handshaked client and server SSLEngines for
+ * testing.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class TestSSLEnginePair implements Closeable {
+ public final TestSSLContext c;
+ public final SSLEngine server;
+ public final SSLEngine client;
+
+ private TestSSLEnginePair(TestSSLContext c,
+ SSLEngine server,
+ SSLEngine client) {
+ this.c = c;
+ this.server = server;
+ this.client = client;
+ }
+
+ public static TestSSLEnginePair create() throws IOException {
+ return create((Hooks) null);
+ }
+
+ public static TestSSLEnginePair create(TestSSLContext c) throws IOException {
+ return create(c, null);
+ }
+
+ public static TestSSLEnginePair create(Hooks hooks) throws IOException {
+ return create(TestSSLContext.create(), hooks);
+ }
+
+ public static TestSSLEnginePair create(TestSSLContext c, Hooks hooks) throws IOException {
+ return create(c, hooks, null);
+ }
+
+ public static TestSSLEnginePair create(TestSSLContext c, Hooks hooks, boolean[] finished)
+ throws IOException {
+ SSLEngine[] engines = connect(c, hooks, finished);
+ return new TestSSLEnginePair(c, engines[0], engines[1]);
+ }
+
+ public static SSLEngine[] connect(TestSSLContext c, Hooks hooks) throws IOException {
+ return connect(c, hooks, null);
+ }
+
+ /**
+ * Create a new connected server/client engine pair within a
+ * existing SSLContext.
+ */
+ public static SSLEngine[] connect(final TestSSLContext c,
+ Hooks hooks,
+ boolean finished[]) throws IOException {
+ if (hooks == null) {
+ hooks = new Hooks();
+ }
+
+ // FINISHED state should be returned only once.
+ boolean[] clientFinished = new boolean[1];
+ boolean[] serverFinished = new boolean[1];
+
+ SSLSession session = c.clientContext.createSSLEngine().getSession();
+
+ int packetBufferSize = session.getPacketBufferSize();
+ ByteBuffer clientToServer = ByteBuffer.allocate(packetBufferSize);
+ ByteBuffer serverToClient = ByteBuffer.allocate(packetBufferSize);
+
+ int applicationBufferSize = session.getApplicationBufferSize();
+ ByteBuffer scratch = ByteBuffer.allocate(applicationBufferSize);
+
+ SSLEngine client = c.clientContext.createSSLEngine(c.host.getHostName(), c.port);
+ SSLEngine server = c.serverContext.createSSLEngine();
+ client.setUseClientMode(true);
+ server.setUseClientMode(false);
+ hooks.beforeBeginHandshake(client, server);
+ client.beginHandshake();
+ server.beginHandshake();
+
+ while (true) {
+ boolean clientDone = client.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING;
+ boolean serverDone = server.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING;
+ if (clientDone && serverDone) {
+ break;
+ }
+
+ boolean progress =
+ handshakeStep(client, clientToServer, serverToClient, scratch, clientFinished);
+ progress |=
+ handshakeStep(server, serverToClient, clientToServer, scratch, serverFinished);
+ if (!progress) {
+ break;
+ }
+ }
+
+ if (finished != null) {
+ assertEquals(2, finished.length);
+ finished[0] = clientFinished[0];
+ finished[1] = serverFinished[0];
+ }
+ return new SSLEngine[] { server, client };
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class Hooks {
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {}
+ }
+
+ @Override
+ public void close() throws SSLException {
+ close(new SSLEngine[] { client, server });
+ }
+
+ public static void close(SSLEngine[] engines) {
+ try {
+ for (SSLEngine engine : engines) {
+ if (engine != null) {
+ engine.closeInbound();
+ engine.closeOutbound();
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static boolean handshakeStep(SSLEngine engine, ByteBuffer output, ByteBuffer input,
+ ByteBuffer scratch, boolean[] finished) throws IOException {
+ try {
+ // make the other side's output into our input
+ input.flip();
+
+ HandshakeStatus status = engine.getHandshakeStatus();
+ switch (status) {
+
+ case NEED_TASK: {
+ boolean progress = false;
+ while (true) {
+ Runnable runnable = engine.getDelegatedTask();
+ if (runnable == null) {
+ return progress;
+ }
+ runnable.run();
+ progress = true;
+ }
+ }
+
+ case NOT_HANDSHAKING:
+ // If we're not handshaking, our peer might still be. Check if there's
+ // any input for us to consume.
+ case NEED_UNWRAP: {
+ // avoid underflow
+ if (input.remaining() == 0) {
+ return false;
+ }
+ int inputPositionBefore = input.position();
+ SSLEngineResult unwrapResult = engine.unwrap(input, scratch);
+ assertEquals(SSLEngineResult.Status.OK, unwrapResult.getStatus());
+ assertEquals(0, scratch.position());
+ assertEquals(0, unwrapResult.bytesProduced());
+ assertEquals(input.position() - inputPositionBefore, unwrapResult.bytesConsumed());
+ assertFinishedOnce(finished, unwrapResult);
+ return true;
+ }
+
+ case NEED_WRAP: {
+ // avoid possible overflow
+ if (output.remaining() != output.capacity()) {
+ return false;
+ }
+ ByteBuffer emptyByteBuffer = ByteBuffer.allocate(0);
+ int inputPositionBefore = emptyByteBuffer.position();
+ int outputPositionBefore = output.position();
+ SSLEngineResult wrapResult = engine.wrap(emptyByteBuffer, output);
+ assertEquals(SSLEngineResult.Status.OK, wrapResult.getStatus());
+ assertEquals(0, wrapResult.bytesConsumed());
+ assertEquals(inputPositionBefore, emptyByteBuffer.position());
+ assertEquals(output.position() - outputPositionBefore,
+ wrapResult.bytesProduced());
+ assertFinishedOnce(finished, wrapResult);
+ return true;
+ }
+
+ case FINISHED:
+ // only returned by wrap/unrap status, not getHandshakeStatus
+ throw new IllegalStateException("Unexpected HandshakeStatus = " + status);
+ default:
+ throw new IllegalStateException("Unknown HandshakeStatus = " + status);
+ }
+ } finally {
+ // shift consumed input, restore to output mode
+ input.compact();
+ }
+ }
+
+ private static void assertFinishedOnce(boolean[] finishedOut, SSLEngineResult result) {
+ if (result.getHandshakeStatus() == HandshakeStatus.FINISHED) {
+ assertFalse("should only return FINISHED once", finishedOut[0]);
+ finishedOut[0] = true;
+ }
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestSSLSessions.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestSSLSessions.java
new file mode 100644
index 0000000..518d7d3
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestSSLSessions.java
@@ -0,0 +1,79 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+package com.android.org.conscrypt.javax.net.ssl;
+
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+/**
+ * TestSSLSessions is a convenience class for other tests that want
+ * precreated SSLSessions for testing. It contains a connected
+ * client/server pair of SSLSession as well as an invalid SSLSession.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class TestSSLSessions {
+ /**
+ * An invalid session that is not connected
+ */
+ public final SSLSession invalid;
+
+ /**
+ * The server side of a connected session
+ */
+ public final SSLSession server;
+
+ /**
+ * The client side of a connected session
+ */
+ public final SSLSession client;
+
+ /**
+ * The associated SSLSocketTest.Helper that is the source of
+ * the client and server SSLSessions.
+ */
+ public final TestSSLSocketPair s;
+
+ private TestSSLSessions(SSLSession invalid,
+ SSLSession server,
+ SSLSession client,
+ TestSSLSocketPair s) {
+ this.invalid = invalid;
+ this.server = server;
+ this.client = client;
+ this.s = s;
+ }
+
+ public void close() {
+ s.close();
+ }
+
+ public static TestSSLSessions create() {
+ return create(TestSSLContext.create());
+ }
+
+ public static TestSSLSessions create(TestSSLContext context) {
+ try {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ SSLSocket ssl = (SSLSocket) sf.createSocket();
+ SSLSession invalid = ssl.getSession();
+ TestSSLSocketPair s = TestSSLSocketPair.create(context).connect();
+ return new TestSSLSessions(invalid, s.server.getSession(), s.client.getSession(), s);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestSSLSocketPair.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestSSLSocketPair.java
new file mode 100644
index 0000000..f6a3039
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestSSLSocketPair.java
@@ -0,0 +1,161 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+package com.android.org.conscrypt.javax.net.ssl;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import javax.net.ssl.SSLSocket;
+import com.android.org.conscrypt.TestUtils;
+
+/**
+ * TestSSLSocketPair is a convenience class for other tests that want
+ * a pair of connected and handshaked client and server SSLSockets for
+ * testing.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class TestSSLSocketPair {
+ public final TestSSLContext c;
+ public final SSLSocket server;
+ public final SSLSocket client;
+ private TestSSLSocketPair(TestSSLContext c, SSLSocket server, SSLSocket client) {
+ this.c = c;
+ this.server = server;
+ this.client = client;
+ }
+ public void close() {
+ c.close();
+ try {
+ server.close();
+ client.close();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public SSLSocket[] sockets() {
+ return new SSLSocket[] {server, client};
+ }
+
+ public TestSSLSocketPair connect() {
+ return connect(null, null);
+ }
+
+ /**
+ * Create a new connected server/client socket pair within a
+ * existing SSLContext. Optionally specify clientCipherSuites to
+ * allow forcing new SSLSession to test SSLSessionContext
+ * caching. Optionally specify serverCipherSuites for testing
+ * cipher suite negotiation.
+ */
+ public TestSSLSocketPair connect(
+ final String[] clientCipherSuites, final String[] serverCipherSuites) {
+ try {
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ Future<Void> s = executor.submit(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ if (serverCipherSuites != null) {
+ server.setEnabledCipherSuites(serverCipherSuites);
+ }
+ TestUtils.setUseSessionTickets(server, true);
+ server.startHandshake();
+ return null;
+ }
+ });
+ Future<Void> c = executor.submit(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ if (clientCipherSuites != null) {
+ client.setEnabledCipherSuites(clientCipherSuites);
+ }
+ TestUtils.setUseSessionTickets(client, true);
+ client.startHandshake();
+ return null;
+ }
+ });
+ executor.shutdown();
+ // catch client and server exceptions separately so we can
+ // potentially log both.
+ Exception serverException;
+ try {
+ s.get(30, TimeUnit.SECONDS);
+ serverException = null;
+ } catch (Exception e) {
+ serverException = e;
+ e.printStackTrace();
+ }
+ Exception clientException;
+ try {
+ c.get(30, TimeUnit.SECONDS);
+ clientException = null;
+ } catch (Exception e) {
+ clientException = e;
+ e.printStackTrace();
+ }
+ if (serverException != null) {
+ throw serverException;
+ }
+ if (clientException != null) {
+ throw clientException;
+ }
+ // Ensure that messages can actually be passed and that any NewSessionTicket messages
+ // that come after the handshake have been processed.
+ exchangeMessages();
+ return this;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private TestSSLSocketPair exchangeMessages() {
+ try {
+ client.getOutputStream().write('A');
+ assertEquals((int) 'A', server.getInputStream().read());
+ server.getOutputStream().write('B');
+ assertEquals((int) 'B', client.getInputStream().read());
+ return this;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static TestSSLSocketPair create() {
+ return create(TestSSLContext.create());
+ }
+
+ /**
+ * based on test_SSLSocket_startHandshake
+ */
+ public static TestSSLSocketPair create(TestSSLContext context) {
+ try {
+ SSLSocket client = (SSLSocket) context.clientContext.getSocketFactory().createSocket(
+ context.host, context.port);
+ SSLSocket server = (SSLSocket) context.serverSocket.accept();
+ return new TestSSLSocketPair(context, server, client);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestTrustManager.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestTrustManager.java
new file mode 100644
index 0000000..aa3a79b
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestTrustManager.java
@@ -0,0 +1,282 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.javax.net.ssl;
+
+import java.io.PrintStream;
+import java.net.Socket;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509ExtendedTrustManager;
+import javax.net.ssl.X509TrustManager;
+import com.android.org.conscrypt.java.security.StandardNames;
+import com.android.org.conscrypt.testing.NullPrintStream;
+
+/**
+ * TestTrustManager is a simple proxy class that wraps an existing
+ * X509ExtendedTrustManager to provide debug logging and recording of
+ * values.
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class TestTrustManager {
+ private static final boolean LOG = false;
+ private static final PrintStream out = LOG ? System.out : new NullPrintStream();
+ private static final Class<?> EXTENDED_TRUST_MANAGER_CLASS = getExtendedTrustManagerClass();
+
+ public static TrustManager[] wrap(TrustManager[] trustManagers) {
+ TrustManager[] result = trustManagers.clone();
+ for (int i = 0; i < result.length; i++) {
+ result[i] = wrap(result[i]);
+ }
+ return result;
+ }
+
+ public static TrustManager wrap(TrustManager trustManager) {
+ if (EXTENDED_TRUST_MANAGER_CLASS != null && EXTENDED_TRUST_MANAGER_CLASS.isInstance(trustManager)) {
+ return new ExtendedWrapper((X509ExtendedTrustManager) trustManager);
+ } else if (trustManager instanceof X509TrustManager) {
+ return new Wrapper((X509TrustManager) trustManager);
+ }
+ return trustManager;
+ }
+
+ private static Class<?> getExtendedTrustManagerClass() {
+ try {
+ return Class.forName("javax.net.ssl.X509ExtendedTrustManager");
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ }
+
+ private static void assertClientAuthType(String authType) {
+ if (!StandardNames.CLIENT_AUTH_TYPES.contains(authType)) {
+ throw new AssertionError("Unexpected client auth type " + authType);
+ }
+ }
+
+ private static void assertServerAuthType(String authType) {
+ if (!StandardNames.SERVER_AUTH_TYPES.contains(authType)) {
+ throw new AssertionError("Unexpected server auth type " + authType);
+ }
+ }
+
+ private static final class Wrapper implements X509TrustManager {
+ private final X509TrustManager trustManager;
+
+ private Wrapper(X509TrustManager trustManager) {
+ out.println("TestTrustManager.<init> trustManager=" + trustManager);
+ this.trustManager = trustManager;
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ out.print("TestTrustManager.checkClientTrusted "
+ + "chain=" + chain.length + " "
+ + "authType=" + authType + " ");
+ try {
+ assertClientAuthType(authType);
+ trustManager.checkClientTrusted(chain, authType);
+ out.println("OK");
+ } catch (CertificateException e) {
+ e.printStackTrace(out);
+ throw e;
+ }
+ }
+
+
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ out.print("TestTrustManager.checkServerTrusted "
+ + "chain=" + chain.length + " "
+ + "authType=" + authType + " ");
+ try {
+ assertServerAuthType(authType);
+ trustManager.checkServerTrusted(chain, authType);
+ out.println("OK");
+ } catch (CertificateException e) {
+ e.printStackTrace(out);
+ throw e;
+ }
+ }
+
+ /**
+ * Returns the list of certificate issuer authorities which are trusted for
+ * authentication of peers.
+ *
+ * @return the list of certificate issuer authorities which are trusted for
+ * authentication of peers.
+ */
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ X509Certificate[] result = trustManager.getAcceptedIssuers();
+ out.print("TestTrustManager.getAcceptedIssuers result=" + result.length);
+ return result;
+ }
+ }
+
+ private static final class ExtendedWrapper extends X509ExtendedTrustManager {
+ private final X509ExtendedTrustManager extendedTrustManager;
+ private final X509TrustManager trustManager;
+
+ ExtendedWrapper(X509ExtendedTrustManager trustManager) {
+ out.println("TestTrustManager.<init> extendedTrustManager=" + trustManager);
+ this.extendedTrustManager = trustManager;
+ this.trustManager = trustManager;
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ out.print("TestTrustManager.checkClientTrusted "
+ + "chain=" + chain.length + " "
+ + "authType=" + authType + " ");
+ try {
+ assertClientAuthType(authType);
+ trustManager.checkClientTrusted(chain, authType);
+ out.println("OK");
+ } catch (CertificateException e) {
+ e.printStackTrace(out);
+ throw e;
+ }
+ }
+
+
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ out.print("TestTrustManager.checkServerTrusted "
+ + "chain=" + chain.length + " "
+ + "authType=" + authType + " ");
+ try {
+ assertServerAuthType(authType);
+ trustManager.checkServerTrusted(chain, authType);
+ out.println("OK");
+ } catch (CertificateException e) {
+ e.printStackTrace(out);
+ throw e;
+ }
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket)
+ throws CertificateException {
+ if (extendedTrustManager == null) {
+ out.print("(fallback to X509TrustManager) ");
+ checkClientTrusted(chain, authType);
+ return;
+ }
+ out.print("TestTrustManager.checkClientTrusted "
+ + "chain=" + chain.length + " "
+ + "authType=" + authType + " "
+ + "socket=" + socket + " ");
+ try {
+ assertClientAuthType(authType);
+ extendedTrustManager.checkClientTrusted(chain, authType, socket);
+ out.println("OK");
+ } catch (CertificateException e) {
+ e.printStackTrace(out);
+ throw e;
+ }
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
+ throws CertificateException {
+ if (extendedTrustManager == null) {
+ out.print("(fallback to X509TrustManager) ");
+ checkClientTrusted(chain, authType);
+ return;
+ }
+ out.print("TestTrustManager.checkClientTrusted "
+ + "chain=" + chain.length + " "
+ + "authType=" + authType + " "
+ + "engine=" + engine + " ");
+ try {
+ assertClientAuthType(authType);
+ extendedTrustManager.checkClientTrusted(chain, authType, engine);
+ out.println("OK");
+ } catch (CertificateException e) {
+ e.printStackTrace(out);
+ throw e;
+ }
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket)
+ throws CertificateException {
+ if (extendedTrustManager == null) {
+ out.print("(fallback to X509TrustManager) ");
+ checkServerTrusted(chain, authType);
+ return;
+ }
+ out.print("TestTrustManager.checkServerTrusted "
+ + "chain=" + chain.length + " "
+ + "authType=" + authType + " "
+ + "socket=" + socket.toString() + " ");
+ try {
+ assertServerAuthType(authType);
+ extendedTrustManager.checkServerTrusted(chain, authType, socket);
+ out.println("OK");
+ } catch (CertificateException e) {
+ e.printStackTrace(out);
+ throw e;
+ }
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
+ throws CertificateException {
+ if (extendedTrustManager == null) {
+ out.print("(fallback to X509TrustManager) ");
+ checkServerTrusted(chain, authType);
+ return;
+ }
+ out.print("TestTrustManager.checkServerTrusted "
+ + "chain=" + chain.length + " "
+ + "authType=" + authType + " "
+ + "engine=" + engine.toString() + " ");
+ try {
+ assertServerAuthType(authType);
+ extendedTrustManager.checkServerTrusted(chain, authType, engine);
+ out.println("OK");
+ } catch (CertificateException e) {
+ e.printStackTrace(out);
+ throw e;
+ }
+ }
+
+ /**
+ * Returns the list of certificate issuer authorities which are trusted for
+ * authentication of peers.
+ *
+ * @return the list of certificate issuer authorities which are trusted for
+ * authentication of peers.
+ */
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ X509Certificate[] result = trustManager.getAcceptedIssuers();
+ out.print("TestTrustManager.getAcceptedIssuers result=" + result.length);
+ return result;
+ }
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/BrokenProvider.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/BrokenProvider.java
new file mode 100644
index 0000000..ef5f6e9
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/BrokenProvider.java
@@ -0,0 +1,80 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt.testing;
+
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+
+/**
+ * A provider that throws UnsupportedOperationException whenever its features are used.
+ * @hide This class is not part of the Android public SDK API
+ */
+@SuppressWarnings("serial")
+public class BrokenProvider extends Provider {
+ public static final String NAME = "BrokenProvider";
+
+ public BrokenProvider() {
+ super(NAME, 1.0, "A broken provider");
+ put("Signature.NONEwithECDSA", BrokenSignatureSpi.ECDSA.class.getName());
+ }
+
+ private static class BrokenSignatureSpi extends SignatureSpi {
+ BrokenSignatureSpi() {}
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public final static class ECDSA extends BrokenSignatureSpi {
+ public ECDSA() {
+ super();
+ }
+ }
+
+ @Override
+ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
+ throw new UnsupportedOperationException("Nope");
+ }
+
+ @Override
+ protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException {
+ throw new UnsupportedOperationException("Nope");
+ }
+
+ @Override
+ protected void engineUpdate(byte b) throws SignatureException {
+ throw new UnsupportedOperationException("Nope");
+ }
+
+ @Override
+ protected void engineUpdate(byte[] b, int off, int len) throws SignatureException {
+ throw new UnsupportedOperationException("Nope");
+ }
+
+ @Override
+ protected byte[] engineSign() throws SignatureException {
+ throw new UnsupportedOperationException("Nope");
+ }
+
+ @Override
+ protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
+ throw new UnsupportedOperationException("Nope");
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ protected void engineSetParameter(String param, Object value)
+ throws InvalidParameterException {
+ throw new UnsupportedOperationException("Nope");
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ protected Object engineGetParameter(String param) throws InvalidParameterException {
+ throw new UnsupportedOperationException("Nope");
+ }
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/FailingSniMatcher.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/FailingSniMatcher.java
new file mode 100644
index 0000000..591c51a
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/FailingSniMatcher.java
@@ -0,0 +1,23 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt.testing;
+
+import javax.net.ssl.SNIMatcher;
+import javax.net.ssl.SNIServerName;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class FailingSniMatcher extends SNIMatcher {
+ private FailingSniMatcher() {
+ super(0);
+ }
+
+ @Override
+ public boolean matches(SNIServerName sniServerName) {
+ return false;
+ }
+
+ public static SNIMatcher create() {
+ return new FailingSniMatcher();
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/NullPrintStream.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/NullPrintStream.java
new file mode 100644
index 0000000..ca1e70b
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/NullPrintStream.java
@@ -0,0 +1,149 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.testing;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.Locale;
+
+/**
+ * A PrintStream that throws away its output.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class NullPrintStream extends PrintStream {
+ public NullPrintStream() {
+ // super class complains if argument is null
+ super((OutputStream) new ByteArrayOutputStream());
+ }
+
+ @Override
+ public boolean checkError() {
+ return false;
+ }
+
+ @Override
+ protected void clearError() {}
+
+ @Override
+ public void close() {}
+
+ @Override
+ public void flush() {}
+
+ @Override
+ public PrintStream format(String format, Object... args) {
+ return this;
+ }
+
+ @Override
+ public PrintStream format(Locale l, String format, Object... args) {
+ return this;
+ }
+
+ @Override
+ public PrintStream printf(String format, Object... args) {
+ return this;
+ }
+
+ @Override
+ public PrintStream printf(Locale l, String format, Object... args) {
+ return this;
+ }
+
+ @Override
+ public void print(char[] charArray) {}
+
+ @Override
+ public void print(char ch) {}
+
+ @Override
+ public void print(double dnum) {}
+
+ @Override
+ public void print(float fnum) {}
+
+ @Override
+ public void print(int inum) {}
+
+ @Override
+ public void print(long lnum) {}
+
+ @Override
+ public void print(Object obj) {}
+
+ @Override
+ public void print(String str) {}
+
+ @Override
+ public void print(boolean bool) {}
+
+ @Override
+ public void println() {}
+
+ @Override
+ public void println(char[] charArray) {}
+
+ @Override
+ public void println(char ch) {}
+
+ @Override
+ public void println(double dnum) {}
+
+ @Override
+ public void println(float fnum) {}
+
+ @Override
+ public void println(int inum) {}
+
+ @Override
+ public void println(long lnum) {}
+
+ @Override
+ public void println(Object obj) {}
+
+ @Override
+ public void println(String str) {}
+
+ @Override
+ public void println(boolean bool) {}
+
+ @Override
+ protected void setError() {}
+
+ @Override
+ public void write(byte[] buffer, int offset, int length) {}
+
+ @Override
+ public void write(int oneByte) {}
+
+ @Override
+ public PrintStream append(char c) {
+ return this;
+ }
+
+ @Override
+ public PrintStream append(CharSequence csq) {
+ return this;
+ }
+
+ @Override
+ public PrintStream append(CharSequence csq, int start, int end) {
+ return this;
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/OpaqueProvider.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/OpaqueProvider.java
new file mode 100644
index 0000000..7ad4b83
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/OpaqueProvider.java
@@ -0,0 +1,353 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt.testing;
+
+import static org.junit.Assert.fail;
+
+import java.math.BigInteger;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.interfaces.ECKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.RSAKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECParameterSpec;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+import com.android.org.conscrypt.java.security.StandardNames;
+
+/**
+ * A provider that supplies and can use keys whose keying material is hidden from callers.
+ * @hide This class is not part of the Android public SDK API
+ */
+@SuppressWarnings("serial")
+public class OpaqueProvider extends Provider {
+
+ public static final String NAME = "OpaqueProvider";
+
+ public OpaqueProvider() {
+ super(NAME, 1.0, "test provider");
+ put("Signature.NONEwithECDSA", OpaqueSignatureSpi.ECDSA.class.getName());
+ put("Cipher.RSA/ECB/NoPadding", OpaqueCipherSpi.NoPadding.class.getName());
+ put("Cipher.RSA/ECB/PKCS1Padding", OpaqueCipherSpi.PKCS1Padding.class.getName());
+ }
+
+ /**
+ * Returns an opaque key that wraps the given key.
+ */
+ public static PrivateKey wrapKey(PrivateKey key) {
+ if (key instanceof RSAPrivateKey) {
+ return new OpaqueDelegatingRSAPrivateKey((RSAPrivateKey) key);
+ } else if (key instanceof ECPrivateKey) {
+ return new OpaqueDelegatingECPrivateKey((ECPrivateKey) key);
+ } else {
+ fail("Unknown key type: " + key.getClass().getName());
+ return null;
+ }
+ }
+
+ /**
+ * Returns an opaque key that wraps the given key and is additionally marked with the
+ * appropriate FooPrivateKey interface for that key type.
+ */
+ public static PrivateKey wrapKeyMarked(PrivateKey key) {
+ if (key instanceof RSAPrivateKey) {
+ return new OpaqueDelegatingMarkedRSAPrivateKey((RSAPrivateKey) key);
+ } else if (key instanceof ECPrivateKey) {
+ return new OpaqueDelegatingMarkedECPrivateKey((ECPrivateKey) key);
+ } else {
+ fail("Unknown key type: " + key.getClass().getName());
+ return null;
+ }
+ }
+
+ private static class OpaqueSignatureSpi extends SignatureSpi {
+ private final String algorithm;
+ private Signature delegate;
+
+ OpaqueSignatureSpi(String algorithm) {
+ this.algorithm = algorithm;
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public final static class ECDSA extends OpaqueSignatureSpi {
+ public ECDSA() {
+ super("NONEwithECDSA");
+ }
+ }
+
+ @Override
+ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
+ fail("Cannot verify");
+ }
+
+ @Override
+ protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException {
+ DelegatingPrivateKey opaqueKey = (DelegatingPrivateKey) privateKey;
+ try {
+ delegate = Signature.getInstance(algorithm);
+ } catch (NoSuchAlgorithmException e) {
+ throw new InvalidKeyException(e);
+ }
+ delegate.initSign(opaqueKey.getDelegate());
+ }
+
+ @Override
+ protected void engineUpdate(byte b) throws SignatureException {
+ delegate.update(b);
+ }
+
+ @Override
+ protected void engineUpdate(byte[] b, int off, int len) throws SignatureException {
+ delegate.update(b, off, len);
+ }
+
+ @Override
+ protected byte[] engineSign() throws SignatureException {
+ return delegate.sign();
+ }
+
+ @Override
+ protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
+ return delegate.verify(sigBytes);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ protected void engineSetParameter(String param, Object value)
+ throws InvalidParameterException {
+ delegate.setParameter(param, value);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ protected Object engineGetParameter(String param) throws InvalidParameterException {
+ return delegate.getParameter(param);
+ }
+ }
+
+ private static class OpaqueCipherSpi extends CipherSpi {
+ private Cipher delegate;
+ private final String algorithm;
+
+ public OpaqueCipherSpi(String algorithm) {
+ this.algorithm = algorithm;
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public final static class NoPadding extends OpaqueCipherSpi {
+ public NoPadding() {
+ super("RSA/ECB/NoPadding");
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ public final static class PKCS1Padding extends OpaqueCipherSpi {
+ public PKCS1Padding() {
+ super("RSA/ECB/PKCS1Padding");
+ }
+ }
+
+ @Override
+ protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
+ fail();
+ }
+
+ @Override
+ protected void engineSetPadding(String padding) throws NoSuchPaddingException {
+ fail();
+ }
+
+ @Override
+ protected int engineGetBlockSize() {
+ return delegate.getBlockSize();
+ }
+
+ @Override
+ protected int engineGetOutputSize(int inputLen) {
+ return delegate.getOutputSize(inputLen);
+ }
+
+ @Override
+ protected byte[] engineGetIV() {
+ return delegate.getIV();
+ }
+
+ @Override
+ protected AlgorithmParameters engineGetParameters() {
+ return delegate.getParameters();
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, SecureRandom random)
+ throws InvalidKeyException {
+ getCipher();
+ delegate.init(opmode, ((DelegatingPrivateKey) key).getDelegate(), random);
+ }
+
+ void getCipher() throws InvalidKeyException {
+ try {
+ delegate = Cipher.getInstance(algorithm, StandardNames.JSSE_PROVIDER_NAME);
+ } catch (NoSuchAlgorithmException | NoSuchPaddingException | NoSuchProviderException e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
+ @Override
+ protected void engineInit(
+ int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ getCipher();
+ delegate.init(opmode, ((DelegatingPrivateKey) key).getDelegate(), params, random);
+ }
+
+ @Override
+ protected void engineInit(
+ int opmode, Key key, AlgorithmParameters params, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ getCipher();
+ delegate.init(opmode, ((DelegatingPrivateKey) key).getDelegate(), params, random);
+ }
+
+ @Override
+ protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
+ return delegate.update(input, inputOffset, inputLen);
+ }
+
+ @Override
+ protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output,
+ int outputOffset) throws ShortBufferException {
+ return delegate.update(input, inputOffset, inputLen, output, outputOffset);
+ }
+
+ @Override
+ protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException {
+ return delegate.doFinal(input, inputOffset, inputLen);
+ }
+
+ @Override
+ protected int engineDoFinal(
+ byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)
+ throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
+ return delegate.doFinal(input, inputOffset, inputLen, output, outputOffset);
+ }
+ }
+
+ private interface DelegatingPrivateKey { PrivateKey getDelegate(); }
+
+ private static class OpaqueDelegatingECPrivateKey
+ implements ECKey, PrivateKey, DelegatingPrivateKey {
+ private final ECPrivateKey delegate;
+
+ private OpaqueDelegatingECPrivateKey(ECPrivateKey delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public PrivateKey getDelegate() {
+ return delegate;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return delegate.getAlgorithm();
+ }
+
+ @Override
+ public String getFormat() {
+ return null;
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return null;
+ }
+
+ @Override
+ public ECParameterSpec getParams() {
+ return delegate.getParams();
+ }
+ }
+
+ private static class OpaqueDelegatingMarkedECPrivateKey extends OpaqueDelegatingECPrivateKey
+ implements ECPrivateKey {
+ private OpaqueDelegatingMarkedECPrivateKey(ECPrivateKey delegate) {
+ super(delegate);
+ }
+
+ @Override
+ public BigInteger getS() {
+ throw new UnsupportedOperationException("Nope");
+ }
+ }
+
+ private static class OpaqueDelegatingRSAPrivateKey
+ implements RSAKey, PrivateKey, DelegatingPrivateKey {
+
+ private final RSAPrivateKey delegate;
+
+ private OpaqueDelegatingRSAPrivateKey(RSAPrivateKey delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return delegate.getAlgorithm();
+ }
+
+ @Override
+ public String getFormat() {
+ return null;
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return null;
+ }
+
+ @Override
+ public BigInteger getModulus() {
+ return delegate.getModulus();
+ }
+
+ @Override
+ public PrivateKey getDelegate() {
+ return delegate;
+ }
+ }
+
+ private static class OpaqueDelegatingMarkedRSAPrivateKey extends OpaqueDelegatingRSAPrivateKey
+ implements RSAPrivateKey {
+ private OpaqueDelegatingMarkedRSAPrivateKey(RSAPrivateKey delegate) {
+ super(delegate);
+ }
+
+ @Override
+ public BigInteger getPrivateExponent() {
+ throw new UnsupportedOperationException("Nope");
+ }
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/RestrictedAlgorithmConstraints.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/RestrictedAlgorithmConstraints.java
new file mode 100644
index 0000000..5f2cbcb
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/RestrictedAlgorithmConstraints.java
@@ -0,0 +1,30 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt.testing;
+
+import java.security.AlgorithmConstraints;
+import java.security.AlgorithmParameters;
+import java.security.CryptoPrimitive;
+import java.security.Key;
+import java.util.Set;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RestrictedAlgorithmConstraints implements AlgorithmConstraints {
+ @Override
+ public boolean permits(
+ Set<CryptoPrimitive> primitives, String algorithm, AlgorithmParameters parameters) {
+ return false;
+ }
+
+ @Override
+ public boolean permits(Set<CryptoPrimitive> primitives, Key key) {
+ return false;
+ }
+
+ @Override
+ public boolean permits(Set<CryptoPrimitive> primitives, String algorithm, Key key,
+ AlgorithmParameters parameters) {
+ return false;
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/Streams.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/Streams.java
new file mode 100644
index 0000000..9225df1
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/Streams.java
@@ -0,0 +1,69 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.org.conscrypt.testing;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class Streams {
+ private Streams() {}
+
+ /**
+ * Returns a byte[] containing the remainder of 'in', closing it when done.
+ */
+ public static byte[] readFully(InputStream in) throws IOException {
+ try {
+ return readFullyNoClose(in);
+ } finally {
+ in.close();
+ }
+ }
+
+ /**
+ * Returns a byte[] containing the remainder of 'in'.
+ */
+ private static byte[] readFullyNoClose(InputStream in) throws IOException {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int count;
+ while ((count = in.read(buffer)) != -1) {
+ bytes.write(buffer, 0, count);
+ }
+ return bytes.toByteArray();
+ }
+
+ /**
+ * Copies all of the bytes from {@code in} to {@code out}. Neither stream is closed.
+ * Returns the total number of bytes transferred.
+ */
+ public static int copy(InputStream in, OutputStream out) throws IOException {
+ int total = 0;
+ byte[] buffer = new byte[8192];
+ int c;
+ while ((c = in.read(buffer)) != -1) {
+ total += c;
+ out.write(buffer, 0, c);
+ }
+ return total;
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/TlsTester.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/TlsTester.java
new file mode 100644
index 0000000..fc8d802
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/TlsTester.java
@@ -0,0 +1,161 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.conscrypt.tlswire;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.Arrays;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import javax.net.ServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import com.android.org.conscrypt.tlswire.handshake.ClientHello;
+import com.android.org.conscrypt.tlswire.handshake.HandshakeMessage;
+import com.android.org.conscrypt.tlswire.record.TlsProtocols;
+import com.android.org.conscrypt.tlswire.record.TlsRecord;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class TlsTester {
+
+ private TlsTester() {}
+
+ public static ClientHello captureTlsHandshakeClientHello(ExecutorService executor,
+ SSLSocketFactory sslSocketFactory) throws Exception {
+ TlsRecord record = captureTlsHandshakeFirstTlsRecord(executor, sslSocketFactory);
+ return parseClientHello(record);
+ }
+
+ public static ClientHello parseClientHello(byte[] data) throws Exception {
+ return parseClientHello(parseRecord(data));
+ }
+
+ private static ClientHello parseClientHello(TlsRecord record) throws Exception {
+ assertEquals("TLS record type", TlsProtocols.HANDSHAKE, record.type);
+ ByteArrayInputStream fragmentIn = new ByteArrayInputStream(record.fragment);
+ HandshakeMessage handshakeMessage = HandshakeMessage.read(new DataInputStream(fragmentIn));
+ assertEquals(
+ "HandshakeMessage type", HandshakeMessage.TYPE_CLIENT_HELLO, handshakeMessage.type);
+ // Assert that the fragment does not contain any more messages
+ assertEquals(0, fragmentIn.available());
+ return (ClientHello) handshakeMessage;
+ }
+
+ public static TlsRecord captureTlsHandshakeFirstTlsRecord(ExecutorService executor,
+ SSLSocketFactory sslSocketFactory) throws Exception {
+ byte[] firstReceivedChunk = captureTlsHandshakeFirstTransmittedChunkBytes(executor, sslSocketFactory);
+ return parseRecord(firstReceivedChunk);
+ }
+
+ public static TlsRecord parseRecord(byte[] data) throws Exception {
+ ByteArrayInputStream firstReceivedChunkIn = new ByteArrayInputStream(data);
+ TlsRecord record = TlsRecord.read(new DataInputStream(firstReceivedChunkIn));
+ // Assert that the chunk does not contain any more data
+ assertEquals(0, firstReceivedChunkIn.available());
+ return record;
+ }
+
+ @SuppressWarnings("FutureReturnValueIgnored")
+ private static byte[] captureTlsHandshakeFirstTransmittedChunkBytes(
+ ExecutorService executor, final SSLSocketFactory sslSocketFactory) throws Exception {
+ // Since there's no straightforward way to obtain a ClientHello from SSLSocket, this test
+ // does the following:
+ // 1. Creates a listening server socket (a plain one rather than a TLS/SSL one).
+ // 2. Creates a client SSLSocket, which connects to the server socket and initiates the
+ // TLS/SSL handshake.
+ // 3. Makes the server socket accept an incoming connection on the server socket, and reads
+ // the first chunk of data received. This chunk is assumed to be the ClientHello.
+ // NOTE: Steps 2 and 3 run concurrently.
+ ServerSocket listeningSocket = null;
+ // Some Socket operations are not interruptible via Thread.interrupt for some reason. To
+ // work around, we unblock these sockets using Socket.close.
+ final Socket[] sockets = new Socket[2];
+ try {
+ // 1. Create the listening server socket.
+ listeningSocket = ServerSocketFactory.getDefault().createServerSocket(0);
+ final ServerSocket finalListeningSocket = listeningSocket;
+ // 2. (in background) Wait for an incoming connection and read its first chunk.
+ final Future<byte[]>
+ readFirstReceivedChunkFuture = executor.submit(new Callable<byte[]>() {
+ @Override
+ public byte[] call() throws Exception {
+ Socket socket = finalListeningSocket.accept();
+ sockets[1] = socket;
+ try {
+ byte[] buffer = new byte[64 * 1024];
+ int bytesRead = socket.getInputStream().read(buffer);
+ if (bytesRead == -1) {
+ throw new EOFException("Failed to read anything");
+ }
+ return Arrays.copyOf(buffer, bytesRead);
+ } finally {
+ closeQuietly(socket);
+ }
+ }
+ });
+ // 3. Create a client socket, connect it to the server socket, and start the TLS/SSL
+ // handshake.
+ executor.submit(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ Socket client = new Socket();
+ sockets[0] = client;
+ try {
+ client.connect(finalListeningSocket.getLocalSocketAddress());
+ // Initiate the TLS/SSL handshake which is expected to fail as soon as the
+ // server socket receives a ClientHello.
+ try {
+ SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(client,
+ "localhost.localdomain", finalListeningSocket.getLocalPort(),
+ true);
+ sslSocket.startHandshake();
+ fail();
+ return null;
+ } catch (IOException expected) {
+ // Ignored.
+ }
+ return null;
+ } finally {
+ closeQuietly(client);
+ }
+ }
+ });
+ // Wait for the ClientHello to arrive
+ return readFirstReceivedChunkFuture.get(10, TimeUnit.SECONDS);
+ } finally {
+ closeQuietly(listeningSocket);
+ closeQuietly(sockets[0]);
+ closeQuietly(sockets[1]);
+ }
+ }
+
+ private static void closeQuietly(Socket socket) {
+ if (socket != null) {
+ try {
+ socket.close();
+ } catch (IOException ignored) {
+ // Ignored.
+ }
+ }
+ }
+
+ private static void closeQuietly(ServerSocket serverSocket) {
+ if (serverSocket != null) {
+ try {
+ serverSocket.close();
+ } catch (IOException ignored) {
+ // Ignored.
+ }
+ }
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/AlpnHelloExtension.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/AlpnHelloExtension.java
new file mode 100644
index 0000000..f0709ec
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/AlpnHelloExtension.java
@@ -0,0 +1,53 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * 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.
+ */
+package com.android.org.conscrypt.tlswire.handshake;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import com.android.org.conscrypt.tlswire.util.IoUtils;
+
+/**
+ * {@code application_layer_protocol_negotiation} {@link HelloExtension} from RFC 7301 section 3.1.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AlpnHelloExtension extends HelloExtension {
+
+ public List<String> protocols;
+
+ @Override
+ protected void parseData() throws IOException {
+ byte[] alpnListBytes = IoUtils.readTlsVariableLengthByteVector(
+ new DataInputStream(new ByteArrayInputStream(data)), 0xffff);
+ protocols = new ArrayList<String>();
+ DataInputStream alpnList = new DataInputStream(new ByteArrayInputStream(alpnListBytes));
+ while (alpnList.available() > 0) {
+ byte[] alpnValue = IoUtils.readTlsVariableLengthByteVector(alpnList, 0xff);
+ protocols.add(new String(alpnValue, "US-ASCII"));
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("HelloExtension{type: elliptic_curves, protocols: ");
+ sb.append(protocols);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/CipherSuite.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/CipherSuite.java
new file mode 100644
index 0000000..85021e5
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/CipherSuite.java
@@ -0,0 +1,464 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2014 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.
+ */
+package com.android.org.conscrypt.tlswire.handshake;
+import java.util.HashMap;
+import java.util.Map;
+/**
+ * {@code CipherSuite} enum from TLS 1.2 RFC 5246.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CipherSuite {
+ // The list of cipher suites below is based on IANA registry
+ // https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml
+ private static final CipherSuite[] CIPHER_SUITES = new CipherSuite[] {
+ new CipherSuite(0x0000, "TLS_NULL_WITH_NULL_NULL"),
+ new CipherSuite(0x0001, "TLS_RSA_WITH_NULL_MD5", "SSL_RSA_WITH_NULL_MD5"),
+ new CipherSuite(0x0002, "TLS_RSA_WITH_NULL_SHA", "SSL_RSA_WITH_NULL_SHA"),
+ new CipherSuite(
+ 0x0003, "TLS_RSA_EXPORT_WITH_RC4_40_MD5", "SSL_RSA_EXPORT_WITH_RC4_40_MD5"),
+ new CipherSuite(0x0004, "TLS_RSA_WITH_RC4_128_MD5", "SSL_RSA_WITH_RC4_128_MD5"),
+ new CipherSuite(0x0005, "TLS_RSA_WITH_RC4_128_SHA", "SSL_RSA_WITH_RC4_128_SHA"),
+ new CipherSuite(0x0006, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"),
+ new CipherSuite(0x0007, "TLS_RSA_WITH_IDEA_CBC_SHA"),
+ new CipherSuite(0x0008, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA",
+ "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA"),
+ new CipherSuite(0x0009, "TLS_RSA_WITH_DES_CBC_SHA", "SSL_RSA_WITH_DES_CBC_SHA"),
+ new CipherSuite(
+ 0x000a, "TLS_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x000b, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"),
+ new CipherSuite(0x000c, "TLS_DH_DSS_WITH_DES_CBC_SHA"),
+ new CipherSuite(0x000d, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x000e, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"),
+ new CipherSuite(0x000f, "TLS_DH_RSA_WITH_DES_CBC_SHA"),
+ new CipherSuite(0x0010, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x0011, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
+ "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"),
+ new CipherSuite(0x0012, "TLS_DHE_DSS_WITH_DES_CBC_SHA", "SSL_DHE_DSS_WITH_DES_CBC_SHA"),
+ new CipherSuite(0x0013, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
+ "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x0014, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
+ "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"),
+ new CipherSuite(0x0015, "TLS_DHE_RSA_WITH_DES_CBC_SHA", "SSL_DHE_RSA_WITH_DES_CBC_SHA"),
+ new CipherSuite(0x0016, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
+ "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x0017, "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5",
+ "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5"),
+ new CipherSuite(0x0018, "TLS_DH_anon_WITH_RC4_128_MD5", "SSL_DH_anon_WITH_RC4_128_MD5"),
+ new CipherSuite(0x0019, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
+ "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"),
+ new CipherSuite(0x001a, "TLS_DH_anon_WITH_DES_CBC_SHA", "SSL_DH_anon_WITH_DES_CBC_SHA"),
+ new CipherSuite(0x001b, "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA",
+ "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x001e, "TLS_KRB5_WITH_DES_CBC_SHA"),
+ new CipherSuite(0x001f, "TLS_KRB5_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x0020, "TLS_KRB5_WITH_RC4_128_SHA"),
+ new CipherSuite(0x0021, "TLS_KRB5_WITH_IDEA_CBC_SHA"),
+ new CipherSuite(0x0022, "TLS_KRB5_WITH_DES_CBC_MD5"),
+ new CipherSuite(0x0023, "TLS_KRB5_WITH_3DES_EDE_CBC_MD5"),
+ new CipherSuite(0x0024, "TLS_KRB5_WITH_RC4_128_MD5"),
+ new CipherSuite(0x0025, "TLS_KRB5_WITH_IDEA_CBC_MD5"),
+ new CipherSuite(0x0026, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA"),
+ new CipherSuite(0x0027, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA"),
+ new CipherSuite(0x0028, "TLS_KRB5_EXPORT_WITH_RC4_40_SHA"),
+ new CipherSuite(0x0029, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5"),
+ new CipherSuite(0x002a, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5"),
+ new CipherSuite(0x002b, "TLS_KRB5_EXPORT_WITH_RC4_40_MD5"),
+ new CipherSuite(0x002c, "TLS_PSK_WITH_NULL_SHA"),
+ new CipherSuite(0x002d, "TLS_DHE_PSK_WITH_NULL_SHA"),
+ new CipherSuite(0x002e, "TLS_RSA_PSK_WITH_NULL_SHA"),
+ new CipherSuite(0x002f, "TLS_RSA_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0x0030, "TLS_DH_DSS_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0x0031, "TLS_DH_RSA_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0x0032, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0x0033, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0x0034, "TLS_DH_anon_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0x0035, "TLS_RSA_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0x0036, "TLS_DH_DSS_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0x0037, "TLS_DH_RSA_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0x0038, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0x0039, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0x003a, "TLS_DH_anon_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0x003b, "TLS_RSA_WITH_NULL_SHA256"),
+ new CipherSuite(0x003c, "TLS_RSA_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0x003d, "TLS_RSA_WITH_AES_256_CBC_SHA256"),
+ new CipherSuite(0x003e, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0x003f, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0x0040, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0x0041, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA"),
+ new CipherSuite(0x0042, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA"),
+ new CipherSuite(0x0043, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA"),
+ new CipherSuite(0x0044, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA"),
+ new CipherSuite(0x0045, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA"),
+ new CipherSuite(0x0046, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA"),
+ new CipherSuite(0x0060, "TLS_RSA_EXPORT1024_WITH_RC4_56_MD5"),
+ new CipherSuite(0x0061, "TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5"),
+ new CipherSuite(0x0062, "TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA"),
+ new CipherSuite(0x0063, "TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA"),
+ new CipherSuite(0x0064, "TLS_RSA_EXPORT1024_WITH_RC4_56_SHA"),
+ new CipherSuite(0x0065, "TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA"),
+ new CipherSuite(0x0066, "TLS_DHE_DSS_WITH_RC4_128_SHA"),
+ new CipherSuite(0x0067, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0x0068, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"),
+ new CipherSuite(0x0069, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"),
+ new CipherSuite(0x006a, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"),
+ new CipherSuite(0x006b, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"),
+ new CipherSuite(0x006c, "TLS_DH_anon_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0x006d, "TLS_DH_anon_WITH_AES_256_CBC_SHA256"),
+ new CipherSuite(0x0084, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA"),
+ new CipherSuite(0x0085, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA"),
+ new CipherSuite(0x0086, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA"),
+ new CipherSuite(0x0087, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA"),
+ new CipherSuite(0x0088, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA"),
+ new CipherSuite(0x0089, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA"),
+ new CipherSuite(0x008a, "TLS_PSK_WITH_RC4_128_SHA"),
+ new CipherSuite(0x008b, "TLS_PSK_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x008c, "TLS_PSK_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0x008d, "TLS_PSK_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0x008e, "TLS_DHE_PSK_WITH_RC4_128_SHA"),
+ new CipherSuite(0x008f, "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x0090, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0x0091, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0x0092, "TLS_RSA_PSK_WITH_RC4_128_SHA"),
+ new CipherSuite(0x0093, "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x0094, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0x0095, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0x0096, "TLS_RSA_WITH_SEED_CBC_SHA"),
+ new CipherSuite(0x0097, "TLS_DH_DSS_WITH_SEED_CBC_SHA"),
+ new CipherSuite(0x0098, "TLS_DH_RSA_WITH_SEED_CBC_SHA"),
+ new CipherSuite(0x0099, "TLS_DHE_DSS_WITH_SEED_CBC_SHA"),
+ new CipherSuite(0x009a, "TLS_DHE_RSA_WITH_SEED_CBC_SHA"),
+ new CipherSuite(0x009b, "TLS_DH_anon_WITH_SEED_CBC_SHA"),
+ new CipherSuite(0x009c, "TLS_RSA_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0x009d, "TLS_RSA_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0x009e, "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0x009f, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0x00a0, "TLS_DH_RSA_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0x00a1, "TLS_DH_RSA_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0x00a2, "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0x00a3, "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0x00a4, "TLS_DH_DSS_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0x00a5, "TLS_DH_DSS_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0x00a6, "TLS_DH_anon_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0x00a7, "TLS_DH_anon_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0x00a8, "TLS_PSK_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0x00a9, "TLS_PSK_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0x00aa, "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0x00ab, "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0x00ac, "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0x00ad, "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0x00ae, "TLS_PSK_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0x00af, "TLS_PSK_WITH_AES_256_CBC_SHA384"),
+ new CipherSuite(0x00b0, "TLS_PSK_WITH_NULL_SHA256"),
+ new CipherSuite(0x00b1, "TLS_PSK_WITH_NULL_SHA384"),
+ new CipherSuite(0x00b2, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0x00b3, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384"),
+ new CipherSuite(0x00b4, "TLS_DHE_PSK_WITH_NULL_SHA256"),
+ new CipherSuite(0x00b5, "TLS_DHE_PSK_WITH_NULL_SHA384"),
+ new CipherSuite(0x00b6, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0x00b7, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384"),
+ new CipherSuite(0x00b8, "TLS_RSA_PSK_WITH_NULL_SHA256"),
+ new CipherSuite(0x00b9, "TLS_RSA_PSK_WITH_NULL_SHA384"),
+ new CipherSuite(0x00ba, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0x00bb, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0x00bc, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0x00bd, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0x00be, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0x00bf, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0x00c0, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256"),
+ new CipherSuite(0x00c1, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256"),
+ new CipherSuite(0x00c2, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256"),
+ new CipherSuite(0x00c3, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256"),
+ new CipherSuite(0x00c4, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256"),
+ new CipherSuite(0x00c5, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256"),
+ new CipherSuite(0x00ff, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"),
+ new CipherSuite(0x1301, "TLS_AES_128_GCM_SHA256"),
+ new CipherSuite(0x1302, "TLS_AES_256_GCM_SHA384"),
+ new CipherSuite(0x1303, "TLS_CHACHA20_POLY1305_SHA256"),
+ new CipherSuite(0x1304, "TLS_AES_128_CCM_SHA256"),
+ new CipherSuite(0x1305, "TLS_AES_128_CCM_8_SHA256"),
+ new CipherSuite(0x5600, "TLS_FALLBACK_SCSV"),
+ new CipherSuite(0xc001, "TLS_ECDH_ECDSA_WITH_NULL_SHA"),
+ new CipherSuite(0xc002, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA"),
+ new CipherSuite(0xc003, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0xc004, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0xc005, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0xc006, "TLS_ECDHE_ECDSA_WITH_NULL_SHA"),
+ new CipherSuite(0xc007, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"),
+ new CipherSuite(0xc008, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0xc009, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0xc00a, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0xc00b, "TLS_ECDH_RSA_WITH_NULL_SHA"),
+ new CipherSuite(0xc00c, "TLS_ECDH_RSA_WITH_RC4_128_SHA"),
+ new CipherSuite(0xc00d, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0xc00e, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0xc00f, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0xc010, "TLS_ECDHE_RSA_WITH_NULL_SHA"),
+ new CipherSuite(0xc011, "TLS_ECDHE_RSA_WITH_RC4_128_SHA"),
+ new CipherSuite(0xc012, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0xc013, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0xc014, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0xc015, "TLS_ECDH_anon_WITH_NULL_SHA"),
+ new CipherSuite(0xc016, "TLS_ECDH_anon_WITH_RC4_128_SHA"),
+ new CipherSuite(0xc017, "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0xc018, "TLS_ECDH_anon_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0xc019, "TLS_ECDH_anon_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0xc01a, "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0xc01b, "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0xc01c, "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0xc01d, "TLS_SRP_SHA_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0xc01e, "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0xc01f, "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0xc020, "TLS_SRP_SHA_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0xc021, "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0xc022, "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0xc023, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0xc024, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"),
+ new CipherSuite(0xc025, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0xc026, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384"),
+ new CipherSuite(0xc027, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0xc028, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"),
+ new CipherSuite(0xc029, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0xc02a, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384"),
+ new CipherSuite(0xc02b, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0xc02c, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0xc02d, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0xc02e, "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0xc02f, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0xc030, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0xc031, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0xc032, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0xc033, "TLS_ECDHE_PSK_WITH_RC4_128_SHA"),
+ new CipherSuite(0xc034, "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0xc035, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0xc036, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0xc037, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0xc038, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384"),
+ new CipherSuite(0xc039, "TLS_ECDHE_PSK_WITH_NULL_SHA"),
+ new CipherSuite(0xc03a, "TLS_ECDHE_PSK_WITH_NULL_SHA256"),
+ new CipherSuite(0xc03b, "TLS_ECDHE_PSK_WITH_NULL_SHA384"),
+ new CipherSuite(0xc03c, "TLS_RSA_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc03d, "TLS_RSA_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc03e, "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc03f, "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc040, "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc041, "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc042, "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc043, "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc044, "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc045, "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc046, "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc047, "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc048, "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc049, "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc04a, "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc04b, "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc04c, "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc04d, "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc04e, "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc04f, "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc050, "TLS_RSA_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc051, "TLS_RSA_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc052, "TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc053, "TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc054, "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc055, "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc056, "TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc057, "TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc058, "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc059, "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc05a, "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc05b, "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc05c, "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc05d, "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc05e, "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc05f, "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc060, "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc061, "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc062, "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc063, "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc064, "TLS_PSK_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc065, "TLS_PSK_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc066, "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc067, "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc068, "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc069, "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc06a, "TLS_PSK_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc06b, "TLS_PSK_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc06c, "TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc06d, "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc06e, "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc06f, "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc070, "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc071, "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc072, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0xc073, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384"),
+ new CipherSuite(0xc074, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0xc075, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384"),
+ new CipherSuite(0xc076, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0xc077, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384"),
+ new CipherSuite(0xc078, "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0xc079, "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384"),
+ new CipherSuite(0xc07a, "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc07b, "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc07c, "TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc07d, "TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc07e, "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc07f, "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc080, "TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc081, "TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc082, "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc083, "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc084, "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc085, "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc086, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc087, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc088, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc089, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc08a, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc08b, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc08c, "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc08d, "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc08e, "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc08f, "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc090, "TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc091, "TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc092, "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc093, "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc094, "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0xc095, "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384"),
+ new CipherSuite(0xc096, "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0xc097, "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384"),
+ new CipherSuite(0xc098, "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0xc099, "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384"),
+ new CipherSuite(0xc09a, "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0xc09b, "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384"),
+ new CipherSuite(0xc09c, "TLS_RSA_WITH_AES_128_CCM"),
+ new CipherSuite(0xc09d, "TLS_RSA_WITH_AES_256_CCM"),
+ new CipherSuite(0xc09e, "TLS_DHE_RSA_WITH_AES_128_CCM"),
+ new CipherSuite(0xc09f, "TLS_DHE_RSA_WITH_AES_256_CCM"),
+ new CipherSuite(0xc0a0, "TLS_RSA_WITH_AES_128_CCM_8"),
+ new CipherSuite(0xc0a1, "TLS_RSA_WITH_AES_256_CCM_8"),
+ new CipherSuite(0xc0a2, "TLS_DHE_RSA_WITH_AES_128_CCM_8"),
+ new CipherSuite(0xc0a3, "TLS_DHE_RSA_WITH_AES_256_CCM_8"),
+ new CipherSuite(0xc0a4, "TLS_PSK_WITH_AES_128_CCM"),
+ new CipherSuite(0xc0a5, "TLS_PSK_WITH_AES_256_CCM"),
+ new CipherSuite(0xc0a6, "TLS_DHE_PSK_WITH_AES_128_CCM"),
+ new CipherSuite(0xc0a7, "TLS_DHE_PSK_WITH_AES_256_CCM"),
+ new CipherSuite(0xc0a8, "TLS_PSK_WITH_AES_128_CCM_8"),
+ new CipherSuite(0xc0a9, "TLS_PSK_WITH_AES_256_CCM_8"),
+ new CipherSuite(0xc0aa, "TLS_PSK_DHE_WITH_AES_128_CCM_8"),
+ new CipherSuite(0xc0ab, "TLS_PSK_DHE_WITH_AES_256_CCM_8"),
+ new CipherSuite(0xc0ac, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM"),
+ new CipherSuite(0xc0ad, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM"),
+ new CipherSuite(0xc0ae, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8"),
+ new CipherSuite(0xc0af, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8"),
+ new CipherSuite(0xcc13, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_OLD"),
+ new CipherSuite(0xcc14, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_OLD"),
+ new CipherSuite(0xcc15, "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_OLD"),
+ new CipherSuite(0xcca8, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"),
+ new CipherSuite(0xcca9, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"),
+ new CipherSuite(0xccaa, "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256"),
+ new CipherSuite(0xccab, "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256"),
+ new CipherSuite(0xccac, "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256"),
+ new CipherSuite(0xccad, "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256"),
+ new CipherSuite(0xccae, "TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256"),
+ };
+ private static final Map<Integer, CipherSuite> CODE_TO_CIPHER_SUITE;
+ private static final Map<String, CipherSuite> NAME_TO_CIPHER_SUITE;
+ static {
+ Map<Integer, CipherSuite> byCode = new HashMap<Integer, CipherSuite>();
+ Map<String, CipherSuite> byName = new HashMap<String, CipherSuite>();
+ for (CipherSuite cipherSuite : CIPHER_SUITES) {
+ if (byCode.put(cipherSuite.code, cipherSuite) != null) {
+ throw new RuntimeException(
+ "Cipher suite multiply defined: " + Integer.toHexString(cipherSuite.code));
+ }
+ String name = cipherSuite.name;
+ if (byName.put(name, cipherSuite) != null) {
+ throw new RuntimeException(
+ "Cipher suite multiply defined: " + cipherSuite.name);
+ }
+ String androidName = cipherSuite.getAndroidName();
+ if (!name.equals(androidName)) {
+ if (byName.put(androidName, cipherSuite) != null) {
+ throw new RuntimeException(
+ "Cipher suite multiply defined: " + cipherSuite.androidName);
+ }
+ }
+ }
+ CODE_TO_CIPHER_SUITE = byCode;
+ NAME_TO_CIPHER_SUITE = byName;
+ }
+ public final int code;
+ public final String name;
+ private final String androidName;
+ private CipherSuite(int code, String name) {
+ this.code = code;
+ this.name = name;
+ this.androidName = null;
+ }
+ private CipherSuite(int code, String name, String androidName) {
+ this.code = code;
+ this.name = name;
+ this.androidName = androidName;
+ }
+ public static CipherSuite valueOf(String name) {
+ CipherSuite result = NAME_TO_CIPHER_SUITE.get(name);
+ if (result != null) {
+ return result;
+ }
+ throw new IllegalArgumentException("Unknown cipher suite: " + name);
+ }
+ public static CipherSuite valueOf(int code) {
+ CipherSuite result = CODE_TO_CIPHER_SUITE.get(code);
+ if (result != null) {
+ return result;
+ }
+ return new CipherSuite(code, Integer.toHexString(code));
+ }
+ public String getAndroidName() {
+ return (androidName != null) ? androidName : name;
+ }
+ @Override
+ public String toString() {
+ return name;
+ }
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + code;
+ return result;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof CipherSuite)) {
+ return false;
+ }
+ CipherSuite other = (CipherSuite) obj;
+ if (code != other.code) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/ClientHello.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/ClientHello.java
new file mode 100644
index 0000000..55d2575
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/ClientHello.java
@@ -0,0 +1,102 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2014 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.
+ */
+package com.android.org.conscrypt.tlswire.handshake;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import com.android.org.conscrypt.tlswire.util.IoUtils;
+import com.android.org.conscrypt.tlswire.util.TlsProtocolVersion;
+
+/**
+ * {@link ClientHello} {@link HandshakeMessage} from TLS 1.2 RFC 5246.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ClientHello extends HandshakeMessage {
+ public TlsProtocolVersion clientVersion;
+ public byte[] random;
+ public byte[] sessionId;
+ public List<CipherSuite> cipherSuites;
+ public List<CompressionMethod> compressionMethods;
+ /** Extensions or {@code null} for no extensions. */
+ public List<HelloExtension> extensions;
+ @Override
+ protected void parseBody(DataInput in) throws IOException {
+ clientVersion = TlsProtocolVersion.read(in);
+ random = new byte[32];
+ in.readFully(random);
+ sessionId = IoUtils.readTlsVariableLengthByteVector(in, 32);
+ int[] cipherSuiteCodes = IoUtils.readTlsVariableLengthUnsignedShortVector(in, 0xfffe);
+ cipherSuites = new ArrayList<CipherSuite>(cipherSuiteCodes.length);
+ for (int i = 0; i < cipherSuiteCodes.length; i++) {
+ cipherSuites.add(CipherSuite.valueOf(cipherSuiteCodes[i]));
+ }
+ byte[] compressionMethodCodes = IoUtils.readTlsVariableLengthByteVector(in, 0xff);
+ compressionMethods = new ArrayList<CompressionMethod>(compressionMethodCodes.length);
+ for (int i = 0; i < compressionMethodCodes.length; i++) {
+ int code = compressionMethodCodes[i] & 0xff;
+ compressionMethods.add(CompressionMethod.valueOf(code));
+ }
+ int extensionsSectionSize;
+ try {
+ extensionsSectionSize = in.readUnsignedShort();
+ } catch (EOFException e) {
+ // No extensions present
+ extensionsSectionSize = 0;
+ }
+ if (extensionsSectionSize > 0) {
+ extensions = new ArrayList<HelloExtension>();
+ byte[] extensionsBytes = new byte[extensionsSectionSize];
+ in.readFully(extensionsBytes);
+ ByteArrayInputStream extensionsIn = new ByteArrayInputStream(extensionsBytes);
+ DataInput extensionsDataIn = new DataInputStream(extensionsIn);
+ while (extensionsIn.available() > 0) {
+ try {
+ extensions.add(HelloExtension.read(extensionsDataIn));
+ } catch (IOException e) {
+ throw new IOException(
+ "Failed to read HelloExtension #" + (extensions.size() + 1));
+ }
+ }
+ }
+ }
+ public HelloExtension findExtensionByType(int extensionType) {
+ if (extensions == null) {
+ return null;
+ }
+ for (HelloExtension extension : extensions) {
+ if (extension.type == extensionType) {
+ return extension;
+ }
+ }
+ return null;
+ }
+ @Override
+ public String toString() {
+ return "ClientHello{client version: " + clientVersion + ", random: "
+ + new BigInteger(1, random).toString(16) + ", sessionId: "
+ + new BigInteger(1, sessionId).toString(16) + ", cipher suites: " + cipherSuites
+ + ", compression methods: " + compressionMethods
+ + ((extensions != null) ? (", extensions: " + String.valueOf(extensions)) : "")
+ + "}";
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/CompressionMethod.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/CompressionMethod.java
new file mode 100644
index 0000000..666ecff
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/CompressionMethod.java
@@ -0,0 +1,69 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2014 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.
+ */
+package com.android.org.conscrypt.tlswire.handshake;
+/**
+ * {@code CompressionMethod} enum from TLS 1.2 RFC 5246.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CompressionMethod {
+ public static final CompressionMethod NULL = new CompressionMethod(0, "null");
+ public static final CompressionMethod DEFLATE = new CompressionMethod(1, "deflate");
+ public final int type;
+ public final String name;
+ private CompressionMethod(int type, String name) {
+ this.type = type;
+ this.name = name;
+ }
+ public static CompressionMethod valueOf(int type) {
+ switch (type) {
+ case 0:
+ return NULL;
+ case 1:
+ return DEFLATE;
+ default:
+ return new CompressionMethod(type, String.valueOf(type));
+ }
+ }
+ @Override
+ public String toString() {
+ return name;
+ }
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + type;
+ return result;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof CompressionMethod)) {
+ return false;
+ }
+ CompressionMethod other = (CompressionMethod) obj;
+ if (type != other.type) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/EllipticCurve.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/EllipticCurve.java
new file mode 100644
index 0000000..01fc90e
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/EllipticCurve.java
@@ -0,0 +1,79 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2016 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.
+ */
+package com.android.org.conscrypt.tlswire.handshake;
+/**
+ * {@code EllipticCurve} enum from RFC 4492 section 5.1.1. Curves are assigned
+ * via the
+ * <a href="https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8">IANA registry</a>.
+ * @hide This class is not part of the Android public SDK API
+ */
+public enum EllipticCurve {
+ SECT163K1(1, "sect163k1"),
+ SECT163R1(2, "sect163r1"),
+ SECT163R2(3, "sect163r2"),
+ SECT193R1(4, "sect193r1"),
+ SECT193R2(5, "sect193r2"),
+ SECT233K1(6, "sect233k1"),
+ SECT233R1(7, "sect233r1"),
+ SECT239K1(8, "sect239k1"),
+ SECT283K1(9, "sect283k1"),
+ SECT283R1(10, "sect283r1"),
+ SECT409K1(11, "sect409k1"),
+ SECT409R1(12, "sect409r1"),
+ SECT571K1(13, "sect571k1"),
+ SECT571R1(14, "sect571r1"),
+ SECP160K1(15, "secp160k1"),
+ SECP160R1(16, "secp160r1"),
+ SECP160R2(17, "secp160r2"),
+ SECP192K1(18, "secp192k1"),
+ SECP192R1(19, "secp192r1"),
+ SECP224K1(20, "secp224k1"),
+ SECP224R1(21, "secp224r1"),
+ SECP256K1(22, "secp256k1"),
+ SECP256R1(23, "secp256r1"),
+ SECP384R1(24, "secp384r1"),
+ SECP521R1(25, "secp521r1"),
+ BRAINPOOLP256R1(26, "brainpoolP256r1"),
+ BRAINPOOLP384R1(27, "brainpoolP384r1"),
+ BRAINPOOLP521R1(28, "brainpoolP521r1"),
+ X25519(29, "x25519"),
+ X448(30, "x448"),
+ ARBITRARY_PRIME(0xFF01, "arbitrary_explicit_prime_curves"),
+ ARBITRARY_CHAR2(0xFF02, "arbitrary_explicit_char2_curves");
+ public final int identifier;
+ public final String name;
+ private EllipticCurve(int identifier, String name) {
+ this.identifier = identifier;
+ this.name = name;
+ }
+ public static EllipticCurve fromIdentifier(int identifier) {
+ for (EllipticCurve curve : values()) {
+ if (curve.identifier == identifier) {
+ return curve;
+ }
+ }
+ throw new AssertionError("Unknown curve identifier " + identifier);
+ }
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(name);
+ sb.append(" (");
+ sb.append(identifier);
+ sb.append(')');
+ return sb.toString();
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/EllipticCurvesHelloExtension.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/EllipticCurvesHelloExtension.java
new file mode 100644
index 0000000..56dc55d
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/EllipticCurvesHelloExtension.java
@@ -0,0 +1,56 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2016 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.
+ */
+package com.android.org.conscrypt.tlswire.handshake;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import com.android.org.conscrypt.tlswire.util.IoUtils;
+
+/**
+ * {@code elliptic_curves} {@link HelloExtension} from RFC 4492 section 5.1.1.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class EllipticCurvesHelloExtension extends HelloExtension {
+ public List<EllipticCurve> supported;
+ public boolean wellFormed;
+ @Override
+ protected void parseData() throws IOException {
+ byte[] ellipticCurvesListBytes = IoUtils.readTlsVariableLengthByteVector(
+ new DataInputStream(new ByteArrayInputStream(data)), 0xffff);
+ ByteArrayInputStream ellipticCurvesListIn =
+ new ByteArrayInputStream(ellipticCurvesListBytes);
+ DataInputStream in = new DataInputStream(ellipticCurvesListIn);
+ wellFormed = (ellipticCurvesListIn.available() % 2) == 0;
+ supported = new ArrayList<EllipticCurve>(ellipticCurvesListIn.available() / 2);
+ while (ellipticCurvesListIn.available() >= 2) {
+ int curve_id = in.readUnsignedShort();
+ supported.add(EllipticCurve.fromIdentifier(curve_id));
+ }
+ }
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("HelloExtension{type: elliptic_curves, wellFormed: ");
+ sb.append(wellFormed);
+ sb.append(", supported: ");
+ sb.append(supported);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/HandshakeMessage.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/HandshakeMessage.java
new file mode 100644
index 0000000..4e04f2f
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/HandshakeMessage.java
@@ -0,0 +1,60 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2014 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.
+ */
+package com.android.org.conscrypt.tlswire.handshake;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.IOException;
+import com.android.org.conscrypt.tlswire.util.IoUtils;
+
+/**
+ * Handshake Protocol message from TLS 1.2 RFC 5246.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class HandshakeMessage {
+ public static final int TYPE_CLIENT_HELLO = 1;
+ public int type;
+ public byte[] body;
+ /**
+ * Parses the provided TLS record as a handshake message.
+ */
+ public static HandshakeMessage read(DataInput in) throws IOException {
+ int type = in.readUnsignedByte();
+ HandshakeMessage result;
+ switch (type) {
+ case TYPE_CLIENT_HELLO:
+ result = new ClientHello();
+ break;
+ default:
+ result = new HandshakeMessage();
+ break;
+ }
+ result.type = type;
+ int bodyLength = IoUtils.readUnsignedInt24(in);
+ result.body = new byte[bodyLength];
+ in.readFully(result.body);
+ result.parseBody(new DataInputStream(new ByteArrayInputStream(result.body)));
+ return result;
+ }
+ /**
+ * Parses the provided body. The default implementation does nothing.
+ *
+ * @throws IOException if an I/O error occurs.
+ */
+ protected void parseBody(@SuppressWarnings("unused") DataInput in) throws IOException {}
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/HelloExtension.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/HelloExtension.java
new file mode 100644
index 0000000..298bd52
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/HelloExtension.java
@@ -0,0 +1,105 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2014 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.
+ */
+package com.android.org.conscrypt.tlswire.handshake;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.Map;
+import com.android.org.conscrypt.tlswire.util.IoUtils;
+
+/**
+ * {@code HelloExtension} struct from TLS 1.2 RFC 5246.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class HelloExtension {
+ public static final int TYPE_SERVER_NAME = 0;
+ public static final int TYPE_ELLIPTIC_CURVES = 10;
+ public static final int TYPE_APPLICATION_LAYER_PROTOCOL_NEGOTIATION = 16;
+ public static final int TYPE_PADDING = 21;
+ public static final int TYPE_SESSION_TICKET = 35;
+ public static final int TYPE_RENEGOTIATION_INFO = 65281;
+ private static final Map<Integer, String> TYPE_TO_NAME = new HashMap<Integer, String>();
+ static {
+ TYPE_TO_NAME.put(TYPE_SERVER_NAME, "server_name");
+ TYPE_TO_NAME.put(1, "max_fragment_length");
+ TYPE_TO_NAME.put(2, "client_certificate_url");
+ TYPE_TO_NAME.put(3, "trusted_ca_keys");
+ TYPE_TO_NAME.put(4, "truncated_hmac");
+ TYPE_TO_NAME.put(5, "status_request");
+ TYPE_TO_NAME.put(6, "user_mapping");
+ TYPE_TO_NAME.put(7, "client_authz");
+ TYPE_TO_NAME.put(8, "server_authz");
+ TYPE_TO_NAME.put(9, "cert_type");
+ TYPE_TO_NAME.put(TYPE_ELLIPTIC_CURVES, "elliptic_curves");
+ TYPE_TO_NAME.put(11, "ec_point_formats");
+ TYPE_TO_NAME.put(12, "srp");
+ TYPE_TO_NAME.put(13, "signature_algorithms");
+ TYPE_TO_NAME.put(14, "use_srtp");
+ TYPE_TO_NAME.put(15, "heartbeat");
+ TYPE_TO_NAME.put(TYPE_APPLICATION_LAYER_PROTOCOL_NEGOTIATION, "application_layer_protocol_negotiation");
+ TYPE_TO_NAME.put(17, "status_request_v2");
+ TYPE_TO_NAME.put(18, "signed_certificate_timestamp");
+ TYPE_TO_NAME.put(19, "client_certificate_type");
+ TYPE_TO_NAME.put(20, "server_certificate_type");
+ TYPE_TO_NAME.put(TYPE_PADDING, "padding");
+ TYPE_TO_NAME.put(TYPE_SESSION_TICKET, "SessionTicket");
+ TYPE_TO_NAME.put(13172, "next_protocol_negotiation");
+ TYPE_TO_NAME.put(30031, "Channel ID (old)");
+ TYPE_TO_NAME.put(30032, "Channel ID (new)");
+ TYPE_TO_NAME.put(TYPE_RENEGOTIATION_INFO, "renegotiation_info");
+ }
+ public int type;
+ public String name;
+ public byte[] data;
+ public static HelloExtension read(DataInput in) throws IOException {
+ int type = in.readUnsignedShort();
+ HelloExtension result;
+ switch (type) {
+ case TYPE_SERVER_NAME:
+ result = new ServerNameHelloExtension();
+ break;
+ case TYPE_ELLIPTIC_CURVES:
+ result = new EllipticCurvesHelloExtension();
+ break;
+ case TYPE_APPLICATION_LAYER_PROTOCOL_NEGOTIATION:
+ result = new AlpnHelloExtension();
+ break;
+ default:
+ result = new HelloExtension();
+ break;
+ }
+ result.type = type;
+ result.name = TYPE_TO_NAME.get(result.type);
+ if (result.name == null) {
+ result.name = String.valueOf(result.type);
+ }
+ result.data = IoUtils.readTlsVariableLengthByteVector(in, 0xffff);
+ result.parseData();
+ return result;
+ }
+ /**
+ * @throws IOException
+ */
+ protected void parseData() throws IOException {}
+ @Override
+ public String toString() {
+ return "HelloExtension{type: " + name + ", data: " + new BigInteger(1, data).toString(16)
+ + "}";
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/ServerNameHelloExtension.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/ServerNameHelloExtension.java
new file mode 100644
index 0000000..27262db
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/handshake/ServerNameHelloExtension.java
@@ -0,0 +1,54 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2014 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.
+ */
+package com.android.org.conscrypt.tlswire.handshake;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import com.android.org.conscrypt.tlswire.util.IoUtils;
+
+/**
+ * {@code server_name} (SNI) {@link HelloExtension} from TLS 1.2 RFC 5246.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ServerNameHelloExtension extends HelloExtension {
+ private static final int TYPE_HOST_NAME = 0;
+ public List<String> hostnames;
+ @Override
+ protected void parseData() throws IOException {
+ byte[] serverNameListBytes = IoUtils.readTlsVariableLengthByteVector(
+ new DataInputStream(new ByteArrayInputStream(data)), 0xffff);
+ ByteArrayInputStream serverNameListIn = new ByteArrayInputStream(serverNameListBytes);
+ DataInputStream in = new DataInputStream(serverNameListIn);
+ hostnames = new ArrayList<String>();
+ while (serverNameListIn.available() > 0) {
+ int type = in.readUnsignedByte();
+ if (type != TYPE_HOST_NAME) {
+ throw new IOException("Unsupported ServerName type: " + type);
+ }
+ byte[] hostnameBytes = IoUtils.readTlsVariableLengthByteVector(in, 0xffff);
+ String hostname = new String(hostnameBytes, "US-ASCII");
+ hostnames.add(hostname);
+ }
+ }
+ @Override
+ public String toString() {
+ return "HelloExtension{type: server_name, hostnames: " + hostnames + "}";
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/record/TlsProtocols.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/record/TlsProtocols.java
new file mode 100644
index 0000000..a96afd1
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/record/TlsProtocols.java
@@ -0,0 +1,29 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2014 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.
+ */
+package com.android.org.conscrypt.tlswire.record;
+/**
+ * Protocols that can run over the TLS Record Protocol from TLS 1.2 RFC 5246.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class TlsProtocols {
+ public static final int CHANGE_CIPHER_SPEC = 20;
+ public static final int ALERT = 21;
+ public static final int HANDSHAKE = 22;
+ public static final int APPLICATION_DATA = 23;
+ public static final int HEARTBEAT = 24;
+ private TlsProtocols() {}
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/record/TlsRecord.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/record/TlsRecord.java
new file mode 100644
index 0000000..c22bb9b
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/record/TlsRecord.java
@@ -0,0 +1,40 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2014 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.
+ */
+package com.android.org.conscrypt.tlswire.record;
+
+import java.io.DataInput;
+import java.io.IOException;
+import com.android.org.conscrypt.tlswire.util.TlsProtocolVersion;
+
+/**
+ * TLS Record Protocol record from TLS 1.2 RFC 5246.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class TlsRecord {
+ public int type;
+ public TlsProtocolVersion version;
+ public byte[] fragment;
+ public static TlsRecord read(DataInput in) throws IOException {
+ TlsRecord result = new TlsRecord();
+ result.type = in.readUnsignedByte();
+ result.version = TlsProtocolVersion.read(in);
+ int fragmentLength = in.readUnsignedShort();
+ result.fragment = new byte[fragmentLength];
+ in.readFully(result.fragment);
+ return result;
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/util/IoUtils.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/util/IoUtils.java
new file mode 100644
index 0000000..ecbefab
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/util/IoUtils.java
@@ -0,0 +1,56 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2014 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.
+ */
+package com.android.org.conscrypt.tlswire.util;
+import java.io.DataInput;
+import java.io.IOException;
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class IoUtils {
+ public static int readUnsignedInt24(DataInput in) throws IOException {
+ return (in.readUnsignedByte() << 16) | in.readUnsignedShort();
+ }
+ public static byte[] readTlsVariableLengthByteVector(DataInput in, int maxSizeBytes)
+ throws IOException {
+ int sizeBytes = readTlsVariableLengthVectorSizeBytes(in, maxSizeBytes);
+ byte[] result = new byte[sizeBytes];
+ in.readFully(result);
+ return result;
+ }
+ public static int[] readTlsVariableLengthUnsignedShortVector(DataInput in, int maxSizeBytes)
+ throws IOException {
+ int sizeBytes = readTlsVariableLengthVectorSizeBytes(in, maxSizeBytes);
+ int elementCount = sizeBytes / 2;
+ int[] result = new int[elementCount];
+ for (int i = 0; i < elementCount; i++) {
+ result[i] = in.readUnsignedShort();
+ }
+ return result;
+ }
+ private static int readTlsVariableLengthVectorSizeBytes(DataInput in, int maxSizeBytes)
+ throws IOException {
+ if (maxSizeBytes < 0x100) {
+ return in.readUnsignedByte();
+ } else if (maxSizeBytes < 0x10000) {
+ return in.readUnsignedShort();
+ } else if (maxSizeBytes < 0x1000000) {
+ return readUnsignedInt24(in);
+ } else {
+ return in.readInt();
+ }
+ }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/util/TlsProtocolVersion.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/util/TlsProtocolVersion.java
new file mode 100644
index 0000000..f9d44e6
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/tlswire/util/TlsProtocolVersion.java
@@ -0,0 +1,92 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2014 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.
+ */
+package com.android.org.conscrypt.tlswire.util;
+import java.io.DataInput;
+import java.io.IOException;
+/**
+ * {@code ProtovolVersion} struct from TLS 1.2 RFC 5246.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class TlsProtocolVersion {
+ public static final TlsProtocolVersion SSLV3 = new TlsProtocolVersion(3, 0, "SSLv3");
+ public static final TlsProtocolVersion TLSv1_0 = new TlsProtocolVersion(3, 1, "TLSv1.0");
+ public static final TlsProtocolVersion TLSv1_1 = new TlsProtocolVersion(3, 2, "TLSv1.1");
+ public static final TlsProtocolVersion TLSv1_2 = new TlsProtocolVersion(3, 3, "TLSv1.2");
+ public static final TlsProtocolVersion TLSv1_3 = new TlsProtocolVersion(3, 4, "TLSv1.3");
+ public final int major;
+ public final int minor;
+ public final String name;
+ private TlsProtocolVersion(int major, int minor, String name) {
+ this.major = major;
+ this.minor = minor;
+ this.name = name;
+ }
+ public static TlsProtocolVersion valueOf(int major, int minor) {
+ if (major == 3) {
+ switch (minor) {
+ case 0:
+ return SSLV3;
+ case 1:
+ return TLSv1_0;
+ case 2:
+ return TLSv1_1;
+ case 3:
+ return TLSv1_2;
+ case 4:
+ return TLSv1_3;
+ }
+ }
+ return new TlsProtocolVersion(major, minor, major + "." + minor);
+ }
+ public static TlsProtocolVersion read(DataInput in) throws IOException {
+ int major = in.readUnsignedByte();
+ int minor = in.readUnsignedByte();
+ return TlsProtocolVersion.valueOf(major, minor);
+ }
+ @Override
+ public String toString() {
+ return name;
+ }
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + major;
+ result = prime * result + minor;
+ return result;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof TlsProtocolVersion)) {
+ return false;
+ }
+ TlsProtocolVersion other = (TlsProtocolVersion) obj;
+ if (major != other.major) {
+ return false;
+ }
+ if (minor != other.minor) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/repackaged/testing/src/main/java/tests/net/DelegatingSSLSocketFactory.java b/repackaged/testing/src/main/java/tests/net/DelegatingSSLSocketFactory.java
new file mode 100644
index 0000000..f93df76
--- /dev/null
+++ b/repackaged/testing/src/main/java/tests/net/DelegatingSSLSocketFactory.java
@@ -0,0 +1,83 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2014 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.
+ */
+package tests.net;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+/**
+ * {@link SSLSocketFactory} which delegates all invocations to the provided delegate
+ * {@code SSLSocketFactory}.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DelegatingSSLSocketFactory extends SSLSocketFactory {
+ private final SSLSocketFactory mDelegate;
+ public DelegatingSSLSocketFactory(SSLSocketFactory delegate) {
+ this.mDelegate = delegate;
+ }
+ /**
+ * Invoked after obtaining a socket from the delegate and before returning it to the caller.
+ *
+ * <p>The default implementation does nothing.
+ */
+ protected SSLSocket configureSocket(SSLSocket socket) throws IOException {
+ return socket;
+ }
+ @Override
+ public String[] getDefaultCipherSuites() {
+ return mDelegate.getDefaultCipherSuites();
+ }
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return mDelegate.getSupportedCipherSuites();
+ }
+ @Override
+ public Socket createSocket() throws IOException {
+ SSLSocket socket = (SSLSocket) mDelegate.createSocket();
+ return configureSocket(socket);
+ }
+ @Override
+ public Socket createSocket(Socket s, String host, int port, boolean autoClose)
+ throws IOException {
+ SSLSocket socket = (SSLSocket) mDelegate.createSocket(s, host, port, autoClose);
+ return configureSocket(socket);
+ }
+ @Override
+ public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
+ SSLSocket socket = (SSLSocket) mDelegate.createSocket(host, port);
+ return configureSocket(socket);
+ }
+ @Override
+ public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
+ throws IOException, UnknownHostException {
+ SSLSocket socket = (SSLSocket) mDelegate.createSocket(host, port, localHost, localPort);
+ return configureSocket(socket);
+ }
+ @Override
+ public Socket createSocket(InetAddress host, int port) throws IOException {
+ SSLSocket socket = (SSLSocket) mDelegate.createSocket(host, port);
+ return configureSocket(socket);
+ }
+ @Override
+ public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
+ int localPort) throws IOException {
+ SSLSocket socket = (SSLSocket) mDelegate.createSocket(address, port, localAddress, localPort);
+ return configureSocket(socket);
+ }
+}
diff --git a/repackaged/testing/src/main/java/tests/net/DelegatingSocketFactory.java b/repackaged/testing/src/main/java/tests/net/DelegatingSocketFactory.java
new file mode 100644
index 0000000..c412ed4
--- /dev/null
+++ b/repackaged/testing/src/main/java/tests/net/DelegatingSocketFactory.java
@@ -0,0 +1,68 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+package tests.net;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import javax.net.SocketFactory;
+/**
+ * {@link SocketFactory} which delegates all invocations to the provided delegate
+ * {@code SocketFactory}.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DelegatingSocketFactory extends SocketFactory {
+ private final SocketFactory mDelegate;
+ public DelegatingSocketFactory(SocketFactory delegate) {
+ this.mDelegate = delegate;
+ }
+ /**
+ * Invoked after obtaining a socket from the delegate and before returning it to the caller.
+ *
+ * <p>The default implementation does nothing.
+ */
+ protected Socket configureSocket(Socket socket) throws IOException {
+ return socket;
+ }
+ @Override
+ public Socket createSocket() throws IOException {
+ Socket socket = mDelegate.createSocket();
+ return configureSocket(socket);
+ }
+ @Override
+ public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
+ Socket socket = mDelegate.createSocket(host, port);
+ return configureSocket(socket);
+ }
+ @Override
+ public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
+ throws IOException, UnknownHostException {
+ Socket socket = mDelegate.createSocket(host, port, localHost, localPort);
+ return configureSocket(socket);
+ }
+ @Override
+ public Socket createSocket(InetAddress host, int port) throws IOException {
+ Socket socket = mDelegate.createSocket(host, port);
+ return configureSocket(socket);
+ }
+ @Override
+ public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
+ int localPort) throws IOException {
+ Socket socket = mDelegate.createSocket(address, port, localAddress, localPort);
+ return configureSocket(socket);
+ }
+}
diff --git a/repackaged/testing/src/main/java/tests/util/ForEachRunner.java b/repackaged/testing/src/main/java/tests/util/ForEachRunner.java
new file mode 100644
index 0000000..614716d
--- /dev/null
+++ b/repackaged/testing/src/main/java/tests/util/ForEachRunner.java
@@ -0,0 +1,52 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2015 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.
+ */
+package tests.util;
+/**
+ * Runner which executes the provided code under test (via a callback) for each provided input
+ * value.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class ForEachRunner {
+ /**
+ * Callback parameterized with a value.
+ * @hide This class is not part of the Android public SDK API
+ */
+ public interface Callback<T> {
+ /**
+ * Invokes the callback for the provided value.
+ */
+ void run(T value) throws Exception;
+ }
+ private ForEachRunner() {}
+ /**
+ * Invokes the provided callback for each of the provided named values.
+ *
+ * @param namesAndValues named values represented as name-value pairs.
+ *
+ * @param <T> type of value.
+ */
+ public static <T> void runNamed(Callback<T> callback, Iterable<Pair<String, T>> namesAndValues)
+ throws Exception {
+ for (Pair<String, T> nameAndValue : namesAndValues) {
+ try {
+ callback.run(nameAndValue.getSecond());
+ } catch (Throwable e) {
+ throw new Exception("Failed for " + nameAndValue.getFirst() + ": " + e.getMessage(), e);
+ }
+ }
+ }
+}
diff --git a/repackaged/testing/src/main/java/tests/util/Pair.java b/repackaged/testing/src/main/java/tests/util/Pair.java
new file mode 100644
index 0000000..62408d3
--- /dev/null
+++ b/repackaged/testing/src/main/java/tests/util/Pair.java
@@ -0,0 +1,100 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2010 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.
+ */
+package tests.util;
+/**
+ * Pair of typed values.
+ *
+ * <p>Pairs are obtained using {@link #of(Object, Object) of}.
+ *
+ * @param <F> type of the first value.
+ * @param <S> type of the second value.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Pair<F, S> {
+ private final F mFirst;
+ private final S mSecond;
+ private Pair(F first, S second) {
+ mFirst = first;
+ mSecond = second;
+ }
+ /**
+ * Gets the pair consisting of the two provided values.
+ *
+ * @param first first value or {@code null}.
+ * @param second second value or {@code null}.
+ */
+ public static <F, S> Pair<F, S> of(F first, S second) {
+ return new Pair<F, S>(first, second);
+ }
+ /**
+ * Gets the first value from this pair.
+ *
+ * @return value or {@code null}.
+ */
+ public F getFirst() {
+ return mFirst;
+ }
+ /**
+ * Gets the second value from this pair.
+ *
+ * @return value or {@code null}.
+ */
+ public S getSecond() {
+ return mSecond;
+ }
+ @Override
+ public String toString() {
+ return "Pair[" + mFirst + ", " + mSecond + "]";
+ }
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((mFirst == null) ? 0 : mFirst.hashCode());
+ result = prime * result + ((mSecond == null) ? 0 : mSecond.hashCode());
+ return result;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof Pair)) {
+ return false;
+ }
+ @SuppressWarnings("rawtypes")
+ Pair other = (Pair) obj;
+ if (mFirst == null) {
+ if (other.mFirst != null) {
+ return false;
+ }
+ } else if (!mFirst.equals(other.mFirst)) {
+ return false;
+ }
+ if (mSecond == null) {
+ if (other.mSecond != null) {
+ return false;
+ }
+ } else if (!mSecond.equals(other.mSecond)) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/repackaged/testing/src/main/java/tests/util/ServiceTester.java b/repackaged/testing/src/main/java/tests/util/ServiceTester.java
new file mode 100644
index 0000000..f5298b7
--- /dev/null
+++ b/repackaged/testing/src/main/java/tests/util/ServiceTester.java
@@ -0,0 +1,203 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package tests.util;
+
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.security.Provider;
+import java.security.Security;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * A utility for testing all the implementations of a particular service (such as MessageDigest or
+ * KeyGenerator).
+ * <p>
+ * An instance of this class may only be used to run one test.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class ServiceTester {
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface Test {
+ /**
+ * Run the test for the given provider and algorithm. This method should throw an exception
+ * if the test fails or do nothing if it passes.
+ */
+ void test(Provider p, String algorithm) throws Exception;
+ }
+
+ private static final String SEPARATOR = "||";
+ private final String service;
+ private final Set<Provider> providers = new LinkedHashSet<>();
+ private final Set<Provider> skipProviders = new HashSet<>();
+ private final Set<String> algorithms = new LinkedHashSet<>();
+ private final Set<String> skipAlgorithms = new HashSet<>();
+ private final Set<String> skipCombinations = new HashSet<>();
+
+ private ServiceTester(String service) {
+ this.service = service;
+ }
+
+ /**
+ * Create a new ServiceTester for the given service.
+ */
+ public static ServiceTester test(String service) {
+ if (service.equalsIgnoreCase("Cipher")) {
+ // Cipher is complicated because the parameterized transformations mean that you have
+ // to check for a lot of combinations (eg, a test for AES/CBC/NoPadding might be satisfied by
+ // a provider providing AES, AES/CBC, AES//NoPadding, or AES/CBC/NoPadding). We don't
+ // really need it, so we haven't implemented it.
+ throw new IllegalArgumentException("ServiceTester doesn't support Cipher");
+ }
+ return new ServiceTester(service);
+ }
+
+ /**
+ * Specifies the list of providers to test. If this method is called multiple times, the
+ * collections are combined. If this method is never called, this will test all installed
+ * providers.
+ *
+ * @throws IllegalArgumentException if a named provider is not installed
+ */
+ public ServiceTester withProviders(Collection<String> providers) {
+ for (String name : providers) {
+ Provider p = Security.getProvider(name);
+ if (p == null) {
+ throw new IllegalArgumentException("No such provider: " + name);
+ }
+ this.providers.add(p);
+ }
+ return this;
+ }
+
+ /**
+ * Causes the given provider to be omitted from this instance's testing. If the given provider
+ * is not installed, does nothing.
+ */
+ public ServiceTester skipProvider(String provider) {
+ Provider p = Security.getProvider(provider);
+ if (p != null) {
+ skipProviders.add(p);
+ }
+ return this;
+ }
+
+ /**
+ * Specifies the algorithm to test. If this method and/or {@link #withAlgorithms(Collection)}}
+ * are called multiple times, all values are combined. If neither method is called, this will
+ * test all algorithms supported by any tested provider.
+ */
+ public ServiceTester withAlgorithm(String algorithm) {
+ this.algorithms.add(algorithm);
+ return this;
+ }
+
+ /**
+ * Specifies the algorithms to test. If this method and/or {@link #withAlgorithm(String)}}
+ * are called multiple times, all values are combined. If neither method is called, this will
+ * test all algorithms supported by any tested provider.
+ */
+ public ServiceTester withAlgorithms(Collection<String> algorithms) {
+ this.algorithms.addAll(algorithms);
+ return this;
+ }
+
+ /**
+ * Causes the given algorithm to be omitted from this instance's testing. If no tested provider
+ * provides the given algorithm, does nothing.
+ */
+ public ServiceTester skipAlgorithm(String algorithm) {
+ skipAlgorithms.add(algorithm);
+ return this;
+ }
+
+ /**
+ * Causes the given combination of provider and algorithm to be omitted from this instance's
+ * testing. If no tested provider provides the given algorithm, does nothing.
+ */
+ public ServiceTester skipCombination(String provider, String algorithm) {
+ Provider p = Security.getProvider(provider);
+ if (p != null) {
+ skipCombinations.add(makeCombination(provider, algorithm));
+ }
+ return this;
+ }
+
+ /**
+ * Runs the given test against the configured combination of providers and algorithms. Continues
+ * running all combinations even if some fail. If any of the test runs fail, this throws
+ * an exception with the details of the failure(s).
+ */
+ public void run(Test test) {
+ if (providers.isEmpty()) {
+ providers.addAll(Arrays.asList(Security.getProviders()));
+ }
+ providers.removeAll(skipProviders);
+ final ByteArrayOutputStream errBuffer = new ByteArrayOutputStream();
+ PrintStream errors = new PrintStream(errBuffer);
+ for (Provider p : providers) {
+ if (algorithms.isEmpty()) {
+ for (Provider.Service s : p.getServices()) {
+ if (s.getType().equals(service) && !skipAlgorithms.contains(s.getAlgorithm())
+ && !shouldSkipCombination(p.getName(), s.getAlgorithm())) {
+ doTest(test, p, s.getAlgorithm(), errors);
+ }
+ }
+ } else {
+ algorithms.removeAll(skipAlgorithms);
+ for (String algorithm : algorithms) {
+ if (p.getService(service, algorithm) != null
+ && !shouldSkipCombination(p.getName(), algorithm)) {
+ doTest(test, p, algorithm, errors);
+ }
+ }
+ }
+ }
+ errors.flush();
+ if (errBuffer.size() > 0) {
+ fail("Tests failed:\n\n" + errBuffer.toString());
+ }
+ }
+
+ private String makeCombination(String provider, String algorithm) {
+ return provider + SEPARATOR + algorithm;
+ }
+
+ private boolean shouldSkipCombination(String provider, String algorithm) {
+ return skipCombinations.contains(makeCombination(provider, algorithm));
+ }
+
+ private void doTest(Test test, Provider p, String algorithm, PrintStream errors) {
+ try {
+ test.test(p, algorithm);
+ } catch (Exception | AssertionError e) {
+ errors.append("Failure testing " + service + ":" + algorithm + " from provider " + p.getName()
+ + ":\n");
+ e.printStackTrace(errors);
+ }
+ }
+
+}
diff --git a/srcgen/default-constructors.txt b/srcgen/default-constructors.txt
new file mode 100644
index 0000000..70f8a22
--- /dev/null
+++ b/srcgen/default-constructors.txt
@@ -0,0 +1,3 @@
+com.android.org.conscrypt.IvParameters
+com.android.org.conscrypt.OpenSSLRSAKeyFactory
+com.android.org.conscrypt.OpenSSLRSAKeyPairGenerator
diff --git a/srcgen/generate_android_src.sh b/srcgen/generate_android_src.sh
new file mode 100755
index 0000000..fc03064
--- /dev/null
+++ b/srcgen/generate_android_src.sh
@@ -0,0 +1,60 @@
+#!/bin/bash
+# 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.
+
+if [[ -z "${ANDROID_BUILD_TOP}" ]]; then
+ echo "Missing environment variables. Did you run build/envsetup.sh and lunch?" >&2
+ exit 1
+fi
+
+PROJECT_DIR=external/conscrypt
+
+PACKAGE_TRANSFORMATIONS="\
+ org.conscrypt:com.android.org.conscrypt \
+"
+
+MODULE_DIRS="\
+ benchmark-android \
+ benchmark-base \
+ common \
+ openjdk \
+ platform \
+ testing \
+"
+DEFAULT_CONSTRUCTORS_FILE=${CONSCRYPT_DIR}/srcgen/default-constructors.txt
+
+SOURCE_DIRS="\
+ src/main/java \
+ src/test/java \
+"
+
+# Repackage the project's source.
+source ${ANDROID_BUILD_TOP}/tools/currysrc/scripts/repackage-common.sh
+
+# Remove some unused test files:
+rm -fr ${REPACKAGED_DIR}/common/src/test/java/com/android/org/conscrypt/ConscryptSuite.java
+rm -fr ${REPACKAGED_DIR}/common/src/test/java/com/android/org/conscrypt/ConscryptJava7Suite.java
+
+# Remove any leftovers from older directory layout
+rm -fr openjdk-integ-tests ${REPACKAGED_DIR}/openjdk-integ-tests
+
+echo "Reformatting generated code to adhere to format required by the preupload check"
+cd ${PROJECT_DIR}
+CLANG_STABLE_BIN=${ANDROID_BUILD_TOP}/prebuilts/clang/host/linux-x86/clang-stable/bin
+${ANDROID_BUILD_TOP}/tools/repohooks/tools/clang-format.py --fix \
+ --clang-format ${CLANG_STABLE_BIN}/clang-format \
+ --git-clang-format ${CLANG_STABLE_BIN}/git-clang-format \
+ --style file \
+ --working-tree \
+ $(git diff --name-only HEAD | grep -E "^repackaged/")
diff --git a/srcgen/intra-core-api.txt b/srcgen/intra-core-api.txt
new file mode 100644
index 0000000..40392f0
--- /dev/null
+++ b/srcgen/intra-core-api.txt
@@ -0,0 +1,17 @@
+method:com.android.org.conscrypt.OpenSSLMessageDigestJDK$MD5#MD5()
+method:com.android.org.conscrypt.OpenSSLMessageDigestJDK$SHA1#SHA1()
+method:com.android.org.conscrypt.OpenSSLMessageDigestJDK$SHA224#SHA224()
+method:com.android.org.conscrypt.OpenSSLMessageDigestJDK$SHA256#SHA256()
+method:com.android.org.conscrypt.OpenSSLMessageDigestJDK$SHA384#SHA384()
+method:com.android.org.conscrypt.OpenSSLMessageDigestJDK$SHA512#SHA512()
+method:com.android.org.conscrypt.OpenSSLRandom#OpenSSLRandom()
+method:com.android.org.conscrypt.OpenSSLProvider#OpenSSLProvider()
+type:com.android.org.conscrypt.OpenSSLMessageDigestJDK
+type:com.android.org.conscrypt.OpenSSLMessageDigestJDK$MD5
+type:com.android.org.conscrypt.OpenSSLMessageDigestJDK$SHA1
+type:com.android.org.conscrypt.OpenSSLMessageDigestJDK$SHA224
+type:com.android.org.conscrypt.OpenSSLMessageDigestJDK$SHA256
+type:com.android.org.conscrypt.OpenSSLMessageDigestJDK$SHA384
+type:com.android.org.conscrypt.OpenSSLMessageDigestJDK$SHA512
+type:com.android.org.conscrypt.OpenSSLRandom
+type:com.android.org.conscrypt.OpenSSLProvider
diff --git a/srcgen/stable-core-platform-api.txt b/srcgen/stable-core-platform-api.txt
new file mode 100644
index 0000000..c882063
--- /dev/null
+++ b/srcgen/stable-core-platform-api.txt
@@ -0,0 +1,58 @@
+method:com.android.org.conscrypt.ClientSessionContext#setPersistentCache(SSLClientSessionCache)
+method:com.android.org.conscrypt.Conscrypt#getDefaultX509TrustManager()
+method:com.android.org.conscrypt.FileClientSessionCache#usingDirectory(File)
+method:com.android.org.conscrypt.OpenSSLProvider#OpenSSLProvider()
+method:com.android.org.conscrypt.OpenSSLSocketImpl#getAlpnSelectedProtocol()
+method:com.android.org.conscrypt.OpenSSLSocketImpl#getNpnSelectedProtocol()
+method:com.android.org.conscrypt.OpenSSLSocketImpl#setAlpnProtocols(byte[])
+method:com.android.org.conscrypt.OpenSSLSocketImpl#setChannelIdPrivateKey(PrivateKey)
+method:com.android.org.conscrypt.OpenSSLSocketImpl#setHandshakeTimeout(int)
+method:com.android.org.conscrypt.OpenSSLSocketImpl#setHostname(String)
+method:com.android.org.conscrypt.OpenSSLSocketImpl#setNpnProtocols(byte[])
+method:com.android.org.conscrypt.OpenSSLSocketImpl#setSoWriteTimeout(int)
+method:com.android.org.conscrypt.OpenSSLSocketImpl#setUseSessionTickets(boolean)
+method:com.android.org.conscrypt.TrustedCertificateIndex#findAllByIssuerAndSignature(X509Certificate)
+method:com.android.org.conscrypt.TrustedCertificateIndex#findByIssuerAndSignature(X509Certificate)
+method:com.android.org.conscrypt.TrustedCertificateIndex#findBySubjectAndPublicKey(X509Certificate)
+method:com.android.org.conscrypt.TrustedCertificateIndex#index(X509Certificate)
+method:com.android.org.conscrypt.TrustedCertificateIndex#TrustedCertificateIndex()
+method:com.android.org.conscrypt.TrustedCertificateStore#aliases()
+method:com.android.org.conscrypt.TrustedCertificateStore#allSystemAliases()
+method:com.android.org.conscrypt.TrustedCertificateStore#containsAlias(String)
+method:com.android.org.conscrypt.TrustedCertificateStore#deleteCertificateEntry(String)
+method:com.android.org.conscrypt.TrustedCertificateStore#findAllIssuers(X509Certificate)
+method:com.android.org.conscrypt.TrustedCertificateStore#findIssuer(X509Certificate)
+method:com.android.org.conscrypt.TrustedCertificateStore#getCertificateAlias(Certificate)
+method:com.android.org.conscrypt.TrustedCertificateStore#getCertificateAlias(Certificate,boolean)
+method:com.android.org.conscrypt.TrustedCertificateStore#getCertificateChain(X509Certificate)
+method:com.android.org.conscrypt.TrustedCertificateStore#getCertificateFile(File,X509Certificate)
+method:com.android.org.conscrypt.TrustedCertificateStore#getCertificate(String)
+method:com.android.org.conscrypt.TrustedCertificateStore#getCertificate(String,boolean)
+method:com.android.org.conscrypt.TrustedCertificateStore#getCreationDate(String)
+method:com.android.org.conscrypt.TrustedCertificateStore#getTrustAnchor(X509Certificate)
+method:com.android.org.conscrypt.TrustedCertificateStore#installCertificate(X509Certificate)
+method:com.android.org.conscrypt.TrustedCertificateStore#isUserAddedCertificate(X509Certificate)
+method:com.android.org.conscrypt.TrustedCertificateStore#isUser(String)
+method:com.android.org.conscrypt.TrustedCertificateStore#setDefaultUserDirectory(File)
+method:com.android.org.conscrypt.TrustedCertificateStore#TrustedCertificateStore()
+method:com.android.org.conscrypt.TrustedCertificateStore#userAliases()
+method:com.android.org.conscrypt.TrustManagerImpl#checkClientTrusted(X509Certificate[],String)
+method:com.android.org.conscrypt.TrustManagerImpl#checkClientTrusted(X509Certificate[],String,Socket)
+method:com.android.org.conscrypt.TrustManagerImpl#checkClientTrusted(X509Certificate[],String,SSLEngine)
+method:com.android.org.conscrypt.TrustManagerImpl#checkServerTrusted(X509Certificate[],String,String)
+method:com.android.org.conscrypt.TrustManagerImpl#getTrustedChainForServer(X509Certificate[],String,Socket)
+method:com.android.org.conscrypt.TrustManagerImpl#getTrustedChainForServer(X509Certificate[],String,SSLEngine)
+method:com.android.org.conscrypt.TrustManagerImpl#handleTrustStorageUpdate()
+method:com.android.org.conscrypt.TrustManagerImpl#TrustManagerImpl(KeyStore)
+method:com.android.org.conscrypt.TrustManagerImpl#TrustManagerImpl(KeyStore,CertPinManager,ConscryptCertStore)
+type:com.android.org.conscrypt.CertPinManager
+type:com.android.org.conscrypt.ClientSessionContext
+type:com.android.org.conscrypt.Conscrypt
+type:com.android.org.conscrypt.ConscryptCertStore
+type:com.android.org.conscrypt.FileClientSessionCache
+type:com.android.org.conscrypt.OpenSSLProvider
+type:com.android.org.conscrypt.OpenSSLSocketImpl
+type:com.android.org.conscrypt.SSLClientSessionCache
+type:com.android.org.conscrypt.TrustedCertificateIndex
+type:com.android.org.conscrypt.TrustedCertificateStore
+type:com.android.org.conscrypt.TrustManagerImpl
diff --git a/srcgen/unsupported-app-usage.json b/srcgen/unsupported-app-usage.json
new file mode 100644
index 0000000..12935e9
--- /dev/null
+++ b/srcgen/unsupported-app-usage.json
@@ -0,0 +1,412 @@
+// See com.google.currysrc.aosp.Annotations.addUnsupportedAppUsage(Path) method for details on the
+// syntax.
+[
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#getAlpnSelectedProtocol()",
+ "maxTargetSdk": "dalvik.annotation.compat.VersionCodes.Q",
+ "publicAlternatives": "Use {@code javax.net.ssl.SSLSocket#getApplicationProtocol()}."
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#getApplicationProtocols()",
+ "maxTargetSdk": "dalvik.annotation.compat.VersionCodes.Q",
+ "publicAlternatives": "Use {@code javax.net.ssl.SSLParameters#getApplicationProtocols()}."
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#getChannelId()",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#getHostname()",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#getHostnameOrIP()",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#getNpnSelectedProtocol()",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#getSoWriteTimeout()",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setAlpnProtocols(byte[])",
+ "maxTargetSdk": "dalvik.annotation.compat.VersionCodes.Q",
+ "publicAlternatives": "Use {@code javax.net.ssl.SSLParameters#setApplicationProtocols(java.lang.String[])}."
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setAlpnProtocols(String[])",
+ "maxTargetSdk": "dalvik.annotation.compat.VersionCodes.Q",
+ "publicAlternatives": "Use {@code javax.net.ssl.SSLParameters#setApplicationProtocols(java.lang.String[])}."
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setApplicationProtocols(String[])",
+ "maxTargetSdk": "dalvik.annotation.compat.VersionCodes.Q",
+ "publicAlternatives": "Use {@code javax.net.ssl.SSLParameters#setApplicationProtocols(java.lang.String[])}."
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setChannelIdEnabled(boolean)",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setChannelIdPrivateKey(PrivateKey)",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setHandshakeTimeout(int)",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setHostname(String)",
+ "maxTargetSdk": "dalvik.annotation.compat.VersionCodes.Q",
+ "publicAlternatives": "Use {@code javax.net.ssl.SSLParameters#setServerNames}."
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setNpnProtocols(byte[])",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setSoWriteTimeout(int)",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setUseSessionTickets(boolean)",
+ "maxTargetSdk": "dalvik.annotation.compat.VersionCodes.Q",
+ "publicAlternatives": "Use {@link android.net.ssl.SSLSockets#setUseSessionTickets}."
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.ClientSessionContext#getSession(String,int)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.ClientSessionContext#setPersistentCache(SSLClientSessionCache)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.ConscryptEngineSocket#setHostname(String)",
+ "maxTargetSdk": "dalvik.annotation.compat.VersionCodes.Q",
+ "publicAlternatives": "Use {@code javax.net.ssl.SSLParameters#setServerNames}."
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.ConscryptEngineSocket#setUseSessionTickets(boolean)",
+ "maxTargetSdk": "dalvik.annotation.compat.VersionCodes.Q",
+ "publicAlternatives": "Use {@link android.net.ssl.SSLSockets#setUseSessionTickets}."
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.ConscryptFileDescriptorSocket#setHostname(String)",
+ "maxTargetSdk": "dalvik.annotation.compat.VersionCodes.Q",
+ "publicAlternatives": "Use {@code javax.net.ssl.SSLParameters#setServerNames}."
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.ConscryptFileDescriptorSocket#setUseSessionTickets(boolean)",
+ "maxTargetSdk": "dalvik.annotation.compat.VersionCodes.Q",
+ "publicAlternatives": "Use {@link android.net.ssl.SSLSockets#setUseSessionTickets}."
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.FileClientSessionCache$Impl#getSessionData(String,int)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.FileClientSessionCache#usingDirectory(File)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#ASN1_seq_pack_X509(long[])"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#ASN1_seq_unpack_X509_bio(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#ASN1_TIME_to_Calendar(long,Calendar)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#BIO_free_all(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#create_BIO_InputStream(OpenSSLBIOInputStream,boolean)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#create_BIO_OutputStream(OutputStream)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#d2i_PKCS7_bio(long,int)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#d2i_SSL_SESSION(byte[])"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#d2i_X509(byte[])"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#d2i_X509_bio(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#d2i_X509_CRL_bio(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#EC_GROUP_clear_free(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#EC_GROUP_new_by_curve_name(String)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#EC_POINT_clear_free(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#EVP_CIPHER_CTX_new()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#EVP_CIPHER_iv_length(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#EVP_get_cipherbyname(String)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#EVP_get_digestbyname(String)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#EVP_MD_CTX_create()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#EVP_MD_CTX_destroy(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#EVP_MD_size(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#EVP_PKEY_free(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#EVP_PKEY_new_RSA(byte[],byte[],byte[],byte[],byte[],byte[],byte[],byte[])"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#get_X509_REVOKED_ext_oids(long,int)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#get_X509_REVOKED_revocationDate(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#i2d_PKCS7(long[])"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#i2d_SSL_SESSION(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#i2d_X509_REVOKED(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#PEM_read_bio_PKCS7(long,int)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#PEM_read_bio_X509(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#PEM_read_bio_X509_CRL(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#RAND_bytes(byte[])"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#RSA_generate_key_ex(int,byte[])"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#SSL_CTX_new()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#SSL_SESSION_cipher(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#SSL_SESSION_free(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#SSL_SESSION_get_time(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#SSL_SESSION_get_version(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#SSL_SESSION_session_id(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#X509_REVOKED_dup(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#X509_REVOKED_get_ext(long,String)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#X509_REVOKED_get_ext_oid(long,String)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#X509_REVOKED_get_serialNumber(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#X509_REVOKED_print(long,long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.NativeCrypto#X509_supported_extension(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLBIOInputStream#OpenSSLBIOInputStream(InputStream,boolean)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLBIOInputStream#getBioContext()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLBIOInputStream#release()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLContextImpl$TLSv12#TLSv12()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLContextImpl#OpenSSLContextImpl()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLContextImpl#getPreferred()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLKey#OpenSSLKey(long)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLKey#fromPrivateKey(PrivateKey)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLKey#getNativeRef()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLKey#getPublicKey()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLKeyHolder#getOpenSSLKey()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLProvider#OpenSSLProvider()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLRandom#OpenSSLRandom()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketFactoryImpl#OpenSSLSocketFactoryImpl()"
+ },
+ {
+ "@location": "field:com.android.org.conscrypt.OpenSSLSocketFactoryImpl#sslParameters"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#getAlpnSelectedProtocol()",
+ "maxTargetSdk": "dalvik.annotation.compat.VersionCodes.Q",
+ "publicAlternatives": "Use {@code javax.net.ssl.SSLSocket#getApplicationProtocol()}."
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#getChannelId()",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#getHostname()",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#getHostnameOrIP()",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#getNpnSelectedProtocol()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#getSoWriteTimeout()",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#setAlpnProtocols(byte[])",
+ "maxTargetSdk": "dalvik.annotation.compat.VersionCodes.Q",
+ "publicAlternatives": "Use {@code javax.net.ssl.SSLParameters#setApplicationProtocols(java.lang.String[])}."
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#setAlpnProtocols(String[])",
+ "maxTargetSdk": "dalvik.annotation.compat.VersionCodes.Q",
+ "publicAlternatives": "Use {@code javax.net.ssl.SSLParameters#setApplicationProtocols(java.lang.String[])}."
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#setChannelIdEnabled(boolean)",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#setChannelIdPrivateKey(PrivateKey)",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#setHandshakeTimeout(int)",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#setHostname(String)",
+ "maxTargetSdk": "dalvik.annotation.compat.VersionCodes.Q",
+ "publicAlternatives": "Use {@code javax.net.ssl.SSLParameters#setServerNames}."
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#setNpnProtocols(byte[])"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#setSoWriteTimeout(int)",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#setUseSessionTickets(boolean)",
+ "maxTargetSdk": "dalvik.annotation.compat.VersionCodes.Q",
+ "publicAlternatives": "Use {@link android.net.ssl.SSLSockets#setUseSessionTickets}."
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLX509Certificate#fromX509PemInputStream(InputStream)"
+ },
+ {
+ "@location": "field:com.android.org.conscrypt.OpenSSLX509Certificate#mContext"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.SSLParametersImpl#getDefault()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.SSLParametersImpl#getDefaultX509TrustManager()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.SSLParametersImpl#getX509TrustManager()",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.SSLParametersImpl#setEnabledProtocols(String[])",
+ "maxTargetSdk": 30,
+ "trackingBug": 170729553
+ },
+ {
+ "@location": "field:com.android.org.conscrypt.SSLParametersImpl#x509TrustManager"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.TrustedCertificateStore#TrustedCertificateStore()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.TrustedCertificateStore#getCertificateChain(X509Certificate)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.TrustManagerImpl#TrustManagerImpl(KeyStore)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.TrustManagerImpl#checkServerTrusted(X509Certificate[],String,String)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.X509PublicKey#X509PublicKey(String,byte[])"
+ }
+]
diff --git a/test-support/Android.bp b/test-support/Android.bp
new file mode 100644
index 0000000..c122bc6
--- /dev/null
+++ b/test-support/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2020 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.
+
+// Conscrypt test support classes.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "external_conscrypt_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["external_conscrypt_license"],
+}
+
+java_library {
+ name: "conscrypt-support",
+ visibility: [
+ "//cts/tests/libcore/luni",
+ "//external/conscrypt/apex/tests",
+ ],
+ srcs: [
+ "src/java/**/*.java",
+ ],
+ platform_apis: true,
+ libs: ["junit"],
+ static_libs: [
+ "androidx.test.runner",
+ ],
+}
diff --git a/test-support/src/java/org/conscrypt/ConscryptInstrumentationListener.java b/test-support/src/java/org/conscrypt/ConscryptInstrumentationListener.java
new file mode 100644
index 0000000..7b60de9
--- /dev/null
+++ b/test-support/src/java/org/conscrypt/ConscryptInstrumentationListener.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2020 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
+ */
+
+package org.conscrypt;
+
+import android.os.Bundle;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.internal.runner.listener.InstrumentationRunListener;
+import com.android.org.conscrypt.Conscrypt;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.Socket;
+import java.util.Objects;
+import javax.net.ssl.SSLSocketFactory;
+import org.junit.runner.Description;
+import org.junit.runner.Result;
+
+/**
+ * An @link(InstrumentationRunListener) which can be used in CTS tests to control the
+ * implementation of @link{SSLSocket} returned by Conscrypt, allowing both implementations
+ * to be tested using the same test classes.
+ *
+ * This listener looks for an instrumentation arg named "conscrypt_sslsocket_implementation".
+ * If its value is "fd" then the file descriptor based implementation will be used, or
+ * if its value is "engine" then the SSLEngine based implementation will be used. Any other
+ * value is invalid.
+ *
+ * The default is set from an @code{testRunStarted} method, i.e. before any tests run and
+ * persists until the ART VM exits, i.e. until all tests in this @code{<test>} clause complete.
+ */
+public class ConscryptInstrumentationListener extends InstrumentationRunListener {
+ private static final String IMPLEMENTATION_ARG_NAME = "conscrypt_sslsocket_implementation";
+ private static final String LOG_TAG = "ConscryptInstList";
+ // Signal used to trigger a dump of Clang coverage information.
+ // See {@code maybeDumpNativeCoverage} below.
+ private final int COVERAGE_SIGNAL = 37;
+
+ private enum Implementation {
+ ENGINE(true, "com.android.org.conscrypt.ConscryptEngineSocket"),
+ FD(false, "com.android.org.conscrypt.ConscryptFileDescriptorSocket");
+
+ private final boolean useEngine;
+ private final String expectedClassName;
+
+ private Implementation(boolean useEngine, String expectedClassName) {
+ this.useEngine = useEngine;
+ this.expectedClassName = expectedClassName;
+ }
+
+ private boolean shouldUseEngine() {
+ return useEngine;
+ }
+
+ private Class<? extends Socket> getExpectedClass() {
+ try {
+ return Class.forName(expectedClassName).asSubclass(Socket.class);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException(
+ "Invalid SSLSocket class: '" + expectedClassName + "'");
+ }
+ }
+
+ private static Implementation lookup(String name) {
+ try {
+ return valueOf(name.toUpperCase());
+ } catch (Exception e) {
+ throw new IllegalArgumentException(
+ "Invalid SSLSocket implementation: '" + name + "'");
+ }
+ }
+ }
+
+ @Override
+ public void testRunStarted(Description description) throws Exception {
+ Bundle argsBundle = InstrumentationRegistry.getArguments();
+ String implementationName = argsBundle.getString(IMPLEMENTATION_ARG_NAME);
+ Implementation implementation = Implementation.lookup(implementationName);
+ selectImplementation(implementation);
+ super.testRunStarted(description);
+ }
+
+ @Override
+ public void testRunFinished(Result result) throws Exception {
+ maybeDumpNativeCoverage();
+ super.testRunFinished(result);
+ }
+
+ /**
+ * If this test process is instrumented for native coverage, then trigger a dump
+ * of the coverage data and wait until either we detect the dumping has finished or 60 seconds,
+ * whichever is shorter.
+ *
+ * Background: Coverage builds install a signal handler for signal 37 which flushes coverage
+ * data to disk, which may take a few seconds. Tests running as an app process will get
+ * killed with SIGKILL once the app code exits, even if the coverage handler is still running.
+ *
+ * Method: If a handler is installed for signal 37, then assume this is a coverage run and
+ * send signal 37. The handler is non-reentrant and so signal 37 will then be blocked until
+ * the handler completes. So after we send the signal, we loop checking the blocked status
+ * for signal 37 until we hit the 60 second deadline. If the signal is blocked then sleep for
+ * 2 seconds, and if it becomes unblocked then the handler exitted so we can return early.
+ * If the signal is not blocked at the start of the loop then most likely the handler has
+ * not yet been invoked. This should almost never happen as it should get blocked on delivery
+ * when we call {@code Os.kill()}, so sleep for a shorter duration (100ms) and try again. There
+ * is a race condition here where the handler is delayed but then runs for less than 100ms and
+ * gets missed, in which case this method will loop with 100ms sleeps until the deadline.
+ *
+ * In the case where the handler runs for more than 60 seconds, the test process will be allowed
+ * to exit so coverage information may be incomplete.
+ *
+ * There is no API for determining signal dispositions, so this method uses the
+ * {@link SignalMaskInfo} class to read the data from /proc. If there is an error parsing
+ * the /proc data then this method will also loop until the 60s deadline passes.
+ *
+ */
+ private void maybeDumpNativeCoverage() {
+ SignalMaskInfo siginfo = new SignalMaskInfo();
+ if (!siginfo.isValid()) {
+ Log.e(LOG_TAG, "Invalid signal info");
+ return;
+ }
+
+ if (!siginfo.isCaught(COVERAGE_SIGNAL)) {
+ // Process is not instrumented for coverage
+ Log.i(LOG_TAG, "Not dumping coverage, no handler installed");
+ return;
+ }
+
+ Log.i(LOG_TAG,
+ String.format("Sending coverage dump signal %d to pid %d uid %d", COVERAGE_SIGNAL,
+ Os.getpid(), Os.getuid()));
+ try {
+ Os.kill(Os.getpid(), COVERAGE_SIGNAL);
+ } catch (ErrnoException e) {
+ Log.e(LOG_TAG, "Unable to send coverage signal", e);
+ return;
+ }
+
+ long start = System.currentTimeMillis();
+ long deadline = start + 60 * 1000L;
+ while (System.currentTimeMillis() < deadline) {
+ siginfo.refresh();
+ try {
+ if (siginfo.isValid() && siginfo.isBlocked(COVERAGE_SIGNAL)) {
+ // Signal is currently blocked so assume a handler is running
+ Thread.sleep(2000L);
+ siginfo.refresh();
+ if (siginfo.isValid() && !siginfo.isBlocked(COVERAGE_SIGNAL)) {
+ // Coverage handler exited while we were asleep
+ Log.i(LOG_TAG,
+ String.format("Coverage dump detected finished after %dms",
+ System.currentTimeMillis() - start));
+ break;
+ }
+ } else {
+ // Coverage signal handler not yet started or invalid siginfo
+ Thread.sleep(100L);
+ }
+ } catch (InterruptedException e) {
+ // ignored
+ }
+ }
+ }
+
+ private void selectImplementation(Implementation implementation) {
+ // Invoke setUseEngineSocketByDefault by reflection as it is an "ExperimentalApi which is
+ // not visible to tests.
+ try {
+ Method method =
+ Conscrypt.class.getDeclaredMethod("setUseEngineSocketByDefault", boolean.class);
+ method.invoke(null, implementation.shouldUseEngine());
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ throw new IllegalStateException("Unable to set SSLSocket implementation", e);
+ }
+
+ // Verify that the default socket factory returns the expected implementation class for
+ // SSLSocket or, more likely, a subclass of it.
+ Socket socket;
+ try {
+ socket = SSLSocketFactory.getDefault().createSocket();
+ } catch (IOException e) {
+ throw new IllegalStateException("Unable to create an SSLSocket", e);
+ }
+
+ Objects.requireNonNull(socket);
+ Class<? extends Socket> expectedClass = implementation.getExpectedClass();
+ if (!expectedClass.isAssignableFrom(socket.getClass())) {
+ throw new IllegalArgumentException("Expected SSLSocket class or subclass of "
+ + expectedClass.getSimpleName() + " but got "
+ + socket.getClass().getSimpleName());
+ }
+ }
+}
diff --git a/test-support/src/java/org/conscrypt/SignalMaskInfo.java b/test-support/src/java/org/conscrypt/SignalMaskInfo.java
new file mode 100644
index 0000000..136a24d
--- /dev/null
+++ b/test-support/src/java/org/conscrypt/SignalMaskInfo.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2020 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
+ */
+
+package org.conscrypt;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Class for reading a process' signal masks from the /proc filesystem. Looks for the
+ * BLOCKED, CAUGHT, IGNORED and PENDING masks from /proc/self/status, each of which is a
+ * 64 bit bitmask with one bit per signal.
+ *
+ * Maintains a map from SignalMaskInfo.Type to the bitmask. The {@code isValid} method
+ * will only return true if all 4 masks were successfully parsed. Provides lookup
+ * methods per signal, e.g. {@code isPending(signum)} which will throw
+ * {@code IllegalStateException} if the current data is not valid.
+ */
+public class SignalMaskInfo {
+ private enum Type {
+ BLOCKED("SigBlk"),
+ CAUGHT("SigCgt"),
+ IGNORED("SigIgn"),
+ PENDING("SigPnd");
+
+ // The tag for this mask in /proc/self/status
+ private final String tag;
+
+ Type(String tag) {
+ this.tag = tag + ":\t";
+ }
+
+ public String getTag() {
+ return tag;
+ }
+
+ public static Map<Type, Long> parseProcinfo(String path) {
+ Map<Type, Long> map = new HashMap<>();
+ try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ for (Type mask : values()) {
+ long value = mask.tryToParse(line);
+ if (value >= 0) {
+ map.put(mask, value);
+ }
+ }
+ }
+ } catch (NumberFormatException | IOException e) {
+ // Ignored - the map will end up being invalid instead.
+ }
+ return map;
+ }
+
+ private long tryToParse(String line) {
+ if (line.startsWith(tag)) {
+ return Long.valueOf(line.substring(tag.length()), 16);
+ } else {
+ return -1;
+ }
+ }
+ }
+
+ private static final String PROCFS_PATH = "/proc/self/status";
+ private Map<Type, Long> maskMap = null;
+
+ SignalMaskInfo() {
+ refresh();
+ }
+
+ public void refresh() {
+ maskMap = Type.parseProcinfo(PROCFS_PATH);
+ }
+
+ public boolean isValid() {
+ return (maskMap != null && maskMap.size() == Type.values().length);
+ }
+
+ public boolean isCaught(int signal) {
+ return isSignalInMask(signal, Type.CAUGHT);
+ }
+
+ public boolean isBlocked(int signal) {
+ return isSignalInMask(signal, Type.BLOCKED);
+ }
+
+ public boolean isPending(int signal) {
+ return isSignalInMask(signal, Type.PENDING);
+ }
+
+ public boolean isIgnored(int signal) {
+ return isSignalInMask(signal, Type.IGNORED);
+ }
+
+ private void checkValid() {
+ if (!isValid()) {
+ throw new IllegalStateException();
+ }
+ }
+
+ private boolean isSignalInMask(int signal, Type mask) {
+ long bit = 1L << (signal - 1);
+ return (getSignalMask(mask) & bit) != 0;
+ }
+
+ private long getSignalMask(Type mask) {
+ checkValid();
+ Long value = maskMap.get(mask);
+ if (value == null) {
+ throw new IllegalStateException();
+ }
+ return value;
+ }
+}