summaryrefslogtreecommitdiff
path: root/src/com/android/se/internal/Util.java
blob: 8e9cfe3e3ebcbeb03c43fe901be8239fda57b585 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * Copyright (c) 2017, The Linux Foundation.
 */

/*
 * Contributed by: Giesecke & Devrient GmbH.
 */

package com.android.se.internal;

import android.content.Context;
import android.content.pm.PackageManager;

import java.security.AccessControlException;

/** Util class for byte[] operations */
public class Util {

    public static final byte END = -1;

    /** Returns a new array containing both the arrays appended */
    public static byte[] mergeBytes(byte[] array1, byte[] array2) {
        byte[] data = new byte[array1.length + array2.length];
        System.arraycopy(array1, 0, data, 0, array1.length);
        System.arraycopy(array2, 0, data, array1.length, array2.length);
        return data;
    }

    /** Extracts the required bytes from the array */
    public static byte[] getMid(byte[] array, int start, int length) {
        byte[] data = new byte[length];
        System.arraycopy(array, start, data, 0, length);
        return data;
    }

    /**
     * Returns a concatenated response.
     *
     * @param r1     the first part of the response.
     * @param r2     the second part of the response.
     * @param length the number of bytes of the second part to be appended.
     * @return a concatenated response.
     */
    public static byte[] appendResponse(byte[] r1, byte[] r2, int length) {
        byte[] rsp = new byte[r1.length + length];
        System.arraycopy(r1, 0, rsp, 0, r1.length);
        System.arraycopy(r2, 0, rsp, r1.length, length);
        return rsp;
    }

    /**
     * Creates a formatted exception message.
     *
     * @param commandName the name of the command. <code>null</code> if not specified.
     * @param sw          the response status word.
     * @return a formatted exception message.
     */
    public static String createMessage(String commandName, int sw) {
        StringBuilder message = new StringBuilder();
        if (commandName != null) {
            message.append(commandName).append(" ");
        }
        message.append("SW1/2 error: ");
        message.append(Integer.toHexString(sw | 0x10000).substring(1));
        return message.toString();
    }

    /**
     * Creates a formatted exception message.
     *
     * @param commandName the name of the command. <code>null</code> if not specified.
     * @param message     the message to be formatted.
     * @return a formatted exception message.
     */
    public static String createMessage(String commandName, String message) {
        if (commandName == null) {
            return message;
        }
        return commandName + " " + message;
    }

    /**
     * Get package name from the user id.
     *
     * <p>This shall fix the problem the issue that process name != package name due to
     * anndroid:process attribute in manifest file.
     *
     * <p>But this call is not really secure either since a uid can be shared between one and more
     * apks
     *
     * @return The first package name associated with this uid.
     */
    public static String getPackageNameFromCallingUid(Context context, int uid) {
        PackageManager packageManager = context.getPackageManager();
        if (packageManager != null) {
            String[] packageName = packageManager.getPackagesForUid(uid);
            if (packageName != null && packageName.length > 0) {
                return packageName[0];
            }
        }
        throw new AccessControlException("Caller PackageName can not be determined");
    }

    /**
     * Returns a copy of the given CLA byte where the channel number bits are set as specified by
     * the
     * given channel number See GlobalPlatform Card Specification 2.2.0.7: 11.1.4 Class Byte
     * Coding.
     *
     * @param cla           the CLA byte. Won't be modified
     * @param channelNumber within [0..3] (for first interindustry class byte coding) or [4..19]
     *                      (for
     *                      further interindustry class byte coding)
     * @return the CLA byte with set channel number bits. The seventh bit indicating the used coding
     * (first/further interindustry class byte coding) might be modified
     */
    public static byte setChannelToClassByte(byte cla, int channelNumber) {
        if (channelNumber < 4) {
            // b7 = 0 indicates the first interindustry class byte coding
            cla = (byte) ((cla & 0xBC) | channelNumber);
        } else if (channelNumber < 20) {
            // b7 = 1 indicates the further interindustry class byte coding
            boolean isSM = (cla & 0x0C) != 0;
            cla = (byte) ((cla & 0xB0) | 0x40 | (channelNumber - 4));
            if (isSM) {
                cla |= 0x20;
            }
        } else {
            throw new IllegalArgumentException("Channel number must be within [0..19]");
        }
        return cla;
    }

    /**
     * Clear the channel number.
     *
     * @return the cla without channel number
     */
    public static byte clearChannelNumber(byte cla) {
        // bit 7 determines which standard is used
        boolean isFirstInterindustryClassByteCoding = (cla & 0x40) == 0x00;

        if (isFirstInterindustryClassByteCoding) {
            // First Interindustry Class Byte Coding
            // see 11.1.4.1: channel number is encoded in the 2 rightmost bits
            return (byte) (cla & 0xFC);
        } else {
            // Further Interindustry Class Byte Coding
            // see 11.1.4.2: channel number is encoded in the 4 rightmost bits
            return (byte) (cla & 0xF0);
        }
    }

    /**
     * Extracts the channel number from a CLA byte. Specified in GlobalPlatform Card Specification
     * 2.2.0.7: 11.1.4 Class Byte Coding.
     *
     * @param cla the command's CLA byte
     * @return the channel number within [0x00..0x0F]
     */
    public static int parseChannelNumber(byte cla) {
        // bit 7 determines which standard is used
        boolean isFirstInterindustryClassByteCoding = (cla & 0x40) == 0x00;

        if (isFirstInterindustryClassByteCoding) {
            // First Interindustry Class Byte Coding
            // see 11.1.4.1: channel number is encoded in the 2 rightmost bits
            return cla & 0x03;
        } else {
            // Further Interindustry Class Byte Coding
            // see 11.1.4.2: channel number is encoded in the 4 rightmost bits
            return (cla & 0x0F) + 4;
        }
    }
}