Merge upstream master
Main changes:
* Fix the SSLEngine state machine. This should make SSLEngine follow
the documented behavior much more closely.
* Add support for AES-GCM-SIV.
* Refactor tests to use a common pattern with helper classes.
* Refactor the OpenSSLCipher class into a bunch of separate classes.
Test: cts -m CtsLibcoreTestCases
Test: cts -m CtsLibcoreOkHttpTestCases
Change-Id: Id9db9bae66d629ee1cd34255c4ca5a7a3c03ba7f
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..3fe4c92
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,441 @@
+//
+// 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__",
+ ],
+}
+
+//
+// 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",
+ "common/src/jni/main/cpp/conscrypt/trace.cc",
+ ],
+
+ 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",
+ ],
+
+ shared_libs: [
+ "liblog",
+ ],
+
+ static_libs: [
+ "libssl",
+ "libcrypto",
+ ],
+
+ sdk_version: "9",
+}
+
+cc_library {
+ name: "libconscrypt_jni",
+ defaults: [
+ "conscrypt_global",
+ "conscrypt_unbundled-jni-defaults",
+ ],
+}
+
+cc_library_host_shared {
+ name: "libconscrypt_openjdk_jni",
+ defaults: ["conscrypt_global"],
+
+ cflags: [
+ "-DCONSCRYPT_OPENJDK",
+ ],
+
+ local_include_dirs: [
+ "common/src/jni/unbundled/include",
+ ],
+
+ static_libs: [
+ "libssl",
+ "libcrypto",
+ ],
+
+ // 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-nojarjar_generated_constants",
+ out: ["org/conscrypt/NativeConstants.java"],
+ cmd: "$(location conscrypt_generate_constants) > $(out)",
+ tools: ["conscrypt_generate_constants"],
+}
+
+// Create the conscrypt library without jarjar for tests
+java_library {
+ name: "conscrypt-nojarjar",
+ visibility: [
+ "//build/make/tools/signapk",
+ ],
+ host_supported: true,
+ hostdex: true,
+
+ srcs: [
+ "common/src/main/java/**/*.java",
+ ":conscrypt-nojarjar_generated_constants",
+ ],
+
+ sdk_version: "none",
+ system_modules: "core-all-system-modules",
+ target: {
+ android: {
+ srcs: ["platform/src/main/java/**/*.java"],
+ libs: ["core-all"],
+ },
+ host: {
+ srcs: ["openjdk/src/main/java/**/*.java"],
+ javacflags: ["-XDignore.symbol.file"],
+ },
+ },
+
+ required: ["libjavacrypto"],
+ java_version: "1.7",
+}
+
+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",
+ visibility: [
+ "//libcore",
+ ],
+ srcs: [
+ "repackaged/common/src/main/java/**/*.java",
+ "repackaged/platform/src/main/java/**/*.java",
+ ":conscrypt_generated_constants",
+ ],
+}
+
+filegroup {
+ name: "conscrypt_public_api_files",
+ visibility: [
+ "//libcore",
+ ],
+ srcs: ["publicapi/src/main/java/**/*.java"],
+}
+
+// Create the conscrypt library from the source produced by the srcgen/generate_android_src.sh
+// script.
+java_library {
+ name: "conscrypt",
+ visibility: [
+ "//art/build",
+ "//device:__subpackages__",
+ "//external/okhttp",
+ "//external/robolectric-shadows",
+ "//external/wycheproof",
+ "//libcore",
+ "//system/apex/tests",
+ ":__subpackages__",
+ ],
+ installable: true,
+ hostdex: true,
+
+ srcs: [
+ ":conscrypt_java_files",
+ ":conscrypt_public_api_files",
+ ],
+
+ // 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",
+ libs: ["core.intra.stubs"],
+ patch_module: "java.base",
+ system_modules: "core-intra-stubs-system-modules",
+
+ // Workaround for b/124476339: libjavacrypto is required for both APEX and
+ // hostdex builds, but adding a top-level required property results in
+ // it being installed to /system on Android.
+ // TODO(b/124476339): move required back to a top level property
+ target: {
+ hostdex: {
+ required: ["libjavacrypto"],
+ },
+ },
+
+ permitted_packages: [
+ "android.net.ssl",
+ "com.android.org.conscrypt",
+ ],
+}
+
+// A guaranteed unstripped version of conscrypt.
+// The build system may or may not strip the conscrypt jar, but this one will
+// not be stripped. See b/24535627.
+java_library {
+ name: "conscrypt-testdex",
+ installable: true,
+
+ static_libs: ["conscrypt"],
+ dex_preopt: {
+ enabled: false,
+ },
+
+ sdk_version: "core_platform",
+
+ required: ["libjavacrypto"],
+}
+
+// Platform conscrypt crypto JNI library
+cc_defaults {
+ name: "libjavacrypto-defaults",
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wunused",
+ "-fvisibility=hidden",
+ ],
+
+ srcs: ["common/src/jni/main/cpp/**/*.cc"],
+ 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: [
+ "libcrypto",
+ "liblog",
+ "libssl",
+ ],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+// Unbundled Conscrypt jar
+java_library {
+ name: "conscrypt_unbundled",
+
+ srcs: [
+ "common/src/main/java/**/*.java",
+ "android/src/main/java/**/*.java",
+ ":conscrypt-nojarjar_generated_constants",
+ ],
+
+ libs: ["conscrypt-stubs"],
+
+ sdk_version: "current",
+ java_version: "1.7",
+}
+
+// Stub library for unbundled builds
+java_library {
+ name: "conscrypt-stubs",
+
+ srcs: ["android-stub/src/main/java/**/*.java"],
+
+ sdk_version: "current",
+ java_version: "1.7",
+}
+
+// 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",
+ ],
+ sdk_version: "9",
+ stl: "c++_shared",
+}
+
+// Make the conscrypt-tests library.
+java_test {
+ name: "conscrypt-tests",
+ visibility: [
+ "//cts/tests/libcore/luni",
+ ],
+ hostdex: true,
+ srcs: [
+ "repackaged/platform/src/test/java/**/*.java",
+ "repackaged/common/src/test/java/**/*.java",
+ "repackaged/openjdk-integ-tests/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",
+ "openjdk-integ-tests/src/test/resources",
+ ],
+
+ sdk_version: "none",
+ libs: [
+ "core-all",
+ "conscrypt",
+ "junit",
+ "mockito-target-minus-junit4",
+ ],
+ system_modules: "core-all-system-modules",
+
+ static_libs: [
+ "bouncycastle-unbundled",
+ "bouncycastle-bcpkix-unbundled",
+ "bouncycastle-ocsp-unbundled",
+ ],
+ javacflags: [
+ "-Xmaxwarns 9999999",
+ //"-Xlint:all",
+ //"-Xlint:-serial,-deprecation,-unchecked",
+ ],
+
+ required: ["libjavacrypto"],
+ java_version: "1.7",
+}
+
+// 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",
+ libs: [
+ "core-all",
+ "conscrypt",
+ "junit",
+ "bouncycastle-unbundled",
+ "bouncycastle-bcpkix-unbundled",
+ "bouncycastle-ocsp-unbundled",
+ "caliper-api-target",
+ ],
+ system_modules: "core-all-system-modules",
+
+ javacflags: [
+ "-Xmaxwarns 9999999",
+ //"-Xlint:all",
+ //"-Xlint:-serial,-deprecation,-unchecked",
+ ],
+
+ required: ["libjavacrypto"],
+ java_version: "1.7",
+}
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..105c94b
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,6 @@
+flooey@google.com
+kroot@google.com
+narayan@google.com
+nfuller@google.com
+prb@google.com
+tobiast@google.com
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 4c8d137..84d310f 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,3 +1,4 @@
[Builtin Hooks]
commit_msg_test_field = true
clang_format = true
+bpfmt = true
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..129da6a
--- /dev/null
+++ b/apex/Android.bp
@@ -0,0 +1,47 @@
+// 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.
+apex_defaults {
+ name: "com.android.conscrypt-defaults",
+ androidManifest: ":com.android.conscrypt-androidManifest",
+ compile_multilib: "both",
+ java_libs: ["conscrypt"],
+ native_shared_libs: ["libjavacrypto"],
+ key: "apex.conscrypt.key",
+ certificate: ":com.android.conscrypt.certificate",
+}
+
+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",
+}
+
+// Production APEX
+apex {
+ name: "com.android.conscrypt",
+ defaults: ["com.android.conscrypt-defaults"],
+ manifest: "apex_manifest.json",
+}
diff --git a/apex/AndroidManifest.xml b/apex/AndroidManifest.xml
new file mode 100644
index 0000000..c25cc17
--- /dev/null
+++ b/apex/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?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.
+ -->
+ <uses-sdk android:minSdkVersion="28" android:maxSdkVersion="28" />
+</manifest>
diff --git a/apex/apex_manifest.json b/apex/apex_manifest.json
new file mode 100644
index 0000000..98222ad
--- /dev/null
+++ b/apex/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.conscrypt",
+ "version": 1
+}
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/testing/Android.bp b/apex/testing/Android.bp
new file mode 100644
index 0000000..12c2756
--- /dev/null
+++ b/apex/testing/Android.bp
@@ -0,0 +1,22 @@
+// 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.
+
+apex {
+ name: "test_com.android.conscrypt",
+ defaults: ["com.android.conscrypt-defaults"],
+ manifest: "test_apex_manifest.json",
+ file_contexts: "com.android.conscrypt",
+ // 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/constants/src/gen/cpp/generate_constants.cc b/constants/src/gen/cpp/generate_constants.cc
index 894a1fa..bd1e995 100644
--- a/constants/src/gen/cpp/generate_constants.cc
+++ b/constants/src/gen/cpp/generate_constants.cc
@@ -40,10 +40,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/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestAES.java b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestAES.java
index 49b9d23..d79dacb 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestAES.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestAES.java
@@ -18,18 +18,38 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import dalvik.system.VMRuntime;
import java.security.AlgorithmParameters;
import java.security.Provider;
import javax.crypto.spec.IvParameterSpec;
import org.conscrypt.TestUtils;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
import tests.util.ServiceTester;
@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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestDESede.java b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestDESede.java
index a0e8581..8af454b 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestDESede.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestDESede.java
@@ -18,18 +18,38 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import dalvik.system.VMRuntime;
import java.security.AlgorithmParameters;
import java.security.Provider;
import javax.crypto.spec.IvParameterSpec;
import org.conscrypt.TestUtils;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
import tests.util.ServiceTester;
@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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestGCM.java b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestGCM.java
index 1c435d3..72b1d23 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestGCM.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestGCM.java
@@ -19,18 +19,38 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import dalvik.system.VMRuntime;
import java.security.AlgorithmParameters;
import java.security.Provider;
import javax.crypto.spec.GCMParameterSpec;
import org.conscrypt.TestUtils;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
import tests.util.ServiceTester;
@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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestOAEP.java b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestOAEP.java
index fb97173..4a847bd 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestOAEP.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/AlgorithmParametersTestOAEP.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import dalvik.system.VMRuntime;
import java.security.AlgorithmParameters;
import java.security.Provider;
import java.security.spec.MGF1ParameterSpec;
@@ -25,14 +26,33 @@
import javax.crypto.spec.PSource;
import javax.crypto.spec.PSource.PSpecified;
import org.conscrypt.TestUtils;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
import tests.util.ServiceTester;
@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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/KeyPairGeneratorTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/KeyPairGeneratorTest.java
index b2ccc51..f8df5ad 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/KeyPairGeneratorTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/KeyPairGeneratorTest.java
@@ -54,14 +54,37 @@
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import org.conscrypt.TestUtils;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import dalvik.system.VMRuntime;
+import sun.security.jca.Providers;
+import org.junit.Test;
import tests.util.ServiceTester;
@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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
@Test
public void test_getInstance() throws Exception {
ServiceTester.test("KeyPairGenerator")
diff --git a/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/MessageDigestTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/MessageDigestTest.java
index 599b3f4..880fc38 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/MessageDigestTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/MessageDigestTest.java
@@ -24,15 +24,36 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
+import dalvik.system.VMRuntime;
import org.conscrypt.TestUtils;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
import tests.util.ServiceTester;
@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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/SignatureTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/SignatureTest.java
index 7d4584b..ecb51ed 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/SignatureTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/SignatureTest.java
@@ -68,16 +68,37 @@
import java.util.concurrent.TimeUnit;
import org.conscrypt.Conscrypt;
import org.conscrypt.TestUtils;
+import dalvik.system.VMRuntime;
import org.conscrypt.testing.BrokenProvider;
import org.conscrypt.testing.OpaqueProvider;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
import tests.util.ServiceTester;
@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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
// 20 bytes for DSA
private final byte[] DATA = new byte[20];
diff --git a/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/cert/CertificateFactoryTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/cert/CertificateFactoryTest.java
index 82b8a45..40e88fe 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/cert/CertificateFactoryTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/cert/CertificateFactoryTest.java
@@ -63,14 +63,34 @@
import org.conscrypt.Conscrypt;
import org.conscrypt.TestUtils;
import org.conscrypt.java.security.StandardNames;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import dalvik.system.VMRuntime;
+import sun.security.jca.Providers;
import tests.util.ServiceTester;
@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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/cert/X509CertificateTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/cert/X509CertificateTest.java
index 6fb84f5..a0068cf 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/cert/X509CertificateTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/cert/X509CertificateTest.java
@@ -27,15 +27,35 @@
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateParsingException;
+import org.junit.AfterClass;
+import dalvik.system.VMRuntime;
import java.security.cert.X509Certificate;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
import tests.util.ServiceTester;
@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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
private static final String VALID_CERT =
"-----BEGIN CERTIFICATE-----\n"
+ "MIIFMjCCAxqgAwIBAgIJAL0mG5fOeJ7xMA0GCSqGSIb3DQEBCwUAMC0xCzAJBgNV\n"
diff --git a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/crypto/CipherTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/crypto/CipherTest.java
index 14af965..983ba06 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/crypto/CipherTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/crypto/CipherTest.java
@@ -74,15 +74,34 @@
import org.conscrypt.TestUtils;
import org.conscrypt.java.security.StandardNames;
import org.conscrypt.java.security.TestKeyStore;
+import org.junit.AfterClass;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import dalvik.system.VMRuntime;
+import sun.security.jca.Providers;
@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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
@BeforeClass
public static void setUp() {
TestUtils.assumeAllowsUnsignedCrypto();
diff --git a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/crypto/ECDHKeyAgreementTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/crypto/ECDHKeyAgreementTest.java
index 94ddbc5..5699461 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/crypto/ECDHKeyAgreementTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/crypto/ECDHKeyAgreementTest.java
@@ -52,10 +52,13 @@
import junit.framework.AssertionFailedError;
import org.conscrypt.Conscrypt;
import org.conscrypt.TestUtils;
+import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import dalvik.system.VMRuntime;
+import sun.security.jca.Providers;
/**
* Tests for all registered Elliptic Curve Diffie-Hellman {@link KeyAgreement} providers.
@@ -63,6 +66,22 @@
@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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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"
diff --git a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/crypto/KeyGeneratorTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/crypto/KeyGeneratorTest.java
index 4ebafb7..2685cef 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/crypto/KeyGeneratorTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/crypto/KeyGeneratorTest.java
@@ -29,14 +29,33 @@
import javax.crypto.SecretKey;
import org.conscrypt.TestUtils;
import org.conscrypt.java.security.StandardNames;
+import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import dalvik.system.VMRuntime;
+import sun.security.jca.Providers;
import tests.util.ServiceTester;
@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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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
diff --git a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLEngineTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLEngineTest.java
index 63fc3f5..4b02e0a 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLEngineTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLEngineTest.java
@@ -31,6 +31,7 @@
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.List;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.KeyManager;
@@ -583,8 +584,14 @@
// 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());
- assertEquals(referenceEngine.getEnabledCipherSuites()[0],
- session.getCipherSuite());
+ String sessionSuite = session.getCipherSuite();
+ List<String> enabledSuites =
+ Arrays.asList(referenceEngine.getEnabledCipherSuites());
+ String message = "Handshake session has invalid cipher suite: "
+ + (sessionSuite == null ? "(null)" : sessionSuite);
+ assertTrue("Expected enabled suites to contain " + sessionSuite
+ + ", got: " + enabledSuites,
+ enabledSuites.contains(sessionSuite));
wasCalled[0] = true;
} catch (Exception e) {
throw new CertificateException("Something broke", e);
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/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..13bd771
--- /dev/null
+++ b/publicapi/src/main/java/android/net/ssl/SSLEngines.java
@@ -0,0 +1,58 @@
+/*
+ * 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 libcore.util.NonNull;
+
+/**
+ * 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);
+ }
+}
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..a669404
--- /dev/null
+++ b/publicapi/src/main/java/android/net/ssl/SSLSockets.java
@@ -0,0 +1,58 @@
+/*
+ * 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.SSLSocket;
+import libcore.util.NonNull;
+
+/**
+ * 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);
+ }
+}
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..66abec6
--- /dev/null
+++ b/publicapi/src/test/java/android/net/ssl/SSLEnginesTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.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 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.SSLException;
+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) throws SSLException { throw new AssertionError(); }
+ @Override public SSLEngineResult unwrap(ByteBuffer byteBuffer, ByteBuffer[] byteBuffers,
+ int i, int i1) throws SSLException { throw new AssertionError(); }
+ @Override public Runnable getDelegatedTask() { throw new AssertionError(); }
+ @Override public void closeInbound() throws SSLException { 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() throws SSLException { 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
+ public void testUseSessionTickets() throws Exception {
+ try {
+ SSLEngines.setUseSessionTickets(new BrokenSSLEngine(), true);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ 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);
+ }
+}
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..02df047
--- /dev/null
+++ b/publicapi/src/test/java/android/net/ssl/SSLSocketsTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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.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 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
+ public void testUseSessionTickets() throws Exception {
+ try {
+ SSLSockets.setUseSessionTickets(new BrokenSSLSocket(), true);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ 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));
+ }
+}
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..84a48c8
--- /dev/null
+++ b/repackaged/benchmark-base/src/main/java/com/android/org/conscrypt/EngineHandshakeBenchmark.java
@@ -0,0 +1,172 @@
+/* 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();
+ }
+ }
+ }
+
+ private static boolean isHandshakeFinished(SSLEngineResult result) {
+ return result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED;
+ }
+}
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..f8a80bb
--- /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.getProtocols;
+import static com.android.org.conscrypt.TestUtils.newTextMessage;
+import static org.junit.Assert.assertEquals;
+
+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;
+import com.android.org.conscrypt.ServerEndpoint.MessageProcessor;
+
+/**
+ * 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(), getProtocols(), 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(), getProtocols(), 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..00aeb8b
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/AbstractConscryptSocket.java
@@ -0,0 +1,774 @@
+/* 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.
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ String getHostname() {
+ return peerHostname;
+ }
+
+ /**
+ * This method enables Server Name Indication
+ *
+ * @param hostname the desired SNI hostname, or null to disable
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ 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.
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ 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
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ 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
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ 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.
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ 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() {
+ if (listeners != null && !listeners.isEmpty()) {
+ // notify the listeners
+ HandshakeCompletedEvent event = new HandshakeCompletedEvent(this, getActiveSession());
+ for (HandshakeCompletedListener listener : listeners) {
+ 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
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ 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.
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ 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.
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ 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.
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ abstract void setChannelIdPrivateKey(PrivateKey privateKey);
+
+ /**
+ * Returns null always for backward compatibility.
+ * @deprecated NPN is not supported
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @Deprecated
+ byte[] getNpnSelectedProtocol() {
+ return null;
+ }
+
+ /**
+ * This method does nothing and is kept for backward compatibility.
+ * @deprecated NPN is not supported
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @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.
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @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.
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @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.
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @Deprecated
+ abstract void setAlpnProtocols(byte[] alpnProtocols);
+
+ /**
+ * Sets the list of ALPN protocols.
+ *
+ * @param protocols the list of ALPN protocols
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @SuppressWarnings("MissingOverride") // For compiling pre Java 9.
+ abstract void setApplicationProtocols(String[] protocols);
+
+ /**
+ * Returns the list of supported ALPN protocols.
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @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..d777735
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/AbstractSessionContext.java
@@ -0,0 +1,305 @@
+/* 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();
+
+ @SuppressWarnings("serial")
+ 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[sessions.size()]))
+ .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
+ 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..a6ac475
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ActiveSession.java
@@ -0,0 +1,326 @@
+/* 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 AbstractSessionContext sessionContext;
+ private byte[] id;
+ private long creationTime;
+ private String protocol;
+ private String peerHost;
+ private int peerPort = -1;
+ private long lastAccessedTime = 0;
+ 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.<byte[]>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 ProvidedSessionDecorator.");
+ }
+
+ @Override
+ public Object getValue(String name) {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ProvidedSessionDecorator.");
+ }
+
+ @Override
+ public void removeValue(String name) {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ProvidedSessionDecorator.");
+ }
+
+ @Override
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ProvidedSessionDecorator.");
+ }
+
+ @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
+ public javax.security.cert.X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ 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;
+ }
+
+ /**
+ * 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/ByteArray.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ByteArray.java
new file mode 100644
index 0000000..c4f7da3
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ByteArray.java
@@ -0,0 +1,47 @@
+/* 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;
+ return Arrays.equals(bytes, lhs.bytes);
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/CertBlacklist.java b/repackaged/common/src/main/java/com/android/org/conscrypt/CertBlacklist.java
new file mode 100644
index 0000000..cecc8ba
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/CertBlacklist.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 CertBlacklist {
+
+ /**
+ * Returns whether the given public key is in the blacklist.
+ */
+ boolean isPublicKeyBlackListed(PublicKey publicKey);
+
+ /**
+ * Returns whether the given serial number is in the blacklist.
+ */
+ boolean isSerialNumberBlackListed(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..ff3bda2
--- /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
+@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..34d6222
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/CertificatePriorityComparator.java
@@ -0,0 +1,170 @@
+/* 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
+ 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..789e716
--- /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
+@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)}.
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi
+ 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
+ */
+ @dalvik.annotation.compat.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..7184dc9
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/Conscrypt.java
@@ -0,0 +1,782 @@
+/* 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.io.InputStream;
+import java.nio.ByteBuffer;
+import java.security.KeyManagementException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.util.Properties;
+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.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
+@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;
+ }
+ }
+
+ /**
+ * @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;
+ try {
+ InputStream 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) {
+ }
+ 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 new OpenSSLProvider(providerName, Platform.provideTrustManagerByDefault());
+ }
+
+ /**
+ * @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 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;
+ }
+
+ public Provider build() {
+ return new OpenSSLProvider(name, provideTrustManager);
+ }
+ }
+
+ 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
+ @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();
+ }
+}
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..472e2da
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptCertStore.java
@@ -0,0 +1,44 @@
+/* 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
+@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..646be02
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptEngine.java
@@ -0,0 +1,1824 @@
+/* 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 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 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 java.io.EOFException;
+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 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;
+import com.android.org.conscrypt.ExternalSession.Provider;
+import com.android.org.conscrypt.NativeRef.SSL_SESSION;
+import com.android.org.conscrypt.NativeSsl.BioWrapper;
+
+/**
+ * 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 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.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.networkBio = ssl.newBio();
+ }
+
+ ConscryptEngine(SSLParametersImpl sslParameters, PeerInfoProvider peerInfoProvider) {
+ this.sslParameters = sslParameters;
+ this.peerInfoProvider = checkNotNull(peerInfoProvider, "peerInfoProvider");
+ this.ssl = newSsl(sslParameters, this);
+ this.networkBio = ssl.newBio();
+ }
+
+ private static NativeSsl newSsl(SSLParametersImpl sslParameters, ConscryptEngine engine) {
+ try {
+ return NativeSsl.newInstance(sslParameters, engine, engine, 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 IllegalStateException("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);
+ }
+ 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 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();
+ }
+ }
+
+ @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
+ closeInbound();
+ sendSSLShutdown();
+ return new SSLEngineResult(Status.CLOSED,
+ pendingOutboundEncryptedBytes() > 0
+ ? NEED_WRAP : NOT_HANDSHAKING,
+ bytesConsumed, bytesProduced);
+ }
+ default: {
+ // Should never get here.
+ sendSSLShutdown();
+ 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 (SSLException e) {
+ // Shut down the SSL and rethrow the exception. Users will need to drain any alerts
+ // from the SSL before closing.
+ sendSSLShutdown();
+ throw convertException(e);
+ } catch (InterruptedIOException e) {
+ return newResult(bytesConsumed, bytesProduced, handshakeStatus);
+ } catch (EOFException e) {
+ closeAll();
+ throw convertException(e);
+ } catch (IOException e) {
+ sendSSLShutdown();
+ 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 (SSLException e) {
+ // Shut down the SSL and rethrow the exception. Users will need to drain any alerts
+ // from the SSL before closing.
+ sendSSLShutdown();
+ throw e;
+ } catch (IOException e) {
+ sendSSLShutdown();
+ 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) {
+ 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();
+ }
+
+ 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 srcsLen = 0;
+ final int endOffset = srcsOffset + srcsLength;
+ for (int i = srcsOffset; i < endOffset; ++i) {
+ final ByteBuffer src = srcs[i];
+ if (src == null) {
+ throw new IllegalArgumentException("srcs[" + i + "] is null");
+ }
+ if (srcsLen == SSL3_RT_MAX_PLAIN_LENGTH) {
+ continue;
+ }
+
+ srcsLen += src.remaining();
+ if (srcsLen > SSL3_RT_MAX_PLAIN_LENGTH || srcsLen < 0) {
+ // If srcLen > MAX_PLAINTEXT_LENGTH or secLen < 0 just set it to
+ // MAX_PLAINTEXT_LENGTH.
+ // This also help us to guard against overflow.
+ // We not break out here as we still need to check for null entries in srcs[].
+ srcsLen = SSL3_RT_MAX_PLAIN_LENGTH;
+ }
+ }
+
+ if (dst.remaining() < calculateOutNetBufSize(srcsLen)) {
+ return new SSLEngineResult(
+ Status.BUFFER_OVERFLOW, getHandshakeStatusInternal(), 0, 0);
+ }
+
+ int bytesProduced = 0;
+ int bytesConsumed = 0;
+ loop:
+ for (int i = srcsOffset; i < endOffset; ++i) {
+ final ByteBuffer src = srcs[i];
+ checkArgument(src != null, "srcs[%d] is null", i);
+ while (src.hasRemaining()) {
+ final SSLEngineResult pendingNetResult;
+ // Write plaintext application data to the SSL engine
+ int result = writePlaintextData(
+ src, min(src.remaining(), SSL3_RT_MAX_PLAIN_LENGTH - bytesConsumed));
+ if (result > 0) {
+ bytesConsumed += result;
+
+ pendingNetResult = readPendingBytesFromBIO(
+ dst, bytesConsumed, bytesProduced, handshakeStatus);
+ if (pendingNetResult != null) {
+ if (pendingNetResult.getStatus() != OK) {
+ return pendingNetResult;
+ }
+ bytesProduced = pendingNetResult.bytesProduced();
+ }
+ if (bytesConsumed == SSL3_RT_MAX_PLAIN_LENGTH) {
+ // If we consumed the maximum amount of bytes for the plaintext length
+ // break out of the loop and start to fill the dst buffer.
+ break loop;
+ }
+ } 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
+ sendSSLShutdown();
+ throw newSslExceptionWithMessage("SSL_write");
+ }
+ }
+ }
+ }
+ // We need to check if pendingWrittenBytesInBIO was checked yet, as we may not 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 new SSLEngineResult(OK, getHandshakeStatusInternal(), bytesConsumed,
+ // bytesProduced);
+ 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 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.isClosed()) {
+ ssl.close();
+ networkBio.close();
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ transitionTo(STATE_CLOSED);
+ } 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 String getApplicationProtocol() {
+ return SSLUtils.toProtocolString(ssl.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..96489f1
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptEngineSocket.java
@@ -0,0 +1,901 @@
+/* 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 javax.net.ssl.SSLEngineResult.Status.OK;
+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 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.X509TrustManager;
+
+/**
+ * Implements crypto handling by delegating to {@link ConscryptEngine}.
+ */
+class ConscryptEngineSocket extends OpenSSLSocketImpl {
+ 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 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());
+
+ // 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.onHandshakeFinished();
+ }
+ });
+
+ // 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) {
+ state = STATE_HANDSHAKE_STARTED;
+ engine.beginHandshake();
+ in = new SSLInputStream();
+ out = new SSLOutputStream();
+ } 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 (SSLException e) {
+ 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 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.
+ throw SSLUtils.toSSLHandshakeException(new EOFException());
+ }
+ 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.
+ 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());
+ }
+ }
+ }
+ } 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);
+ }
+ }
+
+ @Override
+ public final InputStream getInputStream() throws IOException {
+ checkOpen();
+
+ // 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 in;
+ }
+
+ @Override
+ public final OutputStream getOutputStream() throws IOException {
+ checkOpen();
+
+ // 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 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
+ */
+ @Override
+ public final void setHostname(String hostname) {
+ engine.setHostname(hostname);
+ super.setHostname(hostname);
+ }
+
+ @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) {
+ // close() has been called before we've initialized the socket, so just
+ // return.
+ return;
+ }
+
+ synchronized (stateLock) {
+ if (state == STATE_CLOSED) {
+ // close() has already been called, so do nothing and return.
+ return;
+ }
+
+ state = STATE_CLOSED;
+
+ stateLock.notifyAll();
+ }
+
+ try {
+ // Close the underlying socket.
+ super.close();
+ } finally {
+ // Close the engine.
+ engine.closeInbound();
+ engine.closeOutbound();
+
+ // Release any resources we're holding
+ if (in != null) {
+ in.release();
+ }
+ }
+ }
+
+ @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 onHandshakeFinished() {
+ boolean notify = false;
+ synchronized (stateLock) {
+ if (state != STATE_CLOSED) {
+ if (state == STATE_HANDSHAKE_STARTED) {
+ state = STATE_READY_HANDSHAKE_CUT_THROUGH;
+ } else if (state == STATE_HANDSHAKE_COMPLETED) {
+ state = STATE_READY;
+ }
+
+ // Unblock threads that are waiting for our state to transition
+ // into STATE_READY or STATE_READY_HANDSHAKE_CUT_THROUGH.
+ stateLock.notifyAll();
+ notify = true;
+ }
+ }
+
+ if (notify) {
+ notifyHandshakeCompletedListeners();
+ }
+ }
+
+ /**
+ * Waits for the handshake to complete.
+ */
+ private void waitForHandshake() throws IOException {
+ startHandshake();
+
+ synchronized (stateLock) {
+ while (state != STATE_READY && 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();
+ }
+
+ /**
+ * 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 {
+ startHandshake();
+ synchronized (writeLock) {
+ write(new byte[] {(byte) b});
+ }
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ startHandshake();
+ synchronized (writeLock) {
+ writeInternal(ByteBuffer.wrap(b));
+ }
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ startHandshake();
+ 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) {
+ 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");
+ }
+
+ target.flip();
+
+ // Write the data to the socket.
+ writeToSocket();
+ } while (len > 0);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ startHandshake();
+ 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 {
+ startHandshake();
+ 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 (int) singleByte[0];
+ }
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ startHandshake();
+ synchronized (readLock) {
+ return read(b, 0, b.length);
+ }
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ startHandshake();
+ synchronized (readLock) {
+ return readUntilDataAvailable(b, off, len);
+ }
+ }
+
+ @Override
+ public int available() throws IOException {
+ startHandshake();
+ synchronized (readLock) {
+ init();
+ return fromEngine.remaining()
+ + (fromSocket.hasRemaining() || socketInputStream.available() > 0 ? 1 : 0);
+ }
+ }
+
+ 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_READY_HANDSHAKE_CUT_THROUGH;
+ }
+ }
+
+ /**
+ * 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..05af7c1
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptFileDescriptorSocket.java
@@ -0,0 +1,1180 @@
+/* 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 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;
+import com.android.org.conscrypt.ExternalSession.Provider;
+import com.android.org.conscrypt.NativeRef.SSL_SESSION;
+
+/**
+ * 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.AliasChooser,
+ SSLParametersImpl.PSKCallbacks {
+ 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 Provider() {
+ @Override
+ public ConscryptSession provideSession() {
+ return ConscryptFileDescriptorSocket.this.provideSession();
+ }
+ }));
+
+ private int writeTimeoutMilliseconds = 0;
+ private int handshakeTimeoutMilliseconds = -1; // -1 = same as timeout; 0 = infinite
+
+ // 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;
+ }
+
+ // The handshake has completed successfully ...
+
+ // 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 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;
+ }
+ }
+
+ 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;
+ }
+
+ 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 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
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @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
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @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() throws SocketException {
+ 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
+ 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
+ final void setApplicationProtocols(String[] protocols) {
+ sslParameters.setApplicationProtocols(protocols);
+ }
+
+ @Override
+ final String[] getApplicationProtocols() {
+ return sslParameters.getApplicationProtocols();
+ }
+
+ @Override
+ public final String getApplicationProtocol() {
+ return SSLUtils.toProtocolString(ssl.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
+ 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);
+ }
+
+ @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);
+ }
+
+ private ClientSessionContext clientSessionContext() {
+ return sslParameters.getClientSessionContext();
+ }
+
+ private AbstractSessionContext sessionContext() {
+ return sslParameters.getSessionContext();
+ }
+
+ private void transitionTo(int newState) {
+ switch (newState) {
+ 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/ConscryptHostnameVerifier.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptHostnameVerifier.java
new file mode 100644
index 0000000..a62cf9f
--- /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 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(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..c4732f1
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptSession.java
@@ -0,0 +1,56 @@
+/* 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;
+}
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..2fce21f
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/DESEDESecretKeyFactory.java
@@ -0,0 +1,102 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@Internal
+public class DESEDESecretKeyFactory extends SecretKeyFactorySpi {
+
+ @libcore.api.IntraCoreApi
+ 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..26676f0
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/DefaultSSLContextImpl.java
@@ -0,0 +1,133 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@Internal
+public final 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.
+ */
+ @libcore.api.IntraCoreApi
+ public DefaultSSLContextImpl() throws GeneralSecurityException, IOException {
+ super();
+ }
+
+ // 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 ");
+ }
+}
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..1e995fd
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ECParameters.java
@@ -0,0 +1,117 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@Internal
+public class ECParameters extends AlgorithmParametersSpi {
+
+ private OpenSSLECGroupContext curve;
+
+ @libcore.api.IntraCoreApi
+ 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(Platform.getCurveName(curve.getECParameterSpec()));
+ } 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..947ab63
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ExperimentalApi.java
@@ -0,0 +1,52 @@
+/* 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>
+ */
+@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..c6eaa41
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ExternalSession.java
@@ -0,0 +1,214 @@
+/* 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;
+import javax.security.cert.X509Certificate;
+
+/**
+ * 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 initialcapacity of 2 to keep it small in the average case.
+ private final HashMap<String, Object> values = new HashMap<String, Object>(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
+ public 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 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[values.size()]);
+ }
+
+ @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..2526cfe
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/FileClientSessionCache.java
@@ -0,0 +1,386 @@
+/* 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.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
+@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;
+ }
+
+ @dalvik.annotation.compat.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 {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (Exception ignored) {
+ }
+ }
+ }
+ }
+
+ 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
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi
+ 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..d6fd56a
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/GCMParameters.java
@@ -0,0 +1,156 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@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;
+
+ @libcore.api.IntraCoreApi
+ 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..febeda2
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/Internal.java
@@ -0,0 +1,36 @@
+/* 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.
+ */
+@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..7c8f8dc
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/IvParameters.java
@@ -0,0 +1,140 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@Internal
+public class IvParameters extends AlgorithmParametersSpi {
+ private byte[] iv;
+
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static class AES extends IvParameters {
+ @libcore.api.IntraCoreApi
+ public AES() {}
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static class DESEDE extends IvParameters {
+ @libcore.api.IntraCoreApi
+ public DESEDE() {}
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static class ChaCha20 extends IvParameters {
+ @libcore.api.IntraCoreApi
+ 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..4544eb2
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/Java7ExtendedSSLSession.java
@@ -0,0 +1,181 @@
+/* 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;
+import javax.security.cert.X509Certificate;
+
+/**
+ * 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
+ public final 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();
+ }
+}
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..16c4c38
--- /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 null;
+ }
+
+ 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..c1fc87d
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/KeyGeneratorImpl.java
@@ -0,0 +1,245 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@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
+ */
+ @libcore.api.IntraCoreApi
+ public static final class HmacMD5 extends KeyGeneratorImpl {
+ @libcore.api.IntraCoreApi
+ public HmacMD5() {
+ super("HmacMD5", 128);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class HmacSHA1 extends KeyGeneratorImpl {
+ @libcore.api.IntraCoreApi
+ public HmacSHA1() {
+ super("HmacSHA1", 160);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class HmacSHA224 extends KeyGeneratorImpl {
+ @libcore.api.IntraCoreApi
+ public HmacSHA224() {
+ super("HmacSHA224", 224);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class HmacSHA256 extends KeyGeneratorImpl {
+ @libcore.api.IntraCoreApi
+ public HmacSHA256() {
+ super("HmacSHA256", 256);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class HmacSHA384 extends KeyGeneratorImpl {
+ @libcore.api.IntraCoreApi
+ public HmacSHA384() {
+ super("HmacSHA384", 384);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class HmacSHA512 extends KeyGeneratorImpl {
+ @libcore.api.IntraCoreApi
+ public HmacSHA512() {
+ super("HmacSHA512", 512);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class DESEDE extends KeyGeneratorImpl {
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static final class AES extends KeyGeneratorImpl {
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static final class ChaCha20 extends KeyGeneratorImpl {
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static final class ARC4 extends KeyGeneratorImpl {
+ @libcore.api.IntraCoreApi
+ 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..5b02be2
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/KeyManagerFactoryImpl.java
@@ -0,0 +1,117 @@
+/* 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.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();
+ }
+ try {
+ keyStore.load(new FileInputStream(new File(keyStoreName)), pwd);
+ } catch (FileNotFoundException e) {
+ throw new KeyStoreException(e);
+ } catch (IOException e) {
+ throw new KeyStoreException(e);
+ } catch (CertificateException e) {
+ throw new KeyStoreException(e);
+ }
+ }
+
+ }
+
+ }
+
+ /**
+ * @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..4682e1b
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/KeyManagerImpl.java
@@ -0,0 +1,232 @@
+/* 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
+ */
+ KeyManagerImpl(KeyStore keyStore, char[] pwd) {
+ this.hash = new HashMap<String, PrivateKeyEntry>();
+ final Enumeration<String> aliases;
+ try {
+ aliases = keyStore.aliases();
+ } catch (KeyStoreException e) {
+ return;
+ }
+ for (; aliases.hasMoreElements();) {
+ final String alias = aliases.nextElement();
+ try {
+ if (keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) {
+ KeyStore.PrivateKeyEntry entry;
+ try {
+ entry = (KeyStore.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 KeyStore.PrivateKeyEntry(key, certs);
+ }
+ hash.put(alias, entry);
+ }
+ } catch (KeyStoreException ignored) {
+ // Ignored.
+ } catch (UnrecoverableEntryException ignored) {
+ // Ignored.
+ } catch (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<String>();
+ 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[found.size()]);
+ }
+ 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..a313f7c
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/NativeCrypto.java
@@ -0,0 +1,1472 @@
+/* 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.io.FileDescriptor;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.SocketTimeoutException;
+import java.nio.Buffer;
+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;
+import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+
+/**
+ * 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 -----------------------
+
+ @dalvik.annotation.compat.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);
+
+ @dalvik.annotation.compat.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);
+
+ @dalvik.annotation.compat.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);
+
+ @dalvik.annotation.compat.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);
+
+ @dalvik.annotation.compat.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);
+
+ @dalvik.annotation.compat.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);
+
+ // --- Message digest functions --------------
+
+ // These return const references
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native long EVP_get_digestbyname(String name);
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native int EVP_MD_size(long evp_md_const);
+
+ // --- Message digest context functions --------------
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native long EVP_MD_CTX_create();
+
+ static native void EVP_MD_CTX_cleanup(NativeRef.EVP_MD_CTX ctx);
+
+ @dalvik.annotation.compat.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
+ @dalvik.annotation.compat.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;
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native int EVP_CIPHER_iv_length(long evpCipher);
+
+ @dalvik.annotation.compat.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, IndexOutOfBoundsException;
+
+ 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, IndexOutOfBoundsException;
+
+ // --- 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 ----------------------------------------------------------------
+
+ @dalvik.annotation.compat.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;
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native long d2i_X509_bio(long bioCtx);
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native long d2i_X509(byte[] encoded) throws ParsingException;
+
+ @dalvik.annotation.compat.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);
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native byte[] ASN1_seq_pack_X509(long[] x509CertRefs);
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native long[] ASN1_seq_unpack_X509_bio(long bioRef) throws ParsingException;
+
+ static native void X509_free(long x509ctx, OpenSSLX509Certificate holder);
+
+ static native long X509_dup(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_cert_info_enc(long x509ctx, OpenSSLX509Certificate holder);
+
+ 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. */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native long[] d2i_PKCS7_bio(long bioCtx, int which) throws ParsingException;
+
+ /** Returns an array of X509 or X509_CRL pointers. */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native byte[] i2d_PKCS7(long[] certs);
+
+ /** Returns an array of X509 or X509_CRL pointers. */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native long[] PEM_read_bio_PKCS7(long bioCtx, int which);
+
+ // --- X509_CRL ------------------------------------------------------------
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native long d2i_X509_CRL_bio(long bioCtx);
+
+ @dalvik.annotation.compat.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 void X509_delete_ext(long x509, OpenSSLX509Certificate 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);
+
+ 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 --------------------------------------------------------
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native long X509_REVOKED_dup(long x509RevokedCtx);
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native byte[] i2d_X509_REVOKED(long x509RevokedCtx);
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native String[] get_X509_REVOKED_ext_oids(long x509ctx, int critical);
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native byte[] X509_REVOKED_get_ext_oid(long x509RevokedCtx, String oid);
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native byte[] X509_REVOKED_get_serialNumber(long x509RevokedCtx);
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native long X509_REVOKED_get_ext(long x509RevokedCtx, String oid);
+
+ /** Returns ASN1_TIME reference. */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native long get_X509_REVOKED_revocationDate(long x509RevokedCtx);
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native void X509_REVOKED_print(long bioRef, long x509RevokedCtx);
+
+ // --- X509_EXTENSION ------------------------------------------------------
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native int X509_supported_extension(long x509ExtensionRef);
+
+ // --- ASN1_TIME -----------------------------------------------------------
+
+ @dalvik.annotation.compat.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 -------------------------------------------------
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native long create_BIO_InputStream(OpenSSLBIOInputStream is, boolean isFinite);
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native long create_BIO_OutputStream(OutputStream os);
+
+ @dalvik.annotation.compat.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.
+ String[] allCipherSuites = get_cipher_names("ALL:!DHE");
+
+ // 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();
+
+ @dalvik.annotation.compat.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);
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native byte[] SSL_SESSION_session_id(long sslSessionNativePointer);
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native long SSL_SESSION_get_time(long sslSessionNativePointer);
+
+ static native long SSL_SESSION_get_timeout(long sslSessionNativePointer);
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native String SSL_SESSION_get_version(long sslSessionNativePointer);
+
+ @dalvik.annotation.compat.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);
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native void SSL_SESSION_free(long sslSessionNativePointer);
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static native byte[] i2d_SSL_SESSION(long sslSessionNativePointer);
+
+ @dalvik.annotation.compat.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;
+
+ /**
+ * 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);
+ }
+
+ 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 sets a BiFunction that will
+ * be called to delegate protocol selection to the application. Calling this method overrides
+ * {@link #setApplicationProtocols(long, NativeSsl, boolean, byte[])}.
+ */
+ static native void setApplicationProtocolSelector(
+ long ssl, NativeSsl ssl_holder, ApplicationProtocolSelectorAdapter selector) 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;
+
+ /**
+ * Writes data from the given array to the BIO.
+ */
+ static native int ENGINE_SSL_write_BIO_heap(long ssl, NativeSsl ssl_holder, long bioRef, byte[] sourceJava,
+ int sourceOffset, int sourceLength, SSLHandshakeCallbacks shc)
+ throws IOException, IndexOutOfBoundsException;
+
+ /**
+ * 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;
+
+ /**
+ * Reads data from the given BIO into an array.
+ */
+ static native int ENGINE_SSL_read_BIO_heap(long ssl, NativeSsl ssl_holder, long bioRef, byte[] destJava,
+ int destOffset, int destLength, SSLHandshakeCallbacks shc)
+ throws IOException, IndexOutOfBoundsException;
+
+ /**
+ * 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;
+
+ /**
+ * 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..cc981c2
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/NativeRef.java
@@ -0,0 +1,149 @@
+/* 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
+ protected void finalize() throws Throwable {
+ try {
+ if (address != 0) {
+ doFree(address);
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+ abstract void doFree(long 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..a6d5a32
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/NativeSsl.java
@@ -0,0 +1,662 @@
+/* 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 java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.SocketException;
+import java.nio.charset.Charset;
+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;
+import com.android.org.conscrypt.NativeCrypto.SSLHandshakeCallbacks;
+import com.android.org.conscrypt.SSLParametersImpl.AliasChooser;
+import com.android.org.conscrypt.SSLParametersImpl.PSKCallbacks;
+
+/**
+ * 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[keyTypesSet.size()]);
+
+ 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);
+ }
+
+ 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.setApplicationProtocolSelector(ssl, this, parameters.applicationProtocolSelector);
+ }
+
+ // setup server certificates and private keys.
+ // clients will receive a call back to request certificates.
+ if (!isClient()) {
+ Set<String> keyTypes = new HashSet<String>();
+ for (long sslCipherNativePointer : NativeCrypto.SSL_get_ciphers(ssl, this)) {
+ String keyType = SSLUtils.getServerX509KeyType(sslCipherNativePointer);
+ if (keyType != null) {
+ keyTypes.add(keyType);
+ }
+ }
+ X509KeyManager keyManager = parameters.getX509KeyManager();
+ if (keyManager != null) {
+ for (String keyType : keyTypes) {
+ try {
+ setCertificate(aliasChooser.chooseServerAlias(keyManager, keyType));
+ } catch (CertificateEncodingException e) {
+ throw new IOException(e);
+ }
+ }
+ }
+
+ 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);
+ }
+
+ // 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
+ 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() {
+ if (bio != 0) {
+ return NativeCrypto.SSL_pending_written_bytes_in_BIO(bio);
+ } else {
+ return 0;
+ }
+ }
+
+ int writeDirectByteBuffer(long address, int length) throws IOException {
+ return NativeCrypto.ENGINE_SSL_write_BIO_direct(
+ ssl, NativeSsl.this, bio, address, length, handshakeCallbacks);
+ }
+
+ int readDirectByteBuffer(long destAddress, int destLength) throws IOException {
+ return NativeCrypto.ENGINE_SSL_read_BIO_direct(
+ ssl, NativeSsl.this, bio, destAddress, destLength, handshakeCallbacks);
+ }
+
+ void close() {
+ long toFree = bio;
+ bio = 0L;
+ NativeCrypto.BIO_free_all(toFree);
+ }
+ }
+}
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..5ed56e1
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/NativeSslSession.java
@@ -0,0 +1,485 @@
+/* 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;
+import javax.security.cert.X509Certificate;
+
+/**
+ * A utility wrapper that abstracts operations on the underlying native SSL_SESSION instance.
+ *
+ * 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 e) {
+ log(e);
+ return null;
+ } catch (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() throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getLocalCertificates() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+ 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..02c4acd
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OAEPParameters.java
@@ -0,0 +1,293 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@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;
+
+ @libcore.api.IntraCoreApi
+ 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/OpenSSLAeadCipher.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLAeadCipher.java
new file mode 100644
index 0000000..5542eed
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLAeadCipher.java
@@ -0,0 +1,366 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@Internal
+public abstract class OpenSSLAeadCipher extends OpenSSLCipher {
+ /**
+ * 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;
+
+ public 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(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 ShortBufferException("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;
+ }
+ }
+
+ @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..59c59e9
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLAeadCipherAES.java
@@ -0,0 +1,256 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@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
+ */
+ @libcore.api.IntraCoreApi
+ public static class GCM extends OpenSSLAeadCipherAES {
+
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static class AES_128 extends GCM {
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static class AES_256 extends GCM {
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static class GCM_SIV extends OpenSSLAeadCipherAES {
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static class AES_128 extends GCM_SIV {
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static class AES_256 extends GCM_SIV {
+ @libcore.api.IntraCoreApi
+ 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..3d753eb
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLAeadCipherChaCha20.java
@@ -0,0 +1,79 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@Internal
+public class OpenSSLAeadCipherChaCha20 extends OpenSSLAeadCipher {
+ @libcore.api.IntraCoreApi
+ 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..6a14d01
--- /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;
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ OpenSSLBIOInputStream(InputStream is, boolean isFinite) {
+ super(is);
+
+ ctx = NativeCrypto.create_BIO_InputStream(this, isFinite);
+ }
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ long getBioContext() {
+ return ctx;
+ }
+
+ @dalvik.annotation.compat.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/OpenSSLBIOSink.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLBIOSink.java
new file mode 100644
index 0000000..76fc6e1
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLBIOSink.java
@@ -0,0 +1,78 @@
+/* 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.io.ByteArrayOutputStream;
+
+/**
+ * Wraps a BoringSSL BIO to act as a place to write out data.
+ */
+final class OpenSSLBIOSink {
+ private final long ctx;
+ private final ByteArrayOutputStream buffer;
+ private int position;
+
+ static OpenSSLBIOSink create() {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ return new OpenSSLBIOSink(buffer);
+ }
+
+ private OpenSSLBIOSink(ByteArrayOutputStream buffer) {
+ ctx = NativeCrypto.create_BIO_OutputStream(buffer);
+ this.buffer = buffer;
+ }
+
+ int available() {
+ return buffer.size() - position;
+ }
+
+ void reset() {
+ buffer.reset();
+ position = 0;
+ }
+
+ long skip(long byteCount) {
+ int maxLength = Math.min(available(), (int) byteCount);
+ position += maxLength;
+ if (position == buffer.size()) {
+ reset();
+ }
+ return maxLength;
+ }
+
+ long getContext() {
+ return ctx;
+ }
+
+ byte[] toByteArray() {
+ return buffer.toByteArray();
+ }
+
+ int position() {
+ return position;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ NativeCrypto.BIO_free_all(ctx);
+ } finally {
+ super.finalize();
+ }
+ }
+}
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLBIOSource.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLBIOSource.java
new file mode 100644
index 0000000..dbbd985
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLBIOSource.java
@@ -0,0 +1,107 @@
+/* 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.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
+/**
+ * Wrapped by a BoringSSL BIO to act as a source of bytes.
+ */
+final class OpenSSLBIOSource {
+ private OpenSSLBIOInputStream source;
+
+ static OpenSSLBIOSource wrap(ByteBuffer buffer) {
+ return new OpenSSLBIOSource(
+ new OpenSSLBIOInputStream(new ByteBufferInputStream(buffer), false));
+ }
+
+ private OpenSSLBIOSource(OpenSSLBIOInputStream source) {
+ this.source = source;
+ }
+
+ long getContext() {
+ return source.getBioContext();
+ }
+
+ private synchronized void release() {
+ if (source != null) {
+ NativeCrypto.BIO_free_all(source.getBioContext());
+ source = null;
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ release();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private static class ByteBufferInputStream extends InputStream {
+ private final ByteBuffer source;
+
+ ByteBufferInputStream(ByteBuffer source) {
+ this.source = source;
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (source.remaining() > 0) {
+ return source.get();
+ } else {
+ return -1;
+ }
+ }
+
+ @Override
+ public int available() throws IOException {
+ return source.limit() - source.position();
+ }
+
+ @Override
+ public int read(byte[] buffer) throws IOException {
+ int originalPosition = source.position();
+ source.get(buffer);
+ return source.position() - originalPosition;
+ }
+
+ @Override
+ public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
+ int toRead = Math.min(source.remaining(), byteCount);
+ int originalPosition = source.position();
+ source.get(buffer, byteOffset, toRead);
+ return source.position() - originalPosition;
+ }
+
+ @Override
+ public void reset() throws IOException {
+ source.reset();
+ }
+
+ @Override
+ public long skip(long byteCount) throws IOException {
+ long originalPosition = source.position();
+ source.position((int) (originalPosition + byteCount));
+ return source.position() - originalPosition;
+ }
+ }
+}
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..b80803a
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLCipher.java
@@ -0,0 +1,490 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@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..77dcbeb
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLCipherChaCha20.java
@@ -0,0 +1,164 @@
+/* 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.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+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
+ */
+@libcore.api.IntraCoreApi
+@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;
+
+ @libcore.api.IntraCoreApi
+ public OpenSSLCipherChaCha20() {}
+
+ @Override
+ void engineInitInternal(byte[] encodedKey, AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidKeyException, 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 ShortBufferException("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;
+ }
+ assert currentBlockConsumedBytes == BLOCK_SIZE_BYTES;
+ 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)
+ throws IllegalBlockSizeException, BadPaddingException, ShortBufferException {
+ 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..ed6ecb5
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLCipherRSA.java
@@ -0,0 +1,675 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@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 ShortBufferException("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 {
+ public 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
+ */
+ @libcore.api.IntraCoreApi
+ public static final class PKCS1 extends DirectRSA {
+ @libcore.api.IntraCoreApi
+ public PKCS1() {
+ super(NativeConstants.RSA_PKCS1_PADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class Raw extends DirectRSA {
+ @libcore.api.IntraCoreApi
+ public Raw() {
+ super(NativeConstants.RSA_NO_PADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA1 extends OAEP {
+ @libcore.api.IntraCoreApi
+ public SHA1() {
+ 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 OAEP {
+ @libcore.api.IntraCoreApi
+ public SHA224() {
+ 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 OAEP {
+ @libcore.api.IntraCoreApi
+ public SHA256() {
+ 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 OAEP {
+ @libcore.api.IntraCoreApi
+ public SHA384() {
+ 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 OAEP {
+ @libcore.api.IntraCoreApi
+ 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..7f5cabc
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLContextImpl.java
@@ -0,0 +1,209 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@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 algorithm to initialize all sockets. */
+ private final String[] algorithms;
+
+ /** Client session cache. */
+ private final ClientSessionContext clientSessionContext;
+
+ /** Server session cache. */
+ private final ServerSessionContext serverSessionContext;
+
+ SSLParametersImpl sslParameters;
+
+ /** Allows outside callers to get the preferred SSLContext. */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ static OpenSSLContextImpl getPreferred() {
+ return new TLSv13();
+ }
+
+ OpenSSLContextImpl(String[] algorithms) {
+ this.algorithms = algorithms;
+ clientSessionContext = new ClientSessionContext();
+ serverSessionContext = new ServerSessionContext();
+ }
+
+ /**
+ * Constuctor for the DefaultSSLContextImpl.
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ OpenSSLContextImpl() throws GeneralSecurityException, IOException {
+ synchronized (DefaultSSLContextImpl.class) {
+ this.algorithms = null;
+ 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, algorithms);
+ }
+ }
+
+ /**
+ * 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, algorithms);
+ }
+
+ @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
+ */
+ @libcore.api.IntraCoreApi
+ public static final class TLSv13 extends OpenSSLContextImpl {
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static final class TLSv12 extends OpenSSLContextImpl {
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static final class TLSv11 extends OpenSSLContextImpl {
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static final class TLSv1 extends OpenSSLContextImpl {
+ @libcore.api.IntraCoreApi
+ 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..7b11d8c
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECDHKeyAgreement.java
@@ -0,0 +1,155 @@
+/* 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;
+
+/**
+ * Elliptic Curve Diffie-Hellman key agreement backed by the OpenSSL engine.
+ * @hide This class is not part of the Android public SDK API
+ */
+@libcore.api.IntraCoreApi
+@Internal
+public final class OpenSSLECDHKeyAgreement extends KeyAgreementSpi {
+
+ /** OpenSSL handle of the private key. Only available after the engine has been initialized. */
+ private OpenSSLKey mOpenSslPrivateKey;
+
+ /**
+ * 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;
+
+ @libcore.api.IntraCoreApi
+ public OpenSSLECDHKeyAgreement() {}
+
+ @Override
+ public Key engineDoPhase(Key key, boolean lastPhase) throws InvalidKeyException {
+ if (mOpenSslPrivateKey == null) {
+ throw new IllegalStateException("Not initialized");
+ }
+ if (!lastPhase) {
+ throw new IllegalStateException("ECDH 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());
+ }
+ OpenSSLKey openSslPublicKey = OpenSSLKey.fromPublicKey((PublicKey) key);
+
+ byte[] buffer = new byte[mExpectedResultLength];
+ int actualResultLength = NativeCrypto.ECDH_compute_key(
+ buffer,
+ 0,
+ openSslPublicKey.getNativeRef(),
+ mOpenSslPrivateKey.getNativeRef());
+ byte[] result;
+ if (actualResultLength == -1) {
+ throw new RuntimeException("Engine returned " + actualResultLength);
+ } 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
+ }
+
+ @Override
+ protected int engineGenerateSecret(byte[] sharedSecret, int offset)
+ throws ShortBufferException {
+ checkCompleted();
+ int available = sharedSecret.length - offset;
+ if (mResult.length > available) {
+ throw new ShortBufferException(
+ "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());
+ }
+
+ OpenSSLKey openSslKey = OpenSSLKey.fromPrivateKey((PrivateKey) key);
+ int fieldSizeBits = NativeCrypto.EC_GROUP_get_degree(new NativeRef.EC_GROUP(
+ NativeCrypto.EC_KEY_get1_group(openSslKey.getNativeRef())));
+ mExpectedResultLength = (fieldSizeBits + 7) / 8;
+ mOpenSslPrivateKey = openSslKey;
+ }
+
+ @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/OpenSSLECGroupContext.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECGroupContext.java
new file mode 100644
index 0000000..6774258
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECGroupContext.java
@@ -0,0 +1,181 @@
+/* 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;
+
+/**
+ * Represents a BoringSSL EC_GROUP object.
+ */
+final class OpenSSLECGroupContext {
+ private final NativeRef.EC_GROUP groupCtx;
+
+ OpenSSLECGroupContext(NativeRef.EC_GROUP groupCtx) {
+ this.groupCtx = groupCtx;
+ }
+
+ static OpenSSLECGroupContext getCurveByName(String curveName) {
+ // Workaround for OpenSSL not supporting SECG names for NIST P-256 (aka
+ // ANSI X9.62 prime256v1).
+ if ("secp256r1".equals(curveName)) {
+ curveName = "prime256v1";
+ }
+
+ 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);
+ }
+
+ 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..4891b50
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECKeyFactory.java
@@ -0,0 +1,207 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@Internal
+public final class OpenSSLECKeyFactory extends KeyFactorySpi {
+
+ @libcore.api.IntraCoreApi
+ 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..59e2ec0
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECKeyPairGenerator.java
@@ -0,0 +1,138 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@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;
+
+ @libcore.api.IntraCoreApi
+ 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..433ebc4
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECPrivateKey.java
@@ -0,0 +1,249 @@
+/* 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.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;
+import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+
+/**
+ * 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";
+
+ protected transient OpenSSLKey key;
+
+ protected 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() {
+ return "PKCS#8";
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return NativeCrypto.EVP_marshal_private_key(key.getNativeRef());
+ }
+
+ @Override
+ public ECParameterSpec getParams() {
+ return group.getECParameterSpec();
+ }
+
+ @Override
+ public BigInteger getS() {
+ 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 {
+ 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..0476493
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECPublicKey.java
@@ -0,0 +1,174 @@
+/* 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.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;
+import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+
+/**
+ * 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";
+
+ protected transient OpenSSLKey key;
+
+ protected 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 {
+ 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..34bf157
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLEvpCipher.java
@@ -0,0 +1,213 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@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;
+
+ public 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 ShortBufferException("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 ShortBufferException("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..3a7cf5e
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLEvpCipherAES.java
@@ -0,0 +1,353 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@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
+ */
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static class NoPadding extends CBC {
+ @libcore.api.IntraCoreApi
+ public NoPadding() {
+ super(Padding.NOPADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static class PKCS5Padding extends CBC {
+ @libcore.api.IntraCoreApi
+ public PKCS5Padding() {
+ super(Padding.PKCS5PADDING);
+ }
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static class CTR extends AES {
+ @libcore.api.IntraCoreApi
+ public CTR() {
+ super(Mode.CTR, Padding.NOPADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static class NoPadding extends ECB {
+ @libcore.api.IntraCoreApi
+ public NoPadding() {
+ super(Padding.NOPADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static class PKCS5Padding extends ECB {
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static class NoPadding extends CBC {
+ @libcore.api.IntraCoreApi
+ public NoPadding() {
+ super(Padding.NOPADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static class PKCS5Padding extends CBC {
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static class NoPadding extends ECB {
+ @libcore.api.IntraCoreApi
+ public NoPadding() {
+ super(Padding.NOPADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static class PKCS5Padding extends ECB {
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static class NoPadding extends CBC {
+ @libcore.api.IntraCoreApi
+ public NoPadding() {
+ super(Padding.NOPADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static class PKCS5Padding extends CBC {
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static class NoPadding extends ECB {
+ @libcore.api.IntraCoreApi
+ public NoPadding() {
+ super(Padding.NOPADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static class PKCS5Padding extends ECB {
+ @libcore.api.IntraCoreApi
+ 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..5e86792
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLEvpCipherARC4.java
@@ -0,0 +1,73 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@Internal
+public class OpenSSLEvpCipherARC4 extends OpenSSLEvpCipher {
+ @libcore.api.IntraCoreApi
+ 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..bd8f40a
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLEvpCipherDESEDE.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;
+
+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
+ */
+@libcore.api.IntraCoreApi
+@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
+ */
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static class NoPadding extends CBC {
+ @libcore.api.IntraCoreApi
+ public NoPadding() {
+ super(Padding.NOPADDING);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static class PKCS5Padding extends CBC {
+ @libcore.api.IntraCoreApi
+ 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..0307073
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLKey.java
@@ -0,0 +1,355 @@
+/* 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.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;
+import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+
+/**
+ * Represents a BoringSSL {@code EVP_PKEY}.
+ */
+final class OpenSSLKey {
+ private final NativeRef.EVP_PKEY ctx;
+
+ private final boolean wrapped;
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ OpenSSLKey(long ctx) {
+ this(ctx, false);
+ }
+
+ OpenSSLKey(long ctx, boolean wrapped) {
+ this.ctx = new NativeRef.EVP_PKEY(ctx);
+ this.wrapped = wrapped;
+ }
+
+ /**
+ * Returns the EVP_PKEY context for use in JNI calls.
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ NativeRef.EVP_PKEY getNativeRef() {
+ return ctx;
+ }
+
+ boolean isWrapped() {
+ return wrapped;
+ }
+
+ @dalvik.annotation.compat.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();
+ }
+ }
+
+ @dalvik.annotation.compat.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 new OpenSSLRSAPrivateKey(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..7921778
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLKeyHolder.java
@@ -0,0 +1,28 @@
+/* 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 {
+ @dalvik.annotation.compat.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..538aed1
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLMac.java
@@ -0,0 +1,226 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@Internal
+public abstract class OpenSSLMac extends MacSpi {
+ private NativeRef.HMAC_CTX ctx;
+
+ /**
+ * Holds the EVP_MD for the hashing algorithm, e.g.
+ * EVP_get_digestbyname("sha1");
+ */
+ private final long evp_md;
+
+ /**
+ * The secret key used in this keyed MAC.
+ */
+ private 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(long evp_md, int size) {
+ this.evp_md = evp_md;
+ this.size = size;
+ }
+
+ @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();
+ }
+
+ private final void resetContext() {
+ NativeRef.HMAC_CTX ctxLocal = new NativeRef.HMAC_CTX(NativeCrypto.HMAC_CTX_new());
+ if (keyBytes != null) {
+ NativeCrypto.HMAC_Init_ex(ctxLocal, keyBytes, evp_md);
+ }
+
+ this.ctx = ctxLocal;
+ }
+
+ @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.HMAC_CTX ctxLocal = ctx;
+ NativeCrypto.HMAC_Update(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;
+ }
+
+ // MAC 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.HMAC_CTX ctxLocal = ctx;
+ NativeCrypto.HMAC_UpdateDirect(ctxLocal, ptr, len);
+ input.position(position + len);
+ }
+
+ @Override
+ protected byte[] engineDoFinal() {
+ final NativeRef.HMAC_CTX ctxLocal = ctx;
+ final byte[] output = NativeCrypto.HMAC_Final(ctxLocal);
+ resetContext();
+ return output;
+ }
+
+ @Override
+ protected void engineReset() {
+ resetContext();
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class HmacMD5 extends OpenSSLMac {
+ @libcore.api.IntraCoreApi
+ public HmacMD5() {
+ 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 HmacSHA1 extends OpenSSLMac {
+ @libcore.api.IntraCoreApi
+ public HmacSHA1() {
+ 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 HmacSHA224 extends OpenSSLMac {
+ @libcore.api.IntraCoreApi
+ public HmacSHA224() 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 HmacSHA256 extends OpenSSLMac {
+ @libcore.api.IntraCoreApi
+ public HmacSHA256() 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 HmacSHA384 extends OpenSSLMac {
+ @libcore.api.IntraCoreApi
+ public HmacSHA384() 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 HmacSHA512 extends OpenSSLMac {
+ @libcore.api.IntraCoreApi
+ public HmacSHA512() {
+ super(EvpMdRef.SHA512.EVP_MD, EvpMdRef.SHA512.SIZE_BYTES);
+ }
+ }
+}
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..63c53a8
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLProvider.java
@@ -0,0 +1,593 @@
+/* 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.CorePlatformApi
+@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_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";
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi
+ public OpenSSLProvider() {
+ this(Platform.getDefaultProviderName());
+ }
+
+ public OpenSSLProvider(String providerName) {
+ this(providerName, Platform.provideTrustManagerByDefault());
+ }
+
+ OpenSSLProvider(String providerName, boolean includeTrustManager) {
+ 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 === */
+ final String classOpenSSLContextImpl = PREFIX + "OpenSSLContextImpl";
+ final String tls13SSLContext = classOpenSSLContextImpl + "$TLSv13";
+ // Keep SSL as an alias to TLS
+ put("SSLContext.SSL", tls13SSLContext);
+ put("SSLContext.TLS", tls13SSLContext);
+ put("SSLContext.TLSv1", classOpenSSLContextImpl + "$TLSv1");
+ put("SSLContext.TLSv1.1", classOpenSSLContextImpl + "$TLSv11");
+ put("SSLContext.TLSv1.2", classOpenSSLContextImpl + "$TLSv12");
+ put("SSLContext.TLSv1.3", tls13SSLContext);
+ put("SSLContext.Default", PREFIX + "DefaultSSLContextImpl");
+
+ if (includeTrustManager) {
+ put("TrustManagerFactory.PKIX", TrustManagerFactoryImpl.class.getName());
+ put("Alg.Alias.TrustManagerFactory.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");
+
+ /* == 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");
+
+ /* == SecretKeyFactory == */
+ put("SecretKeyFactory.DESEDE", PREFIX + "DESEDESecretKeyFactory");
+ put("Alg.Alias.SecretKeyFactory.TDEA", "DESEDE");
+
+ /* == KeyAgreement == */
+ putECDHKeyAgreementImplClass("OpenSSLECDHKeyAgreement");
+
+ /* == 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");
+
+ /* === 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 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..4565328
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAKeyFactory.java
@@ -0,0 +1,258 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@Internal
+public final class OpenSSLRSAKeyFactory extends KeyFactorySpi {
+ @libcore.api.IntraCoreApi
+ 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..4501a49
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAKeyPairGenerator.java
@@ -0,0 +1,85 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@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;
+
+ @libcore.api.IntraCoreApi
+ 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..22188bc
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPrivateCrtKey.java
@@ -0,0 +1,285 @@
+/* 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.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;
+
+ 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;
+
+ 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 {
+ 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..bb34171
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPrivateKey.java
@@ -0,0 +1,278 @@
+/* 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.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) {
+ 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() {
+ ensureReadParams();
+ return privateExponent;
+ }
+
+ @Override
+ public final BigInteger getModulus() {
+ ensureReadParams();
+ return modulus;
+ }
+
+ @Override
+ public final byte[] getEncoded() {
+ return NativeCrypto.EVP_marshal_private_key(key.getNativeRef());
+ }
+
+ @Override
+ public final String getFormat() {
+ 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 {
+ 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..69d7309
--- /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;
+
+ @dalvik.annotation.compat.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..540d7e4
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLServerSocketFactoryImpl.java
@@ -0,0 +1,104 @@
+/* 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.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 to be created for all instances.
+ */
+ static void setUseEngineSocketByDefault(boolean useEngineSocket) {
+ useEngineSocketByDefault = 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..f62600d
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSignature.java
@@ -0,0 +1,576 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@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
+ */
+ @libcore.api.IntraCoreApi
+ public static final class MD5RSA extends RSAPKCS1Padding {
+ @libcore.api.IntraCoreApi
+ public MD5RSA() {
+ super(EvpMdRef.MD5.EVP_MD);
+ }
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA1RSA extends RSAPKCS1Padding {
+ @libcore.api.IntraCoreApi
+ public SHA1RSA() {
+ super(EvpMdRef.SHA1.EVP_MD);
+ }
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA224RSA extends RSAPKCS1Padding {
+ @libcore.api.IntraCoreApi
+ public SHA224RSA() {
+ super(EvpMdRef.SHA224.EVP_MD);
+ }
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA256RSA extends RSAPKCS1Padding {
+ @libcore.api.IntraCoreApi
+ public SHA256RSA() {
+ super(EvpMdRef.SHA256.EVP_MD);
+ }
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA384RSA extends RSAPKCS1Padding {
+ @libcore.api.IntraCoreApi
+ public SHA384RSA() {
+ super(EvpMdRef.SHA384.EVP_MD);
+ }
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA512RSA extends RSAPKCS1Padding {
+ @libcore.api.IntraCoreApi
+ public SHA512RSA() {
+ super(EvpMdRef.SHA512.EVP_MD);
+ }
+ }
+
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA1ECDSA extends OpenSSLSignature {
+ @libcore.api.IntraCoreApi
+ public SHA1ECDSA() {
+ super(EvpMdRef.SHA1.EVP_MD, EngineType.EC);
+ }
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA224ECDSA extends OpenSSLSignature {
+ @libcore.api.IntraCoreApi
+ public SHA224ECDSA() {
+ super(EvpMdRef.SHA224.EVP_MD, EngineType.EC);
+ }
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA256ECDSA extends OpenSSLSignature {
+ @libcore.api.IntraCoreApi
+ public SHA256ECDSA() {
+ super(EvpMdRef.SHA256.EVP_MD, EngineType.EC);
+ }
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA384ECDSA extends OpenSSLSignature {
+ @libcore.api.IntraCoreApi
+ public SHA384ECDSA() {
+ super(EvpMdRef.SHA384.EVP_MD, EngineType.EC);
+ }
+ }
+ /**
+ * @hide This class is not part of the Android public SDK API
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA512ECDSA extends OpenSSLSignature {
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA1RSAPSS extends RSAPSSPadding {
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA224RSAPSS extends RSAPSSPadding {
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA256RSAPSS extends RSAPSSPadding {
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA384RSAPSS extends RSAPSSPadding {
+ @libcore.api.IntraCoreApi
+ 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
+ */
+ @libcore.api.IntraCoreApi
+ public static final class SHA512RSAPSS extends RSAPSSPadding {
+ @libcore.api.IntraCoreApi
+ 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..9710801
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSignatureRawECDSA.java
@@ -0,0 +1,138 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@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();
+
+ @libcore.api.IntraCoreApi
+ 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..5b7d2b8
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSignatureRawRSA.java
@@ -0,0 +1,203 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@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;
+
+ @libcore.api.IntraCoreApi
+ 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..748c529
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSocketFactoryImpl.java
@@ -0,0 +1,173 @@
+/* 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.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;
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ private final SSLParametersImpl sslParameters;
+ private final IOException instantiationException;
+ private boolean useEngineSocket = useEngineSocketByDefault;
+
+ @dalvik.annotation.compat.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 to be created for all instances.
+ */
+ static void setUseEngineSocketByDefault(boolean useEngineSocket) {
+ useEngineSocketByDefault = 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..42d0261
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSocketImpl.java
@@ -0,0 +1,183 @@
+/* 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
+@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);
+ }
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @Override
+ public String getHostname() {
+ return super.getHostname();
+ }
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi
+ @Override
+ public void setHostname(String hostname) {
+ super.setHostname(hostname);
+ }
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @Override
+ public String getHostnameOrIP() {
+ return super.getHostnameOrIP();
+ }
+
+ @Override
+ public FileDescriptor getFileDescriptor$() {
+ return super.getFileDescriptor$();
+ }
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi
+ @Override
+ public void setSoWriteTimeout(int writeTimeoutMilliseconds) throws SocketException {
+ super.setSoWriteTimeout(writeTimeoutMilliseconds);
+ }
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @Override
+ public int getSoWriteTimeout() throws SocketException {
+ return super.getSoWriteTimeout();
+ }
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi
+ @Override
+ public void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketException {
+ super.setHandshakeTimeout(handshakeTimeoutMilliseconds);
+ }
+
+ @Override
+ public abstract SSLSession getHandshakeSession();
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi
+ @Override
+ public abstract void setUseSessionTickets(boolean useSessionTickets);
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @Override
+ public abstract void setChannelIdEnabled(boolean enabled);
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @Override
+ public abstract byte[] getChannelId() throws SSLException;
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi
+ @Override
+ public abstract void setChannelIdPrivateKey(PrivateKey privateKey);
+
+ /**
+ * @deprecated NPN is not supported
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi
+ @Override
+ @Deprecated
+ public final byte[] getNpnSelectedProtocol() {
+ return super.getNpnSelectedProtocol();
+ }
+
+ /**
+ * @deprecated NPN is not supported
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi
+ @Override
+ @Deprecated
+ public final void setNpnProtocols(byte[] npnProtocols) {
+ super.setNpnProtocols(npnProtocols);
+ }
+
+ /**
+ * @deprecated use {@link #setApplicationProtocols(String[])} instead.
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @Override
+ @Deprecated
+ public final void setAlpnProtocols(String[] alpnProtocols) {
+ setApplicationProtocols(alpnProtocols == null ? EmptyArray.STRING : alpnProtocols);
+ }
+
+ /**
+ * @deprecated use {@link #getApplicationProtocol()} instead.
+ */
+ @dalvik.annotation.
+ compat.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi
+ @Override
+ @Deprecated
+ public final byte[] getAlpnSelectedProtocol() {
+ return SSLUtils.toProtocolBytes(getApplicationProtocol());
+ }
+
+ /**
+ * @deprecated Use {@link #setAlpnProtocols(String[])} instead.
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi
+ @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/OpenSSLX509CRL.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CRL.java
new file mode 100644
index 0000000..58f831d
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CRL.java
@@ -0,0 +1,420 @@
+/* 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.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.security.auth.x500.X500Principal;
+import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+
+/**
+ * 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<OpenSSLX509CRL>(certRefs.length);
+ for (int i = 0; i < certRefs.length; i++) {
+ if (certRefs[i] == 0) {
+ continue;
+ }
+ certs.add(new OpenSSLX509CRL(certRefs[i]));
+ }
+ 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<OpenSSLX509CRL>(certRefs.length);
+ for (int i = 0; i < certRefs.length; i++) {
+ if (certRefs[i] == 0) {
+ continue;
+ }
+ certs.add(new OpenSSLX509CRL(certRefs[i]));
+ }
+ 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<String>(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<String>(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 CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException {
+ NativeCrypto.X509_CRL_verify(mContext, this, pkey.getNativeRef());
+ }
+
+ private void verifyInternal(PublicKey key, String sigProvider) throws CRLException,
+ 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<OpenSSLX509CRLEntry>();
+ for (long entryRef : entryRefs) {
+ try {
+ crlSet.add(new OpenSSLX509CRLEntry(entryRef));
+ } catch (ParsingException e) {
+ // Skip this entry
+ }
+ }
+
+ return crlSet;
+ }
+
+ @Override
+ public byte[] getTBSCertList() throws CRLException {
+ 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
+ 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..a76c1fc
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CertPath.java
@@ -0,0 +1,263 @@
+/* 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) {
+ }
+ }
+ 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) {
+ }
+ }
+ 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..e8e7d50
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509Certificate.java
@@ -0,0 +1,594 @@
+/* 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.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;
+import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+
+/**
+ * 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;
+
+ @dalvik.annotation.compat.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) {
+ return Collections.emptyList();
+ }
+
+ final List<OpenSSLX509Certificate> certs = new ArrayList<OpenSSLX509Certificate>(
+ certRefs.length);
+ for (int i = 0; i < certRefs.length; i++) {
+ if (certRefs[i] == 0) {
+ continue;
+ }
+ certs.add(new OpenSSLX509Certificate(certRefs[i]));
+ }
+ return certs;
+ }
+
+ @dalvik.annotation.compat.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<OpenSSLX509Certificate>(
+ certRefs.length);
+ for (int i = 0; i < certRefs.length; i++) {
+ if (certRefs[i] == 0) {
+ continue;
+ }
+ certs.add(new OpenSSLX509Certificate(certRefs[i]));
+ }
+ 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<String>(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<String>(Arrays.asList(nonCritOids));
+ }
+
+ @Override
+ public boolean hasUnsupportedCriticalExtension() {
+ return (NativeCrypto.get_X509_ex_flags(mContext, this) & NativeConstants.EXFLAG_CRITICAL) != 0;
+ }
+
+ @Override
+ public void checkValidity() throws CertificateExpiredException,
+ CertificateNotYetValidException {
+ checkValidity(new Date());
+ }
+
+ @Override
+ 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_cert_info_enc(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,
+ NoSuchAlgorithmException,
+ InvalidKeyException, 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 CertificateException,
+ NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException,
+ SignatureException {
+ 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, (String) 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 ignored) {
+ } catch (InvalidKeyException 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 ignored) {
+ } catch (InvalidKeySpecException 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() throws CertificateParsingException {
+ 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<List<?>>(altNameArray.length);
+ for (int i = 0; i < altNameArray.length; i++) {
+ coll.add(Collections.unmodifiableList(Arrays.asList(altNameArray[i])));
+ }
+
+ 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;
+ }
+
+ /**
+ * Delete an extension.
+ *
+ * A modified copy of the certificate is returned. The original object
+ * is unchanged.
+ * If the extension is not present, an unmodified copy is returned.
+ */
+ public OpenSSLX509Certificate withDeletedExtension(String oid) {
+ OpenSSLX509Certificate copy = new OpenSSLX509Certificate(NativeCrypto.X509_dup(mContext, this), notBefore, notAfter);
+ NativeCrypto.X509_delete_ext(copy.getContext(), copy, oid);
+ return copy;
+ }
+
+ @Override
+ 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..6097a71
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CertificateFactory.java
@@ -0,0 +1,352 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@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);
+ }
+ }
+
+ /**
+ * 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] == '-') {
+ if (len == PKCS7_MARKER.length && Arrays.equals(PKCS7_MARKER, buffer)) {
+ List<? extends T> items = fromPkcs7PemInputStream(pbis);
+ if (items.size() == 0) {
+ return null;
+ }
+ items.get(0);
+ } else {
+ return fromX509PemInputStream(pbis);
+ }
+ }
+
+ /* PKCS#7 bags have a byte 0x06 at position 4 in the stream. */
+ if (buffer[4] == 0x06) {
+ 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) {
+ }
+ }
+ throw new ParsingException(e);
+ }
+ }
+
+ Collection<? extends T> generateItems(InputStream inStream)
+ throws ParsingException {
+ if (inStream == null) {
+ throw new ParsingException("inStream == null");
+ }
+ try {
+ if (inStream.available() == 0) {
+ return Collections.emptyList();
+ }
+ } catch (IOException e) {
+ throw new ParsingException("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 fromPkcs7PemInputStream(pbis);
+ }
+
+ /* PKCS#7 bags have a byte 0x06 at position 4 in the stream. */
+ if (buffer[4] == 0x06) {
+ return fromPkcs7DerInputStream(pbis);
+ }
+ } catch (Exception e) {
+ if (markable) {
+ try {
+ inStream.reset();
+ } catch (IOException ignored) {
+ }
+ }
+ 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) {
+ }
+ }
+
+ 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);
+ }
+ };
+
+ @libcore.api.IntraCoreApi
+ 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/PSKKeyManager.java b/repackaged/common/src/main/java/com/android/org/conscrypt/PSKKeyManager.java
new file mode 100644
index 0000000..6bc09ad
--- /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> {@code
+ * 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..29ddac7
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/PSSParameters.java
@@ -0,0 +1,160 @@
+/* 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
+ */
+@libcore.api.IntraCoreApi
+@Internal
+public class PSSParameters extends AlgorithmParametersSpi {
+
+ private PSSParameterSpec spec = PSSParameterSpec.DEFAULT;
+
+ @libcore.api.IntraCoreApi
+ 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..c63861d
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/SSLClientSessionCache.java
@@ -0,0 +1,56 @@
+/* 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
+@Internal
+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);
+}
\ No newline at end of file
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..428b27b
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/SSLNullSession.java
@@ -0,0 +1,182 @@
+/* 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 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
+ 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 ProvidedSessionDecorator.");
+ }
+
+ @Override
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ProvidedSessionDecorator.");
+ }
+
+ @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 ProvidedSessionDecorator.");
+ }
+
+ @Override
+ public void removeValue(String name) {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ProvidedSessionDecorator.");
+ }
+}
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..ff0e80b
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/SSLParametersImpl.java
@@ -0,0 +1,691 @@
+/* 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.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.Set;
+import javax.crypto.SecretKey;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+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
+ @dalvik.annotation.compat.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;
+
+ // 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
+ 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;
+ }
+
+ @dalvik.annotation.compat.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.
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ 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}
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ 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;
+ }
+
+ /**
+ * 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) {}
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the default X.509 trust manager.
+ */
+ @dalvik.annotation.compat.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;
+ }
+
+ 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..8200fe8
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/SSLServerSessionCache.java
@@ -0,0 +1,52 @@
+/* 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.
+ */
+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);
+}
\ No newline at end of file
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..f3226e6
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/SSLUtils.java
@@ -0,0 +1,582 @@
+/* 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 java.lang.Math.min;
+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 java.io.ByteArrayInputStream;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+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;
+import javax.security.cert.CertificateException;
+
+/**
+ * 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", "false"));
+ private static final int MAX_PROTOCOL_LENGTH = 255;
+
+ private static final Charset US_ASCII = Charset.forName("US-ASCII");
+
+ // 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.
+ *
+ * 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>.
+ *
+ * 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) throws SSLException {
+ 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<String>(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<String>(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.
+ */
+ 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 e) {
+ SSLPeerUnverifiedException exception = new SSLPeerUnverifiedException(e.getMessage());
+ exception.initCause(exception);
+ throw exception;
+ } catch (CertificateException e) {
+ SSLPeerUnverifiedException exception = new SSLPeerUnverifiedException(e.getMessage());
+ exception.initCause(exception);
+ 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 much 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..4a9d781
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/SessionSnapshot.java
@@ -0,0 +1,187 @@
+/* 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 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();
+ }
+
+ @Override
+ public String getRequestedServerName() {
+ return requestedServerName;
+ }
+
+ @Override
+ public List<byte[]> getStatusResponses() {
+ List<byte[]> ret = new ArrayList<byte[]>(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 ProvidedSessionDecorator.");
+ }
+
+ @Override
+ public Object getValue(String s) {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ProvidedSessionDecorator.");
+ }
+
+ @Override
+ public void removeValue(String s) {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ProvidedSessionDecorator.");
+ }
+
+ @Override
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException(
+ "All calls to this method should be intercepted by ProvidedSessionDecorator.");
+ }
+
+ @Override
+ public X509Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ throw new SSLPeerUnverifiedException("No peer certificates");
+ }
+
+ @Override
+ public Certificate[] getLocalCertificates() {
+ return null;
+ }
+
+ @Override
+ public javax.security.cert.X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ 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;
+ }
+}
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..3e9c20a
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/TrustManagerImpl.java
@@ -0,0 +1,1051 @@
+/* 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.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;
+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;
+
+/**
+ *
+ * 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
+@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 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 CertBlacklist blacklist;
+ 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
+ *
+ * @param keyStore
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi
+ public TrustManagerImpl(KeyStore keyStore) {
+ this(keyStore, null);
+ }
+
+ public TrustManagerImpl(KeyStore keyStore, CertPinManager manager) {
+ this(keyStore, manager, null);
+ }
+
+ @libcore.api.CorePlatformApi
+ public TrustManagerImpl(KeyStore keyStore, CertPinManager manager,
+ ConscryptCertStore certStore) {
+ this(keyStore, manager, certStore, null);
+ }
+
+ public TrustManagerImpl(KeyStore keyStore, CertPinManager manager,
+ ConscryptCertStore certStore,
+ CertBlacklist blacklist) {
+ this(keyStore, manager, certStore, blacklist, null, null, null);
+ }
+
+ /**
+ * For testing only.
+ */
+ public TrustManagerImpl(KeyStore keyStore, CertPinManager manager,
+ ConscryptCertStore certStore, CertBlacklist blacklist, 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 (blacklist == null) {
+ blacklist = Platform.newDefaultBlacklist();
+ }
+ 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.blacklist = blacklist;
+ this.ctVerifier = new CTVerifier(ctLogStore);
+ this.ctPolicy = ctPolicy;
+ }
+
+ 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
+ @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
+ @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
+ @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.
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi
+ 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
+ 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
+ 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
+ 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(hostname, session)) {
+ throw new CertificateException("No subjectAltNames on the certificate match");
+ }
+ }
+ }
+ return checkTrusted(certs, ocspData, tlsSctData, authType, hostname, clientAuth);
+ }
+
+ private 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 ignored) {
+ } catch (SecurityException ignored) {
+ } catch (IllegalAccessException ignored) {
+ } catch (IllegalArgumentException ignored) {
+ } 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 ignored) {
+ } catch (SecurityException ignored) {
+ } catch (IllegalAccessException ignored) {
+ } catch (IllegalArgumentException ignored) {
+ } 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 blacklisted.
+ checkBlacklist(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 blacklist
+ for (X509Certificate cert : wholeChain) {
+ checkBlacklist(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 checkBlacklist(X509Certificate cert) throws CertificateException {
+ if (blacklist != null && blacklist.isPublicKeyBlackListed(cert.getPublicKey())) {
+ throw new CertificateException("Certificate blacklisted 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.
+ */
+ revChecker.setOptions(Collections.singleton(Option.ONLY_END_ENTITY));
+ }
+
+ 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);
+ }
+ }
+
+ /**
+ * 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 enum GlobalHostnameVerifierAdapter implements ConscryptHostnameVerifier {
+ INSTANCE;
+
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ return HttpsURLConnection.getDefaultHostnameVerifier().verify(hostname, session);
+ }
+ }
+
+ private ConscryptHostnameVerifier getHttpsVerifier() {
+ if (hostnameVerifier != null) {
+ return hostnameVerifier;
+ }
+ ConscryptHostnameVerifier defaultVerifier = getDefaultHostnameVerifier();
+ if (defaultVerifier != null) {
+ return defaultVerifier;
+ }
+ return GlobalHostnameVerifierAdapter.INSTANCE;
+ }
+
+ 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..5df6c41
--- /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
+@Internal
+public final class TrustedCertificateIndex {
+
+ private final Map<X500Principal, List<TrustAnchor>> subjectToTrustAnchors
+ = new HashMap<X500Principal, List<TrustAnchor>>();
+
+ @libcore.api.CorePlatformApi
+ public TrustedCertificateIndex() {}
+
+ public TrustedCertificateIndex(Set<TrustAnchor> anchors) {
+ index(anchors);
+ }
+
+ private void index(Set<TrustAnchor> anchors) {
+ for (TrustAnchor anchor : anchors) {
+ index(anchor);
+ }
+ }
+
+ @libcore.api.CorePlatformApi
+ 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
+ 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) {
+ }
+ }
+ }
+ return null;
+ }
+
+ @libcore.api.CorePlatformApi
+ 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
+ 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) {
+ }
+ }
+ 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..e1ea6e0
--- /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;
+
+ @dalvik.annotation.compat.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..4f2d9b8
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CTVerifier.java
@@ -0,0 +1,261 @@
+/* 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.
+ */
+ private 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..69c9367
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/CertificateEntry.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.
+ */
+
+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;
+ }
+
+ /**
+ * @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");
+ }
+
+ OpenSSLX509Certificate preCert = leaf.withDeletedExtension(CTConstants.X509_SCT_LIST_OID);
+ byte[] tbs = preCert.getTBSCertificate();
+
+ 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..092f166
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ct/SerializationException.java
@@ -0,0 +1,42 @@
+/* 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 {
+ 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/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..84c3926
--- /dev/null
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/io/IoUtils.java
@@ -0,0 +1,66 @@
+/* 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) {
+ }
+ }
+ }
+
+ /**
+ * 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) {
+ }
+ }
+ }
+
+ 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/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..3317765
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/CertPinManagerTest.java
@@ -0,0 +1,143 @@
+/* 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.Security;
+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.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+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 static boolean installedProvider;
+ private List<X509Certificate> expectedFullChain;
+ private X509Certificate[] chain;
+
+ @BeforeClass
+ public static void installConscrypt() {
+ installedProvider = TestUtils.installConscryptIfNotPresent();
+ }
+
+ @AfterClass
+ public static void removeConscrypt() {
+ if (installedProvider) {
+ Security.removeProvider(TestUtils.getConscryptProvider().getName());
+ installedProvider = false;
+ }
+ }
+
+ @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/TrustManagerImplTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/TrustManagerImplTest.java
new file mode 100644
index 0000000..40ca21e
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/TrustManagerImplTest.java
@@ -0,0 +1,486 @@
+/* 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 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.HttpsURLConnection;
+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 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 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";
+
+ // The default hostname verifier on OpenJDK rejects all hostnames, so use our own
+ javax.net.ssl.HostnameVerifier oldDefault = HttpsURLConnection.getDefaultHostnameVerifier();
+ try {
+ HttpsURLConnection.setDefaultHostnameVerifier(new TestHostnameVerifier());
+
+ 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));
+ } 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.setDefaultHostnameVerifier(new ConscryptHostnameVerifier() {
+ @Override
+ public boolean verify(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, new TestHostnameVerifier());
+
+ try {
+ tmi.getTrustedChainForServer(chain, "RSA",
+ new FakeSSLSocket(new FakeSSLSession(badHostname, chain), params));
+ } 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);
+
+ 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);
+ } finally {
+ Conscrypt.setDefaultHostnameVerifier(null);
+ HttpsURLConnection.setDefaultHostnameVerifier(oldDefault);
+ }
+ }
+
+ 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();
+ }
+ }
+
+ private static class TestHostnameVerifier
+ extends com.android.org.conscrypt.javax.net.ssl.TestHostnameVerifier
+ implements ConscryptHostnameVerifier {}
+}
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..ac153fb
--- /dev/null
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/ct/CTVerifierTest.java
@@ -0,0 +1,197 @@
+/* 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.security.Security;
+import java.util.Arrays;
+import com.android.org.conscrypt.OpenSSLX509Certificate;
+import com.android.org.conscrypt.TestUtils;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+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 static boolean installedProvider;
+ private OpenSSLX509Certificate ca;
+ private OpenSSLX509Certificate cert;
+ private OpenSSLX509Certificate certEmbedded;
+ private CTVerifier ctVerifier;
+
+ @BeforeClass
+ public static void installConscrypt() {
+ installedProvider = TestUtils.installConscryptIfNotPresent();
+ }
+
+ @AfterClass
+ public static void removeConscrypt() {
+ if (installedProvider) {
+ Security.removeProvider(TestUtils.getConscryptProvider().getName());
+ installedProvider = false;
+ }
+ }
+
+ @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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParameterGeneratorTestDH.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParameterGeneratorTestDH.java
new file mode 100644
index 0000000..8ec1867
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParameterGeneratorTestDSA.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParameterGeneratorTestDSA.java
new file mode 100644
index 0000000..bd192f3
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersPSSTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersPSSTest.java
new file mode 100644
index 0000000..2c47180
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestAES.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestAES.java
new file mode 100644
index 0000000..df55013
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestAES.java
@@ -0,0 +1,91 @@
+/* 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 dalvik.system.VMRuntime;
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import javax.crypto.spec.IvParameterSpec;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
+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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDES.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDES.java
new file mode 100644
index 0000000..603981c
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/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 com.android.org.conscrypt.TestUtils;
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import javax.crypto.spec.IvParameterSpec;
+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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDESede.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDESede.java
new file mode 100644
index 0000000..37ab2be
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDESede.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.java.security;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import com.android.org.conscrypt.TestUtils;
+import dalvik.system.VMRuntime;
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import javax.crypto.spec.IvParameterSpec;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
+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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDH.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDH.java
new file mode 100644
index 0000000..b6429d0
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDSA.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDSA.java
new file mode 100644
index 0000000..f6585fc
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestDSA.java
@@ -0,0 +1,152 @@
+/* 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 com.android.org.conscrypt.TestUtils;
+import java.math.BigInteger;
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import java.security.spec.DSAParameterSpec;
+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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestGCM.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestGCM.java
new file mode 100644
index 0000000..7ab64bc
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestGCM.java
@@ -0,0 +1,120 @@
+/* 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 dalvik.system.VMRuntime;
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import javax.crypto.spec.GCMParameterSpec;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
+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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestOAEP.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestOAEP.java
new file mode 100644
index 0000000..2176981
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/AlgorithmParametersTestOAEP.java
@@ -0,0 +1,259 @@
+/* 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 dalvik.system.VMRuntime;
+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 org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
+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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestDH.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestDH.java
new file mode 100644
index 0000000..c316d94
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestDSA.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestDSA.java
new file mode 100644
index 0000000..d4e6984
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestRSA.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestRSA.java
new file mode 100644
index 0000000..15593ca
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyFactoryTestRSA.java
@@ -0,0 +1,65 @@
+/* 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.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+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 KeyFactoryTestRSA extends
+ AbstractKeyFactoryTest<RSAPublicKeySpec, RSAPrivateKeySpec> {
+
+ @SuppressWarnings("unchecked")
+ public KeyFactoryTestRSA() {
+ super("RSA", RSAPublicKeySpec.class, RSAPrivateKeySpec.class);
+ }
+
+ @Override
+ protected void check(KeyPair keyPair) throws Exception {
+ new CipherAsymmetricCryptHelper("RSA").test(keyPair);
+ }
+
+ @Test
+ public void testExtraBufferSpace_Private() throws Exception {
+ PrivateKey privateKey = DefaultKeys.getPrivateKey("RSA");
+ byte[] encoded = privateKey.getEncoded();
+ byte[] longBuffer = new byte[encoded.length + 147];
+ System.arraycopy(encoded, 0, longBuffer, 0, encoded.length);
+ KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(longBuffer));
+ }
+
+ @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));
+ }
+}
diff --git a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTest.java
new file mode 100644
index 0000000..5687b44
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTest.java
@@ -0,0 +1,468 @@
+/* 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 dalvik.system.VMRuntime;
+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 org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
+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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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", 512);
+ putKeySize("RSASSA-PSS", 512);
+ 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);
+ }
+
+ /** 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;
+ }
+ if ("EC".equals(algorithm)
+ && "SunPKCS11-NSS".equalsIgnoreCase(kpg.getProvider().getName())
+ && keySize == 224) {
+ // TODO(flooey): Remove when we stop supporting Java 6
+ // This Sun provider doesn't support 224-bit EC keys
+ 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 ("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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestDH.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestDH.java
new file mode 100644
index 0000000..16b23f7
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestDSA.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestDSA.java
new file mode 100644
index 0000000..b97adce
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestRSA.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestRSA.java
new file mode 100644
index 0000000..2e9d074
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTestRSA.java
@@ -0,0 +1,34 @@
+/* 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 {
+
+ @SuppressWarnings("unchecked")
+ public KeyPairGeneratorTestRSA() {
+ super("RSA", new CipherAsymmetricCryptHelper("RSA"));
+ }
+
+}
+
diff --git a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/MessageDigestTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/MessageDigestTest.java
new file mode 100644
index 0000000..83590e9
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/MessageDigestTest.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.java.security;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.org.conscrypt.TestUtils;
+import dalvik.system.VMRuntime;
+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 java.util.Set;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
+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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/SignatureTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/SignatureTest.java
new file mode 100644
index 0000000..ada0405
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/SignatureTest.java
@@ -0,0 +1,3224 @@
+/* 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.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 dalvik.system.VMRuntime;
+import java.math.BigInteger;
+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 org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
+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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // END Android-Added: Allow access to deprecated BC algorithms.
+
+ // 20 bytes for DSA
+ private final byte[] 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")
+ .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(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(DATA);
+ assertTrue(sig.getAlgorithm(), sig.verify(signature));
+
+ // After verify, should be reusable as if we are after initVerify
+ sig.update(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"));
+ }
+
+ @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");
+ sig.initVerify(pubKey);
+ sig.update(Vector1Data);
+
+ assertTrue("Signature must match expected signature",
+ sig.verify(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");
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must match expected signature",
+ sig.verify(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");
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must match expected signature",
+ sig.verify(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");
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must match expected signature",
+ sig.verify(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");
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must match expected signature",
+ sig.verify(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) {
+ }
+ }
+
+ @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);
+
+ 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_SHA224withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+
+ final PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA224withRSA");
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertTrue("Signature should match expected",
+ Arrays.equals(signature, SHA224withRSA_Vector2Signature));
+
+ 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_SHA256withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+
+ final PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA256withRSA");
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertTrue("Signature should match expected",
+ Arrays.equals(signature, SHA256withRSA_Vector2Signature));
+
+ 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_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);
+
+ Signature sig = Signature.getInstance("SHA384withRSA");
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertTrue("Signature should match expected",
+ Arrays.equals(signature, SHA384withRSA_Vector2Signature));
+
+ 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_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);
+
+ Signature sig = Signature.getInstance("SHA512withRSA");
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertTrue("Signature should match expected",
+ Arrays.equals(signature, SHA512withRSA_Vector2Signature));
+
+ 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_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);
+
+ Signature sig = Signature.getInstance("MD5withRSA");
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertTrue("Signature should match expected",
+ Arrays.equals(signature, MD5withRSA_Vector2Signature));
+
+ 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_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.
+ */
+ public 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.
+ */
+ public 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.
+ */
+ public 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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/cert/CertificateFactoryTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/cert/CertificateFactoryTest.java
new file mode 100644
index 0000000..54dcee2
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/cert/CertificateFactoryTest.java
@@ -0,0 +1,717 @@
+/* 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.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 dalvik.system.VMRuntime;
+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.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.Date;
+import java.util.GregorianCalendar;
+import java.util.Iterator;
+import java.util.List;
+import java.util.TimeZone;
+import javax.security.auth.x500.X500Principal;
+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.bouncycastle.x509.X509V3CertificateGenerator;
+import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
+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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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==";
+
+ @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);
+ }
+ });
+ }
+
+ private void test_generateCertificate(CertificateFactory cf) throws Exception {
+ {
+ byte[] valid = VALID_CERTIFICATE_PEM.getBytes(Charset.defaultCharset());
+ Certificate c = cf.generateCertificate(new ByteArrayInputStream(valid));
+ assertNotNull(c);
+ }
+
+ {
+ byte[] valid = VALID_CERTIFICATE_PEM_CRLF.getBytes(Charset.defaultCharset());
+ Certificate c = cf.generateCertificate(new ByteArrayInputStream(valid));
+ assertNotNull(c);
+ }
+
+ {
+ byte[] valid = TestUtils.decodeBase64(VALID_CERTIFICATE_DER_BASE64);
+ Certificate c = cf.generateCertificate(new ByteArrayInputStream(valid));
+ assertNotNull(c);
+ }
+
+ 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 expected) {
+ }
+
+ 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 expected) {
+ }
+ }
+
+ /*
+ * 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));
+ }
+ assertFalse(providerName, Arrays.toString(encoded).equals(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, (CertPath) 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);
+ }
+
+ X509V3CertificateGenerator certGen = new 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 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());
+ }
+}
diff --git a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/cert/X509CertificateTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/cert/X509CertificateTest.java
new file mode 100644
index 0000000..6456e70
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/cert/X509CertificateTest.java
@@ -0,0 +1,214 @@
+/* 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.assertEquals;
+import static org.junit.Assert.fail;
+
+import dalvik.system.VMRuntime;
+import java.io.ByteArrayInputStream;
+import java.nio.charset.Charset;
+import java.security.InvalidKeyException;
+import java.security.Provider;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
+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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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";
+
+ // 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 {
+ CertificateFactory cf = CertificateFactory.getInstance("X509", p);
+ try {
+ Certificate c = cf.generateCertificate(
+ new ByteArrayInputStream(MISMATCHED_ALGORITHM_CERT.getBytes(
+ Charset.forName("US-ASCII"))));
+ 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 {
+ CertificateFactory cf = CertificateFactory.getInstance("X509", p);
+ Certificate c = cf.generateCertificate(new ByteArrayInputStream(
+ EC_EXPLICIT_KEY_CERT.getBytes(Charset.forName("US-ASCII"))));
+ 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 {
+ CertificateFactory cf = CertificateFactory.getInstance("X509", p);
+ Certificate c = cf.generateCertificate(new ByteArrayInputStream(
+ VALID_CERT.getBytes(Charset.forName("US-ASCII"))));
+ assertEquals("SHA256WITHRSA",
+ ((X509Certificate) c).getSigAlgName().toUpperCase());
+ }
+ });
+ }
+}
diff --git a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/crypto/AeadCipherTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/crypto/AeadCipherTest.java
new file mode 100644
index 0000000..fd70f86
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/crypto/CipherBasicsTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/crypto/CipherBasicsTest.java
new file mode 100644
index 0000000..0ae78f4
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/crypto/CipherBasicsTest.java
@@ -0,0 +1,280 @@
+/* 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 org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+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.ArrayList;
+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 com.android.org.conscrypt.TestUtils;
+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<String, String>();
+ 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<String, String>();
+ 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 = readCsvResource(entry.getValue());
+ for (String[] line : data) {
+ Key key = new SecretKeySpec(toBytes(line[KEY_INDEX]),
+ getBaseAlgorithm(transformation));
+ byte[] iv = toBytes(line[IV_INDEX]);
+ byte[] plaintext = toBytes(line[PLAINTEXT_INDEX]);
+ byte[] ciphertext = toBytes(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));
+ assertTrue("Provider " + p.getName()
+ + ", algorithm " + transformation
+ + " failed on encryption, data is " + Arrays.toString(line),
+ Arrays.equals(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));
+ assertTrue("Provider " + p.getName()
+ + ", algorithm " + transformation
+ + " failed on decryption, data is " + Arrays.toString(line),
+ Arrays.equals(plaintext, cipher.doFinal(ciphertext)));
+ } catch (InvalidKeyException e) {
+ // Some providers may not support raw SecretKeySpec keys, that's allowed
+ }
+ }
+ }
+ }
+ }
+
+ @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();
+
+ Cipher cipher;
+ try {
+ cipher = Cipher.getInstance(transformation, p);
+ } catch (NoSuchAlgorithmException e) {
+ // This provider doesn't provide this algorithm, ignore it
+ continue;
+ }
+
+ List<String[]> data = readCsvResource(entry.getValue());
+ for (String[] line : data) {
+ Key key = new SecretKeySpec(toBytes(line[KEY_INDEX]),
+ getBaseAlgorithm(transformation));
+ byte[] iv = toBytes(line[IV_INDEX]);
+ byte[] plaintext = toBytes(line[PLAINTEXT_INDEX]);
+ byte[] ciphertext = toBytes(line[CIPHERTEXT_INDEX]);
+ byte[] tag = toBytes(line[TAG_INDEX]);
+ byte[] aad = toBytes(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 {
+ 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);
+ assertTrue("Provider " + p.getName()
+ + ", algorithm " + transformation
+ + " failed on encryption, data is " + Arrays.toString(line),
+ Arrays.equals(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));
+ assertTrue("Provider " + p.getName()
+ + ", algorithm " + transformation
+ + " failed on decryption, data is " + Arrays.toString(line),
+ Arrays.equals(plaintext, cipher.doFinal(combinedOutput)));
+ } 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
+ }
+ }
+ }
+ }
+ }
+
+ private static List<String[]> readCsvResource(String resourceName) throws IOException {
+ InputStream stream = CipherBasicsTest.class.getResourceAsStream(resourceName);
+ List<String[]> lines = new ArrayList<String[]>();
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (line.isEmpty() || line.startsWith("#")) {
+ continue;
+ }
+ lines.add(line.split(",", -1));
+ }
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+ return lines;
+ }
+
+ /**
+ * 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;
+ }
+
+ private static byte[] toBytes(String hex) {
+ return TestUtils.decodeHex(hex, /* allowSingleChar= */ true);
+ }
+}
diff --git a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/crypto/CipherTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/crypto/CipherTest.java
new file mode 100644
index 0000000..0e0ab48
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/crypto/CipherTest.java
@@ -0,0 +1,4754 @@
+/* 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.assertTrue;
+import static org.junit.Assert.fail;
+
+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 org.bouncycastle.asn1.x509.KeyUsage;
+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 org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import dalvik.system.VMRuntime;
+import sun.security.jca.Providers;
+
+/**
+ * @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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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;
+ }
+ 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/PKCS7PADDING", 16);
+ setExpectedBlockSize("AES_128/CBC/NOPADDING", 16);
+ setExpectedBlockSize("AES_128/ECB/PKCS5PADDING", 16);
+ setExpectedBlockSize("AES_128/ECB/PKCS7PADDING", 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/PKCS7PADDING", 16);
+ setExpectedBlockSize("AES_256/CBC/NOPADDING", 16);
+ setExpectedBlockSize("AES_256/ECB/PKCS5PADDING", 16);
+ setExpectedBlockSize("AES_256/ECB/PKCS7PADDING", 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("ARCFOUR", 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/PKCS7PADDING", 8);
+ setExpectedBlockSize("DESEDE/CBC/NOPADDING", 8);
+ setExpectedBlockSize("DESEDE/CFB/PKCS5PADDING", 8);
+ setExpectedBlockSize("DESEDE/CFB/PKCS7PADDING", 8);
+ setExpectedBlockSize("DESEDE/CFB/NOPADDING", 8);
+ setExpectedBlockSize("DESEDE/CTR/PKCS5PADDING", 8);
+ setExpectedBlockSize("DESEDE/CTR/PKCS7PADDING", 8);
+ setExpectedBlockSize("DESEDE/CTR/NOPADDING", 8);
+ setExpectedBlockSize("DESEDE/CTS/PKCS5PADDING", 8);
+ setExpectedBlockSize("DESEDE/CTS/PKCS7PADDING", 8);
+ setExpectedBlockSize("DESEDE/CTS/NOPADDING", 8);
+ setExpectedBlockSize("DESEDE/ECB/PKCS5PADDING", 8);
+ setExpectedBlockSize("DESEDE/ECB/PKCS7PADDING", 8);
+ setExpectedBlockSize("DESEDE/ECB/NOPADDING", 8);
+ setExpectedBlockSize("DESEDE/OFB/PKCS5PADDING", 8);
+ setExpectedBlockSize("DESEDE/OFB/PKCS7PADDING", 8);
+ setExpectedBlockSize("DESEDE/OFB/NOPADDING", 8);
+ setExpectedBlockSize("PBEWITHSHAAND2-KEYTRIPLEDES-CBC", 8);
+ setExpectedBlockSize("PBEWITHSHAAND3-KEYTRIPLEDES-CBC", 8);
+ setExpectedBlockSize("PBEWITHMD5ANDTRIPLEDES", 8);
+ setExpectedBlockSize("PBEWITHSHA1ANDDESEDE", 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 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 {
+ 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";
+ }
+
+ // 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'
+ */
+ public 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'
+ */
+ public 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'
+ */
+ public 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'
+ */
+ public 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'
+ */
+ public 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'
+ */
+ public 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'
+ */
+ public 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'
+ */
+ public 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'
+ */
+ public 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;
+ }
+ 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;
+ }
+
+ 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) {
+ 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 that when reading GCM parameters encoded using ASN1, a value for the tag size
+ // not present indicates a value of 12.
+ // https://b/29876633
+ @Test
+ public void test_DefaultGCMTagSizeAlgorithmParameterSpec() throws Exception {
+ Assume.assumeNotNull(Security.getProvider("BC"));
+ final String AES = "AES";
+ final String AES_GCM = "AES/GCM/NoPadding";
+ byte[] input = new byte[16];
+ byte[] key = new byte[16];
+ Cipher cipher = Cipher.getInstance(AES_GCM, "BC");
+ AlgorithmParameters param = AlgorithmParameters.getInstance("GCM");
+ param.init(new byte[] {
+ (byte) 48, // DER encoding : tag_Sequence
+ (byte) 14, // DER encoding : total length
+ (byte) 4, // DER encoding : tag_OctetString
+ (byte) 12, // DER encoding : counter length
+ (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
+ (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 });
+ cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, AES), param);
+ byte[] ciphertext = cipher.update(input);
+ assertEquals(16, ciphertext.length);
+ byte[] tag = cipher.doFinal();
+ assertEquals(12, tag.length);
+ }
+
+ @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 {
+ Cipher c = Cipher.getInstance("AES/ECB/NoPadding", 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 {
+ Cipher c = Cipher.getInstance("AES/ECB/NoPadding", 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. 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_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);
+ 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)));
+ }
+
+ /**
+ * 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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/crypto/ECDHKeyAgreementTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/crypto/ECDHKeyAgreementTest.java
new file mode 100644
index 0000000..7a0d8f0
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/crypto/ECDHKeyAgreementTest.java
@@ -0,0 +1,551 @@
+/* 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 dalvik.system.VMRuntime;
+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 org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
+
+/**
+ * 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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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];
+ }
+ // 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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/crypto/KeyGeneratorTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/crypto/KeyGeneratorTest.java
new file mode 100644
index 0000000..4028ce9
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/crypto/KeyGeneratorTest.java
@@ -0,0 +1,194 @@
+/* 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 dalvik.system.VMRuntime;
+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 org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
+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
+ @BeforeClass
+ public static void enableDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ VMRuntime.getRuntime().getTargetSdkVersion());
+ }
+
+ @AfterClass
+ public static void restoreDeprecatedAlgorithms() {
+ Providers.setMaximumAllowableApiLevelForBcDeprecation(
+ Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
+ }
+ // 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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/HttpsURLConnectionTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/HttpsURLConnectionTest.java
new file mode 100644
index 0000000..78425dc
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/HttpsURLConnectionTest.java
@@ -0,0 +1,168 @@
+/* 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.assertNotNull;
+import static org.junit.Assert.assertSame;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.URL;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSession;
+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 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:///";
+
+ @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() {
+ assertNotNull(HttpsURLConnection.getDefaultSSLSocketFactory());
+ }
+
+ @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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyManagerFactoryTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyManagerFactoryTest.java
new file mode 100644
index 0000000..d2424c7
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyManagerFactoryTest.java
@@ -0,0 +1,521 @@
+/* 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 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 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 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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyStoreBuilderParametersTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyStoreBuilderParametersTest.java
new file mode 100644
index 0000000..ff34e5b
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SNIHostNameTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SNIHostNameTest.java
new file mode 100644
index 0000000..48e8eee
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLContextTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLContextTest.java
new file mode 100644
index 0000000..fd767b8
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLContextTest.java
@@ -0,0 +1,745 @@
+/* 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.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+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.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 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 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(expected = NoSuchAlgorithmException.class)
+ 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);
+ SSLContext.getInstance("SSLv3", defaultTlsProvider);
+ }
+
+ private static void assertContentsInOrder(List<String> expected, String... actual) {
+ if (expected.size() != actual.length) {
+ fail("Unexpected length. Expected len <" + expected.size() + ">, actual len <"
+ + actual.length + ">, expected <" + expected + ">, actual <"
+ + Arrays.asList(actual) + ">");
+ }
+ if (!expected.equals(Arrays.asList(actual))) {
+ fail("Unexpected element(s). Expected <" + expected + ">, actual <"
+ + Arrays.asList(actual) + ">");
+ }
+ }
+
+ 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) {
+ 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();
+ }
+ });
+ }
+ }
+}
diff --git a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineTest.java
new file mode 100644
index 0000000..fc773ca
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineTest.java
@@ -0,0 +1,949 @@
+/* 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.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.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.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+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());
+ int numUnwrapCalls = 0;
+ while (destIn.position() != sourceBytes.length) {
+ SSLEngineResult destRes = dest.unwrap(sourceToDest, destIn);
+ assertEquals(sourceCipherSuite, HandshakeStatus.NOT_HANDSHAKING,
+ destRes.getHandshakeStatus());
+ numUnwrapCalls++;
+ }
+ destIn.flip();
+ byte[] actual = new byte[destIn.remaining()];
+ destIn.get(actual);
+ assertEquals(sourceCipherSuite, Arrays.toString(sourceBytes), Arrays.toString(actual));
+ assertEquals(sourceCipherSuite, 3, numUnwrapCalls);
+ }
+
+ @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 boolean[] wasCalled = new boolean[1];
+ 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("Expected enabled suites to contain " + sessionSuite
+ + ", got: " + enabledSuites,
+ enabledSuites.contains(sessionSuite));
+ wasCalled[0] = true;
+ } 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();
+ assertTrue(wasCalled[0]);
+ }
+
+ @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 boolean[] wasCalled = new boolean[1];
+ 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
+ assertEquals(referenceEngine.getEnabledCipherSuites()[0],
+ session.getCipherSuite());
+ assertNotNull(session.getLocalCertificates());
+ assertEquals("CN=localhost",
+ ((X509Certificate) session.getLocalCertificates()[0])
+ .getSubjectDN()
+ .getName());
+ assertEquals("CN=Test Intermediate Certificate Authority",
+ ((X509Certificate) session.getLocalCertificates()[0])
+ .getIssuerDN()
+ .getName());
+ wasCalled[0] = true;
+ } 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();
+ assertTrue(wasCalled[0]);
+ }
+
+ @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(TestKeyStore.getServer(), 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();
+ }
+
+ 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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineVersionCompatibilityTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineVersionCompatibilityTest.java
new file mode 100644
index 0000000..bad2a27
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineVersionCompatibilityTest.java
@@ -0,0 +1,755 @@
+/* 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.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.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.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+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 javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+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.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());
+ int numUnwrapCalls = 0;
+ while (destIn.position() != sourceBytes.length) {
+ SSLEngineResult destRes = dest.unwrap(sourceToDest, destIn);
+ assertEquals(sourceCipherSuite, HandshakeStatus.NOT_HANDSHAKING,
+ destRes.getHandshakeStatus());
+ numUnwrapCalls++;
+ }
+ destIn.flip();
+ byte[] actual = new byte[destIn.remaining()];
+ destIn.get(actual);
+ assertEquals(sourceCipherSuite, Arrays.toString(sourceBytes), Arrays.toString(actual));
+ assertEquals(sourceCipherSuite, 3, numUnwrapCalls);
+ }
+
+ @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);
+ }
+
+ 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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLParametersTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLParametersTest.java
new file mode 100644
index 0000000..93cb054
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLServerSocketFactoryTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLServerSocketFactoryTest.java
new file mode 100644
index 0000000..debf19c
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLServerSocketTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLServerSocketTest.java
new file mode 100644
index 0000000..7ad349e
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLServerSocketTest.java
@@ -0,0 +1,130 @@
+/* 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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSessionContextTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSessionContextTest.java
new file mode 100644
index 0000000..4f51dd6
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSessionContextTest.java
@@ -0,0 +1,419 @@
+/* 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
+ 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
+ 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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSessionTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSessionTest.java
new file mode 100644
index 0000000..4fe8310
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSessionTest.java
@@ -0,0 +1,537 @@
+/* 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.
+ }
+ assertNotNull(s.client.getPeerCertificates());
+ TestKeyStore.assertChainLength(s.client.getPeerCertificateChain());
+ try {
+ assertNull(s.server.getPeerCertificateChain());
+ fail();
+ } catch (SSLPeerUnverifiedException expected) {
+ // Ignored.
+ }
+ 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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketFactoryTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketFactoryTest.java
new file mode 100644
index 0000000..d13c039
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketTest.java
new file mode 100644
index 0000000..457ce1d
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketTest.java
@@ -0,0 +1,1104 @@
+/* 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.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.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+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.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+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 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 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;
+import tests.util.ForEachRunner;
+import tests.util.ForEachRunner.Callback;
+import tests.util.Pair;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class SSLSocketTest {
+ private ExecutorService executor;
+ private ThreadGroup threadGroup;
+
+ @Before
+ public void setup() {
+ threadGroup = new ThreadGroup("SSLSocketTest");
+ 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_defaultConfiguration() throws Exception {
+ SSLConfigurationAsserts.assertSSLSocketDefaultConfiguration(
+ (SSLSocket) SSLSocketFactory.getDefault().createSocket());
+ }
+
+ @Test
+ public void test_SSLSocket_getSupportedCipherSuites_returnsCopies() throws Exception {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ 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) throws Exception {
+ 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);
+ try {
+ @SuppressWarnings("unused")
+ int value = server.getInputStream().read();
+ fail();
+ } catch (IOException expected) {
+ // Ignored.
+ }
+ client.setSoTimeout(10);
+ try {
+ @SuppressWarnings("unused")
+ int value = client.getInputStream().read();
+ fail();
+ } catch (IOException expected) {
+ // Ignored.
+ }
+ 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_getEnabledCipherSuites_returnsCopies() throws Exception {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ SSLSocket ssl = (SSLSocket) sf.createSocket();
+ assertNotSame(ssl.getEnabledCipherSuites(), ssl.getEnabledCipherSuites());
+ }
+
+ @Test
+ public void test_SSLSocket_setEnabledCipherSuites_storesCopy() throws Exception {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ 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);
+ SSLSocket ssl = (SSLSocket) context.getSocketFactory().createSocket();
+ try {
+ ssl.setEnabledCipherSuites(null);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ try {
+ ssl.setEnabledCipherSuites(new String[1]);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ try {
+ ssl.setEnabledCipherSuites(new String[] {"Bogus"});
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ 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();
+ SSLSocket ssl = (SSLSocket) sf.createSocket();
+ // 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));
+ }
+
+ @Test
+ public void test_SSLSocket_getSupportedProtocols_returnsCopies() throws Exception {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ SSLSocket ssl = (SSLSocket) sf.createSocket();
+ assertNotSame(ssl.getSupportedProtocols(), ssl.getSupportedProtocols());
+ }
+
+ @Test
+ public void test_SSLSocket_getEnabledProtocols_returnsCopies() throws Exception {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ SSLSocket ssl = (SSLSocket) sf.createSocket();
+ assertNotSame(ssl.getEnabledProtocols(), ssl.getEnabledProtocols());
+ }
+
+ @Test
+ public void test_SSLSocket_setEnabledProtocols_storesCopy() throws Exception {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ 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();
+ SSLSocket ssl = (SSLSocket) sf.createSocket();
+ try {
+ ssl.setEnabledProtocols(null);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ try {
+ ssl.setEnabledProtocols(new String[1]);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ try {
+ ssl.setEnabledProtocols(new String[] {"Bogus"});
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ 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)) {
+ try {
+ ssl.setEnabledProtocols(new String[] {protocol});
+ fail("Should fail when SSLv2Hello is set by itself");
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ } 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;
+ SSLSocket client = (SSLSocket)
+ clientContext.getSocketFactory().createSocket(c.host, c.port);
+ client.setEnabledProtocols(new String[] {"TLSv1.2", "TLSv1"});
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ server.setEnabledProtocols(new String[] {"TLSv1.2", "TLSv1.1", "TLSv1"});
+ 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();
+
+ assertEquals("TLSv1", 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;
+ SSLSocket client = (SSLSocket)
+ clientContext.getSocketFactory().createSocket(c.host, c.port);
+ client.setEnabledProtocols(new String[] {"TLSv1.2", "TLSv1"});
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ server.setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1"});
+ 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();
+
+ assertEquals("TLSv1", client.getSession().getProtocol());
+
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ }
+
+ @Test
+ public void test_SSLSocket_getSession() throws Exception {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ 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();
+ 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 boolean[] wasCalled = new boolean[1];
+ 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());
+ assertEquals(referenceClientSocket.getEnabledCipherSuites()[0],
+ session.getCipherSuite());
+ wasCalled[0] = true;
+ } 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(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ server.startHandshake();
+ return null;
+ }
+ });
+ executor.shutdown();
+ client.startHandshake();
+
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ assertTrue(wasCalled[0]);
+ }
+
+ @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 boolean[] wasCalled = new boolean[1];
+ 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
+ assertEquals(referenceClientSocket.getEnabledCipherSuites()[0],
+ session.getCipherSuite());
+ assertNotNull(session.getLocalCertificates());
+ assertEquals("CN=localhost",
+ ((X509Certificate) session.getLocalCertificates()[0])
+ .getSubjectDN()
+ .getName());
+ assertEquals("CN=Test Intermediate Certificate Authority",
+ ((X509Certificate) session.getLocalCertificates()[0])
+ .getIssuerDN()
+ .getName());
+ wasCalled[0] = true;
+ } 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(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ server.setNeedClientAuth(true);
+ server.startHandshake();
+ return null;
+ }
+ });
+ executor.shutdown();
+ client.startHandshake();
+
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ assertTrue(wasCalled[0]);
+ }
+
+ @Test
+ public void test_SSLSocket_setUseClientMode_afterHandshake() throws Exception {
+ // can't set after handshake
+ TestSSLSocketPair pair = TestSSLSocketPair.create().connect();
+ try {
+ pair.server.setUseClientMode(false);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ try {
+ pair.client.setUseClientMode(false);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // Ignored.
+ }
+ }
+
+ @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(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) {
+ 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();
+ 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();
+ 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 {
+ 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);
+ try {
+ @SuppressWarnings("unused")
+ int value = clientWrapping.getInputStream().read();
+ fail();
+ } catch (SocketTimeoutException expected) {
+ // Ignored.
+ }
+ 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(new Callback<SSLSocketFactory>() {
+ @Override
+ public void run(SSLSocketFactory sslSocketFactory) throws Exception {
+ 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(new Callback<SSLSocketFactory>() {
+ @Override
+ public void run(SSLSocketFactory sslSocketFactory) throws Exception {
+ 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(new Callback<SSLSocketFactory>() {
+ @Override
+ public void run(SSLSocketFactory sslSocketFactory) throws Exception {
+ ClientHello clientHello = TlsTester
+ .captureTlsHandshakeClientHello(executor, sslSocketFactory);
+ assertEquals(TlsProtocolVersion.TLSv1_2, clientHello.clientVersion);
+ }
+ }, getSSLSocketFactoriesToTest());
+ }
+
+ @Test
+ public void test_SSLSocket_ClientHello_compressionMethods() throws Exception {
+ ForEachRunner.runNamed(new Callback<SSLSocketFactory>() {
+ @Override
+ public void run(SSLSocketFactory sslSocketFactory) throws Exception {
+ 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<Pair<String, SSLSocketFactory>>();
+ 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(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ server.setEnabledProtocols(new String[]{"TLSv1.2"});
+ server.setEnabledCipherSuites(serverCipherSuites);
+ server.startHandshake();
+ return null;
+ }
+ });
+ Future<Void> c = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ 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();
+ 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(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ server.setEnabledProtocols(new String[]{"TLSv1.2", "TLSv1.1"});
+ server.startHandshake();
+ return null;
+ }
+ });
+ Future<Void> c = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ 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();
+ 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(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ server.setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1"});
+ server.setEnabledCipherSuites(serverCipherSuites);
+ try {
+ server.startHandshake();
+ fail("Should result in inappropriate fallback");
+ } catch (SSLHandshakeException expected) {
+ Throwable cause = expected.getCause();
+ assertEquals(SSLProtocolException.class, cause.getClass());
+ assertInappropriateFallbackIsCause(cause);
+ }
+ return null;
+ }
+ });
+ Future<Void> c = runAsync(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ client.setEnabledProtocols(new String[]{"TLSv1"});
+ client.setEnabledCipherSuites(clientCipherSuites);
+ try {
+ client.startHandshake();
+ fail("Should receive TLS alert inappropriate fallback");
+ } catch (SSLHandshakeException expected) {
+ 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 {
+ for (final String protocol : new String[] {"TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"}) {
+ 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")));
+ }
+ }
+ }
+
+ 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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java
new file mode 100644
index 0000000..b0594e6
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java
@@ -0,0 +1,2056 @@
+/* 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.assertNull;
+import static org.junit.Assert.assertSame;
+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.Locale;
+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.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+import org.junit.After;
+import org.junit.Before;
+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.ForEachRunner.Callback;
+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() {
+ // 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;
+ 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) {
+ 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();
+ SSLSocket 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());
+ synchronized (handshakeCompletedListenerCalled) {
+ handshakeCompletedListenerCalled[0] = true;
+ handshakeCompletedListenerCalled.notify();
+ }
+ handshakeCompletedListenerCalled[0] = true;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ 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);
+ X509KeyManager keyManager = new X509KeyManager() {
+ @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 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];
+ X509KeyManager keyManager = new X509KeyManager() {
+ @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);
+ }
+ };
+ 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();
+ }
+ /**
+ * 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
+ 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 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 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 static String osName() {
+ return System.getProperty("os.name").toLowerCase(Locale.US).replaceAll("[^a-z0-9]+", "");
+ }
+
+ private static boolean isLinux() {
+ return osName().startsWith("linux");
+ }
+
+ private static boolean isWindows() {
+ return osName().startsWith("windows");
+ }
+
+ private static boolean isOsx() {
+ String name = osName();
+ return name.startsWith("macosx") || name.startsWith("osx");
+ }
+
+ 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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/TrustManagerFactoryTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/TrustManagerFactoryTest.java
new file mode 100644
index 0000000..06ec3a2
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/TrustManagerFactoryTest.java
@@ -0,0 +1,320 @@
+/* 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 com.android.org.conscrypt.Conscrypt;
+import com.android.org.conscrypt.java.security.StandardNames;
+import com.android.org.conscrypt.java.security.TestKeyStore;
+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 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/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/X509KeyManagerTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/X509KeyManagerTest.java
new file mode 100644
index 0000000..96a573d
--- /dev/null
+++ b/repackaged/openjdk-integ-tests/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/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..65d5d11
--- /dev/null
+++ b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Java8PlatformUtil.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 static javax.net.ssl.StandardConstants.SNI_HOST_NAME;
+
+import java.util.Collections;
+import java.util.List;
+import javax.net.ssl.SNIHostName;
+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) {
+ impl.setEndpointIdentificationAlgorithm(params.getEndpointIdentificationAlgorithm());
+ impl.setUseCipherSuitesOrder(params.getUseCipherSuitesOrder());
+ List<SNIServerName> serverNames = params.getServerNames();
+
+ if (serverNames != null) {
+ for (SNIServerName serverName : serverNames) {
+ if (serverName.getType() == SNI_HOST_NAME) {
+ socket.setHostname(((SNIHostName) serverName).getAsciiName());
+ break;
+ }
+ }
+ }
+ }
+
+ 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.singletonList(
+ (SNIServerName) new SNIHostName(socket.getHostname())));
+ }
+ }
+
+ 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() == SNI_HOST_NAME) {
+ engine.setHostname(((SNIHostName) serverName).getAsciiName());
+ break;
+ }
+ }
+ }
+ }
+ 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.singletonList(
+ (SNIServerName) new SNIHostName(engine.getHostname())));
+ }
+ }
+
+ 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..7916ee0
--- /dev/null
+++ b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Platform.java
@@ -0,0 +1,782 @@
+/* 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) {
+ }
+ 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 {
+ Field f_impl = Socket.class.getDeclaredField("impl");
+ f_impl.setAccessible(true);
+ Object socketImpl = f_impl.get(s);
+ 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 ignore) {
+ // passthrough and return addr.getHostAddress()
+ } catch (IllegalAccessException ignore) {
+ } catch (NoSuchMethodException ignore) {
+ }
+
+ 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 (CertificateException ignored) {
+ } catch (NoSuchAlgorithmException ignored) {
+ } catch (IOException 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 CertBlacklist newDefaultBlacklist() {
+ return null;
+ }
+
+ static CTLogStore newDefaultLogStore() {
+ return null;
+ }
+
+ static CTPolicy newDefaultPolicy(CTLogStore logStore) {
+ return null;
+ }
+
+ 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();
+ }
+ });
+ }
+ }
+}
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..e4520d8
--- /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.Matchers.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..adfe804
--- /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.Matchers.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.Matchers;
+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), Matchers.anyListOf(String.class)))
+ .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..a92b6d8
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptEngineTest.java
@@ -0,0 +1,555 @@
+/* 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.getProtocols;
+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.Matchers.same;
+import static org.mockito.Mockito.when;
+
+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 com.android.org.conscrypt.java.security.TestKeyStore;
+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.Matchers;
+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;
+ private static final String[] CIPHERS = TestUtils.getCommonCipherSuites();
+ private static final String RENEGOTIATION_CIPHER = CIPHERS[CIPHERS.length - 1];
+
+ /**
+ * @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), Matchers.anyListOf(String.class)))
+ .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), Matchers.anyListOf(String.class)))
+ .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
+ serverEngine.setEnabledCipherSuites(new String[] {RENEGOTIATION_CIPHER});
+ serverEngine.beginHandshake();
+ doHandshake(false);
+
+ exchangeMessage(newMessage(MESSAGE_SIZE), serverEngine, clientEngine);
+ }
+
+ @Test
+ public void savedSessionWorksAfterClose() throws Exception {
+ setupEngines(TestKeyStore.getClient(), TestKeyStore.getServer());
+ doHandshake(true);
+
+ SSLSession session = clientEngine.getSession();
+ String cipherSuite = session.getCipherSuite();
+
+ clientEngine.closeOutbound();
+ clientEngine.closeInbound();
+
+ assertEquals(cipherSuite, session.getCipherSuite());
+ }
+
+ 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(CIPHERS);
+ 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(getProtocols()[0], provider);
+ return initSslContext(ctx, keyStore);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
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..2ffbbf9
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptSocketTest.java
@@ -0,0 +1,649 @@
+/* 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.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.Matchers.any;
+import static org.mockito.Matchers.anyListOf;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+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.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+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.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];
+
+ @BeforeClass
+ public static void installConscrypt() {
+ TestUtils.installConscryptAsDefaultProvider();
+ }
+
+ @AfterClass
+ public static void removeConscrypt() {
+ Security.removeProvider(TestUtils.getConscryptProvider().getName());
+ }
+
+ /**
+ * 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;
+ }
+
+ @Override
+ Socket newServerSocket(OpenSSLContextImpl context, ServerSocket server,
+ SSLSocketFactory factory) throws IOException {
+ return server.accept();
+ }
+ },
+ PLAIN {
+ @Override
+ Socket newClientSocket(OpenSSLContextImpl context, ServerSocket server,
+ SSLSocketFactory factory) throws IOException {
+ return new Socket(server.getInetAddress(), server.getLocalPort());
+ }
+
+ @Override
+ Socket newServerSocket(OpenSSLContextImpl context, ServerSocket server,
+ SSLSocketFactory factory) throws IOException {
+ return server.accept();
+ }
+ },
+ 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;
+ abstract Socket newServerSocket(OpenSSLContextImpl context, ServerSocket server,
+ SSLSocketFactory factory) throws IOException;
+ }
+
+ /**
+ * 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;
+ }
+ }
+
+ @Parameters(name = "{0} wrapping {1}")
+ public static Object[][] data() {
+ return new Object[][] {
+ {SocketType.FILE_DESCRIPTOR, UnderlyingSocketType.NONE},
+ {SocketType.FILE_DESCRIPTOR, UnderlyingSocketType.PLAIN},
+ // Not supported: {SocketType.FILE_DESCRIPTOR, UnderlyingSocketType.SSL},
+ {SocketType.ENGINE, UnderlyingSocketType.NONE},
+ {SocketType.ENGINE, UnderlyingSocketType.PLAIN},
+ {SocketType.ENGINE, UnderlyingSocketType.SSL}};
+ }
+
+ @Parameter
+ public SocketType socketType;
+
+ @Parameter(1)
+ public UnderlyingSocketType underlyingSocketType;
+
+ private X509Certificate ca;
+ private X509Certificate cert;
+ private X509Certificate certEmbedded;
+ private PrivateKey certKey;
+
+ private Field contextSSLParameters;
+ private ExecutorService executor;
+
+ @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);
+ 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 doHandshake() throws Exception {
+ ServerSocket listener = 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.doHandshake();
+
+ 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.doHandshake();
+
+ 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), anyListOf(String.class)))
+ .thenReturn("spdy/2");
+ c.serverHooks.alpnProtocolSelector = selector;
+
+ c.doHandshake();
+
+ 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), anyListOf(String.class)))
+ .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.doHandshake();
+
+ 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.doHandshake();
+
+ 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.doHandshake();
+
+ 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 = 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 = 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 {
+ TestConnection connection = new TestConnection(new X509Certificate[] {cert, ca}, certKey);
+ connection.doHandshake();
+
+ SSLSession session = connection.client.getSession();
+ String cipherSuite = session.getCipherSuite();
+
+ connection.client.close();
+
+ assertEquals(cipherSuite, session.getCipherSuite());
+ }
+
+ 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/ConscryptTest.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptTest.java
new file mode 100644
index 0000000..91c4f24
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptTest.java
@@ -0,0 +1,48 @@
+/* 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.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+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());
+ }
+}
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..f8a4a6d
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/MockSessionBuilder.java
@@ -0,0 +1,86 @@
+/* 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;
+
+/**
+ * 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.getProtocols()[0]);
+ when(session.getPeerHost()).thenReturn(host);
+ when(session.getPeerPort()).thenReturn(port);
+ when(session.getCipherSuite()).thenReturn(cipherSuite);
+ when(session.toBytes()).thenReturn(encodedBytes);
+ 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..e6c43f4
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/NativeCryptoTest.java
@@ -0,0 +1,3140 @@
+/* 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.Matchers.same;
+import static org.mockito.Mockito.when;
+
+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 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 org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Matchers;
+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);
+
+ 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.
+ */
+ 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;
+
+ TestSSLHandshakeCallbacks(Socket socket, long sslNativePointer, Hooks hooks) {
+ this.socket = socket;
+ this.sslNativePointer = sslNativePointer;
+ this.hooks = hooks;
+ }
+
+ 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;
+ }
+ }
+
+ 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);
+ }
+ 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);
+ 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.setApplicationProtocolSelector(s, null, alpnSelector);
+ }
+ 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);
+ }
+
+ @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);
+
+ 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);
+
+ 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);
+ }
+
+ @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);
+ 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);
+ 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);
+ 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);
+ }
+
+ @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);
+ }
+
+ @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);
+ }
+
+ @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), Matchers.anyListOf(String.class)))
+ .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), Matchers.anyListOf(String.class)))
+ .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);
+ }
+
+ @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();
+ new NativeRef.EVP_PKEY_CTX(pkeyCtx);
+ NativeCrypto.EVP_PKEY_CTX_set_rsa_oaep_md(pkeyCtx, NULL);
+ }
+
+ @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..07439e0
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/OpenSSLX509CertificateTest.java
@@ -0,0 +1,140 @@
+/* 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 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.Modifier;
+import java.util.Arrays;
+import junit.framework.TestCase;
+import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+
+/**
+ * @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 = Field.class.getDeclaredField("modifiers");
+ modifiersField.setAccessible(true);
+ modifiersField.setInt(targetUID, targetUID.getModifiers() & ~Modifier.FINAL);
+ } catch (NoSuchFieldException 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.withDeletedExtension(CT_POISON_EXTENSION).getTBSCertificate(),
+ cert.getTBSCertificate()));
+ }
+
+ public void test_deletingExtensionMakesCopy() throws Exception {
+ /* Calling withDeletedExtension should not modify the original certificate, only make a copy.
+ * 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));
+
+ OpenSSLX509Certificate certWithoutExtension = certPoisoned.withDeletedExtension(CT_POISON_EXTENSION);
+
+ assertTrue(certPoisoned.getCriticalExtensionOIDs().contains(CT_POISON_EXTENSION));
+ assertFalse(certWithoutExtension.getCriticalExtensionOIDs().contains(CT_POISON_EXTENSION));
+ }
+
+ public void test_deletingMissingExtension() throws Exception {
+ /* withDeletedExtension should be safe to call on a certificate without the extension, and
+ * return an identical copy.
+ */
+ OpenSSLX509Certificate cert = loadTestCertificate("cert.pem");
+ assertFalse(cert.getCriticalExtensionOIDs().contains(CT_POISON_EXTENSION));
+
+ OpenSSLX509Certificate cert2 = cert.withDeletedExtension(CT_POISON_EXTENSION);
+ assertEquals(cert, cert2);
+ }
+}
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..eddaa18
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/PlatformTest.java
@@ -0,0 +1,179 @@
+/* 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 org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.lang.reflect.Method;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.List;
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIServerName;
+import javax.net.ssl.SSLParameters;
+import org.junit.Assume;
+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;
+ }
+
+ private static boolean isJavaVersion(int version) {
+ return Platform.javaVersion() >= version;
+ }
+
+ private static void assumeJava8() {
+ Assume.assumeTrue("Require Java 8: " + Platform.javaVersion(), isJavaVersion(8));
+ }
+
+ @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));
+ }
+ }
+
+ 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..a6df39d
--- /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 String[] CIPHERS = TestUtils.getCommonCipherSuites();
+ 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;
+ private volatile boolean stopping;
+
+ Client(boolean useEngineSocket, int port) {
+ try {
+ SSLSocketFactory socketFactory = newConscryptClientContext().getSocketFactory();
+ Conscrypt.setUseEngineSocket(socketFactory, useEngineSocket);
+ socket = (SSLSocket) socketFactory.createSocket(
+ TestUtils.getLoopbackAddress(), port);
+ socket.setEnabledCipherSuites(CIPHERS);
+ } 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 {
+ stopping = true;
+ 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(CIPHERS));
+ 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.setEnabledCipherSuites(CIPHERS);
+ 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..8366738
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/SSLUtilsTest.java
@@ -0,0 +1,226 @@
+/* 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);
+ }
+
+ 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..c5986cc
--- /dev/null
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ServerSessionContextTest.java
@@ -0,0 +1,50 @@
+/* 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
+ 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/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/CertBlacklistImpl.java b/repackaged/platform/src/main/java/com/android/org/conscrypt/CertBlacklistImpl.java
new file mode 100644
index 0000000..e2c0773
--- /dev/null
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/CertBlacklistImpl.java
@@ -0,0 +1,266 @@
+/* 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.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+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 CertBlacklistImpl implements CertBlacklist {
+ private static final Logger logger = Logger.getLogger(CertBlacklistImpl.class.getName());
+
+ private final Set<BigInteger> serialBlacklist;
+ private final Set<byte[]> pubkeyBlacklist;
+
+ /**
+ * public for testing only.
+ */
+ public CertBlacklistImpl(Set<BigInteger> serialBlacklist, Set<byte[]> pubkeyBlacklist) {
+ this.serialBlacklist = serialBlacklist;
+ this.pubkeyBlacklist = pubkeyBlacklist;
+ }
+
+ public static CertBlacklist getDefault() {
+ String androidData = System.getenv("ANDROID_DATA");
+ String blacklistRoot = androidData + "/misc/keychain/";
+ String defaultPubkeyBlacklistPath = blacklistRoot + "pubkey_blacklist.txt";
+ String defaultSerialBlacklistPath = blacklistRoot + "serial_blacklist.txt";
+
+ Set<byte[]> pubkeyBlacklist = readPublicKeyBlackList(defaultPubkeyBlacklistPath);
+ Set<BigInteger> serialBlacklist = readSerialBlackList(defaultSerialBlacklistPath);
+ return new CertBlacklistImpl(serialBlacklist, pubkeyBlacklist);
+ }
+
+ 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 readBlacklist(String path) {
+ try {
+ return readFileAsString(path);
+ } catch (FileNotFoundException ignored) {
+ } catch (IOException e) {
+ logger.log(Level.WARNING, "Could not read blacklist", 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) {
+ }
+ }
+ }
+
+ private static Set<BigInteger> readSerialBlackList(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 serialBlacklist = readBlacklist(path);
+ if (!serialBlacklist.equals("")) {
+ for(String value : serialBlacklist.split(",")) {
+ 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<byte[]> readPublicKeyBlackList(String path) {
+
+ // start out with a base set of known bad values
+ Set<byte[]> bl = new HashSet<byte[]>(Arrays.asList(
+ // Blacklist test cert for CTS. The cert and key can be found in
+ // src/test/resources/blacklist_test_ca.pem and
+ // src/test/resources/blacklist_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 pubkeyBlacklist = readBlacklist(path);
+ if (!pubkeyBlacklist.equals("")) {
+ for (String value : pubkeyBlacklist.split(",")) {
+ value = value.trim();
+ if (isPubkeyHash(value)) {
+ bl.add(value.getBytes(UTF_8));
+ } else {
+ logger.log(Level.WARNING, "Tried to blacklist invalid pubkey " + value);
+ }
+ }
+ }
+
+ return bl;
+ }
+
+ @Override
+ public boolean isPublicKeyBlackListed(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 (byte[] blacklisted : pubkeyBlacklist) {
+ if (Arrays.equals(blacklisted, 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 isSerialNumberBlackListed(BigInteger serial) {
+ return serialBlacklist.contains(serial);
+ }
+
+}
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..c24a313
--- /dev/null
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/Platform.java
@@ -0,0 +1,516 @@
+/* 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 android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructTimeval;
+import dalvik.system.BlockGuard;
+import dalvik.system.CloseGuard;
+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.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.Collections;
+import java.util.List;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.net.ssl.SNIHostName;
+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 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 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) {
+ throw errnoException.rethrowAsSocketException();
+ }
+ }
+
+ 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 CertBlacklist newDefaultBlacklist() {
+ return CertBlacklistImpl.getDefault();
+ }
+
+ static CTLogStore newDefaultLogStore() {
+ return new CTLogStoreImpl();
+ }
+
+ static CTPolicy newDefaultPolicy(CTLogStore logStore) {
+ return new CTPolicyImpl(logStore, 2);
+ }
+}
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..7296890
--- /dev/null
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/TrustedCertificateStore.java
@@ -0,0 +1,691 @@
+/* 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.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;
+import com.android.org.conscrypt.io.IoUtils;
+
+/**
+ * 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
+ * methods {@link #isTrustAnchor} and {@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
+@Internal
+public class TrustedCertificateStore implements ConscryptCertStore {
+
+ private static final 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
+ 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");
+ 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
+ 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;
+
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi
+ public TrustedCertificateStore() {
+ this(PreloadHolder.defaultCaCertsSystemDir, PreloadHolder.defaultCaCertsAddedDir,
+ PreloadHolder.defaultCaCertsDeletedDir);
+ }
+
+ public TrustedCertificateStore(File systemDir, File addedDir, File deletedDir) {
+ this.systemDir = systemDir;
+ this.addedDir = addedDir;
+ this.deletedDir = deletedDir;
+ }
+
+ @libcore.api.CorePlatformApi
+ public Certificate getCertificate(String alias) {
+ return getCertificate(alias, false);
+ }
+
+ @libcore.api.CorePlatformApi
+ 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
+ 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) {
+ return null;
+ }
+ return new Date(time);
+ }
+
+ @libcore.api.CorePlatformApi
+ 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
+ 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
+ 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
+ public boolean containsAlias(String alias) {
+ return containsAlias(alias, false);
+ }
+
+ private boolean containsAlias(String alias, boolean includeDeletedSystem) {
+ return getCertificate(alias, includeDeletedSystem) != null;
+ }
+
+ @libcore.api.CorePlatformApi
+ public String getCertificateAlias(Certificate c) {
+ return getCertificateAlias(c, false);
+ }
+
+ @libcore.api.CorePlatformApi
+ 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
+ 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
+ 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
+ @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
+ 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
+ @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 = findCert(addedDir, issuer, selector, Set.class);
+ 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 = findCert(systemDir, issuer, selector, Set.class);
+ 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
+ */
+ @dalvik.annotation.compat.UnsupportedAppUsage
+ @libcore.api.CorePlatformApi
+ 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);
+ }
+
+ 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
+ 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
+ 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..37c84c8
--- /dev/null
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/ct/CTLogStoreImpl.java
@@ -0,0 +1,257 @@
+/* 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.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+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;
+import com.android.org.conscrypt.Internal;
+import com.android.org.conscrypt.InternalUtil;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@Internal
+public class CTLogStoreImpl implements CTLogStore {
+ private static final Charset US_ASCII = Charset.forName("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 File userLogDir;
+ private File systemLogDir;
+ private CTLogInfo[] fallbackLogs;
+
+ private HashMap<ByteBuffer, CTLogInfo> logCache = new HashMap<>();
+ private 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) {}
+
+ try {
+ return loadLog(new File(systemLogDir, filename));
+ } catch (InvalidLogFileException e) {
+ return null;
+ } catch (FileNotFoundException e) {}
+
+ // 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..4e19318
--- /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/test/java/com/android/org/conscrypt/CertBlacklistTest.java b/repackaged/platform/src/test/java/com/android/org/conscrypt/CertBlacklistTest.java
new file mode 100644
index 0000000..454ac30
--- /dev/null
+++ b/repackaged/platform/src/test/java/com/android/org/conscrypt/CertBlacklistTest.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 CertBlacklistTest extends TestCase {
+
+ private static final String BLACKLIST_CA = "test_blacklist_ca.pem";
+ private static final String BLACKLISTED_CHAIN = "blacklist_test_chain.pem";
+ private static final String BLACKLIST_FALLBACK_VALID_CA = "blacklist_test_valid_ca.pem";
+ private static final String BLACKLISTED_VALID_CHAIN = "blacklist_test_valid_chain.pem";
+
+ /**
+ * Ensure that the test blacklisted CA is actually blacklisted by default.
+ */
+ public void testBlacklistedPublicKey() throws Exception {
+ X509Certificate blacklistedCa = loadCertificate(BLACKLIST_CA);
+ CertBlacklist blacklist = CertBlacklistImpl.getDefault();
+ assertTrue(blacklist.isPublicKeyBlackListed(blacklistedCa.getPublicKey()));
+ }
+
+ /**
+ * Check that the blacklisted CA is rejected even if it used as a root of trust
+ */
+ public void testBlacklistedCaUntrusted() throws Exception {
+ X509Certificate blacklistedCa = loadCertificate(BLACKLIST_CA);
+ assertUntrusted(new X509Certificate[] {blacklistedCa}, getTrustManager(blacklistedCa));
+ }
+
+ /**
+ * Check that a chain that is rooted in a blacklisted trusted CA is rejected.
+ */
+ public void testBlacklistedRootOfTrust() throws Exception {
+ // Chain is leaf -> blacklisted
+ X509Certificate[] chain = loadCertificates(BLACKLISTED_CHAIN);
+ X509Certificate blacklistedCa = loadCertificate(BLACKLIST_CA);
+ assertUntrusted(chain, getTrustManager(blacklistedCa));
+ }
+
+ /** Test that the path building correctly routes around a blacklisted cert where there are
+ * other valid paths available. This prevents breakage where a cert was cross signed by a
+ * blacklisted CA but is still valid due to also being cross signed by CAs that remain trusted.
+ * Path:
+ *
+ * leaf -> intermediate -> blacklisted_ca
+ * \
+ * -------> trusted_ca
+ */
+ public void testBlacklistedIntermediateFallback() throws Exception {
+ X509Certificate[] chain = loadCertificates(BLACKLISTED_VALID_CHAIN);
+ X509Certificate blacklistedCa = loadCertificate(BLACKLIST_CA);
+ X509Certificate validCa = loadCertificate(BLACKLIST_FALLBACK_VALID_CA);
+ assertTrusted(chain, getTrustManager(blacklistedCa, validCa));
+ // Check that without the trusted_ca the chain is invalid (since it only chains to a
+ // blacklisted ca)
+ assertUntrusted(chain, getTrustManager(blacklistedCa));
+ }
+
+ 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..6ca624f
--- /dev/null
+++ b/repackaged/platform/src/test/java/com/android/org/conscrypt/TrustedCertificateStoreTest.java
@@ -0,0 +1,987 @@
+/* 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.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.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 com.android.org.conscrypt.java.security.TestKeyStore;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+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 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);
+ }
+ }
+
+ private TrustedCertificateStore store;
+
+ @Override protected void setUp() {
+ setupStore();
+ }
+
+ private void setupStore() {
+ dirSystem.mkdirs();
+ cleanStore();
+ createStore();
+ }
+
+ private void createStore() {
+ store = new TrustedCertificateStore(dirSystem, dirAdded, dirDeleted);
+ }
+
+ @Override protected 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();
+ }
+
+ public void testEmptyDirectories() throws Exception {
+ assertEmpty();
+ }
+
+ public void testOneSystemOneDeleted() throws Exception {
+ install(getCa1(), getAliasSystemCa1());
+ store.deleteCertificateEntry(getAliasSystemCa1());
+ assertEmpty();
+ assertDeleted(getCa1(), getAliasSystemCa1());
+ }
+
+ public void testTwoSystemTwoDeleted() throws Exception {
+ install(getCa1(), getAliasSystemCa1());
+ store.deleteCertificateEntry(getAliasSystemCa1());
+ install(getCa2(), getAliasSystemCa2());
+ store.deleteCertificateEntry(getAliasSystemCa2());
+ assertEmpty();
+ assertDeleted(getCa1(), getAliasSystemCa1());
+ assertDeleted(getCa2(), getAliasSystemCa2());
+ }
+
+ 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);
+ }
+
+ public void testTwoSystem() throws Exception {
+ testTwo(getCa1(), getAliasSystemCa1(),
+ getCa2(), getAliasSystemCa2());
+ }
+
+ public void testTwoUser() throws Exception {
+ testTwo(getCa1(), getAliasUserCa1(),
+ getCa2(), getAliasUserCa2());
+ }
+
+ public void testOneSystemOneUser() throws Exception {
+ testTwo(getCa1(), getAliasSystemCa1(),
+ getCa2(), getAliasUserCa2());
+ }
+
+ public void testTwoSystemSameSubject() throws Exception {
+ testTwo(getCa1(), getAliasSystemCa1(),
+ getCa3WithCa1Subject(), getAliasSystemCa3Collision());
+ }
+
+ 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();
+ }
+
+ 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);
+ }
+
+
+ public void testOneSystemOneUserOneDeleted() throws Exception {
+ install(getCa1(), getAliasSystemCa1());
+ store.installCertificate(getCa2());
+ store.deleteCertificateEntry(getAliasSystemCa1());
+ assertDeleted(getCa1(), getAliasSystemCa1());
+ assertRootCa(getCa2(), getAliasUserCa2());
+ assertAliases(getAliasUserCa2());
+ }
+
+ public void testOneSystemOneUserOneDeletedSameSubject() throws Exception {
+ install(getCa1(), getAliasSystemCa1());
+ store.installCertificate(getCa3WithCa1Subject());
+ store.deleteCertificateEntry(getAliasSystemCa1());
+ assertDeleted(getCa1(), getAliasSystemCa1());
+ assertRootCa(getCa3WithCa1Subject(), getAliasUserCa3());
+ assertAliases(getAliasUserCa3());
+ }
+
+ public void testUserMaskingSystem() throws Exception {
+ install(getCa1(), getAliasSystemCa1());
+ install(getCa1(), getAliasUserCa1());
+ assertMasked(getCa1(), getAliasSystemCa1());
+ assertRootCa(getCa1(), getAliasUserCa1());
+ assertAliases(getAliasSystemCa1(), getAliasUserCa1());
+ }
+
+ 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();
+ }
+
+ public void testMissingSystemDirectory() throws Exception {
+ cleanStore();
+ createStore();
+ assertEmpty();
+ }
+
+ public void testWithExistingUserDirectories() throws Exception {
+ dirAdded.mkdirs();
+ dirDeleted.mkdirs();
+ install(getCa1(), getAliasSystemCa1());
+ assertRootCa(getCa1(), getAliasSystemCa1());
+ assertAliases(getAliasSystemCa1());
+ }
+
+ 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();
+ }
+
+ 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());
+ }
+
+ 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());
+
+ }
+
+ 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());
+ }
+
+ public void testDeleteEmpty() throws Exception {
+ store.deleteCertificateEntry(getAliasSystemCa1());
+ assertEmpty();
+ assertDeleted(getCa1(), getAliasSystemCa1());
+ }
+
+ public void testDeleteUser() throws Exception {
+ store.installCertificate(getCa1());
+ assertRootCa(getCa1(), getAliasUserCa1());
+ assertAliases(getAliasUserCa1());
+
+ store.deleteCertificateEntry(getAliasUserCa1());
+ assertEmpty();
+ assertDeleted(getCa1(), getAliasUserCa1());
+ assertNoTombstone(getAliasUserCa1());
+ }
+
+ 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());
+ }
+
+ 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));
+ }
+
+ 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()));
+ }
+
+ public void testSystemCaCertsUseCorrectFileNames() throws Exception {
+ TrustedCertificateStore store = new TrustedCertificateStore();
+
+ // 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");
+ 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("System 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
+ // trust. Thus, we assert that they work as expected for all system certificates.
+ assertNotNull("Issuer certificate not found for system certificate " + actualFile,
+ store.findIssuer(cert));
+ assertNotNull("Trust anchor not found for system certificate " + actualFile,
+ store.getTrustAnchor(cert));
+ }
+
+ // 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);
+ }
+
+ 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));
+ }
+
+ 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..606c099
--- /dev/null
+++ b/repackaged/platform/src/test/java/com/android/org/conscrypt/ct/CTLogStoreImplTest.java
@@ -0,0 +1,205 @@
+/* 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 java.io.BufferedWriter;
+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.io.StringBufferInputStream;
+import java.security.PublicKey;
+import junit.framework.TestCase;
+import com.android.org.conscrypt.InternalUtil;
+
+/**
+ * @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 StringBufferInputStream(
+ "-----BEGIN PUBLIC KEY-----\n" +
+ LOG_KEYS[i] + "\n" +
+ "-----END PUBLIC KEY-----\n"));
+ 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 StringBufferInputStream(LOGS_SERIALIZED[0]));
+ 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 StringBufferInputStream("")));
+ try {
+ CTLogStoreImpl.loadLog(new StringBufferInputStream("randomgarbage"));
+ 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/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/TestUtils.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/TestUtils.java
new file mode 100644
index 0000000..0545d77
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/TestUtils.java
@@ -0,0 +1,704 @@
+/* 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 java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+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.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.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+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 com.android.org.conscrypt.java.security.StandardNames;
+import com.android.org.conscrypt.java.security.TestKeyStore;
+import com.android.org.conscrypt.testing.Streams;
+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 = Charset.forName("UTF-8");
+ private static final String PROTOCOL_TLS_V1_2 = "TLSv1.2";
+ private static final String PROTOCOL_TLS_V1_1 = "TLSv1.1";
+ private static final String PROTOCOL_TLS_V1 = "TLSv1";
+ private static final String[] DESIRED_PROTOCOLS =
+ new String[] {PROTOCOL_TLS_V1_2, PROTOCOL_TLS_V1_1, /* For Java 6 */ PROTOCOL_TLS_V1};
+ private static final Provider JDK_PROVIDER = getDefaultTlsProvider();
+ private static final byte[] CHARS =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".getBytes(UTF_8);
+ private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocateDirect(0);
+ private static final String[] PROTOCOLS = getProtocolsInternal();
+
+ static final String TEST_CIPHER = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256";
+
+ private TestUtils() {}
+
+ private static Provider getDefaultTlsProvider() {
+ for (String protocol : DESIRED_PROTOCOLS) {
+ for (Provider p : Security.getProviders()) {
+ if (hasProtocol(p, protocol)) {
+ return p;
+ }
+ }
+ }
+ // For Java 1.6 testing
+ return new BouncyCastleProvider();
+ }
+
+ private static boolean hasProtocol(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 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);
+
+ if (!isClassAvailable("javax.net.ssl.X509ExtendedTrustManager")) {
+ return (Provider) c.newInstance(defaultName, false);
+ } else {
+ return (Provider) c.newInstance(defaultName, true);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static synchronized boolean installConscryptIfNotPresent() {
+ Provider conscryptProvider = getConscryptProvider();
+ if (Security.getProvider(conscryptProvider.getName()) == null) {
+ Security.insertProviderAt(conscryptProvider, 1);
+ return true;
+ }
+ return false;
+ }
+
+ public static synchronized void installConscryptAsDefaultProvider() {
+ final 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), "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)));
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Returns an array containing only {@link #PROTOCOL_TLS_V1_2}.
+ */
+ public static String[] getProtocols() {
+ return PROTOCOLS;
+ }
+
+ private static String[] getProtocolsInternal() {
+ List<String> protocols = new ArrayList<String>();
+ for (String protocol : DESIRED_PROTOCOLS) {
+ if (hasProtocol(getJdkProvider(), protocol)) {
+ protocols.add(protocol);
+ }
+ }
+ return protocols.toArray(new String[protocols.size()]);
+ }
+
+ public static SSLSocketFactory getJdkSocketFactory() {
+ return getSocketFactory(JDK_PROVIDER);
+ }
+
+ public static SSLServerSocketFactory getJdkServerSocketFactory() {
+ return getServerSocketFactory(JDK_PROVIDER);
+ }
+
+ 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);
+ }
+ }
+
+ 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);
+ }
+ }
+
+ public static SSLSocketFactory getConscryptSocketFactory(boolean useEngineSocket) {
+ return setUseEngineSocket(getSocketFactory(getConscryptProvider()), useEngineSocket);
+ }
+
+ public static SSLServerSocketFactory getConscryptServerSocketFactory(boolean useEngineSocket) {
+ return setUseEngineSocket(getServerSocketFactory(getConscryptProvider()), useEngineSocket);
+ }
+
+ private static SSLSocketFactory getSocketFactory(Provider provider) {
+ SSLContext clientContext = initClientSslContext(newContext(provider));
+ return clientContext.getSocketFactory();
+ }
+
+ private static SSLServerSocketFactory getServerSocketFactory(Provider provider) {
+ SSLContext serverContext = initServerSslContext(newContext(provider));
+ return serverContext.getServerSocketFactory();
+ }
+
+ static SSLContext newContext(Provider provider) {
+ try {
+ return SSLContext.getInstance("TLS", provider);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static String[] getCommonCipherSuites() {
+ SSLContext jdkContext =
+ TestUtils.initSslContext(newContext(getJdkProvider()), TestKeyStore.getClient());
+ SSLContext conscryptContext = TestUtils.initSslContext(
+ newContext(getConscryptProvider()), TestKeyStore.getClient());
+ Set<String> supported = new LinkedHashSet<String>();
+ supported.addAll(supportedCiphers(jdkContext));
+ supported.retainAll(supportedCiphers(conscryptContext));
+ filterCiphers(supported);
+
+ return supported.toArray(new String[supported.size()]);
+ }
+
+ private static List<String> supportedCiphers(SSLContext ctx) {
+ return Arrays.asList(ctx.getDefaultSSLParameters().getCipherSuites());
+ }
+
+ private static void filterCiphers(Iterable<String> ciphers) {
+ // Filter all non-TLS ciphers.
+ Iterator<String> iter = ciphers.iterator();
+ while (iter.hasNext()) {
+ String cipher = iter.next();
+ if (cipher.startsWith("SSL_") || cipher.startsWith("TLS_EMPTY")
+ || cipher.contains("_RC4_")) {
+ iter.remove();
+ }
+ }
+ }
+
+ /**
+ * 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 intial 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 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;
+ }
+ }
+}
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..2f851c8
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AbstractKeyFactoryTest.java
@@ -0,0 +1,66 @@
+/* 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.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.KeySpec;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class AbstractKeyFactoryTest<PublicKeySpec extends KeySpec, PrivateKeySpec extends KeySpec> {
+
+ private final String algorithmName;
+ private final Class<PublicKeySpec> publicKeySpecClass;
+ private final Class<PrivateKeySpec> privateKeySpecClass;
+ private KeyFactory factory;
+
+ public AbstractKeyFactoryTest(String algorithmName,
+ Class<PublicKeySpec> publicKeySpecClass,
+ Class<PrivateKeySpec> privateKeySpecClass) {
+ this.algorithmName = algorithmName;
+ this.publicKeySpecClass = publicKeySpecClass;
+ this.privateKeySpecClass = privateKeySpecClass;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ factory = getFactory();
+ }
+
+ private KeyFactory getFactory() throws Exception {
+ return KeyFactory.getInstance(algorithmName);
+ }
+
+ @Test
+ public void testKeyFactory() throws Exception {
+ PrivateKeySpec privateKeySpec = factory.getKeySpec(DefaultKeys.getPrivateKey(algorithmName),
+ privateKeySpecClass);
+ PrivateKey privateKey = factory.generatePrivate(privateKeySpec);
+ PublicKeySpec publicKeySpec = factory.getKeySpec(DefaultKeys.getPublicKey(algorithmName),
+ publicKeySpecClass);
+ PublicKey publicKey = factory.generatePublic(publicKeySpec);
+ check(new KeyPair(publicKey, privateKey));
+ }
+
+ protected void check(KeyPair keyPair) throws Exception {}
+}
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..f9ea7cf
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AbstractKeyPairGeneratorTest.java
@@ -0,0 +1,59 @@
+/* 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);
+ }
+
+ @Test
+ public void testKeyPairGenerator() throws Exception {
+ generator.initialize(1024);
+
+ 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..f9d0898
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/AlgorithmParameterSignatureHelper.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.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 plainData = "some data do sign and verify";
+ private final Class<T> parameterSpecClass;
+
+ public AlgorithmParameterSignatureHelper(String algorithmName, Class<T> parameterSpecCla1ss) {
+ this.algorithmName = algorithmName;
+ 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(algorithmName);
+
+ 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..73f59f7
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/CipherHelper.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.java.security;
+
+import static org.junit.Assert.assertEquals;
+
+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;
+
+ public 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("UTF-8"));
+
+ cipher.init(mode2, decryptKey);
+ byte[] decrypted = cipher.doFinal(encrypted);
+ String decryptedString = new String(decrypted, "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..f75fb94
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/CpuFeatures.java
@@ -0,0 +1,151 @@
+/* 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) {
+ } catch (SecurityException ignored) {
+ } catch (IllegalAccessException ignored) {
+ } catch (IllegalArgumentException 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..5a89f3d
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/DefaultKeys.java
@@ -0,0 +1,210 @@
+/* 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.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 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));
+ }
+
+ 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..917df97
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/StandardNames.java
@@ -0,0 +1,455 @@
+/* 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";
+
+ /**
+ * 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"));
+
+ 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> expected, String[] protocols) {
+ Set<String> remainingProtocols = assertValidProtocols(expected, protocols);
+ assertEquals("Missing protocols", Collections.EMPTY_SET, remainingProtocols);
+ assertEquals(expected.size(), protocols.length);
+ }
+
+ /**
+ * 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) {
+ assertEquals("For protocol \"" + version + "\"",
+ Arrays.toString(SSL_CONTEXT_PROTOCOLS_ENABLED.get(version)),
+ Arrays.toString(protocols));
+ }
+
+ /**
+ * 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..86568a3
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/TestKeyStore.java
@@ -0,0 +1,1155 @@
+/* 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);
+ }
+ }
+
+ /**
+ * 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..ecd8b24
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/FakeSSLSession.java
@@ -0,0 +1,141 @@
+/* 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.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() {
+ 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..ca6e225
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/TestHostnameVerifier.java
@@ -0,0 +1,57 @@
+/* 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;
+
+ private 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..e7b11ff
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/testing/BrokenProvider.java
@@ -0,0 +1,81 @@
+/* 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
+ */
+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/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/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..89857dd
--- /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 (getClass() != obj.getClass()) {
+ 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..88069d2
--- /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 (getClass() != obj.getClass()) {
+ 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..0aa4446
--- /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 (getClass() != obj.getClass()) {
+ 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..1bf662e
--- /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 (getClass() != obj.getClass()) {
+ 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..e2e325c
--- /dev/null
+++ b/repackaged/testing/src/main/java/tests/util/ServiceTester.java
@@ -0,0 +1,179 @@
+/* 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 final String service;
+ private Set<Provider> providers = new LinkedHashSet<>();
+ private Set<Provider> skipProviders = new HashSet<>();
+ private Set<String> algorithms = new LinkedHashSet<>();
+ private Set<String> skipAlgorithms = 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;
+ }
+
+ /**
+ * 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())) {
+ doTest(test, p, s.getAlgorithm(), errors);
+ }
+ }
+ } else {
+ algorithms.removeAll(skipAlgorithms);
+ for (String algorithm : algorithms) {
+ if (p.getService(service, algorithm) != null) {
+ doTest(test, p, algorithm, errors);
+ }
+ }
+ }
+ }
+ errors.flush();
+ if (errBuffer.size() > 0) {
+ fail("Tests failed:\n\n" + errBuffer.toString());
+ }
+ }
+
+ private void doTest(Test test, Provider p, String algorithm, PrintStream errors) {
+ try {
+ test.test(p, algorithm);
+ } catch (Exception e) {
+ errors.append("Failure testing " + service + ":" + algorithm
+ + " from provider " + p.getName() + ":\n");
+ e.printStackTrace(errors);
+ }
+ }
+
+}
diff --git a/srcgen/core-platform-api.txt b/srcgen/core-platform-api.txt
new file mode 100644
index 0000000..c882063
--- /dev/null
+++ b/srcgen/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/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..70c6d44
--- /dev/null
+++ b/srcgen/generate_android_src.sh
@@ -0,0 +1,58 @@
+#!/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 \
+ openjdk-integ-tests \
+ 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}/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/ConscryptSuite.java
+rm -fr ${REPACKAGED_DIR}/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/ConscryptJava7Suite.java
+
+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..656535d
--- /dev/null
+++ b/srcgen/intra-core-api.txt
@@ -0,0 +1,207 @@
+method:com.android.org.conscrypt.DESEDESecretKeyFactory#DESEDESecretKeyFactory()
+method:com.android.org.conscrypt.DefaultSSLContextImpl#DefaultSSLContextImpl()
+method:com.android.org.conscrypt.ECParameters#ECParameters()
+method:com.android.org.conscrypt.GCMParameters#GCMParameters()
+method:com.android.org.conscrypt.IvParameters$AES#AES()
+method:com.android.org.conscrypt.IvParameters$ChaCha20#ChaCha20()
+method:com.android.org.conscrypt.IvParameters$DESEDE#DESEDE()
+method:com.android.org.conscrypt.IvParameters#IvParameters()
+method:com.android.org.conscrypt.KeyGeneratorImpl$AES#AES()
+method:com.android.org.conscrypt.KeyGeneratorImpl$ARC4#ARC4()
+method:com.android.org.conscrypt.KeyGeneratorImpl$ChaCha20#ChaCha20()
+method:com.android.org.conscrypt.KeyGeneratorImpl$DESEDE#DESEDE()
+method:com.android.org.conscrypt.KeyGeneratorImpl$HmacMD5#HmacMD5()
+method:com.android.org.conscrypt.KeyGeneratorImpl$HmacSHA1#HmacSHA1()
+method:com.android.org.conscrypt.KeyGeneratorImpl$HmacSHA224#HmacSHA224()
+method:com.android.org.conscrypt.KeyGeneratorImpl$HmacSHA256#HmacSHA256()
+method:com.android.org.conscrypt.KeyGeneratorImpl$HmacSHA384#HmacSHA384()
+method:com.android.org.conscrypt.KeyGeneratorImpl$HmacSHA512#HmacSHA512()
+method:com.android.org.conscrypt.OAEPParameters#OAEPParameters()
+method:com.android.org.conscrypt.OpenSSLAeadCipherAES$GCM#GCM()
+method:com.android.org.conscrypt.OpenSSLAeadCipherAES$GCM$AES_128#AES_128()
+method:com.android.org.conscrypt.OpenSSLAeadCipherAES$GCM$AES_256#AES_256()
+method:com.android.org.conscrypt.OpenSSLAeadCipherAES$GCM_SIV#GCM_SIV()
+method:com.android.org.conscrypt.OpenSSLAeadCipherAES$GCM_SIV$AES_128#AES_128()
+method:com.android.org.conscrypt.OpenSSLAeadCipherAES$GCM_SIV$AES_256#AES_256()
+method:com.android.org.conscrypt.OpenSSLAeadCipherChaCha20#OpenSSLAeadCipherChaCha20()
+method:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES$CBC$NoPadding#NoPadding()
+method:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES$CBC$PKCS5Padding#PKCS5Padding()
+method:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES$CTR#CTR()
+method:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES$ECB$NoPadding#NoPadding()
+method:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES$ECB$PKCS5Padding#PKCS5Padding()
+method:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_128$CBC$NoPadding#NoPadding()
+method:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_128$CBC$PKCS5Padding#PKCS5Padding()
+method:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_128$ECB$NoPadding#NoPadding()
+method:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_128$ECB$PKCS5Padding#PKCS5Padding()
+method:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_256$CBC$NoPadding#NoPadding()
+method:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_256$CBC$PKCS5Padding#PKCS5Padding()
+method:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_256$ECB$NoPadding#NoPadding()
+method:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_256$ECB$PKCS5Padding#PKCS5Padding()
+method:com.android.org.conscrypt.OpenSSLEvpCipherARC4#OpenSSLEvpCipherARC4()
+method:com.android.org.conscrypt.OpenSSLEvpCipherDESEDE$CBC$NoPadding#NoPadding()
+method:com.android.org.conscrypt.OpenSSLEvpCipherDESEDE$CBC$PKCS5Padding#PKCS5Padding()
+method:com.android.org.conscrypt.OpenSSLCipherChaCha20#OpenSSLCipherChaCha20()
+method:com.android.org.conscrypt.OpenSSLCipherRSA$OAEP$SHA1#SHA1()
+method:com.android.org.conscrypt.OpenSSLCipherRSA$OAEP$SHA224#SHA224()
+method:com.android.org.conscrypt.OpenSSLCipherRSA$OAEP$SHA256#SHA256()
+method:com.android.org.conscrypt.OpenSSLCipherRSA$OAEP$SHA384#SHA384()
+method:com.android.org.conscrypt.OpenSSLCipherRSA$OAEP$SHA512#SHA512()
+method:com.android.org.conscrypt.OpenSSLCipherRSA$PKCS1#PKCS1()
+method:com.android.org.conscrypt.OpenSSLCipherRSA$Raw#Raw()
+method:com.android.org.conscrypt.OpenSSLContextImpl$TLSv1#TLSv1()
+method:com.android.org.conscrypt.OpenSSLContextImpl$TLSv11#TLSv11()
+method:com.android.org.conscrypt.OpenSSLContextImpl$TLSv12#TLSv12()
+method:com.android.org.conscrypt.OpenSSLContextImpl$TLSv13#TLSv13()
+method:com.android.org.conscrypt.OpenSSLECDHKeyAgreement#OpenSSLECDHKeyAgreement()
+method:com.android.org.conscrypt.OpenSSLECKeyFactory#OpenSSLECKeyFactory()
+method:com.android.org.conscrypt.OpenSSLECKeyPairGenerator#OpenSSLECKeyPairGenerator()
+method:com.android.org.conscrypt.OpenSSLMac$HmacMD5#HmacMD5()
+method:com.android.org.conscrypt.OpenSSLMac$HmacSHA1#HmacSHA1()
+method:com.android.org.conscrypt.OpenSSLMac$HmacSHA224#HmacSHA224()
+method:com.android.org.conscrypt.OpenSSLMac$HmacSHA256#HmacSHA256()
+method:com.android.org.conscrypt.OpenSSLMac$HmacSHA384#HmacSHA384()
+method:com.android.org.conscrypt.OpenSSLMac$HmacSHA512#HmacSHA512()
+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.OpenSSLRSAKeyFactory#OpenSSLRSAKeyFactory()
+method:com.android.org.conscrypt.OpenSSLRSAKeyPairGenerator#OpenSSLRSAKeyPairGenerator()
+method:com.android.org.conscrypt.OpenSSLRandom#OpenSSLRandom()
+method:com.android.org.conscrypt.OpenSSLSignature$MD5RSA#MD5RSA()
+method:com.android.org.conscrypt.OpenSSLSignature$SHA1ECDSA#SHA1ECDSA()
+method:com.android.org.conscrypt.OpenSSLSignature$SHA1RSA#SHA1RSA()
+method:com.android.org.conscrypt.OpenSSLSignature$SHA1RSAPSS#SHA1RSAPSS()
+method:com.android.org.conscrypt.OpenSSLSignature$SHA224ECDSA#SHA224ECDSA()
+method:com.android.org.conscrypt.OpenSSLSignature$SHA224RSA#SHA224RSA()
+method:com.android.org.conscrypt.OpenSSLSignature$SHA224RSAPSS#SHA224RSAPSS()
+method:com.android.org.conscrypt.OpenSSLSignature$SHA256ECDSA#SHA256ECDSA()
+method:com.android.org.conscrypt.OpenSSLSignature$SHA256RSA#SHA256RSA()
+method:com.android.org.conscrypt.OpenSSLSignature$SHA256RSAPSS#SHA256RSAPSS()
+method:com.android.org.conscrypt.OpenSSLSignature$SHA384ECDSA#SHA384ECDSA()
+method:com.android.org.conscrypt.OpenSSLSignature$SHA384RSA#SHA384RSA()
+method:com.android.org.conscrypt.OpenSSLSignature$SHA384RSAPSS#SHA384RSAPSS()
+method:com.android.org.conscrypt.OpenSSLSignature$SHA512ECDSA#SHA512ECDSA()
+method:com.android.org.conscrypt.OpenSSLSignature$SHA512RSA#SHA512RSA()
+method:com.android.org.conscrypt.OpenSSLSignature$SHA512RSAPSS#SHA512RSAPSS()
+method:com.android.org.conscrypt.OpenSSLSignatureRawECDSA#OpenSSLSignatureRawECDSA()
+method:com.android.org.conscrypt.OpenSSLSignatureRawRSA#OpenSSLSignatureRawRSA()
+method:com.android.org.conscrypt.OpenSSLX509CertificateFactory#OpenSSLX509CertificateFactory()
+method:com.android.org.conscrypt.PSSParameters#PSSParameters()
+type:com.android.org.conscrypt.DESEDESecretKeyFactory
+type:com.android.org.conscrypt.DefaultSSLContextImpl
+type:com.android.org.conscrypt.ECParameters
+type:com.android.org.conscrypt.GCMParameters
+type:com.android.org.conscrypt.IvParameters
+type:com.android.org.conscrypt.IvParameters$AES
+type:com.android.org.conscrypt.IvParameters$ChaCha20
+type:com.android.org.conscrypt.IvParameters$DESEDE
+type:com.android.org.conscrypt.KeyGeneratorImpl
+type:com.android.org.conscrypt.KeyGeneratorImpl$AES
+type:com.android.org.conscrypt.KeyGeneratorImpl$ARC4
+type:com.android.org.conscrypt.KeyGeneratorImpl$ChaCha20
+type:com.android.org.conscrypt.KeyGeneratorImpl$DESEDE
+type:com.android.org.conscrypt.KeyGeneratorImpl$HmacMD5
+type:com.android.org.conscrypt.KeyGeneratorImpl$HmacSHA1
+type:com.android.org.conscrypt.KeyGeneratorImpl$HmacSHA224
+type:com.android.org.conscrypt.KeyGeneratorImpl$HmacSHA256
+type:com.android.org.conscrypt.KeyGeneratorImpl$HmacSHA384
+type:com.android.org.conscrypt.KeyGeneratorImpl$HmacSHA512
+type:com.android.org.conscrypt.OAEPParameters
+type:com.android.org.conscrypt.OpenSSLCipher
+type:com.android.org.conscrypt.OpenSSLAeadCipher
+type:com.android.org.conscrypt.OpenSSLAeadCipherAES
+type:com.android.org.conscrypt.OpenSSLAeadCipherAES$GCM
+type:com.android.org.conscrypt.OpenSSLAeadCipherAES$GCM$AES_128
+type:com.android.org.conscrypt.OpenSSLAeadCipherAES$GCM$AES_256
+type:com.android.org.conscrypt.OpenSSLAeadCipherAES$GCM_SIV
+type:com.android.org.conscrypt.OpenSSLAeadCipherAES$GCM_SIV$AES_128
+type:com.android.org.conscrypt.OpenSSLAeadCipherAES$GCM_SIV$AES_256
+type:com.android.org.conscrypt.OpenSSLAeadCipherChaCha20
+type:com.android.org.conscrypt.OpenSSLEvpCipher
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES$CBC
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES$CBC$NoPadding
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES$CBC$PKCS5Padding
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES$CTR
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES$ECB
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES$ECB$NoPadding
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES$ECB$PKCS5Padding
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_128
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_128$CBC
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_128$CBC$NoPadding
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_128$CBC$PKCS5Padding
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_128$ECB
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_128$ECB$NoPadding
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_128$ECB$PKCS5Padding
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_256
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_256$CBC
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_256$CBC$NoPadding
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_256$CBC$PKCS5Padding
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_256$ECB
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_256$ECB$NoPadding
+type:com.android.org.conscrypt.OpenSSLEvpCipherAES$AES_256$ECB$PKCS5Padding
+type:com.android.org.conscrypt.OpenSSLEvpCipherARC4
+type:com.android.org.conscrypt.OpenSSLEvpCipherDESEDE
+type:com.android.org.conscrypt.OpenSSLEvpCipherDESEDE$CBC
+type:com.android.org.conscrypt.OpenSSLEvpCipherDESEDE$CBC$NoPadding
+type:com.android.org.conscrypt.OpenSSLEvpCipherDESEDE$CBC$PKCS5Padding
+type:com.android.org.conscrypt.OpenSSLCipherChaCha20
+type:com.android.org.conscrypt.OpenSSLCipherRSA
+type:com.android.org.conscrypt.OpenSSLCipherRSA$OAEP
+type:com.android.org.conscrypt.OpenSSLCipherRSA$OAEP$SHA1
+type:com.android.org.conscrypt.OpenSSLCipherRSA$OAEP$SHA224
+type:com.android.org.conscrypt.OpenSSLCipherRSA$OAEP$SHA256
+type:com.android.org.conscrypt.OpenSSLCipherRSA$OAEP$SHA384
+type:com.android.org.conscrypt.OpenSSLCipherRSA$OAEP$SHA512
+type:com.android.org.conscrypt.OpenSSLCipherRSA$PKCS1
+type:com.android.org.conscrypt.OpenSSLCipherRSA$Raw
+type:com.android.org.conscrypt.OpenSSLContextImpl
+type:com.android.org.conscrypt.OpenSSLContextImpl$TLSv1
+type:com.android.org.conscrypt.OpenSSLContextImpl$TLSv11
+type:com.android.org.conscrypt.OpenSSLContextImpl$TLSv12
+type:com.android.org.conscrypt.OpenSSLContextImpl$TLSv13
+type:com.android.org.conscrypt.OpenSSLECDHKeyAgreement
+type:com.android.org.conscrypt.OpenSSLECKeyFactory
+type:com.android.org.conscrypt.OpenSSLECKeyPairGenerator
+type:com.android.org.conscrypt.OpenSSLMac
+type:com.android.org.conscrypt.OpenSSLMac$HmacMD5
+type:com.android.org.conscrypt.OpenSSLMac$HmacSHA1
+type:com.android.org.conscrypt.OpenSSLMac$HmacSHA224
+type:com.android.org.conscrypt.OpenSSLMac$HmacSHA256
+type:com.android.org.conscrypt.OpenSSLMac$HmacSHA384
+type:com.android.org.conscrypt.OpenSSLMac$HmacSHA512
+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.OpenSSLRSAKeyFactory
+type:com.android.org.conscrypt.OpenSSLRSAKeyPairGenerator
+type:com.android.org.conscrypt.OpenSSLRandom
+type:com.android.org.conscrypt.OpenSSLSignature
+type:com.android.org.conscrypt.OpenSSLSignature$MD5RSA
+type:com.android.org.conscrypt.OpenSSLSignature$SHA1ECDSA
+type:com.android.org.conscrypt.OpenSSLSignature$SHA1RSA
+type:com.android.org.conscrypt.OpenSSLSignature$SHA1RSAPSS
+type:com.android.org.conscrypt.OpenSSLSignature$SHA224ECDSA
+type:com.android.org.conscrypt.OpenSSLSignature$SHA224RSA
+type:com.android.org.conscrypt.OpenSSLSignature$SHA224RSAPSS
+type:com.android.org.conscrypt.OpenSSLSignature$SHA256ECDSA
+type:com.android.org.conscrypt.OpenSSLSignature$SHA256RSA
+type:com.android.org.conscrypt.OpenSSLSignature$SHA256RSAPSS
+type:com.android.org.conscrypt.OpenSSLSignature$SHA384ECDSA
+type:com.android.org.conscrypt.OpenSSLSignature$SHA384RSA
+type:com.android.org.conscrypt.OpenSSLSignature$SHA384RSAPSS
+type:com.android.org.conscrypt.OpenSSLSignature$SHA512ECDSA
+type:com.android.org.conscrypt.OpenSSLSignature$SHA512RSA
+type:com.android.org.conscrypt.OpenSSLSignature$SHA512RSAPSS
+type:com.android.org.conscrypt.OpenSSLSignatureRawECDSA
+type:com.android.org.conscrypt.OpenSSLSignatureRawRSA
+type:com.android.org.conscrypt.OpenSSLX509CertificateFactory
+type:com.android.org.conscrypt.PSSParameters
diff --git a/srcgen/unsupported-app-usage.json b/srcgen/unsupported-app-usage.json
new file mode 100644
index 0000000..20d30f0
--- /dev/null
+++ b/srcgen/unsupported-app-usage.json
@@ -0,0 +1,334 @@
+// See com.google.currysrc.aosp.Annotations.addUnsupportedAppUsage(Path) method for details on the
+// syntax.
+[
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#getAlpnSelectedProtocol()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#getApplicationProtocols()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#getChannelId()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#getHostname()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#getHostnameOrIP()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#getNpnSelectedProtocol()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#getSoWriteTimeout()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setAlpnProtocols(byte[])"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setAlpnProtocols(String[])"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setApplicationProtocols(String[])"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setChannelIdEnabled(boolean)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setChannelIdPrivateKey(PrivateKey)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setHandshakeTimeout(int)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setHostname(String)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setNpnProtocols(byte[])"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setSoWriteTimeout(int)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.AbstractConscryptSocket#setUseSessionTickets(boolean)"
+ },
+ {
+ "@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.ConscryptFileDescriptorSocket#setHostname(String)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.ConscryptFileDescriptorSocket#setUseSessionTickets(boolean)"
+ },
+ {
+ "@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()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#getChannelId()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#getHostname()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#getHostnameOrIP()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#getNpnSelectedProtocol()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#getSoWriteTimeout()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#setAlpnProtocols(byte[])"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#setAlpnProtocols(String[])"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#setChannelIdEnabled(boolean)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#setChannelIdPrivateKey(PrivateKey)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#setHandshakeTimeout(int)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#setHostname(String)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#setNpnProtocols(byte[])"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#setSoWriteTimeout(int)"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.OpenSSLSocketImpl#setUseSessionTickets(boolean)"
+ },
+ {
+ "@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()"
+ },
+ {
+ "@location": "method:com.android.org.conscrypt.SSLParametersImpl#setEnabledProtocols(String[])"
+ },
+ {
+ "@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[])"
+ }
+]