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.Util; 21 22import com.android.verifiedboot.storage.BackupInterface; 23import com.android.verifiedboot.globalstate.owner.OwnerInterface; 24 25class VersionStorage implements BackupInterface { 26 final public static byte NUM_SLOTS = (byte) 8; 27 final public static byte SLOT_BYTES = (byte) 8; 28 final private static byte EXPORT_VERSION = (byte)0x01; 29 private OwnerInterface globalState; 30 private byte[] storage; 31 32 public VersionStorage(OwnerInterface globalStateRef) { 33 storage = new byte[NUM_SLOTS * SLOT_BYTES]; 34 globalState = globalStateRef; 35 Util.arrayFillNonAtomic(storage, (short) 0, (short) storage.length, (byte) 0x00); 36 } 37 38 /** 39 * Copies content from the given slot in |out| and returns true. 40 * 41 * @param slot slot number to retrieve 42 * @param out array to copy the slot data to. 43 * @param oOffset offset into |out| to start the copy at. 44 * @return 0x0 on success and an error otherwise. 45 */ 46 public short getSlot(byte slot, byte[] out, short oOffset) { 47 if (slot > NUM_SLOTS - 1) { 48 return 0x0001; 49 } 50 try { 51 Util.arrayCopy(storage, (short)(SLOT_BYTES * slot), 52 out, oOffset, SLOT_BYTES); 53 } catch (CardRuntimeException e) { 54 return 0x0002; 55 } 56 return 0x0; 57 } 58 59 /** 60 * Copies content for the given slot from |in| and returns true. 61 * 62 * @param slot slot number to retrieve 63 * @param in array to copy the slot data from. 64 * @param iOffset into |in| to start the copy at. 65 * @return 0x0 on success or an error code. 66 */ 67 public short setSlot(byte slot, byte[] in, short iOffset) { 68 if (slot > NUM_SLOTS - 1) { 69 return 0x0001; 70 } 71 // Slots can be set only if we're in the bootloader 72 // or we're not yet in production. 73 if (globalState.production() == true && 74 globalState.inBootloader() == false) { 75 return 0x0003; 76 } 77 try { 78 Util.arrayCopy(in, iOffset, 79 storage, (short)(SLOT_BYTES * slot), SLOT_BYTES); 80 } catch (CardRuntimeException e) { 81 return 0x0002; 82 } 83 return 0; 84 } 85 86 /** 87 * {@inheritDoc} 88 * 89 * Checks the size and version prefix prior to copying. 90 */ 91 @Override 92 public boolean restore(byte[] inBytes, short inBytesOffset, short inBytesLength) { 93 if (inBytesLength == (short) 0 || 94 inBytesLength > (short)(storage.length + 1)) { 95 return false; 96 } 97 if (inBytes[0] != EXPORT_VERSION) { 98 return false; 99 } 100 try { 101 Util.arrayCopy(inBytes, inBytesOffset, storage, (short) 0, inBytesLength); 102 } catch (CardRuntimeException e) { 103 return false; 104 } 105 return true; 106 } 107 108 /** 109 * {@inheritDoc} 110 * 111 * Copies storage to outBytes with a leading version byte which can be 112 * checked on restore. 113 */ 114 @Override 115 public short backup(byte[] outBytes, short outBytesOffset) { 116 try { 117 // Tag the export version that way if any internal storage format changes 118 // occur, they can be handled. 119 outBytes[(short)(outBytesOffset + 1)] = EXPORT_VERSION; 120 Util.arrayCopy(storage, (short) 0, outBytes, (short)(outBytesOffset + 1), 121 (short)storage.length); 122 return (short)(storage.length + 1); 123 } catch (CardRuntimeException e) { 124 return 0x0; 125 } 126 } 127 128 /** 129 * {@inheritDoc} 130 */ 131 @Override 132 public short backupSize() { 133 return (short)(storage.length + 1); 134 } 135} 136