Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(389)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentManifestVerifier.java

Issue 2645813006: Download web payment manifests. (Closed)
Patch Set: Rebase Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.chrome.browser.payments;
6
7 import android.content.pm.PackageInfo;
8 import android.content.pm.ResolveInfo;
9 import android.content.pm.Signature;
10
11 import org.chromium.base.Log;
12 import org.chromium.chrome.browser.UrlConstants;
13 import org.chromium.components.payments.PaymentManifestDownloader;
14 import org.chromium.components.payments.PaymentManifestDownloader.ManifestDownlo adCallback;
15 import org.chromium.components.payments.PaymentManifestParser;
16 import org.chromium.components.payments.PaymentManifestParser.ManifestParseCallb ack;
17 import org.chromium.payments.mojom.PaymentManifestSection;
18
19 import java.net.URI;
20 import java.security.MessageDigest;
21 import java.security.NoSuchAlgorithmException;
22 import java.util.ArrayList;
23 import java.util.Formatter;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Set;
27
28 /**
29 * Verifies that the discovered native Android payment apps have the sufficient privileges
30 * to handle a single payment method. Downloads and parses the manifest to compa re package
31 * names, versions, and signatures to the apps.
32 *
33 * Spec:
34 * https://docs.google.com/document/d/1izV4uC-tiRJG3JLooqY3YRLU22tYOsLTNq0P_InPJ eE/edit#heading=h.cjp3jlnl47h5
35 */
36 public class PaymentManifestVerifier implements ManifestDownloadCallback, Manife stParseCallback {
37 private static final String TAG = "cr_PaymentManifest";
38
39 /** Interface for the callback to invoke when finished verification. */
40 public interface ManifestVerifyCallback {
41 /**
42 * Enables invoking the given native Android payment app for the given p ayment method.
43 * Called when the app has been found to have the right privileges to ha ndle this payment
44 * method.
45 *
46 * @param methodName The payment method name that the payment app offer s to handle.
47 * @param resolveInfo Identifying information for the native Android pay ment app.
48 */
49 void onValidPaymentApp(URI methodName, ResolveInfo resolveInfo);
50
51 /**
52 * Disables invoking the given native Android payment app for the given payment method.
53 * Called when the app has been found to not have the right privileges t o handle this
54 * payment app.
55 *
56 * @param methodName The payment method name that the payment app offer s to handle.
57 * @param resolveInfo Identifying information for the native Android pay ment app.
58 */
59 void onInvalidPaymentApp(URI methodName, ResolveInfo resolveInfo);
60
61 /**
62 * Disables invoking any native Android payment app for the given paymen t method. Called if
63 * unable to download or parse the payment method manifest.
64 *
65 * @param methodName The payment method name that has an invalid payment method manifest.
66 */
67 void onInvalidManifest(URI methodName);
68 }
69
70 /** Identifying information about an installed native Android payment app. * /
71 private static class AppInfo {
72 /** Identifies a native Android payment app. */
73 public ResolveInfo resolveInfo;
74
75 /** The version code for the native Android payment app, e.g., 123. */
76 public long version;
77
78 /**
79 * The SHA256 certificate fingerprints for the native Android payment ap p, .e.g,
80 * ["308201dd30820146020101300d06092a864886f70d010105050030"].
81 */
82 public Set<String> sha256CertFingerprints;
83 }
84
85 private final PaymentManifestDownloader mDownloader;
86 private final URI mMethodName;
87 private final List<AppInfo> mMatchingApps;
88 private final PaymentManifestParser mParser;
89 private final PackageManagerDelegate mPackageManagerDelegate;
90 private final ManifestVerifyCallback mCallback;
91 private final MessageDigest mMessageDigest;
92
93 /**
94 * Builds the manifest verifier.
95 *
96 * @param methodName The name of the payment method name that ap ps offer to handle.
97 * Must be an absolute URI with HTTPS scheme.
98 * @param matchingApps The identifying information for the native Android payment apps
99 * that offer to handle this payment method.
100 * @param downloader The manifest downloader.
101 * @param parser The manifest parser.
102 * @param packageManagerDelegate The package information retriever.
103 * @param callback The callback to be notified of verification result.
104 */
105 public PaymentManifestVerifier(URI methodName, List<ResolveInfo> matchingApp s,
106 PaymentManifestDownloader downloader, PaymentManifestParser parser,
107 PackageManagerDelegate packageManagerDelegate, ManifestVerifyCallbac k callback) {
108 assert methodName.isAbsolute();
109 assert UrlConstants.HTTPS_SCHEME.equals(methodName.getScheme());
110 assert !matchingApps.isEmpty();
111
112 mMethodName = methodName;
113 mMatchingApps = new ArrayList<>();
114 for (int i = 0; i < matchingApps.size(); i++) {
115 AppInfo appInfo = new AppInfo();
116 appInfo.resolveInfo = matchingApps.get(i);
117 mMatchingApps.add(appInfo);
118 }
119 mDownloader = downloader;
120 mParser = parser;
121 mPackageManagerDelegate = packageManagerDelegate;
122 mCallback = callback;
123
124 MessageDigest md = null;
125 try {
126 md = MessageDigest.getInstance("SHA-256");
127 } catch (NoSuchAlgorithmException e) {
128 // Intentionally ignore.
129 Log.d(TAG, "Unable to generate SHA-256 hashes. Only \"package\": \"* \" supported.");
130 }
131 mMessageDigest = md;
132 }
133
134 /**
135 * Verifies that the discovered native Android payment apps have the suffici ent
136 * privileges to handle this payment method.
137 */
138 public void verify() {
139 mDownloader.download(mMethodName, this);
140 }
141
142 @Override
143 public void onManifestDownloadSuccess(String content) {
144 mParser.parse(content, this);
145 }
146
147 @Override
148 public void onManifestDownloadFailure() {
149 mCallback.onInvalidManifest(mMethodName);
150 }
151
152 @Override
153 public void onManifestParseSuccess(PaymentManifestSection[] manifest) {
154 assert manifest != null;
155 assert manifest.length > 0;
156
157 for (int i = 0; i < manifest.length; i++) {
158 PaymentManifestSection section = manifest[i];
159 // "package": "*" in the manifest file indicates an unrestricted pay ment method. Any app
160 // can use this payment method name.
161 if ("*".equals(section.packageName)) {
162 for (int j = 0; j < mMatchingApps.size(); j++) {
163 mCallback.onValidPaymentApp(mMethodName, mMatchingApps.get(j ).resolveInfo);
164 }
165 return;
166 }
167 }
168
169 if (mMessageDigest == null) {
170 mCallback.onInvalidManifest(mMethodName);
171 return;
172 }
173
174 for (int i = 0; i < mMatchingApps.size(); i++) {
175 AppInfo appInfo = mMatchingApps.get(i);
176 PackageInfo packageInfo = mPackageManagerDelegate.getPackageInfoWith Signatures(
177 appInfo.resolveInfo.activityInfo.packageName);
178
179 // Leaving appInfo.sha256CertFingerprints uninitialized will call on InvalidPaymentApp()
180 // for this app below.
181 if (packageInfo == null) continue;
182
183 appInfo.version = packageInfo.versionCode;
184 appInfo.sha256CertFingerprints = new HashSet<>();
185 Signature[] signatures = packageInfo.signatures;
186 for (int j = 0; j < signatures.length; j++) {
187 mMessageDigest.update(signatures[j].toByteArray());
188
189 // The digest is reset after completing the hash computation.
190 appInfo.sha256CertFingerprints.add(byteArrayToString(mMessageDig est.digest()));
191 }
192 }
193
194 List<Set<String>> sectionsFingerprints = new ArrayList<>();
195 for (int i = 0; i < manifest.length; i++) {
196 PaymentManifestSection section = manifest[i];
197 Set<String> fingerprints = new HashSet<>();
198 if (section.sha256CertFingerprints != null) {
199 for (int j = 0; j < section.sha256CertFingerprints.length; j++) {
200 fingerprints.add(byteArrayToString(section.sha256CertFingerp rints[j]));
201 }
202 }
203 sectionsFingerprints.add(fingerprints);
204 }
205
206 for (int i = 0; i < mMatchingApps.size(); i++) {
207 AppInfo appInfo = mMatchingApps.get(i);
208 boolean isAllowed = false;
209 for (int j = 0; j < manifest.length; j++) {
210 PaymentManifestSection section = manifest[j];
211 if (appInfo.resolveInfo.activityInfo.packageName.equals(section. packageName)
212 && appInfo.version >= section.version
213 && appInfo.sha256CertFingerprints != null
214 && appInfo.sha256CertFingerprints.equals(sectionsFingerp rints.get(j))) {
215 mCallback.onValidPaymentApp(mMethodName, appInfo.resolveInfo );
216 isAllowed = true;
217 break;
218 }
219 }
220 if (!isAllowed) mCallback.onInvalidPaymentApp(mMethodName, appInfo.r esolveInfo);
221 }
222 }
223
224 /**
225 * Formats bytes into a string for easier comparison as a member of a set.
226 *
227 * @param input Input bytes.
228 * @return A string representation of the input bytes, e.g., "0123456789abcd ef".
229 */
230 private static String byteArrayToString(byte[] input) {
231 if (input == null) return null;
232
233 StringBuilder builder = new StringBuilder(input.length * 2);
234 Formatter formatter = new Formatter(builder);
235 for (byte b : input) {
236 formatter.format("%02x", b);
237 }
238
239 return builder.toString();
240 }
241
242 @Override
243 public void onManifestParseFailure() {
244 mCallback.onInvalidManifest(mMethodName);
245 }
246 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698