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 // Shared interface for accessing hardware state. 17 // 18 19 package com.android.verifiedboot.storage; 20 21 import javacard.framework.AID; 22 import javacard.framework.Applet; 23 import javacard.framework.ISO7816; 24 import javacard.framework.ISOException; 25 import javacard.framework.JCSystem; 26 import javacard.framework.Shareable; 27 28 import com.nxp.id.jcopx.util.SystemInfo; 29 30 import com.android.verifiedboot.globalstate.owner.OwnerInterface; 31 import com.android.verifiedboot.globalstate.callback.CallbackInterface; 32 33 class GlobalStateImpl implements OwnerInterface { 34 // Used to track if a client needs to be renotified in case of a 35 // power down, etc. 36 final static byte CLIENT_STATE_CLEAR_PENDING = (byte)0x1; 37 // Scenario values 38 final static byte BOOTLOADER_UNDEFINED = (byte) 0xff; 39 final static byte BOOTLOADER_HIGH = (byte) 0x5a; 40 final static byte BOOTLOADER_LOW = (byte) 0xa5; 41 42 private Object[] clientApplets; 43 private byte[] clientAppletState; 44 boolean inProduction; 45 46 47 public GlobalStateImpl() { 48 // Support up to 10 clients. 49 clientApplets = new Object[10]; 50 // Used to store mask for each client. 51 clientAppletState = new byte[clientApplets.length]; 52 // Used to signal the end of factory provisioning. 53 inProduction = false; 54 } 55 56 /** 57 * Returns the index of the given AID in clientApplets 58 * if existent. Returns -1 if not found. 59 * 60 * @param aid The client applet AID to find. 61 */ 62 private short findClientApplet(AID aid) { 63 for (short i = 0; i < clientApplets.length; ++i) { 64 if (clientApplets[i] == null) { 65 continue; 66 } 67 if (((AID)clientApplets[i]).equals(aid)) { 68 return i; 69 } 70 } 71 return (short) -1; 72 } 73 74 /** 75 * {@inheritDoc} 76 * 77 * It is expected that an applet can call notifyOnDataClear() on every 78 * select. 79 * 80 * @param unregister If true, will remove the caller's AID from the registered store. 81 * If false, will add the caller's AID to the register store. 82 */ 83 @Override 84 public boolean notifyOnDataClear(boolean unregister) { 85 final AID aid = JCSystem.getPreviousContextAID(); 86 short firstFreeSlot = -1; 87 for (short i = 0; i < clientApplets.length; ++i) { 88 if (clientApplets[i] == null) { 89 if (firstFreeSlot == -1) { 90 firstFreeSlot = i; 91 } 92 continue; 93 } 94 if (((AID)clientApplets[i]).equals(aid)) { 95 if (unregister == true) { 96 clientApplets[i] = null; 97 // Clean up memory if we can. 98 if (JCSystem.isObjectDeletionSupported()) { 99 JCSystem.requestObjectDeletion(); 100 } 101 return true; 102 } else { 103 // Already registered. 104 return true; 105 } 106 } 107 } 108 // Not registered anyway. 109 if (unregister == true) { 110 return true; 111 } 112 // No spaces left. 113 if (firstFreeSlot == -1) { 114 return false; 115 } 116 clientApplets[firstFreeSlot] = aid; 117 return true; 118 } 119 120 121 /** 122 * {@inheritDoc} 123 * 124 * Processes an acknowledgement request from the given AID. 125 */ 126 @Override 127 public void reportDataCleared() { 128 final AID aid = JCSystem.getPreviousContextAID(); 129 short id = findClientApplet(aid); 130 if (id >= clientAppletState.length) { 131 // This would be surprising. 132 return; 133 } 134 if (id == (short) -1) { 135 // Not found. 136 return; 137 } 138 if ((clientAppletState[id] & CLIENT_STATE_CLEAR_PENDING) 139 == CLIENT_STATE_CLEAR_PENDING) { 140 clientAppletState[id] ^= CLIENT_STATE_CLEAR_PENDING; 141 } 142 } 143 144 /** 145 * {@inheritDoc} 146 * 147 * Returns true if data still needs to be cleared. 148 */ 149 @Override 150 public boolean dataClearNeeded() { 151 final AID aid = JCSystem.getPreviousContextAID(); 152 short id = findClientApplet(aid); 153 if (id >= clientAppletState.length) { 154 // This would be surprising. 155 return false; 156 } 157 if (id == (short) -1) { 158 return false; 159 } 160 return ((clientAppletState[id] & CLIENT_STATE_CLEAR_PENDING) 161 == CLIENT_STATE_CLEAR_PENDING); 162 } 163 164 /** 165 * {@inheritDoc} 166 * 167 * Walks all clientApplets, and if they exist, checks if the have not 168 * cleared the pending action bit. If any applets need to clear data, 169 * false will be returned. 170 */ 171 @Override 172 public boolean globalDataClearComplete() { 173 for (short i = 0; i < clientApplets.length; ++i) { 174 if (clientApplets[i] == null) { 175 continue; 176 } 177 if ((clientAppletState[i] & CLIENT_STATE_CLEAR_PENDING) 178 == CLIENT_STATE_CLEAR_PENDING) { 179 return false; 180 } 181 } 182 return true; 183 } 184 185 /** 186 * {@inheritDoc} 187 * 188 * Notifies all clients that a data clear is needed. 189 * 190 * If a power down or other interrupting event occurs, it is expected 191 * that the clients will always call dataClearNeeded() prior to doing work 192 * in process(). 193 * 194 * However, the secure boot applet will check globalDataClearComplete() 195 * on its first process() invocation after power on and call this method 196 * with resume=true if a data clear was intended but incomplete. 197 */ 198 @Override 199 public void triggerDataClear(boolean resume) { 200 // Two passes for a full 201 // - First just sets the byte atomically. 202 // - Second attempts notification. 203 if (resume == false) { 204 for (short i = 0; i < clientApplets.length; ++i) { 205 if (clientApplets[i] == null) { 206 continue; 207 } 208 clientAppletState[i] |= CLIENT_STATE_CLEAR_PENDING; 209 } 210 } 211 for (short i = 0; i < clientApplets.length; ++i) { 212 if (clientApplets[i] == null) { 213 continue; 214 } 215 if ((clientAppletState[i] & CLIENT_STATE_CLEAR_PENDING) 216 == CLIENT_STATE_CLEAR_PENDING) { 217 ((CallbackInterface) JCSystem.getAppletShareableInterfaceObject( 218 (AID)clientApplets[i], (byte)0)).clearData(); 219 } 220 } 221 } 222 223 /** 224 * {@inheritDoc} 225 * 226 * Returns true if the AP reset GPIO latch has not been cleared. 227 */ 228 @Override 229 public boolean inBootloader() { 230 try { 231 switch (SystemInfo.getExternalState( 232 SystemInfo.SYSTEMINFO_SCENARIO_0)) { 233 case BOOTLOADER_HIGH: 234 return true; 235 case BOOTLOADER_LOW: 236 case BOOTLOADER_UNDEFINED: 237 default: 238 return false; 239 } 240 } catch (ISOException e) { 241 // If we can't read it, we fail closed unless we're in debug mode. 242 return false; 243 } 244 } 245 246 /** 247 * Returns the external signal that feeds inBootloader(). 248 */ 249 public byte inBootloaderRaw() { 250 try { 251 return SystemInfo.getExternalState(SystemInfo.SYSTEMINFO_SCENARIO_0); 252 } catch (ISOException e) { 253 return (byte) 0x0; 254 } 255 } 256 257 /** 258 * {@inheritDoc} 259 * 260 * @param val value assigned to the inProduction value. 261 * @return true if changed and false otherwise. 262 */ 263 @Override 264 public boolean setProduction(boolean val) { 265 // Move to production is one way except for RMA - which 266 // is handled in bootloader mode. 267 if (val == false) { 268 if (inBootloader() == false) { 269 return false; 270 } 271 } 272 inProduction = val; 273 return true; 274 } 275 276 /** 277 * {@inheritDoc} 278 * 279 * accessor for inProduction. 280 */ 281 @Override 282 public boolean production() { 283 return inProduction; 284 } 285 } 286