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