OSDN Git Service

adfeddd504c42bb093ce8e1205a779fd079380b2
[android-x86/frameworks-base.git] / core / java / android / se / omapi / Session.java
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) 2017, The Linux Foundation.
18  */
19 /*
20  * Contributed by: Giesecke & Devrient GmbH.
21  */
22
23 package android.se.omapi;
24
25 import android.annotation.NonNull;
26 import android.annotation.Nullable;
27 import android.os.RemoteException;
28 import android.os.ServiceSpecificException;
29 import android.util.Log;
30
31 import java.io.IOException;
32 import java.util.NoSuchElementException;
33
34 /**
35  * Instances of this class represent a connection session to one of the Secure
36  * Elements available on the device. These objects can be used to get a
37  * communication channel with an Applet in the Secure Element.
38  * This channel can be the basic channel or a logical channel.
39  *
40  * @see <a href="http://simalliance.org">SIMalliance Open Mobile API  v3.0</a>
41  */
42 public class Session {
43
44     private final Object mLock = new Object();
45     private final SEService mService;
46     private final Reader mReader;
47     private final ISecureElementSession mSession;
48     private static final String TAG = "OMAPI.Session";
49
50     Session(@NonNull SEService service, @NonNull ISecureElementSession session,
51             @NonNull Reader reader) {
52         if (service == null || reader == null || session == null) {
53             throw new IllegalArgumentException("Parameters cannot be null");
54         }
55         mService = service;
56         mReader = reader;
57         mSession = session;
58     }
59
60     /**
61      * Get the reader that provides this session.
62      *
63      * @return The Reader object.
64      */
65     public @NonNull Reader getReader() {
66         return mReader;
67     }
68
69     /**
70      * Get the Answer to Reset of this Secure Element. <br>
71      * The returned byte array can be null if the ATR for this Secure Element is
72      * not available.
73      *
74      * @throws IllegalStateException if there was an error connecting to SE or
75      *                               if the service was not connected.
76      * @return the ATR as a byte array or null.
77      */
78     public @Nullable byte[] getATR() {
79         if (!mService.isConnected()) {
80             throw new IllegalStateException("service not connected to system");
81         }
82         try {
83             return mSession.getAtr();
84         } catch (RemoteException e) {
85             throw new IllegalStateException(e.getMessage());
86         }
87     }
88
89     /**
90      * Close the connection with the Secure Element. This will close any
91      * channels opened by this application with this Secure Element.
92      */
93     public void close() {
94         if (!mService.isConnected()) {
95             Log.e(TAG, "service not connected to system");
96             return;
97         }
98         synchronized (mLock) {
99             try {
100                 mSession.close();
101             } catch (RemoteException e) {
102                 Log.e(TAG, "Error closing session", e);
103             }
104         }
105     }
106
107     /**
108      * Tells if this session is closed.
109      *
110      * @return <code>true</code> if the session is closed, false otherwise.
111      */
112     public boolean isClosed() {
113         try {
114             return mSession.isClosed();
115         } catch (RemoteException e) {
116             // If there was an error here, then the session is considered close
117             return true;
118         }
119     }
120
121     /**
122      * Close any channel opened on this session.
123      */
124     public void closeChannels() {
125         if (!mService.isConnected()) {
126             Log.e(TAG, "service not connected to system");
127             return;
128         }
129
130         synchronized (mLock) {
131             try {
132                 mSession.closeChannels();
133             } catch (RemoteException e) {
134                 Log.e(TAG, "Error closing channels", e);
135             }
136         }
137     }
138
139     /**
140      * Get an access to the basic channel, as defined in the ISO/IEC 7816-4 specification (the
141      * one that has number 0). The obtained object is an instance of the Channel class.
142      * If the AID is null, it means no Applet is to be selected on this channel and the default
143      * Applet is used. If the AID is defined then the corresponding Applet is selected.
144      * Once this channel has been opened by a device application, it is considered as "locked"
145      * by this device application, and other calls to this method will return null, until the
146      * channel is closed. Some Secure Elements (like the UICC) might always keep the basic channel
147      * locked (i.e. return null to applications), to prevent access to the basic channel, while
148      * some other might return a channel object implementing some kind of filtering on the
149      * commands, restricting the set of accepted command to a smaller set.
150      * It is recommended for the UICC to reject the opening of the basic channel to a specific
151      * applet, by always answering null to such a request.
152      * For other Secure Elements, the recommendation is to accept opening the basic channel
153      * on the default applet until another applet is selected on the basic channel. As there is no
154      * other way than a reset to select again the default applet, the implementation of the
155      * transport API should guarantee that the openBasicChannel(null) command will return
156      * null until a reset occurs.
157      * With previous release (V2.05) it was not possible to set P2 value, this value was always
158      * set to '00'.Except for specific needs it is recommended to keep P2 to '00'. It is
159      * recommended that the device allows all values for P2, however only the following values
160      * are mandatory: '00', '04', '08', '0C'(as defined in [2])
161      * The implementation of the underlying SELECT command within this method shall be
162      * based on ISO 7816-4 with following options:
163      * <ul>
164      * <li>CLA = '00'</li>
165      * <li>INS = 'A4'</li>
166      * <li>P1 = '04' (Select by DF name/application identifier)</li>
167      * </ul>
168      *
169      * The select response data can be retrieved with byte[] getSelectResponse().
170      * The API shall handle received status word as follow. If the status word indicates that the
171      * Secure Element was able to open a channel (e.g. status word '90 00' or status words
172      * referencing a warning in ISO-7816-4: '62 XX' or '63 XX') the API shall keep the
173      * channel opened and the next getSelectResponse() shall return the received status
174      * word.
175      * Other received status codes indicating that the Secure Element was able not to open a
176      * channel shall be considered as an error and the corresponding channel shall not be
177      * opened.
178      * The function without P2 as parameter is provided for backwards compatibility and will
179      * fall back to a select command with P2='00'.
180      *
181      * @param aid the AID of the Applet to be selected on this channel, as a
182      *            byte array, or null if no Applet is to be selected.
183      * @param p2 the P2 parameter of the SELECT APDU executed on this channel.
184      * @throws IOException if there is a communication problem to the reader or
185      *             the Secure Element.
186      * @throws IllegalStateException if the Secure Element session is used after
187      *             being closed.
188      * @throws IllegalArgumentException if the aid's length is not within 5 to
189      *             16 (inclusive).
190      * @throws SecurityException if the calling application cannot be granted
191      *             access to this AID or the default Applet on this
192      *             session.
193      * @throws NoSuchElementException if the AID on the Secure Element is not available or cannot be
194      *             selected.
195      * @throws UnsupportedOperationException if the given P2 parameter is not
196      *             supported by the device
197      * @return an instance of Channel if available or null.
198      */
199     public @Nullable Channel openBasicChannel(@Nullable byte[] aid, @Nullable byte p2)
200             throws IOException {
201         if (!mService.isConnected()) {
202             throw new IllegalStateException("service not connected to system");
203         }
204
205         synchronized (mLock) {
206             try {
207                 ISecureElementChannel channel = mSession.openBasicChannel(aid, p2,
208                         mReader.getSEService().getListener());
209                 if (channel == null) {
210                     return null;
211                 }
212                 return new Channel(mService, this, channel);
213             } catch (ServiceSpecificException e) {
214                 if (e.errorCode == SEService.IO_ERROR) {
215                     throw new IOException(e.getMessage());
216                 } else if (e.errorCode == SEService.NO_SUCH_ELEMENT_ERROR) {
217                     throw new NoSuchElementException(e.getMessage());
218                 } else {
219                     throw new IllegalStateException(e.getMessage());
220                 }
221             } catch (RemoteException e) {
222                 throw new IllegalStateException(e.getMessage());
223             }
224         }
225     }
226
227     /**
228      * Open a logical channel with the Secure Element, selecting the Applet represented by
229      * the given AID. If the AID is null, which means no Applet is to be selected on this
230      * channel, the default Applet is used. It's up to the Secure Element to choose which
231      * logical channel will be used.
232      * With previous release (V2.05) it was not possible to set P2 value, this value was always
233      * set to '00'.Except for specific needs it is recommended to keep P2 to '00'. It is
234      * recommended that the device allows all values for P2, however only the following values
235      * are mandatory: '00', '04', '08', '0C'(as defined in [2])
236      * The implementation of the underlying SELECT command within this method shall be
237      * based on ISO 7816-4 with following options:
238      *
239      * <ul>
240      * <li>CLA = '01' to '03', '40 to 4F'</li>
241      * <li>INS = 'A4'</li>
242      * <li>P1 = '04' (Select by DF name/application identifier)</li>
243      * </ul>
244      *
245      * The select response data can be retrieved with byte[] getSelectResponse().
246      * The API shall handle received status word as follow. If the status word indicates that the
247      * Secure Element was able to open a channel (e.g. status word '90 00' or status words
248      * referencing a warning in ISO-7816-4: '62 XX' or '63 XX') the API shall keep the
249      * channel opened and the next getSelectResponse() shall return the received status
250      * word.
251      * Other received status codes indicating that the Secure Element was able not to open a
252      * channel shall be considered as an error and the corresponding channel shall not be
253      * opened.
254      * In case of UICC it is recommended for the API to reject the opening of the logical
255      * channel without a specific AID, by always answering null to such a request.
256      * The function without P2 as parameter is provided for backwards compatibility and will
257      * fall back to a select command with P2=00.
258      *
259      * @param aid the AID of the Applet to be selected on this channel, as a
260      *            byte array.
261      * @param p2 the P2 parameter of the SELECT APDU executed on this channel.
262      * @throws IOException if there is a communication problem to the reader or
263      *             the Secure Element.
264      * @throws IllegalStateException if the Secure Element is used after being
265      *             closed.
266      * @throws IllegalArgumentException if the aid's length is not within 5 to
267      *             16 (inclusive).
268      * @throws SecurityException if the calling application cannot be granted
269      *             access to this AID or the default Applet on this
270      *             session.
271      * @throws NoSuchElementException if the AID on the Secure Element is not
272      *             available or cannot be selected or a logical channel is already
273      *             open to a non-multiselectable Applet.
274      * @throws UnsupportedOperationException if the given P2 parameter is not
275      *             supported by the device.
276      * @return an instance of Channel. Null if the Secure Element is unable to
277      *         provide a new logical channel.
278      */
279     public @Nullable Channel openLogicalChannel(@Nullable byte[] aid, @Nullable byte p2)
280             throws IOException {
281         if (!mService.isConnected()) {
282             throw new IllegalStateException("service not connected to system");
283         }
284         synchronized (mLock) {
285             try {
286                 ISecureElementChannel channel = mSession.openLogicalChannel(
287                         aid,
288                         p2,
289                         mReader.getSEService().getListener());
290                 if (channel == null) {
291                     return null;
292                 }
293                 return new Channel(mService, this, channel);
294             } catch (ServiceSpecificException e) {
295                 if (e.errorCode == SEService.IO_ERROR) {
296                     throw new IOException(e.getMessage());
297                 } else if (e.errorCode == SEService.NO_SUCH_ELEMENT_ERROR) {
298                     throw new NoSuchElementException(e.getMessage());
299                 } else {
300                     throw new IllegalStateException(e.getMessage());
301                 }
302             } catch (RemoteException e) {
303                 throw new IllegalStateException(e.getMessage());
304             }
305         }
306     }
307 }