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