aboutsummaryrefslogtreecommitdiff
path: root/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework
diff options
context:
space:
mode:
authorDouglas Sigelbaum <sigelbaum@google.com>2017-08-31 16:42:37 -0700
committerDouglas Sigelbaum <sigelbaum@google.com>2017-09-13 15:24:11 -0700
commit96be336b4584215c04e49de7e27e5b15648fb496 (patch)
tree65cf928eb734eb2316963e3058c00d28cfa8bf33 /input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework
parent03c96abdc9195b6be58765156002812ecee91ab9 (diff)
downloadandroid-96be336b4584215c04e49de7e27e5b15648fb496.tar.gz
Autofill sample: Adding pkg signature check.
Also, minor refactor to AutofillDataSource to make getInstance() parameter-less. Bug: 38182790 Test: manual Change-Id: Ib8e6780dfde2e263d9648d78df6b7e70477cf146
Diffstat (limited to 'input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework')
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/MyAutofillService.kt17
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/PackageVerifier.kt98
2 files changed, 112 insertions, 3 deletions
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/MyAutofillService.kt b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/MyAutofillService.kt
index f74c5873..704d17a1 100644
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/MyAutofillService.kt
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/MyAutofillService.kt
@@ -23,19 +23,24 @@ import android.service.autofill.FillResponse
import android.service.autofill.SaveCallback
import android.service.autofill.SaveRequest
import android.util.Log
-import android.view.autofill.AutofillId
+import android.widget.Toast
import com.example.android.autofillframework.CommonUtil.TAG
import com.example.android.autofillframework.CommonUtil.bundleToString
import com.example.android.autofillframework.R
import com.example.android.autofillframework.multidatasetservice.datasource.SharedPrefsAutofillRepository
import com.example.android.autofillframework.multidatasetservice.settings.MyPreferences
-import java.util.Arrays
class MyAutofillService : AutofillService() {
override fun onFillRequest(request: FillRequest, cancellationSignal: CancellationSignal,
callback: FillCallback) {
- val structure = request.getFillContexts().get(request.getFillContexts().size - 1).structure
+ val structure = request.fillContexts[request.fillContexts.size - 1].structure
+ val packageName = structure.activityComponent.packageName
+ if (!PackageVerifier.isValidPackage(applicationContext, packageName)) {
+ Toast.makeText(applicationContext, R.string.invalid_package_signature,
+ Toast.LENGTH_SHORT).show()
+ return
+ }
val data = request.clientState
Log.d(TAG, "onFillRequest(): data=" + bundleToString(data))
cancellationSignal.setOnCancelListener { Log.w(TAG, "Cancel autofill not implemented in this sample.") }
@@ -68,6 +73,12 @@ class MyAutofillService : AutofillService() {
override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) {
val context = request.fillContexts
val structure = context[context.size - 1].structure
+ val packageName = structure.activityComponent.packageName
+ if (!PackageVerifier.isValidPackage(applicationContext, packageName)) {
+ Toast.makeText(applicationContext, R.string.invalid_package_signature,
+ Toast.LENGTH_SHORT).show()
+ return
+ }
val data = request.clientState
Log.d(TAG, "onSaveRequest(): data=" + bundleToString(data))
val parser = StructureParser(structure)
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/PackageVerifier.kt b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/PackageVerifier.kt
new file mode 100644
index 00000000..d059a233
--- /dev/null
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/PackageVerifier.kt
@@ -0,0 +1,98 @@
+package com.example.android.autofillframework.multidatasetservice
+
+/*
+ * 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.
+ */
+
+import android.content.Context
+import android.content.pm.PackageManager
+import android.util.Log
+import com.example.android.autofillframework.CommonUtil.TAG
+import java.io.ByteArrayInputStream
+import java.security.MessageDigest
+import java.security.cert.CertificateFactory
+import java.security.cert.X509Certificate
+
+object PackageVerifier {
+
+
+ /**
+ * Verifies if a package is valid by matching its certificate with the previously stored
+ * certificate.
+ */
+ fun isValidPackage(context: Context, packageName: String): Boolean {
+ val hash: String
+ try {
+ hash = getCertificateHash(context, packageName)
+ Log.d(TAG, "Hash for $packageName: $hash")
+ } catch (e: Exception) {
+ Log.w(TAG, "Error getting hash for $packageName: $e")
+ return false
+ }
+
+ return verifyHash(context, packageName, hash)
+ }
+
+ private fun getCertificateHash(context: Context, packageName: String): String {
+ val pm = context.packageManager
+ val packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES)
+ val signatures = packageInfo.signatures
+ val cert = signatures[0].toByteArray()
+ ByteArrayInputStream(cert).use { input ->
+ val factory = CertificateFactory.getInstance("X509")
+ val x509 = factory.generateCertificate(input) as X509Certificate
+ val md = MessageDigest.getInstance("SHA256")
+ val publicKey = md.digest(x509.encoded)
+ return toHexFormat(publicKey)
+ }
+ }
+
+ private fun toHexFormat(bytes: ByteArray): String {
+ val builder = StringBuilder(bytes.size * 2)
+ for (i in bytes.indices) {
+ var hex = Integer.toHexString(bytes[i].toInt())
+ val length = hex.length
+ if (length == 1) {
+ hex = "0" + hex
+ }
+ if (length > 2) {
+ hex = hex.substring(length - 2, length)
+ }
+ builder.append(hex.toUpperCase())
+ if (i < bytes.size - 1) {
+ builder.append(':')
+ }
+ }
+ return builder.toString()
+ }
+
+ private fun verifyHash(context: Context, packageName: String, hash: String): Boolean {
+ val prefs = context.applicationContext.getSharedPreferences(
+ "package-hashes", Context.MODE_PRIVATE)
+ if (!prefs.contains(packageName)) {
+ Log.d(TAG, "Creating intial hash for " + packageName)
+ prefs.edit().putString(packageName, hash).apply()
+ return true
+ }
+
+ val existingHash = prefs.getString(packageName, null)
+ if (hash != existingHash) {
+ Log.w(TAG, "hash mismatch for " + packageName + ": expected " + existingHash
+ + ", got " + hash)
+ return false
+ }
+ return true
+ }
+} \ No newline at end of file