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