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.isDebuggable();
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         super.onCreate();
211         Log.i(mTag, Thread.currentThread().getName() + " onCreate");
212         initialize();
213         createTerminals();
214 
215         // Add vendor stable service only if it is configured
216         if (getResources().getBoolean(R.bool.secure_element_vintf_enabled)) {
217             ServiceManager.addService(VSTABLE_SECURE_ELEMENT_SERVICE,
218                     mSecureElementServiceBinderVntf);
219         }
220 
221         // Since ISecureElementService is marked with VINTF stability
222         // to use this same interface within the system partition, will use
223         // forceDowngradeToSystemStability and register it.
224         mSecureElementServiceBinder.forceDowngradeToSystemStability();
225         ServiceManager.addService(Context.SECURE_ELEMENT_SERVICE, mSecureElementServiceBinder);
226     }
227 
228     /**
229      * In case the onDestroy is called, we free the memory and
230      * close all the channels.
231      */
onDestroy()232     public void onDestroy() {
233         super.onDestroy();
234         Log.i(mTag, "onDestroy");
235         for (Terminal terminal : mTerminals.values()) {
236             terminal.closeChannels();
237             terminal.close();
238         }
239         if (mMultiSimConfigChangedReceiver != null) {
240             this.unregisterReceiver(mMultiSimConfigChangedReceiver);
241         }
242     }
243 
addTerminals(String terminalName)244     private void addTerminals(String terminalName) {
245         int index = 1;
246         String name = null;
247         if (terminalName.startsWith(SecureElementService.UICC_TERMINAL)) {
248             index = mActiveSimCount + 1;
249         }
250         try {
251             do {
252                 name = terminalName + Integer.toString(index);
253                 Terminal terminal = new Terminal(name, this);
254 
255                 Log.i(mTag, "Check if terminal " + name + " is available.");
256                 // Only retry on fail for the first terminal of each type.
257                 terminal.initialize(index == 1);
258                 mTerminals.put(name, terminal);
259                 if (terminalName.equals(UICC_TERMINAL)) {
260                     mActiveSimCount = index;
261                 }
262             } while (++index > 0);
263         } catch (NoSuchElementException e) {
264             Log.i(mTag, "No HAL implementation for " + name);
265         } catch (RemoteException | RuntimeException e) {
266             Log.e(mTag, "Error in getService() for " + name);
267         }
268     }
269 
createTerminals()270     private void createTerminals() {
271         // Check for all SE HAL implementations
272         addTerminals(ESE_TERMINAL);
273         addTerminals(UICC_TERMINAL);
274     }
275 
refreshUiccTerminals(int activeSimCount)276     private void refreshUiccTerminals(int activeSimCount) {
277         String name = null;
278         synchronized (this) {
279             if (activeSimCount < mActiveSimCount) {
280                 // Remove non-supported UICC terminals
281                 for (int i = activeSimCount + 1; i <= mActiveSimCount; i++) {
282                     name = UICC_TERMINAL + Integer.toString(i);
283                     Terminal terminal = mTerminals.get(name);
284                     if (terminal != null) {
285                         terminal.closeChannels();
286                         terminal.close();
287                     }
288                     mTerminals.remove(name);
289                     Log.i(mTag, name + " is removed from available Terminals");
290                 }
291                 mActiveSimCount = activeSimCount;
292             } else if (activeSimCount > mActiveSimCount) {
293                 // Try to initialize new UICC terminals
294                 addTerminals(UICC_TERMINAL);
295             }
296         }
297     }
298 
getPackageNameFromCallingUid(int uid)299     private String getPackageNameFromCallingUid(int uid) {
300         PackageManager packageManager = getPackageManager();
301         if (packageManager != null) {
302             String[] packageName = packageManager.getPackagesForUid(uid);
303             if (packageName != null && packageName.length > 0) {
304                 return packageName[0];
305             }
306         }
307         throw new AccessControlException("PackageName can not be determined");
308     }
309 
getUUIDFromCallingUid(int uid)310     private byte[] getUUIDFromCallingUid(int uid) {
311         byte[] uuid = HalRefDoParser.getInstance().findUUID(Binder.getCallingUid());
312 
313         if (uuid != null) {
314             return uuid;
315         }
316 
317         return null;
318     }
319 
320     final class SecureElementSession extends ISecureElementSession.Stub {
321 
322         private final SecureElementReader mReader;
323         /** List of open channels in use of by this client. */
324         private final List<Channel> mChannels = new ArrayList<>();
325         private final Object mLock = new Object();
326         private boolean mIsClosed;
327         private byte[] mAtr;
328 
SecureElementSession(SecureElementReader reader)329         SecureElementSession(SecureElementReader reader) {
330             if (reader == null) {
331                 throw new NullPointerException("SecureElementReader cannot be null");
332             }
333             mReader = reader;
334             mAtr = mReader.getAtr();
335             mIsClosed = false;
336         }
337 
getReader()338         public ISecureElementReader getReader() throws RemoteException {
339             return mReader;
340         }
341 
342         @Override
getAtr()343         public byte[] getAtr() throws RemoteException {
344             return mAtr;
345         }
346 
347         @Override
close()348         public void close() throws RemoteException {
349             closeChannels();
350             mReader.removeSession(this);
351             synchronized (mLock) {
352                 mIsClosed = true;
353             }
354         }
355 
removeChannel(Channel channel)356         void removeChannel(Channel channel) {
357             synchronized (mLock) {
358                 if (mChannels != null) {
359                     mChannels.remove(channel);
360                 }
361             }
362         }
363 
364         @Override
closeChannels()365         public void closeChannels() throws RemoteException {
366             synchronized (mLock) {
367                 while (mChannels.size() > 0) {
368                     try {
369                         mChannels.get(0).close();
370                     } catch (Exception ignore) {
371                         Log.e(mTag, "SecureElementSession Channel - close Exception "
372                                 + ignore.getMessage());
373                     }
374                 }
375             }
376         }
377 
378         @Override
isClosed()379         public boolean isClosed() throws RemoteException {
380             synchronized (mLock) {
381                 return mIsClosed;
382             }
383         }
384 
385         @Override
openBasicChannel(byte[] aid, byte p2, ISecureElementListener listener)386         public ISecureElementChannel openBasicChannel(byte[] aid, byte p2,
387                 ISecureElementListener listener) throws RemoteException {
388             if (DEBUG) {
389                 Log.i(mTag, "openBasicChannel() AID = "
390                         + ByteArrayConverter.byteArrayToHexString(aid) + ", P2 = " + p2);
391             }
392             if (isClosed()) {
393                 throw new IllegalStateException("Session is closed");
394             } else if (listener == null) {
395                 throw new NullPointerException("listener must not be null");
396             } else if ((p2 != 0x00) && (p2 != 0x04) && (p2 != 0x08)
397                     && (p2 != (byte) 0x0C)) {
398                 throw new UnsupportedOperationException("p2 not supported: "
399                         + String.format("%02x ", p2 & 0xFF));
400             }
401 
402             String packageName = null;
403             byte[] uuid = null;
404             try {
405                 packageName = getPackageNameFromCallingUid(Binder.getCallingUid());
406             } catch (AccessControlException e) {
407                 // Since packageName not found for calling process, try to find UUID mapping
408                 // provided by vendors for the calling process UID
409                 // (vendor provide UUID mapping for native services to access secure element)
410                 Log.d(mTag, "openBasicChannel() trying to find mapping uuid");
411                 // Allow UUID based access only on embedded secure elements eSE.
412                 if (mReader.getTerminal().getName().startsWith(SecureElementService.ESE_TERMINAL)) {
413                     uuid = getUUIDFromCallingUid(Binder.getCallingUid());
414                 }
415                 if (uuid == null) {
416                     Log.e(mTag, "openBasicChannel() uuid mapping for calling uid is not found");
417                     throw e;
418                 }
419             }
420             Channel channel = null;
421 
422             try {
423                 channel = mReader.getTerminal().openBasicChannel(this, aid, p2, listener,
424                         packageName, uuid, Binder.getCallingPid());
425             } catch (IOException e) {
426                 throw new ServiceSpecificException(SEService.IO_ERROR, e.getMessage());
427             } catch (NoSuchElementException e) {
428                 throw new ServiceSpecificException(SEService.NO_SUCH_ELEMENT_ERROR, e.getMessage());
429             }
430 
431             if (channel == null) {
432                 Log.i(mTag, "OpenBasicChannel() - returning null");
433                 return null;
434             }
435             Log.i(mTag, "Open basic channel success. Channel: "
436                     + channel.getChannelNumber());
437 
438             synchronized (mLock) {
439                 mChannels.add(channel);
440             }
441             return channel.new SecureElementChannel();
442         }
443 
444         @Override
openLogicalChannel(byte[] aid, byte p2, ISecureElementListener listener)445         public ISecureElementChannel openLogicalChannel(byte[] aid, byte p2,
446                 ISecureElementListener listener) throws RemoteException {
447             if (DEBUG) {
448                 Log.i(mTag, "openLogicalChannel() AID = "
449                         + ByteArrayConverter.byteArrayToHexString(aid) + ", P2 = " + p2);
450             }
451             if (isClosed()) {
452                 throw new IllegalStateException("Session is closed");
453             } else if (listener == null) {
454                 throw new NullPointerException("listener must not be null");
455             } else if ((p2 != 0x00) && (p2 != 0x04) && (p2 != 0x08)
456                     && (p2 != (byte) 0x0C)) {
457                 throw new UnsupportedOperationException("p2 not supported: "
458                         + String.format("%02x ", p2 & 0xFF));
459             }
460 
461             String packageName = null;
462             byte[] uuid = null;
463             try {
464                 packageName = getPackageNameFromCallingUid(Binder.getCallingUid());
465             } catch (AccessControlException e) {
466                 // Since packageName not found for calling process, try to find UUID mapping
467                 // provided by vendors for the calling process UID
468                 // (vendor provide UUID mapping for native services to access secure element)
469                 Log.d(mTag, "openLogicalChannel() trying to find mapping uuid");
470                 // Allow UUID based access only on embedded secure elements eSE.
471                 if (mReader.getTerminal().getName().startsWith(SecureElementService.ESE_TERMINAL)) {
472                     uuid = getUUIDFromCallingUid(Binder.getCallingUid());
473                 }
474                 if (uuid == null) {
475                     Log.e(mTag, "openLogicalChannel() uuid mapping for calling uid is not found");
476                     throw e;
477                 }
478             }
479             Channel channel = null;
480 
481             try {
482                 channel = mReader.getTerminal().openLogicalChannel(this, aid, p2, listener,
483                         packageName, uuid, Binder.getCallingPid());
484             } catch (IOException e) {
485                 throw new ServiceSpecificException(SEService.IO_ERROR, e.getMessage());
486             } catch (NoSuchElementException e) {
487                 throw new ServiceSpecificException(SEService.NO_SUCH_ELEMENT_ERROR, e.getMessage());
488             }
489 
490             if (channel == null) {
491                 Log.i(mTag, "openLogicalChannel() - returning null");
492                 return null;
493             }
494             Log.i(mTag, "openLogicalChannel() Success. Channel: "
495                     + channel.getChannelNumber());
496 
497             synchronized (mLock) {
498                 mChannels.add(channel);
499             }
500             return channel.new SecureElementChannel();
501         }
502 
503         @Override
getInterfaceHash()504         public String getInterfaceHash() {
505             return ISecureElementSession.HASH;
506         }
507 
508         @Override
getInterfaceVersion()509         public int getInterfaceVersion() {
510             return ISecureElementSession.VERSION;
511         }
512     }
513 
514     private final BroadcastReceiver mMultiSimConfigChangedReceiver = new BroadcastReceiver() {
515         @Override
516         public void onReceive(Context context, Intent intent) {
517             String action = intent.getAction();
518             if (action.equals(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED)) {
519                 int activeSimCount =
520                         intent.getIntExtra(TelephonyManager.EXTRA_ACTIVE_SIM_SUPPORTED_COUNT, 1);
521                 Log.i(mTag, "received action MultiSimConfigChanged. Refresh UICC terminals");
522                 Log.i(mTag, "Current ActiveSimCount:" + activeSimCount
523                         + ". Previous ActiveSimCount:" + mActiveSimCount);
524 
525                 // Check for any change to UICC SE HAL implementations
526                 refreshUiccTerminals(activeSimCount);
527             }
528         }
529     };
530 }
531