1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.security.app.authenticator;
18 
19 import android.content.Context;
20 import android.content.pm.ApplicationInfo;
21 import android.content.pm.PackageManager;
22 import android.os.Binder;
23 import android.os.Build;
24 
25 import org.jspecify.annotations.NonNull;
26 
27 import java.security.MessageDigest;
28 import java.security.NoSuchAlgorithmException;
29 
30 /**
31  * Provides utility methods that facilitate app signing identity verification.
32  */
33 class AppAuthenticatorUtils {
34     private static final char[] HEX_CHARACTERS = "0123456789abcdef".toCharArray();
35 
36     private Context mContext;
37 
38     /**
39      * Package private constructor accepting the {@code context} to be used for package queries.
40      */
AppAuthenticatorUtils(Context context)41     AppAuthenticatorUtils(Context context) {
42         mContext = context;
43     }
44 
45     /**
46      * Returns the ID of the process that sent the current transaction being processed, or the ID
47      * of the current process if not currently processing a transaction.
48      *
49      * @see Binder#getCallingPid()
50      */
getCallingPid()51     int getCallingPid() {
52         return Binder.getCallingPid();
53     }
54 
55     /**
56      * Returns the uid assigned to the process that sent the current transaction being processed,
57      * or the uid assigned to the current process if not currently processing a transaction.
58      *
59      * @see Binder#getCallingUid()
60      */
getCallingUid()61     int getCallingUid() {
62         return Binder.getCallingUid();
63     }
64 
65     /**
66      * Returns the uid assigned to specified {@code packageName}.
67      *
68      * @throws PackageManager.NameNotFoundException if the specified package cannot be found on
69      * the device
70      *
71      * @see ApplicationInfo#uid
72      */
73     @SuppressWarnings("deprecation")
getUidForPackage(String packageName)74     int getUidForPackage(String packageName) throws PackageManager.NameNotFoundException {
75         ApplicationInfo appInfo = mContext.getPackageManager().getApplicationInfo(packageName, 0);
76         return appInfo.uid;
77     }
78 
79     /**
80      * Returns the API level as reported by {@code Build.VERSION.SDK_INT}.
81      */
getApiLevel()82     static int getApiLevel() {
83         return Build.VERSION.SDK_INT;
84     }
85 
86     /**
87      * Computes the digest of the provided {@code data} using the specified {@code
88      * digestAlgorithm}, returning a {@code String} representing the hex encoding of the digest.
89      *
90      * <p>The specified {@code digestAlgorithm} must be one supported from API level 1; use of
91      * MD5 and SHA-1 are strongly discouraged.
92      */
computeDigest(@onNull String digestAlgorithm, byte @NonNull [] data)93     static String computeDigest(@NonNull String digestAlgorithm, byte @NonNull [] data) {
94         MessageDigest messageDigest;
95         try {
96             messageDigest = MessageDigest.getInstance(digestAlgorithm);
97         } catch (NoSuchAlgorithmException e) {
98             // Should never happen; the AppAuthenticator only accepts digest algorithms that are
99             // available from API level 1.
100             throw new AppAuthenticatorUtilsException(digestAlgorithm + " not supported on this "
101                     + "device", e);
102         }
103         return toHexString(messageDigest.digest(data));
104     }
105 
106     /**
107      * Returns a {@code String} representing the hex encoding of the provided {@code data}.
108      */
toHexString(byte @NonNull [] data)109     static String toHexString(byte @NonNull [] data) {
110         char[] result = new char[data.length * 2];
111         for (int i = 0; i < data.length; i++) {
112             int resultIndex = i * 2;
113             result[resultIndex] = HEX_CHARACTERS[(data[i] >> 4) & 0x0f];
114             result[resultIndex + 1] = HEX_CHARACTERS[data[i] & 0x0f];
115         }
116         return new String(result);
117     }
118 
119     /**
120      * This {@code RuntimeException} is thrown when an unexpected error is encountered while
121      * performing a utility operation.
122      */
123     private static class AppAuthenticatorUtilsException extends RuntimeException {
AppAuthenticatorUtilsException(@onNull String message, Throwable reason)124         AppAuthenticatorUtilsException(@NonNull String message, Throwable reason) {
125             super(message, reason);
126         }
127     }
128 }
129