blob: d5f8c82bf47e2b3d1bce52740f9785b805f7d804 [file] [log] [blame]
Ruchi Kandoia1f94012017-12-08 15:07:03 -08001/*
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
23package android.se.omapi;
24
25import android.annotation.NonNull;
26import android.annotation.Nullable;
27import android.os.RemoteException;
Ruchi Kandoi816a0532018-02-01 16:15:25 -080028import android.os.ServiceSpecificException;
Ruchi Kandoia1f94012017-12-08 15:07:03 -080029import android.util.Log;
30
31import java.io.IOException;
32import 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 */
Ruchi Kandoif0082402018-03-27 10:03:34 -070042public final class Session {
Ruchi Kandoia1f94012017-12-08 15:07:03 -080043
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
Ruchi Kandoid785fc42018-03-22 11:06:36 -070050 Session(@NonNull SEService service, @NonNull ISecureElementSession session,
51 @NonNull Reader reader) {
Ruchi Kandoia1f94012017-12-08 15:07:03 -080052 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 */
Ruchi Kandoid785fc42018-03-22 11:06:36 -0700199 public @Nullable Channel openBasicChannel(@Nullable byte[] aid, @Nullable byte p2)
200 throws IOException {
Ruchi Kandoia1f94012017-12-08 15:07:03 -0800201 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);
Ruchi Kandoi816a0532018-02-01 16:15:25 -0800213 } 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 }
Ruchi Kandoia1f94012017-12-08 15:07:03 -0800221 } catch (RemoteException e) {
Ruchi Kandoi816a0532018-02-01 16:15:25 -0800222 throw new IllegalStateException(e.getMessage());
Ruchi Kandoia1f94012017-12-08 15:07:03 -0800223 }
224 }
225 }
226
227 /**
Ruchi Kandoif0082402018-03-27 10:03:34 -0700228 * This method is provided to ease the development of mobile application and for compliancy
229 * with existing applications.
230 * This method is equivalent to openBasicChannel(aid, P2=0x00)
231 *
232 * @param aid the AID of the Applet to be selected on this channel, as a
233 * byte array, or null if no Applet is to be selected.
234 * @throws IOException if there is a communication problem to the reader or
235 * the Secure Element.
236 * @throws IllegalStateException if the Secure Element session is used after
237 * being closed.
238 * @throws IllegalArgumentException if the aid's length is not within 5 to
239 * 16 (inclusive).
240 * @throws SecurityException if the calling application cannot be granted
241 * access to this AID or the default Applet on this
242 * session.
243 * @throws NoSuchElementException if the AID on the Secure Element is not available or cannot be
244 * selected.
245 * @throws UnsupportedOperationException if the given P2 parameter is not
246 * supported by the device
247 * @return an instance of Channel if available or null.
248 */
249 public @Nullable Channel openBasicChannel(@Nullable byte[] aid) throws IOException {
250 return openBasicChannel(aid, (byte) 0x00);
251 }
252
253 /**
Ruchi Kandoia1f94012017-12-08 15:07:03 -0800254 * Open a logical channel with the Secure Element, selecting the Applet represented by
255 * the given AID. If the AID is null, which means no Applet is to be selected on this
256 * channel, the default Applet is used. It's up to the Secure Element to choose which
257 * logical channel will be used.
258 * With previous release (V2.05) it was not possible to set P2 value, this value was always
259 * set to '00'.Except for specific needs it is recommended to keep P2 to '00'. It is
260 * recommended that the device allows all values for P2, however only the following values
261 * are mandatory: '00', '04', '08', '0C'(as defined in [2])
262 * The implementation of the underlying SELECT command within this method shall be
263 * based on ISO 7816-4 with following options:
264 *
265 * <ul>
266 * <li>CLA = '01' to '03', '40 to 4F'</li>
267 * <li>INS = 'A4'</li>
268 * <li>P1 = '04' (Select by DF name/application identifier)</li>
269 * </ul>
270 *
271 * The select response data can be retrieved with byte[] getSelectResponse().
272 * The API shall handle received status word as follow. If the status word indicates that the
273 * Secure Element was able to open a channel (e.g. status word '90 00' or status words
274 * referencing a warning in ISO-7816-4: '62 XX' or '63 XX') the API shall keep the
275 * channel opened and the next getSelectResponse() shall return the received status
276 * word.
277 * Other received status codes indicating that the Secure Element was able not to open a
278 * channel shall be considered as an error and the corresponding channel shall not be
279 * opened.
280 * In case of UICC it is recommended for the API to reject the opening of the logical
281 * channel without a specific AID, by always answering null to such a request.
282 * The function without P2 as parameter is provided for backwards compatibility and will
283 * fall back to a select command with P2=00.
284 *
285 * @param aid the AID of the Applet to be selected on this channel, as a
286 * byte array.
287 * @param p2 the P2 parameter of the SELECT APDU executed on this channel.
288 * @throws IOException if there is a communication problem to the reader or
289 * the Secure Element.
290 * @throws IllegalStateException if the Secure Element is used after being
291 * closed.
292 * @throws IllegalArgumentException if the aid's length is not within 5 to
293 * 16 (inclusive).
294 * @throws SecurityException if the calling application cannot be granted
295 * access to this AID or the default Applet on this
296 * session.
297 * @throws NoSuchElementException if the AID on the Secure Element is not
298 * available or cannot be selected or a logical channel is already
299 * open to a non-multiselectable Applet.
300 * @throws UnsupportedOperationException if the given P2 parameter is not
301 * supported by the device.
302 * @return an instance of Channel. Null if the Secure Element is unable to
303 * provide a new logical channel.
304 */
Ruchi Kandoid785fc42018-03-22 11:06:36 -0700305 public @Nullable Channel openLogicalChannel(@Nullable byte[] aid, @Nullable byte p2)
306 throws IOException {
Ruchi Kandoia1f94012017-12-08 15:07:03 -0800307 if (!mService.isConnected()) {
308 throw new IllegalStateException("service not connected to system");
309 }
310 synchronized (mLock) {
311 try {
312 ISecureElementChannel channel = mSession.openLogicalChannel(
313 aid,
314 p2,
315 mReader.getSEService().getListener());
316 if (channel == null) {
317 return null;
318 }
319 return new Channel(mService, this, channel);
Ruchi Kandoi816a0532018-02-01 16:15:25 -0800320 } catch (ServiceSpecificException e) {
321 if (e.errorCode == SEService.IO_ERROR) {
322 throw new IOException(e.getMessage());
323 } else if (e.errorCode == SEService.NO_SUCH_ELEMENT_ERROR) {
324 throw new NoSuchElementException(e.getMessage());
325 } else {
326 throw new IllegalStateException(e.getMessage());
327 }
Ruchi Kandoia1f94012017-12-08 15:07:03 -0800328 } catch (RemoteException e) {
Ruchi Kandoi816a0532018-02-01 16:15:25 -0800329 throw new IllegalStateException(e.getMessage());
Ruchi Kandoia1f94012017-12-08 15:07:03 -0800330 }
331 }
332 }
Ruchi Kandoif0082402018-03-27 10:03:34 -0700333
334 /**
335 * This method is provided to ease the development of mobile application and for compliancy
336 * with existing applications.
337 * This method is equivalent to openLogicalChannel(aid, P2=0x00)
338 *
339 * @param aid the AID of the Applet to be selected on this channel, as a
340 * byte array.
341 * @throws IOException if there is a communication problem to the reader or
342 * the Secure Element.
343 * @throws IllegalStateException if the Secure Element is used after being
344 * closed.
345 * @throws IllegalArgumentException if the aid's length is not within 5 to
346 * 16 (inclusive).
347 * @throws SecurityException if the calling application cannot be granted
348 * access to this AID or the default Applet on this
349 * session.
350 * @throws NoSuchElementException if the AID on the Secure Element is not
351 * available or cannot be selected or a logical channel is already
352 * open to a non-multiselectable Applet.
353 * @throws UnsupportedOperationException if the given P2 parameter is not
354 * supported by the device.
355 * @return an instance of Channel. Null if the Secure Element is unable to
356 * provide a new logical channel.
357 */
358 public @Nullable Channel openLogicalChannel(@Nullable byte[] aid) throws IOException {
359 return openLogicalChannel(aid, (byte) 0x00);
360 }
Ruchi Kandoia1f94012017-12-08 15:07:03 -0800361}