1 /*
2  * Copyright (C) 2017 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  * Copyright (c) 2017, The Linux Foundation.
18  */
19 
20 /*
21  * Contributed by: Giesecke & Devrient GmbH.
22  */
23 
24 package com.android.se.internal;
25 
26 import android.content.Context;
27 import android.content.pm.PackageManager;
28 
29 import java.security.AccessControlException;
30 
31 /** Util class for byte[] operations */
32 public class Util {
33 
34     public static final byte END = -1;
35 
36     /** Returns a new array containing both the arrays appended */
mergeBytes(byte[] array1, byte[] array2)37     public static byte[] mergeBytes(byte[] array1, byte[] array2) {
38         byte[] data = new byte[array1.length + array2.length];
39         System.arraycopy(array1, 0, data, 0, array1.length);
40         System.arraycopy(array2, 0, data, array1.length, array2.length);
41         return data;
42     }
43 
44     /** Extracts the required bytes from the array */
getMid(byte[] array, int start, int length)45     public static byte[] getMid(byte[] array, int start, int length) {
46         byte[] data = new byte[length];
47         System.arraycopy(array, start, data, 0, length);
48         return data;
49     }
50 
51     /**
52      * Returns a concatenated response.
53      *
54      * @param r1     the first part of the response.
55      * @param r2     the second part of the response.
56      * @param length the number of bytes of the second part to be appended.
57      * @return a concatenated response.
58      */
appendResponse(byte[] r1, byte[] r2, int length)59     public static byte[] appendResponse(byte[] r1, byte[] r2, int length) {
60         byte[] rsp = new byte[r1.length + length];
61         System.arraycopy(r1, 0, rsp, 0, r1.length);
62         System.arraycopy(r2, 0, rsp, r1.length, length);
63         return rsp;
64     }
65 
66     /**
67      * Creates a formatted exception message.
68      *
69      * @param commandName the name of the command. <code>null</code> if not specified.
70      * @param sw          the response status word.
71      * @return a formatted exception message.
72      */
createMessage(String commandName, int sw)73     public static String createMessage(String commandName, int sw) {
74         StringBuilder message = new StringBuilder();
75         if (commandName != null) {
76             message.append(commandName).append(" ");
77         }
78         message.append("SW1/2 error: ");
79         message.append(Integer.toHexString(sw | 0x10000).substring(1));
80         return message.toString();
81     }
82 
83     /**
84      * Creates a formatted exception message.
85      *
86      * @param commandName the name of the command. <code>null</code> if not specified.
87      * @param message     the message to be formatted.
88      * @return a formatted exception message.
89      */
createMessage(String commandName, String message)90     public static String createMessage(String commandName, String message) {
91         if (commandName == null) {
92             return message;
93         }
94         return commandName + " " + message;
95     }
96 
97     /**
98      * Get package name from the user id.
99      *
100      * <p>This shall fix the problem the issue that process name != package name due to
101      * anndroid:process attribute in manifest file.
102      *
103      * <p>But this call is not really secure either since a uid can be shared between one and more
104      * apks
105      *
106      * @return The first package name associated with this uid.
107      */
getPackageNameFromCallingUid(Context context, int uid)108     public static String getPackageNameFromCallingUid(Context context, int uid) {
109         PackageManager packageManager = context.getPackageManager();
110         if (packageManager != null) {
111             String[] packageName = packageManager.getPackagesForUid(uid);
112             if (packageName != null && packageName.length > 0) {
113                 return packageName[0];
114             }
115         }
116         throw new AccessControlException("Caller PackageName can not be determined");
117     }
118 
119     /**
120      * Returns a copy of the given CLA byte where the channel number bits are set as specified by
121      * the
122      * given channel number See GlobalPlatform Card Specification 2.2.0.7: 11.1.4 Class Byte
123      * Coding.
124      *
125      * @param cla           the CLA byte. Won't be modified
126      * @param channelNumber within [0..3] (for first interindustry class byte coding) or [4..19]
127      *                      (for
128      *                      further interindustry class byte coding)
129      * @return the CLA byte with set channel number bits. The seventh bit indicating the used coding
130      * (first/further interindustry class byte coding) might be modified
131      */
setChannelToClassByte(byte cla, int channelNumber)132     public static byte setChannelToClassByte(byte cla, int channelNumber) {
133         if (channelNumber < 4) {
134             // b7 = 0 indicates the first interindustry class byte coding
135             cla = (byte) ((cla & 0xBC) | channelNumber);
136         } else if (channelNumber < 20) {
137             // b7 = 1 indicates the further interindustry class byte coding
138             boolean isSM = (((cla & 0x40) == 0x00) && ((cla & 0x0C) != 0));
139             cla = (byte) ((cla & 0xB0) | 0x40 | (channelNumber - 4));
140             if (isSM) {
141                 cla |= 0x20;
142             }
143         } else {
144             throw new IllegalArgumentException("Channel number must be within [0..19]");
145         }
146         return cla;
147     }
148 
149     /**
150      * Clear the channel number.
151      *
152      * @return the cla without channel number
153      */
clearChannelNumber(byte cla)154     public static byte clearChannelNumber(byte cla) {
155         // bit 7 determines which standard is used
156         boolean isFirstInterindustryClassByteCoding = (cla & 0x40) == 0x00;
157 
158         if (isFirstInterindustryClassByteCoding) {
159             // First Interindustry Class Byte Coding
160             // see 11.1.4.1: channel number is encoded in the 2 rightmost bits
161             return (byte) (cla & 0xFC);
162         } else {
163             // Further Interindustry Class Byte Coding
164             // see 11.1.4.2: channel number is encoded in the 4 rightmost bits
165             return (byte) (cla & 0xF0);
166         }
167     }
168 
169     /**
170      * Extracts the channel number from a CLA byte. Specified in GlobalPlatform Card Specification
171      * 2.2.0.7: 11.1.4 Class Byte Coding.
172      *
173      * @param cla the command's CLA byte
174      * @return the channel number within [0x00..0x0F]
175      */
parseChannelNumber(byte cla)176     public static int parseChannelNumber(byte cla) {
177         // bit 7 determines which standard is used
178         boolean isFirstInterindustryClassByteCoding = (cla & 0x40) == 0x00;
179 
180         if (isFirstInterindustryClassByteCoding) {
181             // First Interindustry Class Byte Coding
182             // see 11.1.4.1: channel number is encoded in the 2 rightmost bits
183             return cla & 0x03;
184         } else {
185             // Further Interindustry Class Byte Coding
186             // see 11.1.4.2: channel number is encoded in the 4 rightmost bits
187             return (cla & 0x0F) + 4;
188         }
189     }
190 }
191