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