Home | History | Annotate | Download | only in omapi
      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 final 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      * 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     /**
    254      * 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      */
    305     public @Nullable Channel openLogicalChannel(@Nullable byte[] aid, @Nullable byte p2)
    306             throws IOException {
    307         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);
    320             } 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                 }
    328             } catch (RemoteException e) {
    329                 throw new IllegalStateException(e.getMessage());
    330             }
    331         }
    332     }
    333 
    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     }
    361 }
    362