• 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.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 
AccessControlEnforcer(Terminal terminal)83     public AccessControlEnforcer(Terminal terminal) {
84 
85         mTerminal = terminal;
86         mAccessRuleCache = new AccessRuleCache();
87     }
88 
getDefaultAccessControlAid()89     public static byte[] getDefaultAccessControlAid() {
90         return AraController.getAraMAid();
91     }
92 
decodeCertificate(byte[] certData)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 */
getAppCertHash(Certificate appCert)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 
getPackageManager()115     public PackageManager getPackageManager() {
116         return mPackageManager;
117     }
118 
setPackageManager(PackageManager packageManager)119     public void setPackageManager(PackageManager packageManager) {
120         mPackageManager = packageManager;
121     }
122 
getTerminal()123     public Terminal getTerminal() {
124         return mTerminal;
125     }
126 
getAccessRuleCache()127     public AccessRuleCache getAccessRuleCache() {
128         return mAccessRuleCache;
129     }
130 
131     /** Resets the Access Control for the Secure Element */
reset()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 */
initialize()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 */
checkCommand(Channel channel, byte[] command)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 */
setUpChannelAccess(byte[] aid, String packageName, boolean checkRefreshTag)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 
internal_setUpChannelAccess(byte[] aid, String packageName, boolean checkRefreshTag)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 */
getAccessRule( byte[] aid, Certificate[] appCerts)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      */
getAPPCerts(String packageName)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 */
isNfcEventAllowed(byte[] aid, String[] packageNames, boolean checkRefreshTag)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 
internal_isNfcEventAllowed(byte[] aid, String[] packageNames, boolean checkRefreshTag)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 
updateAccessRuleIfNeed()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 */
dump(PrintWriter writer)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 
readSecurityProfile()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