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) 2015-2017, The Linux Foundation.
18  */
19 /*
20  * Contributed by: Giesecke & Devrient GmbH.
21  */
22 
23 package com.android.se;
24 
25 import android.os.Binder;
26 import android.os.IBinder;
27 import android.os.RemoteException;
28 import android.os.ServiceSpecificException;
29 import android.se.omapi.ISecureElementChannel;
30 import android.se.omapi.ISecureElementListener;
31 import android.se.omapi.SEService;
32 import android.util.Log;
33 
34 import com.android.se.SecureElementService.SecureElementSession;
35 import com.android.se.security.ChannelAccess;
36 
37 import java.io.IOException;
38 
39 /**
40  * Represents a Channel opened with the Secure Element
41  */
42 public class Channel implements IBinder.DeathRecipient {
43 
44     private final String mTag = "SecureElement-Channel";
45     private final int mChannelNumber;
46     private final Object mLock = new Object();
47     private IBinder mBinder = null;
48     private boolean mIsClosed;
49     private SecureElementSession mSession;
50     private Terminal mTerminal;
51     private byte[] mSelectResponse;
52     private ChannelAccess mChannelAccess = null;
53     private int mCallingPid = 0;
54     private byte[] mAid = null;
55 
Channel(SecureElementSession session, Terminal terminal, int channelNumber, byte[] selectResponse, byte[] aid, ISecureElementListener listener)56     Channel(SecureElementSession session, Terminal terminal, int channelNumber,
57             byte[] selectResponse, byte[] aid, ISecureElementListener listener) {
58         if (terminal == null) {
59             throw new IllegalArgumentException("Arguments can't be null");
60         }
61         mSession = session;
62         mTerminal = terminal;
63         mIsClosed = false;
64         mSelectResponse = selectResponse;
65         mChannelNumber = channelNumber;
66         mAid = aid;
67         if (listener != null) {
68             try {
69                 mBinder = listener.asBinder();
70                 mBinder.linkToDeath(this, 0);
71             } catch (RemoteException e) {
72                 Log.e(mTag, "Failed to register client listener");
73             }
74         }
75     }
76 
77     /**
78      * Close this channel if the client died.
79      */
binderDied()80     public void binderDied() {
81         try {
82             Log.e(mTag, Thread.currentThread().getName() + " Client "
83                     + mBinder.toString() + " died");
84             close();
85         } catch (Exception ignore) {
86         }
87     }
88 
89     /**
90      * Closes the channel.
91      */
close()92     public synchronized void close() {
93         synchronized (mLock) {
94             if (isBasicChannel()) {
95                 Log.i(mTag, "Close basic channel - Select without AID ...");
96                 mTerminal.selectDefaultApplication();
97             }
98 
99             mTerminal.closeChannel(this);
100             mIsClosed = true;
101             if (mBinder != null) {
102                 mBinder.unlinkToDeath(this, 0);
103             }
104             if (mSession != null) {
105                 mSession.removeChannel(this);
106             }
107         }
108     }
109 
110     /**
111      * Transmits the given byte and returns the response.
112      */
transmit(byte[] command)113     public byte[] transmit(byte[] command) throws IOException {
114         if (isClosed()) {
115             throw new IllegalStateException("Channel is closed");
116         }
117         if (command == null) {
118             throw new NullPointerException("Command must not be null");
119         }
120         if (mChannelAccess == null) {
121             throw new SecurityException("Channel access not set");
122         }
123         if (mChannelAccess.getCallingPid() != mCallingPid) {
124             throw new SecurityException("Wrong Caller PID.");
125         }
126 
127         // Validate the APDU command format and throw IllegalArgumentException, if necessary.
128         CommandApduValidator.execute(command);
129 
130         if (((command[0] & (byte) 0x80) == 0)
131                 && ((command[0] & (byte) 0x60) != (byte) 0x20)) {
132             // ISO command
133             if (command[1] == (byte) 0x70) {
134                 throw new SecurityException("MANAGE CHANNEL command not allowed");
135             }
136             if ((command[1] == (byte) 0xA4) && (command[2] == (byte) 0x04)) {
137                 // SELECT by DF name is only allowed for CarrierPrivilege applications
138                 // or system privilege applications
139                 if (ChannelAccess.ACCESS.ALLOWED != mChannelAccess.getPrivilegeAccess()) {
140                     throw new SecurityException("SELECT by DF name command not allowed");
141                 }
142             }
143         }
144 
145         checkCommand(command);
146         synchronized (mLock) {
147             // set channel number bits
148             command[0] = setChannelToClassByte(command[0], mChannelNumber);
149             return mTerminal.transmit(command);
150         }
151     }
152 
selectNext()153     private boolean selectNext() throws IOException {
154         if (isClosed()) {
155             throw new IllegalStateException("Channel is closed");
156         } else if (mChannelAccess == null) {
157             throw new IllegalStateException("Channel access not set.");
158         } else if (mChannelAccess.getCallingPid() != mCallingPid) {
159             throw new SecurityException("Wrong Caller PID.");
160         } else if (mAid == null || mAid.length == 0) {
161             throw new UnsupportedOperationException("No aid given");
162         }
163 
164         byte[] selectCommand = new byte[5 + mAid.length];
165         selectCommand[0] = 0x00;
166         selectCommand[1] = (byte) 0xA4;
167         selectCommand[2] = 0x04;
168         selectCommand[3] = 0x02; // next occurrence
169         selectCommand[4] = (byte) mAid.length;
170         System.arraycopy(mAid, 0, selectCommand, 5, mAid.length);
171 
172         // set channel number bits
173         selectCommand[0] = setChannelToClassByte(selectCommand[0], mChannelNumber);
174 
175         byte[] bufferSelectResponse = mTerminal.transmit(selectCommand);
176 
177         if (bufferSelectResponse.length < 2) {
178             throw new UnsupportedOperationException("Transmit failed");
179         }
180         int sw1 = bufferSelectResponse[bufferSelectResponse.length - 2] & 0xFF;
181         int sw2 = bufferSelectResponse[bufferSelectResponse.length - 1] & 0xFF;
182         int sw = (sw1 << 8) | sw2;
183 
184         if (((sw & 0xF000) == 0x9000) || ((sw & 0xFF00) == 0x6200)
185                 || ((sw & 0xFF00) == 0x6300)) {
186             mSelectResponse = bufferSelectResponse.clone();
187             return true;
188         } else if ((sw & 0xFF00) == 0x6A00) {
189             return false;
190         } else {
191             throw new UnsupportedOperationException("Unsupported operation");
192         }
193     }
194 
195     /**
196      * Returns a copy of the given CLA byte where the channel number bits are set
197      * as specified by the given channel number
198      *
199      * <p>See GlobalPlatform Card Specification 2.2.0.7: 11.1.4 Class Byte Coding
200      *
201      * @param cla           the CLA byte. Won't be modified
202      * @param channelNumber within [0..3] (for first inter-industry class byte
203      *                      coding) or [4..19] (for further inter-industry class byte coding)
204      * @return the CLA byte with set channel number bits. The seventh bit
205      * indicating the used coding
206      * (first/further interindustry class byte coding) might be modified
207      */
setChannelToClassByte(byte cla, int channelNumber)208     private byte setChannelToClassByte(byte cla, int channelNumber) {
209         if (channelNumber < 4) {
210             // b7 = 0 indicates the first interindustry class byte coding
211             cla = (byte) ((cla & 0xBC) | channelNumber);
212         } else if (channelNumber < 20) {
213             // b7 = 1 indicates the further interindustry class byte coding
214             boolean isSm = (cla & 0x0C) != 0;
215             cla = (byte) ((cla & 0xB0) | 0x40 | (channelNumber - 4));
216             if (isSm) {
217                 cla |= 0x20;
218             }
219         } else {
220             throw new IllegalArgumentException("Channel number must be within [0..19]");
221         }
222         return cla;
223     }
224 
getChannelAccess()225     public ChannelAccess getChannelAccess() {
226         return this.mChannelAccess;
227     }
228 
setChannelAccess(ChannelAccess channelAccess)229     public void setChannelAccess(ChannelAccess channelAccess) {
230         this.mChannelAccess = channelAccess;
231     }
232 
setCallingPid(int pid)233     private void setCallingPid(int pid) {
234         mCallingPid = pid;
235     }
236 
checkCommand(byte[] command)237     private void checkCommand(byte[] command) {
238         if (mTerminal.getAccessControlEnforcer() != null) {
239             // check command if it complies to the access rules.
240             // if not an exception is thrown
241             mTerminal.getAccessControlEnforcer().checkCommand(this, command);
242         } else {
243             // Allow access to Privileged App even if Access Control Enforcer is
244             // not initialized
245             if (ChannelAccess.ACCESS.ALLOWED != mChannelAccess.getPrivilegeAccess()) {
246                 throw new SecurityException("Access Controller not set for Terminal: "
247                         + mTerminal.getName());
248             }
249         }
250     }
251 
252     /**
253      * true if aid could be selected during opening the channel
254      * false if aid could not be or was not selected.
255      *
256      * @return boolean.
257      */
hasSelectedAid()258     public boolean hasSelectedAid() {
259         return (mAid != null);
260     }
261 
getChannelNumber()262     public int getChannelNumber() {
263         return mChannelNumber;
264     }
265 
266     /**
267      * Returns the data as received from the application select command
268      * inclusively the status word.
269      *
270      * The returned byte array contains the data bytes in the following order:
271      * first data byte, ... , last data byte, sw1, sw2
272      *
273      * @return null if an application SELECT command has not been performed or
274      * the selection response can not be retrieved by the reader
275      * implementation.
276      */
getSelectResponse()277     public byte[] getSelectResponse() {
278         return (hasSelectedAid() ? mSelectResponse : null);
279     }
280 
isBasicChannel()281     public boolean isBasicChannel() {
282         return (mChannelNumber == 0) ? true : false;
283     }
284 
isClosed()285     public boolean isClosed() {
286         return mIsClosed;
287     }
288 
289     // Implementation of the SecureElement Channel interface according to OMAPI.
290     final class SecureElementChannel extends ISecureElementChannel.Stub {
291 
292         @Override
close()293         public void close() throws RemoteException {
294             Channel.this.close();
295         }
296 
297         @Override
isClosed()298         public boolean isClosed() throws RemoteException {
299             return Channel.this.isClosed();
300         }
301 
302         @Override
isBasicChannel()303         public boolean isBasicChannel() throws RemoteException {
304             return Channel.this.isBasicChannel();
305         }
306 
307         @Override
getSelectResponse()308         public byte[] getSelectResponse() throws RemoteException {
309             return Channel.this.getSelectResponse();
310         }
311 
312         @Override
transmit(byte[] command)313         public byte[] transmit(byte[] command) throws RemoteException {
314             Channel.this.setCallingPid(Binder.getCallingPid());
315             try {
316                 return Channel.this.transmit(command);
317             } catch (IOException e) {
318                 throw new ServiceSpecificException(SEService.IO_ERROR, e.getMessage());
319             }
320         }
321 
322         @Override
selectNext()323         public boolean selectNext() throws RemoteException {
324             Channel.this.setCallingPid(Binder.getCallingPid());
325             try {
326                 return Channel.this.selectNext();
327             } catch (IOException e) {
328                 throw new ServiceSpecificException(SEService.IO_ERROR, e.getMessage());
329             }
330         }
331     }
332 }
333