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