1b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik/**
2b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * Copyright (C) 2008 The Android Open Source Project
3b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik *
4b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * use this file except in compliance with the License. You may obtain a copy
6b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * of the License at
7b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik *
8b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik *      http://www.apache.org/licenses/LICENSE-2.0
9b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik *
10b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * Unless required by applicable law or agreed to in writing, software
11b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * License for the specific language governing permissions and limitations
14b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * under the License.
15b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik */
16b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
17b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikpackage com.google.android.googlelogin;
18b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
19b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikimport android.content.Context;
20b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikimport android.content.pm.PackageInfo;
21b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikimport android.content.pm.PackageManager;
22b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikimport android.content.pm.Signature;
23b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikimport android.content.pm.PackageManager.NameNotFoundException;
24b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikimport android.text.TextUtils;
25b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
26b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik/**
27b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * Helper class that verifies the installed package for Google Apps package is
28b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * infact Google's Google Apps package.
29b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * <p>
30b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * Before attempting to bind to a service, call
31b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * {@link #isServiceAvailable(Context, String)}. After bound, make sure you are
32b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * bound to a Google-provided service by calling {@link #isGoogleAppsVerified(Context)}.
33b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik */
34b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikclass GoogleAppsVerifier {
35b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
36b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    /*
37b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * Magic signature strings. One is from the emulator in the SDK, and the
38b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * other from a production device.
39b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     */
40b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private static final String SIGNATURE_1 = "308204a830820390a003020102020900d585b86c7dd34ef5300d06092a864886f70d0101040500308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d301e170d3038303431353233333635365a170d3335303930313233333635365a308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d30820120300d06092a864886f70d01010105000382010d00308201080282010100d6ce2e080abfe2314dd18db3cfd3185cb43d33fa0c74e1bdb6d1db8913f62c5c39df56f846813d65bec0f3ca426b07c5a8ed5a3990c167e76bc999b927894b8f0b22001994a92915e572c56d2a301ba36fc5fc113ad6cb9e7435a16d23ab7dfaeee165e4df1f0a8dbda70a869d516c4e9d051196ca7c0c557f175bc375f948c56aae86089ba44f8aa6a4dd9a7dbf2c0a352282ad06b8cc185eb15579eef86d080b1d6189c0f9af98b1c2ebd107ea45abdb68a3c7838a5e5488c76c53d40b121de7bbd30e620c188ae1aa61dbbc87dd3c645f2f55f3d4c375ec4070a93f7151d83670c16a971abe5ef2d11890e1b8aef3298cf066bf9e6ce144ac9ae86d1c1b0f020103a381fc3081f9301d0603551d0e041604148d1cc5be954c433c61863a15b04cbc03f24fe0b23081c90603551d230481c13081be80148d1cc5be954c433c61863a15b04cbc03f24fe0b2a1819aa48197308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d820900d585b86c7dd34ef5300c0603551d13040530030101ff300d06092a864886f70d0101040500038201010019d30cf105fb78923f4c0d7dd223233d40967acfce00081d5bd7c6e9d6ed206b0e11209506416ca244939913d26b4aa0e0f524cad2bb5c6e4ca1016a15916ea1ec5dc95a5e3a010036f49248d5109bbf2e1e618186673a3be56daf0b77b1c229e3c255e3e84c905d2387efba09cbf13b202b4e5a22c93263484a23d2fc29fa9f1939759733afd8aa160f4296c2d0163e8182859c6643e9c1962fa0c18333335bc090ff9a6b22ded1ad444229a539a94eefadabd065ced24b3e51e5dd7b66787bef12fe97fba484c423fb4ff8cc494c02f0f5051612ff6529393e8e46eac5bb21f277c151aa5f2aa627d1e89da70ab6033569de3b9897bfff7ca9da3e1243f60b";
41b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private static final String SIGNATURE_2 = "308204433082032ba003020102020900c2e08746644a308d300d06092a864886f70d01010405003074310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e205669657731143012060355040a130b476f6f676c6520496e632e3110300e060355040b1307416e64726f69643110300e06035504031307416e64726f6964301e170d3038303832313233313333345a170d3336303130373233313333345a3074310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e205669657731143012060355040a130b476f6f676c6520496e632e3110300e060355040b1307416e64726f69643110300e06035504031307416e64726f696430820120300d06092a864886f70d01010105000382010d00308201080282010100ab562e00d83ba208ae0a966f124e29da11f2ab56d08f58e2cca91303e9b754d372f640a71b1dcb130967624e4656a7776a92193db2e5bfb724a91e77188b0e6a47a43b33d9609b77183145ccdf7b2e586674c9e1565b1f4c6a5955bff251a63dabf9c55c27222252e875e4f8154a645f897168c0b1bfc612eabf785769bb34aa7984dc7e2ea2764cae8307d8c17154d7ee5f64a51a44a602c249054157dc02cd5f5c0e55fbef8519fbe327f0b1511692c5a06f19d18385f5c4dbc2d6b93f68cc2979c70e18ab93866b3bd5db8999552a0e3b4c99df58fb918bedc182ba35e003c1b4b10dd244a8ee24fffd333872ab5221985edab0fc0d0b145b6aa192858e79020103a381d93081d6301d0603551d0e04160414c77d8cc2211756259a7fd382df6be398e4d786a53081a60603551d2304819e30819b8014c77d8cc2211756259a7fd382df6be398e4d786a5a178a4763074310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e205669657731143012060355040a130b476f6f676c6520496e632e3110300e060355040b1307416e64726f69643110300e06035504031307416e64726f6964820900c2e08746644a308d300c0603551d13040530030101ff300d06092a864886f70d010104050003820101006dd252ceef85302c360aaace939bcff2cca904bb5d7a1661f8ae46b2994204d0ff4a68c7ed1a531ec4595a623ce60763b167297a7ae35712c407f208f0cb109429124d7b106219c084ca3eb3f9ad5fb871ef92269a8be28bf16d44c8d9a08e6cb2f005bb3fe2cb96447e868e731076ad45b33f6009ea19c161e62641aa99271dfd5228c5c587875ddb7f452758d661f6cc0cccb7352e424cc4365c523532f7325137593c4ae341f4db41edda0d0b1071a7c440f0fe9ea01cb627ca674369d084bd2fd911ff06cdbf2cfa10dc0f893ae35762919048c7efc64c7144178342f70581c9de573af55b390dd7fdb9418631895d5f759f30112687ff621410c069308a";
42b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
43b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private static final String GOOGLEAPPS_PACKAGE_NAME =
44b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            GoogleLoginServiceConstants.SERVICE_PACKAGE_NAME;
45b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
46b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    /**
47b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * The possible signatures for the Google Apps package.
48b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     */
49b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private static final Signature[] GOOGLEAPPS_PACKAGE_SIGNATURES = new Signature[] {
50b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        new Signature(SIGNATURE_1), new Signature(SIGNATURE_2)
51b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    };
52b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
53b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    /**
54b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * Checks whether the given service name is available in the Google Apps
55b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * package.
56b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * <p>
57b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * NOTE: This does *not* do any signature checking to ensure the
58b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * "Google Apps package" is infact from Google. After you bind to the
59b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * service, call {@link #isGoogleAppsVerified(Context)}.
60b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     *
61b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * @param context The context.
62b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * @param serviceName The service name as in the Google Apps manifest.
63b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * @return Whether it is available on the current system.
64b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     */
65b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    public static boolean isServiceAvailable(Context context, String serviceName) {
66b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
67b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        try {
68b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            PackageManager packageManager = context.getPackageManager();
69b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            PackageInfo packageInfo = packageManager.getPackageInfo(GOOGLEAPPS_PACKAGE_NAME,
70b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                    PackageManager.GET_SERVICES);
71b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
72b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            if (packageInfo.services == null) {
73b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                return false;
74b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            }
75b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
76b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            int numServices = packageInfo.services.length;
77b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            for (int i = 0; i < numServices; i++) {
78b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                String name = packageInfo.services[i].name;
79b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                if (!TextUtils.isEmpty(name) && name.equals(serviceName)) {
80b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                    return true;
81b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                }
82b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            }
83b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
84b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        } catch (NameNotFoundException e) {
85b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            // Fallthrough to returning false
86b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        } catch (UnsupportedOperationException e) {
87b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            // A mock implementation of context may throw this, so fallthrough
88b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            // to returning false
89b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        }
90b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
91b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        return false;
92b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    }
93b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
94b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    /**
95b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * Verifies that the installed Google Apps package is infact the one
96b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * provided by Google (and not someone spoofing us).
97b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * <p>
98b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * NOTE: It is important this is called *after* you are bound to the
99b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * service. Otherwise, it is possible that between the time you call this
100b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * (returns true) and the time you bind, that the Google Apps package was
101b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * swapped to a fake one. Rare, but possible.
102b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     *
103b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * @param context The context.
104b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * @return Whether the Google Apps package is provided by Google.
105b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     */
106b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    public static boolean isGoogleAppsVerified(Context context) {
107b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
108b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        try {
109b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            PackageManager packageManager = context.getPackageManager();
110b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            PackageInfo packageInfo = packageManager.getPackageInfo(GOOGLEAPPS_PACKAGE_NAME,
111b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                    PackageManager.GET_SIGNATURES);
112b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
113b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            if (packageInfo.signatures == null) {
114b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                return false;
115b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            }
116b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
117b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            int numGoogleSignatures = GOOGLEAPPS_PACKAGE_SIGNATURES.length;
118b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            int numSignatures = packageInfo.signatures.length;
119b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            for (int i = 0; i < numSignatures; i++) {
120b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                for (int j = 0; j < numGoogleSignatures; j++) {
121b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                    if (GOOGLEAPPS_PACKAGE_SIGNATURES[j].equals(packageInfo.signatures[i])) {
122b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                        return true;
123b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                    }
124b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                }
125b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            }
126b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
127b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        } catch (NameNotFoundException e) {
128b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        }
129b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
130b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        return false;
131b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    }
132b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik}
133