Home | History | Annotate | Download | only in storage
      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 // Test on device with:
     17 //    echo -e '00A4040010A0000004765049584C424F4F54000101 9000\n8000000000 9000\n' | ese-replay nq-nci
     18 // Install (after loading the two Shareable caps) with:
     19 // ${JAVA_HOME}/bin/java -jar gp.jar   -d --install avb_storage.cap
     20 //
     21 
     22 package com.android.verifiedboot.storage;
     23 
     24 import javacard.framework.AID;
     25 import javacard.framework.APDU;
     26 import javacard.framework.Applet;
     27 import javacard.framework.CardRuntimeException;
     28 import javacard.framework.ISO7816;
     29 import javacard.framework.ISOException;
     30 import javacard.framework.JCSystem;
     31 import javacard.framework.Shareable;
     32 import javacard.framework.Util;
     33 
     34 import javacard.security.KeyBuilder;
     35 import javacard.security.MessageDigest;
     36 import javacard.security.RSAPublicKey;
     37 import javacard.security.Signature;
     38 
     39 // Enables processing longer messages atomically.
     40 import javacardx.apdu.ExtendedLength;
     41 
     42 import com.android.verifiedboot.globalstate.callback.CallbackInterface;
     43 import com.android.verifiedboot.globalstate.owner.OwnerInterface;
     44 
     45 import com.android.verifiedboot.storage.GlobalStateImpl;
     46 import com.android.verifiedboot.storage.BasicLock;
     47 import com.android.verifiedboot.storage.CarrierLock;
     48 import com.android.verifiedboot.storage.LockInterface;
     49 import com.android.verifiedboot.storage.OsBackupInterface;
     50 import com.android.verifiedboot.storage.VersionStorage;
     51 
     52 import com.android.verifiedboot.storage.JcopBackupImpl;
     53 
     54 public class Storage extends Applet implements ExtendedLength, Shareable {
     55     final static byte VERSION = (byte) 0x01;
     56     final static byte APPLET_CLA = (byte)0x80;
     57 
     58     /* Note, globalState never needs to be backed up as any clients should re-register on every
     59      * call -- not just on install().
     60      */
     61     private GlobalStateImpl globalState;
     62     private VersionStorage versionStorage;
     63     private OsBackupInterface osBackupImpl;
     64     /* lockStorage can be backed up directly, as long as the locks themselves have been
     65      * properly intiialized.
     66      */
     67     private byte[] lockStorage;
     68     private LockInterface[] locks;
     69     private byte[] reservedMetadata;
     70     private byte[] metadata;
     71     private short metadataLength;
     72 
     73     // Indices into locks[].
     74     private final static byte LOCK_CARRIER = (byte) 0x00;
     75     private final static byte LOCK_DEVICE = (byte) 0x01;
     76     private final static byte LOCK_BOOT = (byte) 0x02;
     77     private final static byte LOCK_OWNER = (byte) 0x03;
     78 
     79     private final static byte INS_GET_STATE = (byte) 0x00;
     80     private final static byte INS_LOAD = (byte) 0x02;
     81     private final static byte INS_STORE = (byte) 0x04;
     82     private final static byte INS_GET_LOCK = (byte) 0x06;
     83     private final static byte INS_SET_LOCK = (byte) 0x08;
     84     private final static byte INS_SET_PRODUCTION = (byte) 0x0a;
     85     private final static byte INS_CARRIER_LOCK_TEST = (byte) 0x0c;
     86     private final static byte INS_RESET = (byte) 0x0e;
     87     private final static byte INS_LOAD_META = (byte) 0x10;
     88 
     89     private final static byte RESET_FACTORY = (byte) 0x0;
     90     private final static byte RESET_LOCKS = (byte) 0x1;
     91 
     92     private final static byte LOAD_META_CLEAR = (byte) 0x0;
     93     private final static byte LOAD_META_APPEND = (byte) 0x1;
     94 
     95     private final static short NO_METADATA = (short) 0;
     96     private final static short NO_REQ_LOCKS = (short) 0;
     97     // Plenty of space for an owner key and any serialization.
     98     private final static short OWNER_LOCK_METADATA_SIZE = (short) 2048;
     99     private final static short INCOMING_BYTES_MAX = (short) 1024;
    100 
    101     /**
    102      * Installs this applet.
    103      *
    104      * @param params the installation parameters
    105      * @param offset the starting offset of the parameters
    106      * @param length the length of the parameters
    107      */
    108     public static void install(byte[] bArray, short bOffset, byte bLength) {
    109         // GP-compliant-ish JavaCard applet registration
    110         short aidOffset = bOffset;
    111         short aidLength = bArray[aidOffset++];
    112         short privsOffset = (short)(aidOffset + aidLength);
    113         short privLength = bArray[privsOffset++];
    114         // Grab the install parameters.
    115         short paramsOffset = (short)(privsOffset + privLength);
    116         short paramLength = bArray[paramsOffset++];
    117 
    118         Storage applet = new Storage();
    119         applet.register(bArray, aidOffset, (byte)aidLength);
    120         if (paramLength == 0) {
    121             // TODO(wad) Should we fail the install on failure?
    122             applet.restore(bArray);
    123         }
    124     }
    125 
    126     private Storage() {
    127         globalState = new GlobalStateImpl();
    128         osBackupImpl = new JcopBackupImpl();
    129 
    130         versionStorage = new VersionStorage(globalState);
    131         osBackupImpl.track(OsBackupInterface.TAG_VERSION_STORAGE,
    132                            versionStorage);
    133 
    134         lockStorage = new byte[4096];
    135         // Reserve metadata for scratch if there's no transient
    136         reservedMetadata = new byte[OWNER_LOCK_METADATA_SIZE];
    137         metadata = null;
    138 
    139         // Initialize all supported locks here.
    140         locks = new LockInterface[4];
    141         // LOCK_CARRIER can be set only when not in production mode
    142         // but can be unlocked any time authenticated data is provided.
    143         locks[LOCK_CARRIER] = new CarrierLock();
    144         osBackupImpl.track(OsBackupInterface.TAG_LOCK_CARRIER,
    145                            locks[LOCK_CARRIER]);
    146 
    147         // LOCK_DEVICE can be toggled any time from anywhere.  It
    148         // expresses a HLOS management policy.
    149         locks[LOCK_DEVICE] = new BasicLock(NO_METADATA, NO_REQ_LOCKS);
    150         BasicLock lockRef = (BasicLock)locks[LOCK_DEVICE];
    151         lockRef.requireHLOS(true);
    152         osBackupImpl.track(OsBackupInterface.TAG_LOCK_DEVICE,
    153                            lockRef);
    154 
    155          // LOCK_BOOT can only be toggled if both the carrier and device
    156          // locks are clear and then, only in the bootloader/fastboot.
    157         locks[LOCK_BOOT] = new BasicLock(NO_METADATA, (short) 2);
    158         lockRef = (BasicLock)locks[LOCK_BOOT];
    159         lockRef.addRequiredLock(locks[LOCK_CARRIER]);
    160         lockRef.addRequiredLock(locks[LOCK_DEVICE]);
    161         lockRef.requireBootloader(true);
    162         osBackupImpl.track(OsBackupInterface.TAG_LOCK_BOOT,
    163                            lockRef);
    164 
    165         // LOCK_OWNER can be toggled at any time if the BOOT_LOCK is unlocked.
    166         // It modifies the behavior of LOCK_BOOT by providing an alternative
    167         // "owner" boot key.
    168         locks[LOCK_OWNER] = new BasicLock(OWNER_LOCK_METADATA_SIZE, (short) 1);
    169         lockRef = (BasicLock)locks[LOCK_OWNER];
    170         lockRef.addRequiredLock(locks[LOCK_BOOT]);
    171         lockRef.requireMetadata(true);
    172         osBackupImpl.track(OsBackupInterface.TAG_LOCK_OWNER,
    173                            lockRef);
    174 
    175         short offset = (short) 0;
    176         byte lockNum = (byte) 0;
    177         for ( ; lockNum < (byte) locks.length; ++lockNum) {
    178             if (locks[lockNum].getStorageNeeded() >
    179                 (short)(lockStorage.length - offset)) {
    180                 ISOException.throwIt((short) 0xfeed);
    181             }
    182             locks[lockNum].initialize(globalState, lockStorage, offset);
    183             offset += locks[lockNum].getStorageNeeded();
    184         }
    185 
    186     }
    187 
    188     /**
    189       * Returns the globalState or OsBackupInterface object.
    190       *
    191       * @param clientAid AID of the caller.
    192       * @param arg Object request indicator
    193       */
    194     @Override
    195     public Shareable getShareableInterfaceObject(AID clientAid, byte arg) {
    196         if (clientAid != null) {  // TODO: check AID.
    197             switch (arg) {
    198                 case (byte) 0:
    199                   return globalState;
    200                 default:
    201                   return osBackupImpl.getShareableInterfaceObject(clientAid, arg);
    202             }
    203         }
    204         return globalState;
    205     }
    206 
    207     /**
    208      * Emits the state of this Applet to the wire.
    209      *
    210      * Format:
    211      * VERSION (byte)
    212      * Length (short)
    213      * [global_state.OwnerInterface data]
    214      *   inBootloaderRaw (byte)
    215      *   inBootloader (boolean byte)
    216      *   production (byte)
    217      * [lock state]
    218      *   numLocks (byte)
    219      *   locks[0].initialized (short)
    220      *   ...
    221      *   locks[numLocks - 1].initialized (short)
    222      * [lockStorage]
    223      *   lockStorageLength (short)
    224      *   lockStorage (lockStorageLength=4096)
    225      *
    226      * TODO(wad) It'd be nice to TLV these values...
    227      *
    228      * @return 0x00 if the response has been sent.
    229      */
    230     private short sendStorageState(APDU apdu) {
    231         final byte buffer[] = apdu.getBuffer();
    232         byte[] working = new byte[2];
    233         short value = 0;
    234         short resp = 0;
    235         byte i;
    236         short expectedLength = apdu.setOutgoing();
    237         short length = (short)(2 + 1 + 2 + 1 + 1 + 1 + 1 + (2 * locks.length) +
    238                                2 + lockStorage.length + 2);
    239         if (expectedLength < length) {
    240             // Error with length.
    241             buffer[0] = (byte) 0x01;
    242             buffer[1] = (byte) 0x00;
    243             buffer[2] = (byte)(length >> 8);
    244             buffer[3] = (byte)(length & 0xff);
    245             apdu.setOutgoingLength((short) 4);
    246             apdu.sendBytes((short) 0, (short) 4);
    247             return 0x0;
    248         }
    249         try {
    250             apdu.setOutgoingLength(length);
    251         } catch (CardRuntimeException e) {
    252             return 0x0101;
    253         }
    254 
    255         // Send the usual prefix status indicating we made it this far.
    256         try {
    257             Util.setShort(working, (short) 0, (short) 0x0);
    258             apdu.sendBytesLong(working, (short) 0, (short) 2);
    259             length -= 2;
    260         } catch (CardRuntimeException e) {
    261             return 0x0001;
    262         }
    263 
    264         try {
    265             working[0] = VERSION;
    266             apdu.sendBytesLong(working, (short) 0, (short) 1);
    267             length--;
    268         } catch (CardRuntimeException e) {
    269             return 0x0001;
    270         }
    271 
    272         try {
    273             Util.setShort(working, (short) 0, length);
    274             apdu.sendBytesLong(working, (short) 0, (short) 2);
    275             length -= 2;
    276         } catch (CardRuntimeException e) {
    277             ISOException.throwIt(length);
    278         }
    279 
    280         try {
    281             working[0] = globalState.inBootloaderRaw();
    282             apdu.sendBytesLong(working, (short) 0, (short) 1);
    283             length--;
    284         } catch (CardRuntimeException e) {
    285             ISOException.throwIt(length);
    286         }
    287 
    288         try {
    289             working[0] = (byte)0;
    290             if (globalState.inBootloader() == true) {
    291                 working[0] = (byte)1;
    292             }
    293             apdu.sendBytesLong(working, (short) 0, (short) 1);
    294             length--;
    295         } catch (CardRuntimeException e) {
    296             ISOException.throwIt(length);
    297         }
    298 
    299         try {
    300             working[0] = (byte)0;
    301             if (globalState.production() == true) {
    302                 working[0] = (byte)1;
    303             }
    304             apdu.sendBytesLong(working, (short) 0, (short) 1);
    305             length--;
    306         } catch (CardRuntimeException e) {
    307             ISOException.throwIt(length);
    308         }
    309         try {
    310             working[0] = (byte)locks.length;
    311             apdu.sendBytesLong(working, (short) 0, (short) 1);
    312             length--;
    313         } catch (CardRuntimeException e) {
    314             ISOException.throwIt(length);
    315         }
    316 
    317         try {
    318             for (i = 0; i < (byte)locks.length; ++i) {
    319                 Util.setShort(working, (short) 0, locks[i].initialized());
    320                 apdu.sendBytesLong(working, (short) 0, (short) 2);
    321                 length -= 2;
    322             }
    323         } catch (CardRuntimeException e) {
    324             ISOException.throwIt(length);
    325         }
    326 
    327         try {
    328             Util.setShort(working, (short) 0, (short)lockStorage.length);
    329             apdu.sendBytesLong(working, (short) 0, (short) 2);
    330             length -= 2;
    331         } catch (CardRuntimeException e) {
    332             ISOException.throwIt(length);
    333         }
    334 
    335         try {
    336           apdu.sendBytesLong(lockStorage, (short) 0, (short) lockStorage.length);
    337           length -= (short) lockStorage.length;
    338         } catch (CardRuntimeException e) {
    339             ISOException.throwIt(length);
    340         }
    341         if (length != 0) {
    342             ISOException.throwIt(length);
    343         }
    344         return 0;
    345     }
    346 
    347     private void sendResponseCode(APDU apdu, short resp) {
    348         final byte buffer[] = apdu.getBuffer();
    349         buffer[0] = (byte)(resp >> 8);
    350         buffer[1] = (byte)(resp & 0xff);
    351         apdu.setOutgoingAndSend((short)0, (short)2);
    352     }
    353 
    354     /**
    355      * Returns 0x0 if no data needs to be sent.
    356      */
    357     private short sendLockData(APDU apdu, byte p1, byte p2) {
    358         final byte buffer[] = apdu.getBuffer();
    359         short resp = 0;
    360         if (p1 >= (byte)locks.length) {
    361             return 0x0001;
    362         }
    363         if (locks[p1].initialized() != 0) {
    364           return locks[p1].initialized();
    365         }
    366 
    367         if (p2 == (byte) 0x00) {
    368             resp = locks[p1].get(buffer, (short) 2);
    369             Util.setShort(buffer, (short) 0, resp);
    370             apdu.setOutgoingAndSend((short) 0, (short) 3);
    371             return 0;
    372         }
    373         short length = (short)(3 + locks[p1].metadataLength());
    374         try {
    375             byte[] resp_val = new byte[1];
    376             apdu.setOutgoing();
    377             apdu.setOutgoingLength(length);
    378 
    379             // Send a successful response code.
    380             resp_val[0] = (byte) 0x00;
    381             apdu.sendBytesLong(resp_val, (short) 0, (short) 1);
    382             apdu.sendBytesLong(resp_val, (short) 0, (short) 1);
    383             // Then the lock byte.
    384             apdu.sendBytesLong(lockStorage, locks[p1].lockOffset(), (short) 1);
    385             // Then any exported metadata.  Note that the metadataOffset may
    386             // exclude some data which is considered private to the lock.
    387             apdu.sendBytesLong(lockStorage, locks[p1].metadataOffset(),
    388                                locks[p1].metadataLength());
    389             return 0;
    390         } catch (CardRuntimeException e) {
    391             return 0x0002;
    392         }
    393     }
    394 
    395     /**
    396      * Fills the incoming buffer from APDU streams.
    397      *
    398      * @param apdu payload from the client.
    399      * @param incoming buffer to fill from apdu buffer.
    400      * @param iOffset starting offset into incoming.
    401      * @param total total bytes to read from APDU.
    402      * @return offset/length into incoming.
    403      */
    404     private short fillIncomingBuffer(APDU apdu, byte[] incoming, short iOffset, short available) {
    405         final byte buffer[] = apdu.getBuffer();
    406         final short cdataOffset = apdu.getOffsetCdata();
    407         short sum = 0;
    408         while (available > 0) {
    409             Util.arrayCopyNonAtomic(buffer, cdataOffset,
    410                            incoming, (short)(sum + iOffset), available);
    411             sum += available;
    412             try {
    413               available = apdu.receiveBytes(cdataOffset);
    414               if (sum > (short)(incoming.length - available)) {
    415                 available = (short)(incoming.length - sum);
    416               }
    417             } catch (CardRuntimeException e) {
    418               available = 0;
    419             }
    420         }
    421         return (short)(sum + iOffset);
    422     }
    423 
    424     public boolean select() {
    425         metadataLength = (short) 0;
    426         // Try to get the RAM needed.
    427         if (metadata == null ||
    428             metadata == reservedMetadata) {
    429             try {
    430                 metadata = JCSystem.makeTransientByteArray(
    431                         OWNER_LOCK_METADATA_SIZE,
    432                         JCSystem.CLEAR_ON_DESELECT);
    433             } catch (CardRuntimeException e) {
    434                 metadata = reservedMetadata;
    435             }
    436         }
    437         return true;
    438     }
    439     /**
    440      * Handles incoming APDU requests
    441      *
    442      * @param apdu payload from the client.
    443      */
    444     public void process(APDU apdu) {
    445         final byte buffer[] = apdu.getBuffer();
    446         final byte cla = buffer[ISO7816.OFFSET_CLA];
    447         final byte ins = buffer[ISO7816.OFFSET_INS];
    448         // Handle standard commands
    449         if (apdu.isISOInterindustryCLA()) {
    450             switch (ins) {
    451             case ISO7816.INS_SELECT:
    452                 // Do nothing, successfully
    453                 return;
    454             default:
    455                 ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
    456             }
    457             ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
    458         }
    459 
    460         short availableBytes = apdu.setIncomingAndReceive();
    461         short numBytes = apdu.getIncomingLength();
    462         short cdataOffset = apdu.getOffsetCdata();
    463 
    464         // Maximum possible transmission before triggering weirdness
    465         // (really it is 6 * 254 - framing).
    466         if (numBytes > INCOMING_BYTES_MAX) {
    467           sendResponseCode(apdu, (short)0x0f00);
    468           return;
    469         }
    470 
    471         byte p1 = (byte)(buffer[ISO7816.OFFSET_P1] & (byte)0xff);
    472         byte p2 = (byte)(buffer[ISO7816.OFFSET_P2] & (byte)0xff);
    473         short length = 0;
    474         short expectedLength = 0;
    475         short resp = 0;
    476         boolean enable = false;
    477         if (p1 != 0) {
    478           enable = true;
    479         }
    480 
    481         switch (buffer[ISO7816.OFFSET_INS]) {
    482         case INS_GET_STATE:  /* getStorageState(0x0, 0x0) */
    483             resp = sendStorageState(apdu);
    484             if (resp != 0) {
    485                 sendResponseCode(apdu, resp);
    486             }
    487             return;
    488         case INS_LOAD: /* getSlot(id) */
    489             resp = versionStorage.getSlot(p1, buffer, (short) 2);
    490             buffer[0] = (byte)(resp >> 8);
    491             buffer[1] = (byte)(resp & 0xff);
    492             length = 2;
    493             if (resp == 0) {
    494                 length += (short) VersionStorage.SLOT_BYTES;
    495             }
    496             // Always send the two bytes of status as they are more
    497             // useful than the APDU error.
    498             apdu.setOutgoingAndSend((short)0, length);
    499             return;
    500         case INS_STORE: /* setSlot(id) {uint64_t} */
    501             resp = versionStorage.setSlot(p1, buffer, cdataOffset);
    502             Util.setShort(buffer, (short) 0, resp);
    503             apdu.setOutgoingAndSend((short) 0, (short) 2);
    504             return;
    505         case INS_GET_LOCK: /* getLock(lockId, sendMetadata) */
    506             resp = sendLockData(apdu, p1, p2);
    507             if (resp != 0) {
    508                 sendResponseCode(apdu, resp);
    509             }
    510             return;
    511         case INS_SET_LOCK: /* setlock(index, val) { useMetadata(byte) } */
    512             if (p1 >= (byte)locks.length) {
    513                 sendResponseCode(apdu, (short)0x0100);
    514                 return;
    515             }
    516             // useMetadata argument byte is required.
    517             if (numBytes != 1) {
    518                 sendResponseCode(apdu, (short)0x0200);
    519                 return;
    520             }
    521             if (buffer[cdataOffset] == (byte) 0) {
    522                 resp = locks[p1].set(p2);
    523             } else if (buffer[cdataOffset] == (byte) 1) {
    524                 resp = locks[p1].setWithMetadata(p2, metadata,
    525                                                  (short) 0,
    526                                                  metadataLength);
    527                 // "Consume" the metadata even if an error occurred.
    528                 metadataLength = (short)0;
    529             }
    530             sendResponseCode(apdu, resp);
    531             return;
    532         case INS_SET_PRODUCTION: /* setProduction(p1) */
    533             if (globalState.setProduction(enable) == true) {
    534                 resp = 0x0000;
    535             } else {
    536                 resp = 0x0001;
    537             }
    538             sendResponseCode(apdu, resp);
    539             return;
    540         /* carrierLockTest() { testVector } */
    541         case INS_CARRIER_LOCK_TEST:
    542             try {
    543                 short copied = fillIncomingBuffer(apdu, metadata, (short)0,
    544                                                   availableBytes);
    545                 if (numBytes != copied) {
    546                     // Declared length did not match read bytes.
    547                     sendResponseCode(apdu, (short)0x0101);
    548                     return;
    549                 }
    550                 resp = ((CarrierLock)locks[LOCK_CARRIER]).testVector(metadata,
    551                     (short)0, copied);
    552                 sendResponseCode(apdu, resp);
    553                 return;
    554             } catch (CardRuntimeException e) {
    555                 sendResponseCode(apdu, (short)0x0201);
    556                 return;
    557             }
    558         /* reset(0x0=factory 0x1=locks) {} */
    559         case INS_RESET:
    560             if (p1 != RESET_LOCKS) {
    561               /* Not implemented */
    562               resp = 0x0001;
    563               sendResponseCode(apdu, resp);
    564               return;
    565             }
    566             if (globalState.production() == true) {
    567               resp = 0x0100;
    568               sendResponseCode(apdu, resp);
    569               return;
    570             }
    571             Util.arrayFillNonAtomic(lockStorage, (short) 0,
    572                                     (short) lockStorage.length, (byte) 0x00);
    573             return;
    574         /* load_meta(new|append) {} */
    575         case INS_LOAD_META:
    576             if (p1 == LOAD_META_CLEAR) {
    577                 metadataLength = (short) 0;
    578                 sendResponseCode(apdu, (short) 0x0000);
    579                 return;
    580             }
    581             if (p1 != LOAD_META_APPEND) {
    582                 sendResponseCode(apdu, (short) 0x0100);
    583                 return;
    584             }
    585             try  {
    586                 // fillIncomingBuffer will only copy up to the length.
    587                 short copied = fillIncomingBuffer(apdu, metadata,
    588                                                   metadataLength,
    589                                                   availableBytes);
    590                 copied -= metadataLength; // just the new stuff
    591                 metadataLength += copied;
    592                 if (numBytes != copied) {
    593                     // Could not read all the bytes -- the data is
    594                     // copied though.
    595                     sendResponseCode(apdu, (short)0x0101);
    596                     return;
    597                 }
    598             } catch (CardRuntimeException e) {
    599                 sendResponseCode(apdu, (short)0x0201);
    600                 return;
    601             }
    602             sendResponseCode(apdu, (short) 0x0000);
    603             return;
    604         default:
    605             ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
    606         }
    607     }
    608 
    609     /**
    610      * Restores data across upgrades
    611      *
    612      * @param buffer bytes
    613      * @return true on success and false on failure.
    614      */
    615     private boolean restore(byte[] buffer) {
    616         return osBackupImpl.restore(buffer, (short) 0);
    617     }
    618 }
    619