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.util.Log; 39 40 import com.android.se.Channel; 41 import com.android.se.Terminal; 42 import com.android.se.security.AccessRuleCache; 43 import com.android.se.security.ChannelAccess; 44 import com.android.se.security.gpac.BerTlv; 45 import com.android.se.security.gpac.ParserException; 46 import com.android.se.security.gpac.REF_AR_DO; 47 import com.android.se.security.gpac.Response_ALL_AR_DO; 48 import com.android.se.security.gpac.Response_DO_Factory; 49 50 import java.io.IOException; 51 import java.security.AccessControlException; 52 import java.util.ArrayList; 53 import java.util.Iterator; 54 import java.util.MissingResourceException; 55 import java.util.NoSuchElementException; 56 57 /** Reads and Maintains the ARA access for the Secure Element */ 58 public class AraController { 59 60 public static final byte[] ARA_M_AID = 61 new byte[]{ 62 (byte) 0xA0, 63 (byte) 0x00, 64 (byte) 0x00, 65 (byte) 0x01, 66 (byte) 0x51, 67 (byte) 0x41, 68 (byte) 0x43, 69 (byte) 0x4C, 70 (byte) 0x00 71 }; 72 private final String mTag = "SecureElement-AraController"; 73 private AccessRuleCache mAccessRuleCache = null; 74 private Terminal mTerminal = null; 75 private AccessRuleApplet mApplet = null; 76 77 public AraController(AccessRuleCache cache, Terminal terminal) { 78 mAccessRuleCache = cache; 79 mTerminal = terminal; 80 } 81 82 public static byte[] getAraMAid() { 83 return ARA_M_AID; 84 } 85 86 /** 87 * Initialize the AraController, reads the refresh tag. 88 * and fetch the access rules 89 */ 90 public synchronized void initialize() throws IOException, NoSuchElementException { 91 Channel channel = mTerminal.openLogicalChannelWithoutChannelAccess(getAraMAid()); 92 if (channel == null) { 93 throw new MissingResourceException("could not open channel", "", ""); 94 } 95 96 // set access conditions to access ARA-M. 97 ChannelAccess araChannelAccess = new ChannelAccess(); 98 araChannelAccess.setAccess(ChannelAccess.ACCESS.ALLOWED, mTag); 99 araChannelAccess.setApduAccess(ChannelAccess.ACCESS.ALLOWED); 100 channel.setChannelAccess(araChannelAccess); 101 102 try { 103 // set new applet handler since a new channel is used. 104 mApplet = new AccessRuleApplet(channel); 105 byte[] tag = mApplet.readRefreshTag(); 106 // if refresh tag is equal to the previous one it is not 107 // neccessary to read all rules again. 108 if (mAccessRuleCache.isRefreshTagEqual(tag)) { 109 Log.i(mTag, "Refresh tag unchanged. Using access rules from cache."); 110 return; 111 } 112 Log.i(mTag, "Refresh tag has changed."); 113 // set new refresh tag and empty cache. 114 mAccessRuleCache.setRefreshTag(tag); 115 mAccessRuleCache.clearCache(); 116 117 Log.i(mTag, "Read ARs from ARA"); 118 readAllAccessRules(); 119 } catch (IOException e) { 120 // Some kind of communication problem happened while transmit() was executed. 121 // IOError shall be notified to the client application in this case. 122 throw e; 123 } catch (Exception e) { 124 Log.i(mTag, "ARA error: " + e.getLocalizedMessage()); 125 throw new AccessControlException(e.getLocalizedMessage()); 126 } finally { 127 if (channel != null) { 128 channel.close(); 129 } 130 } 131 } 132 133 private void readAllAccessRules() throws AccessControlException, IOException { 134 try { 135 byte[] data = mApplet.readAllAccessRules(); 136 // no data returned, but no exception 137 // -> no rule. 138 if (data == null) { 139 return; 140 } 141 142 BerTlv tlv = Response_DO_Factory.createDO(data); 143 if (tlv == null || !(tlv instanceof Response_ALL_AR_DO)) { 144 throw new AccessControlException("No valid data object found"); 145 } 146 ArrayList<REF_AR_DO> array = ((Response_ALL_AR_DO) tlv).getRefArDos(); 147 148 if (array != null && array.size() != 0) { 149 Iterator<REF_AR_DO> iter = array.iterator(); 150 while (iter.hasNext()) { 151 REF_AR_DO refArDo = iter.next(); 152 mAccessRuleCache.putWithMerge(refArDo.getRefDo(), refArDo.getArDo()); 153 } 154 } 155 } catch (ParserException e) { 156 throw new AccessControlException("Parsing Data Object Exception: " 157 + e.getMessage()); 158 } 159 } 160 } 161