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 17package com.android.verifiedboot.storage; 18 19import javacard.framework.CardRuntimeException; 20import javacard.framework.JCSystem; 21import javacard.framework.Util; 22 23import javacard.security.KeyBuilder; 24import javacard.security.MessageDigest; 25import javacard.security.RSAPublicKey; 26import javacard.security.Signature; 27 28import com.android.verifiedboot.storage.LockInterface; 29import com.android.verifiedboot.globalstate.owner.OwnerInterface; 30 31class BasicLock implements LockInterface { 32 // Layout: LockValue (byte) 33 private byte[] storage; 34 private short storageOffset; 35 private OwnerInterface globalState; 36 private boolean onlyInBootloader; 37 private boolean onlyInHLOS; 38 private boolean needMetadata; 39 private short metadataSize; 40 private LockInterface[] requiredLocks; 41 42 /** 43 * Initializes the instance. 44 * 45 * @param maxMetadataSize length of the metadata 46 * @param requiredLocks specify the number of locks that unlocking 47 * will depend on. 48 * 49 */ 50 public BasicLock(short maxMetadataSize, short requiredLockNum) { 51 onlyInBootloader = false; 52 onlyInHLOS = false; 53 needMetadata = false; 54 metadataSize = maxMetadataSize; 55 requiredLocks = new LockInterface[requiredLockNum]; 56 } 57 58 /** 59 * {@inheritDoc} 60 */ 61 @Override 62 public short backupSize() { 63 return getStorageNeeded(); 64 } 65 66 67 /** 68 * {@inheritDoc} 69 */ 70 @Override 71 public short backup(byte[] outBytes, short outBytesOffset) { 72 Util.arrayCopy(storage, storageOffset, 73 outBytes, outBytesOffset, 74 backupSize()); 75 return backupSize(); 76 } 77 78 /** 79 * {@inheritDoc} 80 */ 81 @Override 82 public boolean restore(byte[] inBytes, short inBytesOffset, 83 short inBytesLength) { 84 if (inBytesLength > backupSize() || inBytesLength == (short)0) { 85 return false; 86 } 87 Util.arrayCopy(inBytes, inBytesOffset, 88 storage, storageOffset, 89 inBytesLength); 90 return true; 91 } 92 93 /** 94 * Indicates that it is required that the {@link #globalState} is 95 * in the bootloader when the lock is changed. 96 * 97 * @param inBootloader true if changes can only happen in the bootloader. 98 */ 99 public void requireBootloader(boolean inBootloader) { 100 onlyInBootloader = inBootloader; 101 } 102 103 /** 104 * Indicates that it is required that the {@link #globalState} is 105 * NOT in the bootloader when the lock is changed. 106 * 107 * @param inHLOS true if changes can only happen in the bootloader. 108 */ 109 public void requireHLOS(boolean inHLOS) { 110 onlyInHLOS = inHLOS; 111 } 112 113 114 /** 115 * Indicates that metadata must be supplied when locking. 116 * 117 * @param atLock true if metadata must be supplied. 118 */ 119 public void requireMetadata(boolean atLock) { 120 needMetadata = atLock; 121 } 122 123 /** 124 * Adds a lock that must be unlocked to enable 125 * this lock to toggle. 126 * 127 * @param lock lock to depend on 128 * @return true on success or false on no space. 129 */ 130 public boolean addRequiredLock(LockInterface lock) { 131 for (short i = 0; i < (short) requiredLocks.length; ++i) { 132 if (requiredLocks[i] == null) { 133 requiredLocks[i] = lock; 134 return true; 135 } 136 } 137 return false; 138 } 139 140 /** 141 * {@inheritDoc} 142 * 143 * Return the error states useful for diagnostics. 144 */ 145 @Override 146 public short initialized() { 147 if (storage == null) { 148 return 1; 149 } 150 if (globalState == null) { 151 return 2; 152 } 153 return 0; 154 } 155 /** 156 * {@inheritDoc} 157 */ 158 @Override 159 public short getStorageNeeded() { 160 return (short)(1 + metadataLength()); 161 } 162 163 /** 164 * Sets the backing store to use for state. 165 * 166 * @param extStorage external array to use for storage 167 * @param extStorageOffset where to begin storing data 168 * 169 * This should be called before use. 170 */ 171 @Override 172 public void initialize(OwnerInterface globalStateOwner, byte[] extStorage, 173 short extStorageOffset) { 174 globalState = globalStateOwner; 175 // Zero it first (in case we are interrupted). 176 Util.arrayFillNonAtomic(extStorage, extStorageOffset, 177 getStorageNeeded(), (byte) 0x00); 178 storage = extStorage; 179 storageOffset = extStorageOffset; 180 } 181 182 /** 183 * {@inheritDoc} 184 */ 185 @Override 186 public short get(byte[] lockOut, short lockOffset) { 187 if (storage == null) { 188 return 0x0001; 189 } 190 try { 191 Util.arrayCopy(storage, storageOffset, 192 lockOut, lockOffset, (short) 1); 193 } catch (CardRuntimeException e) { 194 return 0x0002; 195 } 196 return 0; 197 } 198 199 /** 200 * {@inheritDoc} 201 * 202 * Returns 0xffff if {@link #initialize()} has not yet been called. 203 */ 204 @Override 205 public short lockOffset() { 206 if (storage == null) { 207 return (short) 0xffff; 208 } 209 return storageOffset; 210 } 211 212 213 /** 214 * {@inheritDoc} 215 * 216 */ 217 @Override 218 public short metadataOffset() { 219 if (storage == null) { 220 return (short) 0xffff; 221 } 222 return (short)(lockOffset() + 1); 223 } 224 225 /** 226 * {@inheritDoc} 227 * 228 * @return length of metadata. 229 */ 230 public short metadataLength() { 231 return metadataSize; 232 } 233 234 /** 235 * Ensures any requiredLocks are unlocked. 236 * @return true if allowed or false if not. 237 */ 238 public boolean prerequisitesMet() { 239 if (requiredLocks.length != 0) { 240 byte[] temp = new byte[1]; 241 short resp = 0; 242 for (short l = 0; l < requiredLocks.length; ++l) { 243 resp = requiredLocks[l].get(temp, (short) 0); 244 // On error or not cleared, fail. 245 if (resp != 0 || temp[0] != (byte) 0x0) { 246 return false; 247 } 248 } 249 } 250 return true; 251 } 252 253 /** 254 * {@inheritDoc} 255 * 256 * Returns 0x0 on success. 257 */ 258 @Override 259 public short set(byte val) { 260 if (storage == null) { 261 return 0x0001; 262 } 263 // Do not require meta on unlock. 264 if (val != 0) { 265 // While an invalid combo, we can just make the require flag 266 // pointless if metadataLength == 0. 267 if (needMetadata == true && metadataLength() > 0) { 268 return 0x0002; 269 } 270 } 271 // To relock, the lock must be unlocked, then relocked. 272 if (val != (byte)0 && storage[lockOffset()] != (byte)0) { 273 return 0x0005; 274 } 275 if (globalState.production() == true) { 276 // Enforce only when in production. 277 if (onlyInBootloader == true) { 278 // If onlyInBootloader is false, we allow toggling regardless. 279 if (globalState.inBootloader() == false) { 280 return 0x0003; 281 } 282 } 283 if (onlyInHLOS == true) { 284 // If onlyInHLOS is false, we allow toggling regardless. 285 if (globalState.inBootloader() == true) { 286 return 0x0003; 287 } 288 } 289 } 290 if (prerequisitesMet() == false) { 291 return 0x0a00; 292 } 293 try { 294 storage[storageOffset] = val; 295 } catch (CardRuntimeException e) { 296 return 0x0004; 297 } 298 return 0; 299 } 300 301 /** 302 * {@inheritDoc} 303 * 304 * If configured with {@link #requiredMetadata}, will populate the 305 * metadata. Otherwise, it will just call {@link #set}. 306 * 307 */ 308 @Override 309 public short setWithMetadata(byte lockValue, byte[] lockMeta, 310 short lockMetaOffset, short lockMetaLength) { 311 if (storage == null) { 312 return 0x0001; 313 } 314 // No overruns, please. 315 if (lockMetaLength > metadataLength()) { 316 return 0x0002; 317 } 318 // To relock, the lock must be unlocked, then relocked. 319 // This ensures that a lock like LOCK_OWNER cannot have its key value 320 // changed without first having the permission to unlock and lock again. 321 if (lockValue != (byte)0 && storage[lockOffset()] != (byte)0) { 322 return 0x0005; 323 } 324 if (metadataLength() == 0) { 325 return set(lockValue); 326 } 327 // Before copying, ensure changing the lock state is currently permitted. 328 if (prerequisitesMet() == false) { 329 return 0x0a00; 330 } 331 try { 332 // When unlocking, do so before clearing the metadata. 333 if (lockValue == (byte) 0) { 334 JCSystem.beginTransaction(); 335 storage[lockOffset()] = lockValue; 336 JCSystem.commitTransaction(); 337 } 338 if (lockMetaLength == 0) { 339 // An empty lockMeta will clear the value. 340 Util.arrayFillNonAtomic(storage, metadataOffset(), 341 metadataLength(), (byte) 0x00); 342 } else { 343 Util.arrayCopyNonAtomic(lockMeta, lockMetaOffset, 344 storage, metadataOffset(), 345 lockMetaLength); 346 } 347 // When locking, do so after the copy as interrupting it will 348 // not impact its use in a locked state. 349 if (lockValue != (byte) 0) { 350 JCSystem.beginTransaction(); 351 storage[lockOffset()] = lockValue; 352 JCSystem.commitTransaction(); 353 } 354 } catch (CardRuntimeException e) { 355 return 0x0004; 356 } 357 return 0; 358 } 359} 360