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) 2014-2017, The Linux Foundation. 18 */ 19 20 /* 21 * Copyright 2012 Giesecke & Devrient GmbH. 22 * 23 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 24 * use this file except in compliance with the License. You may obtain a copy of 25 * the License at 26 * 27 * http://www.apache.org/licenses/LICENSE-2.0 28 * 29 * Unless required by applicable law or agreed to in writing, software 30 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 31 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 32 * License for the specific language governing permissions and limitations under 33 * the License. 34 */ 35 36 package com.android.se.security; 37 38 import android.content.pm.PackageInfo; 39 import android.content.pm.PackageManager; 40 import android.content.pm.PackageManager.NameNotFoundException; 41 import android.content.pm.Signature; 42 import android.os.Build; 43 import android.os.SystemProperties; 44 import android.util.Log; 45 46 import com.android.se.Channel; 47 import com.android.se.SecureElementService; 48 import com.android.se.Terminal; 49 import com.android.se.internal.ByteArrayConverter; 50 import com.android.se.security.ChannelAccess.ACCESS; 51 import com.android.se.security.ara.AraController; 52 import com.android.se.security.arf.ArfController; 53 54 import java.io.IOException; 55 import java.io.PrintWriter; 56 import java.security.AccessControlException; 57 import java.security.MessageDigest; 58 import java.security.NoSuchAlgorithmException; 59 import java.util.ArrayList; 60 import java.util.List; 61 import java.util.MissingResourceException; 62 import java.util.NoSuchElementException; 63 64 /** Reads and Maintains the ARF and ARA access control for a particular Secure Element */ 65 public class AccessControlEnforcer { 66 67 private final String mTag = "SecureElement-AccessControlEnforcer"; 68 private static final boolean DEBUG = Build.IS_DEBUGGABLE; 69 private PackageManager mPackageManager = null; 70 private boolean mNoRuleFound = false; 71 private AraController mAraController = null; 72 private boolean mUseAra = true; 73 private ArfController mArfController = null; 74 private boolean mUseArf = false; 75 private AccessRuleCache mAccessRuleCache = null; 76 private boolean mRulesRead = false; 77 private Terminal mTerminal = null; 78 private ChannelAccess mInitialChannelAccess = new ChannelAccess(); 79 private boolean mFullAccess = false; 80 AccessControlEnforcer(Terminal terminal)81 public AccessControlEnforcer(Terminal terminal) { 82 83 mTerminal = terminal; 84 mAccessRuleCache = new AccessRuleCache(); 85 } 86 getDefaultAccessControlAid()87 public byte[] getDefaultAccessControlAid() { 88 if (mAraController != null) { 89 return mAraController.getAccessControlAid(); 90 } 91 return AraController.getAraMAid(); 92 } 93 getPackageManager()94 public PackageManager getPackageManager() { 95 return mPackageManager; 96 } 97 setPackageManager(PackageManager packageManager)98 public void setPackageManager(PackageManager packageManager) { 99 mPackageManager = packageManager; 100 } 101 getTerminal()102 public Terminal getTerminal() { 103 return mTerminal; 104 } 105 getAccessRuleCache()106 public AccessRuleCache getAccessRuleCache() { 107 return mAccessRuleCache; 108 } 109 110 /** Resets the Access Control for the Secure Element */ reset()111 public synchronized void reset() { 112 // Destroy any previous Controler 113 // in order to reset the ACE 114 Log.i(mTag, "Reset the ACE for terminal:" + mTerminal.getName()); 115 mAccessRuleCache.reset(); 116 mAraController = null; 117 mArfController = null; 118 } 119 120 /** Initializes the Access Control for the Secure Element */ initialize()121 public synchronized void initialize() throws IOException, MissingResourceException { 122 boolean status = true; 123 String denyMsg = ""; 124 // allow access to set up access control for a channel 125 mInitialChannelAccess.setApduAccess(ChannelAccess.ACCESS.ALLOWED); 126 mInitialChannelAccess.setNFCEventAccess(ChannelAccess.ACCESS.ALLOWED); 127 mInitialChannelAccess.setAccess(ChannelAccess.ACCESS.ALLOWED, ""); 128 129 readSecurityProfile(); 130 mNoRuleFound = false; 131 132 // 1 - Let's try to use ARA 133 if (mUseAra && mAraController == null) { 134 mAraController = new AraController(mAccessRuleCache, mTerminal); 135 } 136 137 if (mUseAra && mAraController != null) { 138 try { 139 mAraController.initialize(); 140 Log.i(mTag, "ARA applet is used for:" + mTerminal.getName()); 141 // disable other access methods 142 mUseArf = false; 143 mFullAccess = false; 144 } catch (IOException | MissingResourceException e) { 145 throw e; 146 } catch (Exception e) { 147 // ARA cannot be used since we got an exception during initialization 148 mUseAra = false; 149 denyMsg = e.getLocalizedMessage(); 150 if (e instanceof NoSuchElementException) { 151 Log.i(mTag, "No ARA applet found in: " + mTerminal.getName()); 152 if (!mUseArf) { 153 // ARA does not exist on the secure element right now, 154 // but it might be installed later. 155 mNoRuleFound = true; 156 status = mFullAccess; 157 } 158 } else if (mTerminal.getName().startsWith(SecureElementService.UICC_TERMINAL)) { 159 // A possible explanation could simply be due to the fact that the UICC is old 160 // and does not support logical channel (and is not compliant with GP spec). 161 // We should simply act as if no ARA was available in this case. 162 if (!mUseArf) { 163 // Only ARA was the candidate to retrieve access rules, 164 // but it is not 100% sure if the expected ARA really does not exist. 165 // Full access should not be granted in this case. 166 mFullAccess = false; 167 status = false; 168 } 169 } else { 170 // ARA is available but doesn't work properly. 171 // We are going to disable everything per security req. 172 mUseArf = false; 173 mFullAccess = false; 174 status = false; 175 Log.i(mTag, "Problem accessing ARA, Access DENIED " 176 + e.getLocalizedMessage()); 177 } 178 } 179 } 180 181 // 2 - Let's try to use ARF since ARA cannot be used 182 if (mUseArf && mArfController == null) { 183 mArfController = new ArfController(mAccessRuleCache, mTerminal); 184 } 185 186 if (mUseArf && mArfController != null) { 187 try { 188 mArfController.initialize(); 189 // disable other access methods 190 Log.i(mTag, "ARF rules are used for:" + mTerminal.getName()); 191 mFullAccess = false; 192 } catch (IOException | MissingResourceException e) { 193 throw e; 194 } catch (Exception e) { 195 // ARF cannot be used since we got an exception 196 mUseArf = false; 197 denyMsg = e.getLocalizedMessage(); 198 Log.e(mTag, e.getMessage()); 199 if (e instanceof NoSuchElementException) { 200 Log.i(mTag, "No ARF found in: " + mTerminal.getName()); 201 // ARF does not exist on the secure element right now, 202 // but it might be added later. 203 mNoRuleFound = true; 204 status = mFullAccess; 205 } else { 206 // It is not 100% sure if the expected ARF really does not exist. 207 // No ARF might be due to a kind of temporary problem, 208 // so full access should not be granted in this case. 209 mFullAccess = false; 210 status = false; 211 } 212 } 213 } 214 215 /* 4 - Let's block everything since neither ARA, ARF or fullaccess can be used */ 216 if (!mUseArf && !mUseAra && !mFullAccess) { 217 mInitialChannelAccess.setApduAccess(ChannelAccess.ACCESS.DENIED); 218 mInitialChannelAccess.setNFCEventAccess(ChannelAccess.ACCESS.DENIED); 219 mInitialChannelAccess.setAccess(ChannelAccess.ACCESS.DENIED, denyMsg); 220 Log.i(mTag, "Deny any access to:" + mTerminal.getName()); 221 } 222 223 mRulesRead = status; 224 } 225 226 /** 227 * Returns the result of the previous attempt to select ARA and/or ARF. 228 * 229 * @return true if no rule was found in the previous attempt. 230 */ isNoRuleFound()231 public boolean isNoRuleFound() { 232 return mNoRuleFound; 233 } 234 235 /** Check if the Channel has permission for the given APDU */ checkCommand(Channel channel, byte[] command)236 public synchronized void checkCommand(Channel channel, byte[] command) { 237 ChannelAccess ca = channel.getChannelAccess(); 238 if (ca == null) { 239 throw new AccessControlException(mTag + "Channel access not set"); 240 } 241 String reason = ca.getReason(); 242 if (reason.length() == 0) { 243 reason = "Unspecified"; 244 } 245 if (DEBUG) { 246 Log.i(mTag, "checkCommand() : Access = " + ca.getAccess() + " APDU Access = " 247 + ca.getApduAccess() + " Reason = " + reason); 248 } 249 if (ca.getAccess() != ACCESS.ALLOWED) { 250 throw new AccessControlException(mTag + reason); 251 } 252 if (ca.isUseApduFilter()) { 253 ApduFilter[] accessConditions = ca.getApduFilter(); 254 if (accessConditions == null || accessConditions.length == 0) { 255 throw new AccessControlException(mTag + "Access Rule not available:" 256 + reason); 257 } 258 for (ApduFilter ac : accessConditions) { 259 if (CommandApdu.compareHeaders(command, ac.getMask(), ac.getApdu())) { 260 return; 261 } 262 } 263 throw new AccessControlException(mTag + "Access Rule does not match: " 264 + reason); 265 } 266 if (ca.getApduAccess() == ChannelAccess.ACCESS.ALLOWED) { 267 return; 268 } else { 269 throw new AccessControlException(mTag + "APDU access NOT allowed"); 270 } 271 } 272 273 /** Sets up the Channel Access for the given Package */ setUpChannelAccess(byte[] aid, String packageName, boolean checkRefreshTag)274 public ChannelAccess setUpChannelAccess(byte[] aid, String packageName, boolean checkRefreshTag) 275 throws IOException, MissingResourceException { 276 ChannelAccess channelAccess = null; 277 // check result of channel access during initialization procedure 278 if (mInitialChannelAccess.getAccess() == ChannelAccess.ACCESS.DENIED) { 279 throw new AccessControlException( 280 mTag + "access denied: " + mInitialChannelAccess.getReason()); 281 } 282 // this is the new GP Access Control Enforcer implementation 283 if (mUseAra || mUseArf) { 284 channelAccess = internal_setUpChannelAccess(aid, packageName, 285 checkRefreshTag); 286 } 287 if (channelAccess == null || (channelAccess.getApduAccess() != ChannelAccess.ACCESS.ALLOWED 288 && !channelAccess.isUseApduFilter())) { 289 if (mFullAccess) { 290 // if full access is set then we reuse the initial channel access, 291 // since we got so far it allows everything with a descriptive reason. 292 channelAccess = mInitialChannelAccess; 293 } else { 294 throw new AccessControlException(mTag + "no APDU access allowed!"); 295 } 296 } 297 channelAccess.setPackageName(packageName); 298 return channelAccess.clone(); 299 } 300 internal_setUpChannelAccess(byte[] aid, String packageName, boolean checkRefreshTag)301 private synchronized ChannelAccess internal_setUpChannelAccess(byte[] aid, 302 String packageName, boolean checkRefreshTag) throws IOException, 303 MissingResourceException { 304 if (packageName == null || packageName.isEmpty()) { 305 throw new AccessControlException("package names must be specified"); 306 } 307 try { 308 // estimate SHA-1 and SHA-256 hash values of the device application's certificate. 309 List<byte[]> appCertHashes = getAppCertHashes(packageName); 310 // APP certificates must be available => otherwise Exception 311 if (appCertHashes == null || appCertHashes.size() == 0) { 312 throw new AccessControlException( 313 "Application certificates are invalid or do not exist."); 314 } 315 if (checkRefreshTag) { 316 updateAccessRuleIfNeed(); 317 } 318 return getAccessRule(aid, appCertHashes); 319 } catch (IOException | MissingResourceException e) { 320 throw e; 321 } catch (Throwable exp) { 322 throw new AccessControlException(exp.getMessage()); 323 } 324 } 325 326 /** Fetches the Access Rules for the given application and AID pair */ getAccessRule( byte[] aid, List<byte []> appCertHashes)327 public ChannelAccess getAccessRule( 328 byte[] aid, List<byte []> appCertHashes) 329 throws AccessControlException { 330 if (DEBUG) { 331 for (byte[] appCertHash : appCertHashes) { 332 Log.i(mTag, "getAccessRule() appCert = " 333 + ByteArrayConverter.byteArrayToHexString(appCertHash)); 334 } 335 } 336 ChannelAccess channelAccess = null; 337 // if read all is true get rule from cache. 338 if (mRulesRead) { 339 // get rules from internal storage 340 channelAccess = mAccessRuleCache.findAccessRule(aid, appCertHashes); 341 } 342 // if no rule was found return an empty access rule 343 // with all access denied. 344 if (channelAccess == null) { 345 channelAccess = new ChannelAccess(); 346 channelAccess.setAccess(ChannelAccess.ACCESS.DENIED, "no access rule found!"); 347 channelAccess.setApduAccess(ChannelAccess.ACCESS.DENIED); 348 channelAccess.setNFCEventAccess(ChannelAccess.ACCESS.DENIED); 349 } 350 return channelAccess; 351 } 352 353 /** 354 * Returns hashes of certificate chain for one package. 355 */ getAppCertHashes(String packageName)356 private List<byte[]> getAppCertHashes(String packageName) 357 throws NoSuchAlgorithmException, AccessControlException { 358 if (packageName == null || packageName.length() == 0) { 359 throw new AccessControlException("Package Name not defined"); 360 } 361 PackageInfo foundPkgInfo; 362 try { 363 foundPkgInfo = mPackageManager.getPackageInfo(packageName, 364 PackageManager.GET_SIGNATURES); 365 } catch (NameNotFoundException ne) { 366 throw new AccessControlException("Package does not exist"); 367 } 368 if (foundPkgInfo == null) { 369 throw new AccessControlException("Package does not exist"); 370 } 371 MessageDigest md = MessageDigest.getInstance("SHA"); 372 MessageDigest md256 = MessageDigest.getInstance("SHA-256"); 373 if (md == null || md256 == null) { 374 throw new AccessControlException("Hash can not be computed"); 375 } 376 List<byte[]> appCertHashes = new ArrayList<byte[]>(); 377 for (Signature signature : foundPkgInfo.signatures) { 378 appCertHashes.add(md.digest(signature.toByteArray())); 379 appCertHashes.add(md256.digest(signature.toByteArray())); 380 } 381 return appCertHashes; 382 } 383 384 /** Returns true if the given application is allowed to recieve NFC Events */ isNfcEventAllowed(byte[] aid, String[] packageNames)385 public synchronized boolean[] isNfcEventAllowed(byte[] aid, 386 String[] packageNames) { 387 if (mUseAra || mUseArf) { 388 return internal_isNfcEventAllowed(aid, packageNames); 389 } else { 390 // if ARA and ARF is not available and 391 // - terminal DOES NOT belong to a UICC -> mFullAccess is true 392 // - terminal belongs to a UICC -> mFullAccess is false 393 boolean[] ret = new boolean[packageNames.length]; 394 for (int i = 0; i < ret.length; i++) { 395 ret[i] = mFullAccess; 396 } 397 return ret; 398 } 399 } 400 internal_isNfcEventAllowed(byte[] aid, String[] packageNames)401 private synchronized boolean[] internal_isNfcEventAllowed(byte[] aid, 402 String[] packageNames) { 403 int i = 0; 404 boolean[] nfcEventFlags = new boolean[packageNames.length]; 405 for (String packageName : packageNames) { 406 // estimate hash value of the device application's certificate. 407 try { 408 List<byte[]> appCertHashes = getAppCertHashes(packageName); 409 // APP certificates must be available => otherwise Exception 410 if (appCertHashes == null || appCertHashes.size() == 0) { 411 nfcEventFlags[i] = false; 412 } else { 413 ChannelAccess channelAccess = getAccessRule(aid, appCertHashes); 414 nfcEventFlags[i] = 415 (channelAccess.getNFCEventAccess() == ChannelAccess.ACCESS.ALLOWED); 416 } 417 } catch (Exception e) { 418 Log.w(mTag, " Access Rules for NFC: " + e.getLocalizedMessage()); 419 nfcEventFlags[i] = false; 420 } 421 i++; 422 } 423 return nfcEventFlags; 424 } 425 updateAccessRuleIfNeed()426 private void updateAccessRuleIfNeed() throws IOException { 427 if (mUseAra && mAraController != null) { 428 try { 429 mAraController.initialize(); 430 mUseArf = false; 431 mFullAccess = false; 432 } catch (IOException | MissingResourceException e) { 433 // There was a communication error between the terminal and the secure element 434 // or failure in retrieving rules due to the lack of a new logical channel. 435 // These errors must be distinguished from other ones. 436 throw e; 437 } catch (Exception e) { 438 throw new AccessControlException("No ARA applet found in " + mTerminal.getName()); 439 } 440 } else if (mUseArf && mArfController != null) { 441 try { 442 mArfController.initialize(); 443 } catch (IOException | MissingResourceException e) { 444 // There was a communication error between the terminal and the secure element 445 // or failure in retrieving rules due to the lack of a new logical channel. 446 // These errors must be distinguished from other ones. 447 throw e; 448 } catch (Exception e) { 449 throw new AccessControlException("No ARF found in " + mTerminal.getName()); 450 } 451 } 452 } 453 454 /** Returns true if the given package has Carrier Privileges */ checkCarrierPrivilege(PackageInfo pInfo, boolean checkRefreshTag)455 public synchronized boolean checkCarrierPrivilege(PackageInfo pInfo, boolean checkRefreshTag) { 456 if (!mUseAra && !mUseArf) { 457 return false; 458 } 459 if (checkRefreshTag) { 460 try { 461 updateAccessRuleIfNeed(); 462 } catch (IOException | MissingResourceException e) { 463 throw new AccessControlException("Access-Control not found in " 464 + mTerminal.getName()); 465 } 466 } 467 if (!mRulesRead) { 468 return false; 469 } 470 try { 471 List<byte[]> appCertHashes = getAppCertHashes(pInfo.packageName); 472 if (appCertHashes == null || appCertHashes.size() == 0) { 473 return false; 474 } 475 476 return mAccessRuleCache.checkCarrierPrivilege(pInfo.packageName, appCertHashes); 477 } catch (Exception e) { 478 Log.w(mTag, " checkCarrierPrivilege: " + e.getLocalizedMessage()); 479 } 480 return false; 481 } 482 483 /** Debug information to be used by dumpsys */ dump(PrintWriter writer)484 public void dump(PrintWriter writer) { 485 writer.println(mTag + ":"); 486 487 writer.println("mUseArf: " + mUseArf); 488 writer.println("mUseAra: " + mUseAra); 489 if (mUseAra && mAraController != null) { 490 if (getDefaultAccessControlAid() == null) { 491 writer.println("AraInUse: default applet"); 492 } else { 493 writer.println("AraInUse: " + ByteArrayConverter.byteArrayToHexString( 494 getDefaultAccessControlAid())); 495 } 496 } 497 writer.println("mInitialChannelAccess:"); 498 writer.println(mInitialChannelAccess.toString()); 499 writer.println(); 500 501 /* Dump the access rule cache */ 502 if (mAccessRuleCache != null) mAccessRuleCache.dump(writer); 503 } 504 readSecurityProfile()505 private void readSecurityProfile() { 506 if (!Build.IS_DEBUGGABLE) { 507 mUseArf = true; 508 mUseAra = true; 509 mFullAccess = false; // Per default we don't grant full access. 510 } else { 511 String level = SystemProperties.get("service.seek", "useara usearf"); 512 level = SystemProperties.get("persist.service.seek", level); 513 514 if (level.contains("usearf")) { 515 mUseArf = true; 516 } else { 517 mUseArf = false; 518 } 519 if (level.contains("useara")) { 520 mUseAra = true; 521 } else { 522 mUseAra = false; 523 } 524 if (level.contains("fullaccess")) { 525 mFullAccess = true; 526 } else { 527 mFullAccess = false; 528 } 529 } 530 if (!mTerminal.getName().startsWith(SecureElementService.UICC_TERMINAL)) { 531 // ARF is supported only on UICC. 532 mUseArf = false; 533 } 534 Log.i( 535 mTag, 536 "Allowed ACE mode: ara=" + mUseAra + " arf=" + mUseArf + " fullaccess=" 537 + mFullAccess); 538 } 539 } 540