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