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) 2015-2017, The Linux Foundation. 18 */ 19 20 /* 21 * Copyright 2012 Giesecke & Devrient GmbH. 22 * 23 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 24 * use this file except in compliance with the License. You may obtain a copy of 25 * 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, WITHOUT 31 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 32 * License for the specific language governing permissions and limitations under 33 * the License. 34 */ 35 36 package com.android.se.security.ara; 37 38 import android.content.Context; 39 import android.text.TextUtils; 40 import android.util.Log; 41 42 import com.android.se.Channel; 43 import com.android.se.R; 44 import com.android.se.SecureElementService; 45 import com.android.se.Terminal; 46 import com.android.se.internal.ByteArrayConverter; 47 import com.android.se.security.AccessRuleCache; 48 import com.android.se.security.ChannelAccess; 49 import com.android.se.security.gpac.BerTlv; 50 import com.android.se.security.gpac.ParserException; 51 import com.android.se.security.gpac.REF_AR_DO; 52 import com.android.se.security.gpac.Response_ALL_AR_DO; 53 import com.android.se.security.gpac.Response_DO_Factory; 54 55 import java.io.IOException; 56 import java.security.AccessControlException; 57 import java.util.ArrayList; 58 import java.util.Iterator; 59 import java.util.MissingResourceException; 60 import java.util.NoSuchElementException; 61 62 /** Reads and Maintains the ARA access for the Secure Element */ 63 public class AraController { 64 65 public static final byte[] ARA_M_AID = 66 new byte[]{ 67 (byte) 0xA0, 68 (byte) 0x00, 69 (byte) 0x00, 70 (byte) 0x01, 71 (byte) 0x51, 72 (byte) 0x41, 73 (byte) 0x43, 74 (byte) 0x4C, 75 (byte) 0x00 76 }; 77 private final String mTag = "SecureElement-AraController"; 78 private AccessRuleCache mAccessRuleCache = null; 79 private Terminal mTerminal = null; 80 private AccessRuleApplet mApplet = null; 81 private Context mContext = null; 82 private String[] mAids = new String[0]; 83 private byte[] mAccessControlAid = ARA_M_AID; 84 AraController(AccessRuleCache cache, Terminal terminal)85 public AraController(AccessRuleCache cache, Terminal terminal) { 86 mAccessRuleCache = cache; 87 mTerminal = terminal; 88 mContext = mTerminal.getContext(); 89 if (mTerminal.getName().startsWith(SecureElementService.ESE_TERMINAL)) { 90 mAids = mContext.getResources().getStringArray( 91 R.array.config_ara_aid_candidate_list_ese); 92 } 93 } 94 getAraMAid()95 public static byte[] getAraMAid() { 96 return ARA_M_AID; 97 } 98 getAccessControlAid()99 public byte[] getAccessControlAid() { 100 return mAccessControlAid; 101 } 102 103 /** 104 * Initialize the AraController, reads the refresh tag. 105 * and fetch the access rules 106 */ initialize()107 public synchronized void initialize() throws IOException, NoSuchElementException { 108 Channel channel = null; 109 byte[] aid = null; 110 111 // try to fetch access rules from ARA Aid list 112 for (String araAid : mAids) { 113 if (!TextUtils.isEmpty(araAid)) { 114 aid = ByteArrayConverter.hexStringToByteArray(araAid); 115 } else { 116 aid = null; 117 } 118 try { 119 channel = mTerminal.openLogicalChannelWithoutChannelAccess(aid); 120 if (channel == null) { 121 throw new MissingResourceException("could not open channel", "", ""); 122 } 123 mAccessControlAid = aid; 124 break; 125 } catch (NoSuchElementException e) { 126 Log.i(mTag, "applet:" + araAid + " is not accessible"); 127 continue; 128 } 129 } 130 131 // try to fetch access rules from ARA-M if all ARA in Aid list is not accessible 132 if (channel == null) { 133 channel = mTerminal.openLogicalChannelWithoutChannelAccess(getAraMAid()); 134 if (channel == null) { 135 throw new MissingResourceException("could not open channel", "", ""); 136 } 137 } 138 139 // set access conditions to access ARA. 140 ChannelAccess araChannelAccess = new ChannelAccess(); 141 araChannelAccess.setAccess(ChannelAccess.ACCESS.ALLOWED, ""); 142 araChannelAccess.setApduAccess(ChannelAccess.ACCESS.ALLOWED); 143 channel.setChannelAccess(araChannelAccess); 144 145 try { 146 // set new applet handler since a new channel is used. 147 mApplet = new AccessRuleApplet(channel); 148 byte[] tag = mApplet.readRefreshTag(); 149 // if refresh tag is equal to the previous one it is not 150 // necessary to read all rules again. 151 if (mAccessRuleCache.isRefreshTagEqual(tag)) { 152 Log.i(mTag, "Refresh tag unchanged. Using access rules from cache."); 153 return; 154 } 155 Log.i(mTag, "Refresh tag has changed."); 156 // set new refresh tag and empty cache. 157 mAccessRuleCache.setRefreshTag(tag); 158 mAccessRuleCache.clearCache(); 159 160 Log.i(mTag, "Read ARs from ARA"); 161 readAllAccessRules(); 162 } catch (IOException e) { 163 // Some kind of communication problem happened while transmit() was executed. 164 // IOError shall be notified to the client application in this case. 165 throw e; 166 } catch (Exception e) { 167 Log.i(mTag, "ARA error: " + e.getLocalizedMessage()); 168 throw new AccessControlException(e.getLocalizedMessage()); 169 } finally { 170 if (channel != null) { 171 channel.close(); 172 } 173 } 174 } 175 readAllAccessRules()176 private void readAllAccessRules() throws AccessControlException, IOException { 177 try { 178 byte[] data = mApplet.readAllAccessRules(); 179 // no data returned, but no exception 180 // -> no rule. 181 if (data == null) { 182 return; 183 } 184 185 BerTlv tlv = Response_DO_Factory.createDO(data); 186 if (tlv == null || !(tlv instanceof Response_ALL_AR_DO)) { 187 throw new AccessControlException("No valid data object found"); 188 } 189 ArrayList<REF_AR_DO> array = ((Response_ALL_AR_DO) tlv).getRefArDos(); 190 191 if (array != null && array.size() != 0) { 192 Iterator<REF_AR_DO> iter = array.iterator(); 193 while (iter.hasNext()) { 194 REF_AR_DO refArDo = iter.next(); 195 mAccessRuleCache.putWithMerge(refArDo.getRefDo(), refArDo.getArDo()); 196 } 197 } 198 } catch (ParserException e) { 199 throw new AccessControlException("Parsing Data Object Exception: " 200 + e.getMessage()); 201 } 202 } 203 } 204