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 */ PKCS15Handler(SecureElement handle)87 public PKCS15Handler(SecureElement handle) { 88 mSEHandle = handle; 89 } 90 91 /** Updates "Access Control Rules" */ updateACRules()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] */ initACEntryPoint()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 */ selectACRulesContainer(byte[] aid)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 */ loadAccessControlRules(String secureElement)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