Home | History | Annotate | Download | only in PKCS15
      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 /*
     21  * Copyright (C) 2011 Deutsche Telekom, A.G.
     22  *
     23  * Licensed under the Apache License, Version 2.0 (the "License");
     24  * you may not use this file except in compliance with the License.
     25  * You may obtain a copy of the License at
     26  *
     27  *      http://www.apache.org/licenses/LICENSE-2.0
     28  *
     29  * Unless required by applicable law or agreed to in writing, software
     30  * distributed under the License is distributed on an "AS IS" BASIS,
     31  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     32  * See the License for the specific language governing permissions and
     33  * limitations under the License.
     34  */
     35 
     36 /*
     37  * Contributed by: Giesecke & Devrient GmbH.
     38  */
     39 
     40 package com.android.se.security.arf.pkcs15;
     41 
     42 import android.util.Log;
     43 
     44 import com.android.se.Channel;
     45 import com.android.se.security.arf.SecureElement;
     46 import com.android.se.security.arf.SecureElementException;
     47 
     48 import java.io.IOException;
     49 import java.security.AccessControlException;
     50 import java.security.cert.CertificateException;
     51 import java.util.MissingResourceException;
     52 import java.util.NoSuchElementException;
     53 
     54 /** Handles PKCS#15 topology */
     55 public class PKCS15Handler {
     56 
     57     // AID of the GPAC Applet/ADF
     58     public static final byte[] GPAC_ARF_AID = {
     59             (byte) 0xA0, 0x00, 0x00, 0x00, 0x18, 0x47, 0x50, 0x41, 0x43, 0x2D, 0x31, 0x35
     60     };
     61     // AID of the PKCS#15 ADF
     62     public static final byte[] PKCS15_AID = {
     63             (byte) 0xA0, 0x00, 0x00, 0x00, 0x63, 0x50, 0x4B, 0x43, 0x53, 0x2D, 0x31, 0x35
     64     };
     65     // AIDs of "Access Control Rules" containers
     66     public static final byte[][] CONTAINER_AIDS = {PKCS15_AID, GPAC_ARF_AID, null};
     67     public final String mTag = "SecureElement-PKCS15Handler";
     68     // Handle to "Secure Element"
     69     private SecureElement mSEHandle;
     70     // "Secure Element" label
     71     private String mSELabel = null;
     72     // Handle to "Logical Channel" allocated by the SE
     73     private Channel mArfChannel = null;
     74     // "EF Access Control Main" object
     75     private EFACMain mACMainObject = null;
     76     // EF AC Rules object
     77     private EFACRules mACRulesObject = null;
     78     private byte[] mPkcs15Path = null;
     79     private byte[] mACMainPath = null;
     80     private boolean mACMFfound = true;
     81 
     82     /**
     83      * Constructor
     84      *
     85      * @param handle Handle to "Secure Element"
     86      */
     87     public PKCS15Handler(SecureElement handle) {
     88         mSEHandle = handle;
     89     }
     90 
     91     /** Updates "Access Control Rules" */
     92     private boolean updateACRules() throws CertificateException, IOException,
     93             MissingResourceException, NoSuchElementException, PKCS15Exception,
     94             SecureElementException {
     95         byte[] ACRulesPath = null;
     96         if (!mACMFfound) {
     97             mSEHandle.resetAccessRules();
     98             mACMainPath = null;
     99             if (mArfChannel != null) mSEHandle.closeArfChannel();
    100             this.initACEntryPoint();
    101         }
    102         try {
    103             ACRulesPath = mACMainObject.analyseFile();
    104             mACMFfound = true;
    105         } catch (IOException e) {
    106             // IOException must be propagated to the access control enforcer.
    107             throw e;
    108         } catch (Exception e) {
    109             Log.i(mTag, "ACMF Not found !");
    110             mACMainObject = null;
    111             mSEHandle.resetAccessRules();
    112             mACMFfound = false;
    113             throw e;
    114         }
    115         // Check if rules must be updated
    116         if (ACRulesPath != null) {
    117             Log.i(mTag, "Access Rules needs to be updated...");
    118             if (mACRulesObject == null) {
    119                 mACRulesObject = new EFACRules(mSEHandle);
    120             }
    121             mSEHandle.clearAccessRuleCache();
    122             mACMainPath = null;
    123             if (mArfChannel != null) mSEHandle.closeArfChannel();
    124 
    125             this.initACEntryPoint();
    126 
    127             try {
    128                 mACRulesObject.analyseFile(ACRulesPath);
    129             } catch (IOException e) {
    130                 // IOException must be propagated to the access control enforcer.
    131                 throw e;
    132             } catch (Exception e) {
    133                 Log.i(mTag, "Exception: clear access rule cache and refresh tag");
    134                 mSEHandle.resetAccessRules();
    135                 throw e;
    136             }
    137             return true;
    138         } else {
    139             Log.i(mTag, "Refresh Tag has not been changed...");
    140             return false;
    141         }
    142     }
    143 
    144     /** Initializes "Access Control" entry point [ACMain] */
    145     private void initACEntryPoint() throws CertificateException, IOException,
    146             MissingResourceException, NoSuchElementException, PKCS15Exception,
    147             SecureElementException {
    148 
    149         byte[] DODFPath = null;
    150         boolean absent = true;
    151 
    152         for (int ind = 0; ind < CONTAINER_AIDS.length; ind++) {
    153             try {
    154                 boolean result = selectACRulesContainer(CONTAINER_AIDS[ind]);
    155                 // NoSuchElementException was not thrown by the terminal.
    156                 // The terminal confirmed that the specified applet or PKCS#15 ADF exists
    157                 // or could not determine that it does not exists on the secure element.
    158                 absent = false;
    159                 if (!result) {
    160                     continue;
    161                 }
    162 
    163                 byte[] acMainPath = null;
    164                 if (mACMainPath == null) {
    165                     EFODF ODFObject = new EFODF(mSEHandle);
    166                     DODFPath = ODFObject.analyseFile(mPkcs15Path);
    167                     EFDODF DODFObject = new EFDODF(mSEHandle);
    168                     acMainPath = DODFObject.analyseFile(DODFPath);
    169 
    170                     mACMainPath = acMainPath;
    171                 } else {
    172                     if (mPkcs15Path != null) {
    173                         acMainPath = new byte[mPkcs15Path.length + mACMainPath.length];
    174                         System.arraycopy(mPkcs15Path, 0, acMainPath, 0, mPkcs15Path.length);
    175                         System.arraycopy(mACMainPath, 0, acMainPath, mPkcs15Path.length,
    176                                 mACMainPath.length);
    177 
    178                     } else {
    179                         acMainPath = mACMainPath;
    180                     }
    181                 }
    182                 mACMainObject = new EFACMain(mSEHandle, acMainPath);
    183                 break;
    184             } catch (NoSuchElementException e) {
    185                 // The specified applet or PKCS#15 ADF does not exist.
    186                 // Let us check the next candidate.
    187             }
    188         }
    189 
    190         if (absent) {
    191             // All the candidate applet and/or PKCS#15 ADF cannot be found on the secure element.
    192             throw new NoSuchElementException("No ARF exists");
    193         }
    194     }
    195 
    196     /**
    197      * Selects "Access Control Rules" container
    198      *
    199      * @param AID Identification of the GPAC Applet/PKCS#15 ADF; <code>null</code> for EF_DIR file
    200      * @return <code>true</code> when container is active; <code>false</code> otherwise
    201      */
    202     private boolean selectACRulesContainer(byte[] aid) throws IOException, MissingResourceException,
    203             NoSuchElementException, PKCS15Exception, SecureElementException {
    204         if (aid == null) {
    205             mArfChannel = mSEHandle.openLogicalArfChannel(new byte[]{});
    206             if (mArfChannel != null) {
    207                 Log.i(mTag, "Logical channels are used to access to PKC15");
    208             } else {
    209                 return false;
    210             }
    211             // estimate PKCS15 path only if it is not known already.
    212             if (mPkcs15Path == null) {
    213                 mACMainPath = null;
    214                 // EF_DIR parsing
    215                 EFDIR DIRObject = new EFDIR(mSEHandle);
    216                 mPkcs15Path = DIRObject.lookupAID(PKCS15_AID);
    217                 if (mPkcs15Path == null) {
    218                     Log.i(mTag, "Cannot use ARF: cannot select PKCS#15 directory via EF Dir");
    219                     // TODO: Here it might be possible to set a default path
    220                     // so that SIMs without EF-Dir could be supported.
    221                     throw new NoSuchElementException("Cannot select PKCS#15 directory via EF Dir");
    222                 }
    223             }
    224         } else {
    225             // if an AID is given use logical channel.
    226             // Selection of Applet/ADF via AID is done via SCAPI and logical Channels
    227             mArfChannel = mSEHandle.openLogicalArfChannel(aid);
    228             if (mArfChannel == null) {
    229                 Log.w(mTag, "GPAC/PKCS#15 ADF not found!!");
    230                 return false;
    231             }
    232             // ARF is selected via AID.
    233             // if there is a change from path selection to AID
    234             // selection, then reset AC Main path.
    235             if (mPkcs15Path != null) {
    236                 mACMainPath = null;
    237             }
    238             mPkcs15Path = null; // selection is done via AID
    239         }
    240         return true;
    241     }
    242 
    243     /**
    244      * Loads "Access Control Rules" from container
    245      *
    246      * @return false if access rules where not read due to constant refresh tag.
    247      */
    248     public synchronized boolean loadAccessControlRules(String secureElement) throws IOException,
    249             MissingResourceException, NoSuchElementException {
    250         mSELabel = secureElement;
    251         Log.i(mTag, "- Loading " + mSELabel + " rules...");
    252         try {
    253             initACEntryPoint();
    254             return updateACRules();
    255         } catch (IOException | MissingResourceException | NoSuchElementException e) {
    256             throw e;
    257         } catch (Exception e) {
    258             Log.e(mTag, mSELabel + " rules not correctly initialized! " + e.getLocalizedMessage());
    259             throw new AccessControlException(e.getLocalizedMessage());
    260         } finally {
    261             // Close previously opened channel
    262             if (mArfChannel != null) mSEHandle.closeArfChannel();
    263         }
    264     }
    265 }
    266