• 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  * Contributed by: Giesecke & Devrient GmbH.
21  */
22 
23 package com.android.se;
24 
25 import android.app.Service;
26 import android.content.BroadcastReceiver;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.IntentFilter;
30 import android.content.pm.PackageManager;
31 import android.os.Binder;
32 import android.os.Build;
33 import android.os.IBinder;
34 import android.os.RemoteException;
35 import android.os.ServiceManager;
36 import android.os.ServiceSpecificException;
37 import android.os.UserHandle;
38 import android.se.omapi.ISecureElementChannel;
39 import android.se.omapi.ISecureElementListener;
40 import android.se.omapi.ISecureElementReader;
41 import android.se.omapi.ISecureElementService;
42 import android.se.omapi.ISecureElementSession;
43 import android.se.omapi.SEService;
44 import android.telephony.TelephonyManager;
45 import android.util.Log;
46 
47 import com.android.se.Terminal.SecureElementReader;
48 import com.android.se.internal.ByteArrayConverter;
49 import com.android.se.security.HalRefDoParser;
50 
51 import java.io.FileDescriptor;
52 import java.io.IOException;
53 import java.io.PrintWriter;
54 import java.security.AccessControlException;
55 import java.util.ArrayList;
56 import java.util.LinkedHashMap;
57 import java.util.List;
58 import java.util.NoSuchElementException;
59 import java.util.Vector;
60 
61 /**
62  * Underlying implementation for OMAPI SEService
63  */
64 public final class SecureElementService extends Service {
65 
66     public static final String UICC_TERMINAL = "SIM";
67     public static final String ESE_TERMINAL = "eSE";
68     public static final String VSTABLE_SECURE_ELEMENT_SERVICE =
69             "android.se.omapi.ISecureElementService/default";
70     private final String mTag = "SecureElementService";
71     private static final boolean DEBUG = Build.IS_DEBUGGABLE;
72     // LinkedHashMap will maintain the order of insertion
73     private LinkedHashMap<String, Terminal> mTerminals = new LinkedHashMap<String, Terminal>();
74     private int mActiveSimCount = 0;
75     private class SecureElementServiceBinder extends ISecureElementService.Stub {
76 
77         @Override
getReaders()78         public String[] getReaders() throws RemoteException {
79             try {
80                 // This determines calling process is application/framework
81                 String packageName = getPackageNameFromCallingUid(Binder.getCallingUid());
82                 Log.d(mTag, "getReaders() for " + packageName);
83                 return mTerminals.keySet().toArray(new String[mTerminals.size()]);
84             } catch (AccessControlException e) {
85                 // since packagename not found, UUID might be used to access
86                 // allow only to use eSE readers with UUID based requests
87                 Vector<String> eSEReaders = new Vector<String>();
88                 for (String reader : mTerminals.keySet()) {
89                     if (reader.startsWith(SecureElementService.ESE_TERMINAL)) {
90                         Log.i(mTag, "Adding Reader: " + reader);
91                         eSEReaders.add(reader);
92                     }
93                 }
94 
95                 return eSEReaders.toArray(new String[eSEReaders.size()]);
96             }
97         }
98 
99         @Override
getReader(String reader)100         public ISecureElementReader getReader(String reader) throws RemoteException {
101             Log.d(mTag, "getReader() " + reader);
102             Terminal terminal = null;
103             try {
104                 // This determines calling process is application/framework
105                 String packageName = getPackageNameFromCallingUid(Binder.getCallingUid());
106                 Log.d(mTag, "getReader() for " + packageName);
107                 terminal = getTerminal(reader);
108             } catch (AccessControlException e) {
109                 // since packagename not found, UUID might be used to access
110                 // allow only to use eSE readers with UUID based requests
111                 if (reader.startsWith(SecureElementService.ESE_TERMINAL)) {
112                     terminal = getTerminal(reader);
113                 } else {
114                     Log.d(mTag, "only eSE readers can access SE using UUID");
115                 }
116             }
117             if (terminal != null) {
118                 return terminal.new SecureElementReader(SecureElementService.this);
119             } else {
120                 throw new IllegalArgumentException("Reader: " + reader + " not supported");
121             }
122         }
123 
124         @Override
isNfcEventAllowed(String reader, byte[] aid, String[] packageNames, int userId)125         public synchronized boolean[] isNfcEventAllowed(String reader, byte[] aid,
126                 String[] packageNames, int userId) throws RemoteException {
127             if (aid == null || aid.length == 0) {
128                 aid = new byte[]{0x00, 0x00, 0x00, 0x00, 0x00};
129             }
130             if (aid.length < 5 || aid.length > 16) {
131                 throw new IllegalArgumentException("AID out of range");
132             }
133             if (packageNames == null || packageNames.length == 0) {
134                 throw new IllegalArgumentException("package names not specified");
135             }
136             Terminal terminal = getTerminal(reader);
137             Context context;
138             try {
139                 context = createContextAsUser(UserHandle.of(userId), /*flags=*/0);
140             } catch (IllegalStateException e) {
141                 context = null;
142                 Log.d(mTag, "fail to call createContextAsUser for userId:" + userId);
143             }
144             return context == null ? null : terminal.isNfcEventAllowed(
145                     context.getPackageManager(), aid, packageNames);
146 
147         }
148 
149         @Override
dump(FileDescriptor fd, PrintWriter writer, String[] args)150         protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
151             for (Terminal terminal : mTerminals.values()) {
152                 terminal.dump(writer);
153             }
154         }
155 
156         @Override
getInterfaceHash()157         public String getInterfaceHash() {
158             return ISecureElementService.HASH;
159         }
160 
161         @Override
getInterfaceVersion()162         public int getInterfaceVersion() {
163             return ISecureElementService.VERSION;
164         }
165     }
166 
167     private final ISecureElementService.Stub mSecureElementServiceBinder =
168             new SecureElementServiceBinder();
169 
170     private final ISecureElementService.Stub mSecureElementServiceBinderVntf =
171             new SecureElementServiceBinder();
172 
SecureElementService()173     public SecureElementService() {
174         super();
175     }
176 
initialize()177     private void initialize() {
178         // listen for events
179         IntentFilter intentFilter = new IntentFilter();
180         intentFilter.addAction(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED);
181         this.registerReceiver(mMultiSimConfigChangedReceiver, intentFilter);
182     }
183 
184     /** Returns the terminal from the Reader name. */
getTerminal(String reader)185     private Terminal getTerminal(String reader) {
186         if (reader == null) {
187             throw new NullPointerException("reader must not be null");
188         }
189         if (reader.equals("SIM")) {
190             reader = "SIM1";
191         }
192         Terminal terminal = mTerminals.get(reader);
193         if (terminal == null) {
194             throw new IllegalArgumentException("Reader: " + reader + " doesn't exist");
195         }
196         return terminal;
197     }
198 
199     @Override
onBind(Intent intent)200     public IBinder onBind(Intent intent) {
201         Log.i(mTag, Thread.currentThread().getName() + " onBind");
202         if (ISecureElementService.class.getName().equals(intent.getAction())) {
203             return mSecureElementServiceBinder;
204         }
205         return null;
206     }
207 
208     @Override
onCreate()209     public void onCreate() {
210         Log.i(mTag, Thread.currentThread().getName() + " onCreate");
211         initialize();
212         createTerminals();
213 
214         // Add vendor stable service only if it is configured
215         if (getResources().getBoolean(R.bool.secure_element_vintf_enabled)) {
216             ServiceManager.addService(VSTABLE_SECURE_ELEMENT_SERVICE,
217                     mSecureElementServiceBinderVntf);
218         }
219 
220         // Since ISecureElementService is marked with VINTF stability
221         // to use this same interface within the system partition, will use
222         // forceDowngradeToSystemStability and register it.
223         mSecureElementServiceBinder.forceDowngradeToSystemStability();
224         ServiceManager.addService(Context.SECURE_ELEMENT_SERVICE, mSecureElementServiceBinder);
225     }
226 
227     /**
228      * In case the onDestroy is called, we free the memory and
229      * close all the channels.
230      */
onDestroy()231     public void onDestroy() {
232         Log.i(mTag, "onDestroy");
233         for (Terminal terminal : mTerminals.values()) {
234             terminal.closeChannels();
235             terminal.close();
236         }
237         if (mMultiSimConfigChangedReceiver != null) {
238             this.unregisterReceiver(mMultiSimConfigChangedReceiver);
239         }
240     }
241 
addTerminals(String terminalName)242     private void addTerminals(String terminalName) {
243         int index = 1;
244         String name = null;
245         if (terminalName.startsWith(SecureElementService.UICC_TERMINAL)) {
246             index = mActiveSimCount + 1;
247         }
248         try {
249             do {
250                 name = terminalName + Integer.toString(index);
251                 Terminal terminal = new Terminal(name, this);
252 
253                 Log.i(mTag, "Check if terminal " + name + " is available.");
254                 // Only retry on fail for the first terminal of each type.
255                 terminal.initialize(index == 1);
256                 mTerminals.put(name, terminal);
257                 if (terminalName.equals(UICC_TERMINAL)) {
258                     mActiveSimCount = index;
259                 }
260             } while (++index > 0);
261         } catch (NoSuchElementException e) {
262             Log.i(mTag, "No HAL implementation for " + name);
263         } catch (RemoteException | RuntimeException e) {
264             Log.e(mTag, "Error in getService() for " + name);
265         }
266     }
267 
createTerminals()268     private void createTerminals() {
269         // Check for all SE HAL implementations
270         addTerminals(ESE_TERMINAL);
271         addTerminals(UICC_TERMINAL);
272     }
273 
refreshUiccTerminals(int activeSimCount)274     private void refreshUiccTerminals(int activeSimCount) {
275         String name = null;
276         synchronized (this) {
277             if (activeSimCount < mActiveSimCount) {
278                 // Remove non-supported UICC terminals
279                 for (int i = activeSimCount + 1; i <= mActiveSimCount; i++) {
280                     name = UICC_TERMINAL + Integer.toString(i);
281                     Terminal terminal = mTerminals.get(name);
282                     if (terminal != null) {
283                         terminal.closeChannels();
284                         terminal.close();
285                     }
286                     mTerminals.remove(name);
287                     Log.i(mTag, name + " is removed from available Terminals");
288                 }
289                 mActiveSimCount = activeSimCount;
290             } else if (activeSimCount > mActiveSimCount) {
291                 // Try to initialize new UICC terminals
292                 addTerminals(UICC_TERMINAL);
293             }
294         }
295     }
296 
getPackageNameFromCallingUid(int uid)297     private String getPackageNameFromCallingUid(int uid) {
298         PackageManager packageManager = getPackageManager();
299         if (packageManager != null) {
300             String[] packageName = packageManager.getPackagesForUid(uid);
301             if (packageName != null && packageName.length > 0) {
302                 return packageName[0];
303             }
304         }
305         throw new AccessControlException("PackageName can not be determined");
306     }
307 
getUUIDFromCallingUid(int uid)308     private byte[] getUUIDFromCallingUid(int uid) {
309         byte[] uuid = HalRefDoParser.getInstance().findUUID(Binder.getCallingUid());
310 
311         if (uuid != null) {
312             return uuid;
313         }
314 
315         return null;
316     }
317 
318     final class SecureElementSession extends ISecureElementSession.Stub {
319 
320         private final SecureElementReader mReader;
321         /** List of open channels in use of by this client. */
322         private final List<Channel> mChannels = new ArrayList<>();
323         private final Object mLock = new Object();
324         private boolean mIsClosed;
325         private byte[] mAtr;
326 
SecureElementSession(SecureElementReader reader)327         SecureElementSession(SecureElementReader reader) {
328             if (reader == null) {
329                 throw new NullPointerException("SecureElementReader cannot be null");
330             }
331             mReader = reader;
332             mAtr = mReader.getAtr();
333             mIsClosed = false;
334         }
335 
getReader()336         public ISecureElementReader getReader() throws RemoteException {
337             return mReader;
338         }
339 
340         @Override
getAtr()341         public byte[] getAtr() throws RemoteException {
342             return mAtr;
343         }
344 
345         @Override
close()346         public void close() throws RemoteException {
347             closeChannels();
348             mReader.removeSession(this);
349             synchronized (mLock) {
350                 mIsClosed = true;
351             }
352         }
353 
removeChannel(Channel channel)354         void removeChannel(Channel channel) {
355             synchronized (mLock) {
356                 if (mChannels != null) {
357                     mChannels.remove(channel);
358                 }
359             }
360         }
361 
362         @Override
closeChannels()363         public void closeChannels() throws RemoteException {
364             synchronized (mLock) {
365                 while (mChannels.size() > 0) {
366                     try {
367                         mChannels.get(0).close();
368                     } catch (Exception ignore) {
369                         Log.e(mTag, "SecureElementSession Channel - close Exception "
370                                 + ignore.getMessage());
371                     }
372                 }
373             }
374         }
375 
376         @Override
isClosed()377         public boolean isClosed() throws RemoteException {
378             synchronized (mLock) {
379                 return mIsClosed;
380             }
381         }
382 
383         @Override
openBasicChannel(byte[] aid, byte p2, ISecureElementListener listener)384         public ISecureElementChannel openBasicChannel(byte[] aid, byte p2,
385                 ISecureElementListener listener) throws RemoteException {
386             if (DEBUG) {
387                 Log.i(mTag, "openBasicChannel() AID = "
388                         + ByteArrayConverter.byteArrayToHexString(aid) + ", P2 = " + p2);
389             }
390             if (isClosed()) {
391                 throw new IllegalStateException("Session is closed");
392             } else if (listener == null) {
393                 throw new NullPointerException("listener must not be null");
394             } else if ((p2 != 0x00) && (p2 != 0x04) && (p2 != 0x08)
395                     && (p2 != (byte) 0x0C)) {
396                 throw new UnsupportedOperationException("p2 not supported: "
397                         + String.format("%02x ", p2 & 0xFF));
398             }
399 
400             String packageName = null;
401             byte[] uuid = null;
402             try {
403                 packageName = getPackageNameFromCallingUid(Binder.getCallingUid());
404             } catch (AccessControlException e) {
405                 // Since packageName not found for calling process, try to find UUID mapping
406                 // provided by vendors for the calling process UID
407                 // (vendor provide UUID mapping for native services to access secure element)
408                 Log.d(mTag, "openBasicChannel() trying to find mapping uuid");
409                 // Allow UUID based access only on embedded secure elements eSE.
410                 if (mReader.getTerminal().getName().startsWith(SecureElementService.ESE_TERMINAL)) {
411                     uuid = getUUIDFromCallingUid(Binder.getCallingUid());
412                 }
413                 if (uuid == null) {
414                     Log.e(mTag, "openBasicChannel() uuid mapping for calling uid is not found");
415                     throw e;
416                 }
417             }
418             Channel channel = null;
419 
420             try {
421                 channel = mReader.getTerminal().openBasicChannel(this, aid, p2, listener,
422                         packageName, uuid, Binder.getCallingPid());
423             } catch (IOException e) {
424                 throw new ServiceSpecificException(SEService.IO_ERROR, e.getMessage());
425             } catch (NoSuchElementException e) {
426                 throw new ServiceSpecificException(SEService.NO_SUCH_ELEMENT_ERROR, e.getMessage());
427             }
428 
429             if (channel == null) {
430                 Log.i(mTag, "OpenBasicChannel() - returning null");
431                 return null;
432             }
433             Log.i(mTag, "Open basic channel success. Channel: "
434                     + channel.getChannelNumber());
435 
436             synchronized (mLock) {
437                 mChannels.add(channel);
438             }
439             return channel.new SecureElementChannel();
440         }
441 
442         @Override
openLogicalChannel(byte[] aid, byte p2, ISecureElementListener listener)443         public ISecureElementChannel openLogicalChannel(byte[] aid, byte p2,
444                 ISecureElementListener listener) throws RemoteException {
445             if (DEBUG) {
446                 Log.i(mTag, "openLogicalChannel() AID = "
447                         + ByteArrayConverter.byteArrayToHexString(aid) + ", P2 = " + p2);
448             }
449             if (isClosed()) {
450                 throw new IllegalStateException("Session is closed");
451             } else if (listener == null) {
452                 throw new NullPointerException("listener must not be null");
453             } else if ((p2 != 0x00) && (p2 != 0x04) && (p2 != 0x08)
454                     && (p2 != (byte) 0x0C)) {
455                 throw new UnsupportedOperationException("p2 not supported: "
456                         + String.format("%02x ", p2 & 0xFF));
457             }
458 
459             String packageName = null;
460             byte[] uuid = null;
461             try {
462                 packageName = getPackageNameFromCallingUid(Binder.getCallingUid());
463             } catch (AccessControlException e) {
464                 // Since packageName not found for calling process, try to find UUID mapping
465                 // provided by vendors for the calling process UID
466                 // (vendor provide UUID mapping for native services to access secure element)
467                 Log.d(mTag, "openLogicalChannel() trying to find mapping uuid");
468                 // Allow UUID based access only on embedded secure elements eSE.
469                 if (mReader.getTerminal().getName().startsWith(SecureElementService.ESE_TERMINAL)) {
470                     uuid = getUUIDFromCallingUid(Binder.getCallingUid());
471                 }
472                 if (uuid == null) {
473                     Log.e(mTag, "openLogicalChannel() uuid mapping for calling uid is not found");
474                     throw e;
475                 }
476             }
477             Channel channel = null;
478 
479             try {
480                 channel = mReader.getTerminal().openLogicalChannel(this, aid, p2, listener,
481                         packageName, uuid, Binder.getCallingPid());
482             } catch (IOException e) {
483                 throw new ServiceSpecificException(SEService.IO_ERROR, e.getMessage());
484             } catch (NoSuchElementException e) {
485                 throw new ServiceSpecificException(SEService.NO_SUCH_ELEMENT_ERROR, e.getMessage());
486             }
487 
488             if (channel == null) {
489                 Log.i(mTag, "openLogicalChannel() - returning null");
490                 return null;
491             }
492             Log.i(mTag, "openLogicalChannel() Success. Channel: "
493                     + channel.getChannelNumber());
494 
495             synchronized (mLock) {
496                 mChannels.add(channel);
497             }
498             return channel.new SecureElementChannel();
499         }
500 
501         @Override
getInterfaceHash()502         public String getInterfaceHash() {
503             return ISecureElementSession.HASH;
504         }
505 
506         @Override
getInterfaceVersion()507         public int getInterfaceVersion() {
508             return ISecureElementSession.VERSION;
509         }
510     }
511 
512     private final BroadcastReceiver mMultiSimConfigChangedReceiver = new BroadcastReceiver() {
513         @Override
514         public void onReceive(Context context, Intent intent) {
515             String action = intent.getAction();
516             if (action.equals(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED)) {
517                 int activeSimCount =
518                         intent.getIntExtra(TelephonyManager.EXTRA_ACTIVE_SIM_SUPPORTED_COUNT, 1);
519                 Log.i(mTag, "received action MultiSimConfigChanged. Refresh UICC terminals");
520                 Log.i(mTag, "Current ActiveSimCount:" + activeSimCount
521                         + ". Previous ActiveSimCount:" + mActiveSimCount);
522 
523                 // Check for any change to UICC SE HAL implementations
524                 refreshUiccTerminals(activeSimCount);
525             }
526         }
527     };
528 }
529