All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.keyple.calypso.transaction.CalypsoPo Maven / Gradle / Ivy

There is a newer version: 1.0.0
Show newest version
/* **************************************************************************************
 * Copyright (c) 2018 Calypso Networks Association https://www.calypsonet-asso.org/
 *
 * See the NOTICE file(s) distributed with this work for additional information
 * regarding copyright ownership.
 *
 * This program and the accompanying materials are made available under the terms of the
 * Eclipse Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0
 *
 * SPDX-License-Identifier: EPL-2.0
 ************************************************************************************** */
package org.eclipse.keyple.calypso.transaction;

import java.util.*;
import org.eclipse.keyple.calypso.command.PoClass;
import org.eclipse.keyple.calypso.command.po.PoRevision;
import org.eclipse.keyple.calypso.command.po.parser.GetDataFciRespPars;
import org.eclipse.keyple.core.card.message.CardSelectionResponse;
import org.eclipse.keyple.core.card.selection.AbstractSmartCard;
import org.eclipse.keyple.core.util.ByteArrayUtil;

/**
 * The CalypsoPo class gathers all the information about the current PO retrieved from the response
 * to the select application command.
 *
 * 

An instance of CalypsoPo can be obtained by casting the AbstractSmartCard object from the * selection process (e.g. (CalypsoPo) matchingSelection.getSmartCard()) * *

The various information contained in CalypsoPo is accessible by getters and includes: * *

    *
  • The application identification fields (revision/version, class, DF name, serial number, * ATR, issuer) *
  • The indication of the presence of optional features (Stored Value, PIN, Rev3.2 mode, * ratification management) *
  • The management information of the modification buffer *
  • The invalidation status *
*/ public class CalypsoPo extends AbstractSmartCard { private final boolean isConfidentialSessionModeSupported; private final boolean isDeselectRatificationSupported; private final boolean isSvFeatureAvailable; private final boolean isPinFeatureAvailable; private final boolean isPublicAuthenticationSupported; private final boolean isDfInvalidated; private final PoClass poClass; private final byte[] calypsoSerialNumber; private final byte[] startupInfo; private final PoRevision revision; private final byte[] dfName; private static final int PO_REV1_ATR_LENGTH = 20; private static final int REV1_PO_DEFAULT_WRITE_OPERATIONS_NUMBER_SUPPORTED_PER_SESSION = 3; private static final int REV2_PO_DEFAULT_WRITE_OPERATIONS_NUMBER_SUPPORTED_PER_SESSION = 6; private static final int SI_BUFFER_SIZE_INDICATOR = 0; private static final int SI_PLATFORM = 1; private static final int SI_APPLICATION_TYPE = 2; private static final int SI_APPLICATION_SUBTYPE = 3; private static final int SI_SOFTWARE_ISSUER = 4; private static final int SI_SOFTWARE_VERSION = 5; private static final int SI_SOFTWARE_REVISION = 6; // Application type bitmasks features private static final byte APP_TYPE_WITH_CALYPSO_PIN = 0x01; private static final byte APP_TYPE_WITH_CALYPSO_SV = 0x02; private static final byte APP_TYPE_RATIFICATION_COMMAND_REQUIRED = 0x04; private static final byte APP_TYPE_CALYPSO_REV_32_MODE = 0x08; private static final byte APP_TYPE_WITH_PUBLIC_AUTHENTICATION = 0x10; // buffer indicator to buffer size lookup table private static final int[] BUFFER_SIZE_INDICATOR_TO_BUFFER_SIZE = new int[] { 0, 0, 0, 0, 0, 0, 215, 256, 304, 362, 430, 512, 608, 724, 861, 1024, 1217, 1448, 1722, 2048, 2435, 2896, 3444, 4096, 4870, 5792, 6888, 8192, 9741, 11585, 13777, 16384, 19483, 23170, 27554, 32768, 38967, 46340, 55108, 65536, 77935, 92681, 110217, 131072, 155871, 185363, 220435, 262144, 311743, 370727, 440871, 524288, 623487, 741455, 881743, 1048576 }; private final int modificationsCounterMax; private boolean modificationCounterIsInBytes = true; private DirectoryHeader directoryHeader; private final Map efBySfi = new HashMap(); private final Map efBySfiBackup = new HashMap(); private final Map sfiByLid = new HashMap(); private final Map sfiByLidBackup = new HashMap(); private Boolean isDfRatified = null; private Integer pinAttemptCounter; private Integer svBalance; private int svLastTNum; private SvLoadLogRecord svLoadLogRecord; private SvDebitLogRecord svDebitLogRecord; /** * Constructor. * * @param cardSelectionResponse the response to the selection application command */ CalypsoPo(CardSelectionResponse cardSelectionResponse) { super(cardSelectionResponse); int bufferSizeIndicator; int bufferSizeValue; if (hasFci() && getFciBytes().length > 2) { /* Parse PO FCI - to retrieve DF Name (AID), Serial Number, & StartupInfo */ GetDataFciRespPars poFciRespPars = new GetDataFciRespPars(cardSelectionResponse.getSelectionStatus().getFci(), null); // 4 fields extracted by the low level parser dfName = poFciRespPars.getDfName(); calypsoSerialNumber = poFciRespPars.getApplicationSerialNumber(); startupInfo = poFciRespPars.getDiscretionaryData(); isDfInvalidated = poFciRespPars.isDfInvalidated(); byte applicationType = getApplicationType(); revision = determineRevision(applicationType); // session buffer size bufferSizeIndicator = startupInfo[SI_BUFFER_SIZE_INDICATOR]; bufferSizeValue = BUFFER_SIZE_INDICATOR_TO_BUFFER_SIZE[bufferSizeIndicator]; if (revision == PoRevision.REV2_4) { /* old cards have their modification counter in number of commands */ modificationCounterIsInBytes = false; modificationsCounterMax = REV2_PO_DEFAULT_WRITE_OPERATIONS_NUMBER_SUPPORTED_PER_SESSION; } else { modificationsCounterMax = bufferSizeValue; } isConfidentialSessionModeSupported = (applicationType & APP_TYPE_CALYPSO_REV_32_MODE) != 0; isDeselectRatificationSupported = (applicationType & APP_TYPE_RATIFICATION_COMMAND_REQUIRED) == 0; isSvFeatureAvailable = (applicationType & APP_TYPE_WITH_CALYPSO_SV) != 0; isPinFeatureAvailable = (applicationType & APP_TYPE_WITH_CALYPSO_PIN) != 0; isPublicAuthenticationSupported = (applicationType & APP_TYPE_WITH_PUBLIC_AUTHENTICATION) != 0; } else { /* * FCI is not provided: we consider it is Calypso PO rev 1, it's serial number is * provided in the ATR */ if (!hasAtr()) { throw new IllegalStateException( "Unable to identify this PO: Neither the CFI nor the ATR are available."); } byte[] atr = getAtrBytes(); /* basic check: we expect to be here following a selection based on the ATR */ if (atr.length != PO_REV1_ATR_LENGTH) { throw new IllegalStateException( "Unexpected ATR length: " + ByteArrayUtil.toHex(getAtrBytes())); } revision = PoRevision.REV1_0; dfName = null; calypsoSerialNumber = new byte[8]; /* old cards have their modification counter in number of commands */ modificationCounterIsInBytes = false; /* * the array is initialized with 0 (cf. default value for primitive types) */ System.arraycopy(atr, 12, calypsoSerialNumber, 4, 4); modificationsCounterMax = REV1_PO_DEFAULT_WRITE_OPERATIONS_NUMBER_SUPPORTED_PER_SESSION; startupInfo = new byte[7]; // create buffer size indicator startupInfo[0] = (byte) modificationsCounterMax; // create the startup info with the 6 bytes of the ATR from position 6 System.arraycopy(atr, 6, startupInfo, 1, 6); // TODO check these flags isConfidentialSessionModeSupported = false; isDeselectRatificationSupported = true; isSvFeatureAvailable = false; isPinFeatureAvailable = false; isPublicAuthenticationSupported = false; isDfInvalidated = false; } /* Rev1 and Rev2 expects the legacy class byte while Rev3 expects the ISO class byte */ if (revision == PoRevision.REV1_0 || revision == PoRevision.REV2_4) { poClass = PoClass.LEGACY; } else { poClass = PoClass.ISO; } } /** * Resolve the PO revision from the application type byte * *
    *
  • if %1-------  →  CLAP  → & * nbsp; REV3.1 *
  • if %00101---  →  REV3.2 *
  • if %00100---  →  REV3.1 *
  • otherwise  →  REV2.4 *
* * @param applicationType the application type (field of startup info) * @return the {@link PoRevision} */ private PoRevision determineRevision(byte applicationType) { if (((applicationType & 0xFF) & (1 << 7)) != 0) { /* CLAP */ return PoRevision.REV3_1_CLAP; } else if ((applicationType >> 3) == (byte) (0x05)) { return PoRevision.REV3_2; } else if ((applicationType >> 3) == (byte) (0x04)) { return PoRevision.REV3_1; } else { return PoRevision.REV2_4; } } /** * The PO revision indicates the generation of the product presented. * *

It will also have an impact on the internal construction of some commands to take into * account the specificities of the different POs. * * @return an enum giving the identified PO revision */ public final PoRevision getRevision() { return revision; } /** * The DF name is the name of the application DF as defined in ISO/IEC 7816-4. * *

It also corresponds to the complete representation of the target covered by the AID value * provided in the selection command. * *

The AID selects the application by specifying all or part of the targeted DF Name (5 bytes * minimum). * * @return a byte array containing the DF Name bytes (5 to 16 bytes) */ public final byte[] getDfNameBytes() { return dfName; } /** @return the DF name as an HEX string (see getDfNameBytes) */ public final String getDfName() { return ByteArrayUtil.toHex(getDfNameBytes()); } /** * The serial number to be used as diversifier for key derivation.
* This is the complete number returned by the PO in its response to the Select command. * * @return a byte array containing the Calypso Serial Number (8 bytes) */ protected final byte[] getCalypsoSerialNumber() { return calypsoSerialNumber; } /** * The serial number for the application, is unique ID for the PO. * * @return a byte array containing the Application Serial Number (8 bytes) */ public final byte[] getApplicationSerialNumberBytes() { byte[] applicationSerialNumber = calypsoSerialNumber.clone(); applicationSerialNumber[0] = 0; applicationSerialNumber[1] = 0; return applicationSerialNumber; } /** * The serial number for the application, is unique ID for the PO. * * @return a String representing the Application Serial Number (8 hex bytes) */ public final String getApplicationSerialNumber() { return ByteArrayUtil.toHex(getApplicationSerialNumberBytes()); } /** * @return the startup info field from the FCI as an HEX string * @since 0.9 */ public final String getStartupInfo() { return ByteArrayUtil.toHex(startupInfo); } protected final boolean isSerialNumberExpiring() { throw new IllegalStateException("Not yet implemented"); } protected final byte[] getSerialNumberExpirationBytes() { throw new IllegalStateException("Not yet implemented"); } /** * The Answer To Reset is sent by the PO is ISO7816-3 mode and in contactless mode for PC/SC * readers. * *

When the ATR is obtained in contactless mode, it is in fact reconstructed by the reader from * information obtained from the lower communication layers.Therefore, it may differ from one * reader to another depending on the interpretation that has been made by the manufacturer of the * PC/SC standard. * *

This field is not interpreted in the Calypso module. * * @return an HEX chain representing the ATR * @throws IllegalStateException if the ATR is not available (see {@code hasAtr()} method) * @since 0.9 */ public final String getAtr() { return ByteArrayUtil.toHex(getAtrBytes()); } /** * @return the maximum length of data that an APDU in this PO can carry * @since 0.9 */ protected final int getPayloadCapacity() { // TODO make this value dependent on the type of PO identified return 250; } /** * Specifies whether the change counter allowed in session is established in number of operations * or number of bytes modified. * *

This varies depending on the revision of the PO. * * @return true if the counter is number of bytes */ protected final boolean isModificationsCounterInBytes() { return modificationCounterIsInBytes; } /** * Indicates the maximum number of changes allowed in session. * *

This number can be a number of operations or a number of commands (see * isModificationsCounterInBytes) * * @return the maximum number of modifications allowed */ protected final int getModificationsCounter() { return modificationsCounterMax; } /** * The platform identification byte is the reference of the chip * * @return the platform identification byte */ public final byte getPlatform() { return startupInfo[SI_PLATFORM]; } /** * The Application Type byte determines the Calypso Revision and various options * * @return the Application Type byte */ public final byte getApplicationType() { return startupInfo[SI_APPLICATION_TYPE]; } /** * Indicates whether the Confidential Session Mode is supported or not (since rev 3.2). * *

This boolean is interpreted from the Application Type byte * * @return true if the Confidential Session Mode is supported */ public final boolean isConfidentialSessionModeSupported() { return isConfidentialSessionModeSupported; } /** * Indicates if the ratification is done on deselect (ratification command not necessary) * *

This boolean is interpreted from the Application Type byte * * @return true if the ratification command is required */ public final boolean isDeselectRatificationSupported() { return isDeselectRatificationSupported; } /** * Indicates whether the PO has the Calypso Stored Value feature. * *

This boolean is interpreted from the Application Type byte * * @return true if the PO has the Stored Value feature */ public final boolean isSvFeatureAvailable() { return isSvFeatureAvailable; } /** * Indicates whether the PO has the Calypso PIN feature. * *

This boolean is interpreted from the Application Type byte * * @return true if the PO has the PIN feature */ public final boolean isPinFeatureAvailable() { return isPinFeatureAvailable; } /** * Indicates whether the Public Authentication is supported or not (since rev 3.3). * *

This boolean is interpreted from the Application Type byte * * @return true if the Public Authentication is supported */ public final boolean isPublicAuthenticationSupported() { return isPublicAuthenticationSupported; } /** * The Application Subtype indicates to the terminal a reference to the file structure of the * Calypso DF. * * @return the Application Subtype byte */ public final byte getApplicationSubtype() { return startupInfo[SI_APPLICATION_SUBTYPE]; } /** * The Software Issuer byte indicates the entity responsible for the software of the selected * application. * * @return the Software Issuer byte */ public final byte getSoftwareIssuer() { return startupInfo[SI_SOFTWARE_ISSUER]; } /** * The Software Version field may be set to any fixed value by the Software Issuer of the Calypso * application. * * @return the Software Version byte */ public final byte getSoftwareVersion() { return startupInfo[SI_SOFTWARE_VERSION]; } /** * The Software Revision field may be set to any fixed value by the Software Issuer of the Calypso * application. * * @return the Software Revision byte */ public final byte getSoftwareRevision() { return startupInfo[SI_SOFTWARE_REVISION]; } /** * Depending on the type of PO, the session modification byte indicates the maximum number of * bytes that can be modified or the number of possible write commands in a session. * * @return the Session Modifications byte */ public final byte getSessionModification() { return startupInfo[SI_BUFFER_SIZE_INDICATOR]; } /** * Indicated whether the PO has been invalidated or not. * *

An invalidated PO has 6283 as status word in response to the Select Application command. * * @return true if the PO has been invalidated. */ public final boolean isDfInvalidated() { return isDfInvalidated; } /** * Indicated whether the last session with this PO has been ratified or not. * *

* * @return true if the PO has been ratified. * @throws IllegalStateException if these methods is call when no session has been opened */ public final boolean isDfRatified() { if (isDfRatified != null) { return isDfRatified; } throw new IllegalStateException( "Unable to determine the ratification status. No session was opened."); } /** * (package-private)
* Sets the Stored Value data from the SV Get command * * @param svBalance the current SV balance * @param svLastTNum the last SV transaction number * @param svLoadLogRecord the SV load log record (may be null if not available) * @param svDebitLogRecord the SV debit log record (may be null if not available) */ final void setSvData( int svBalance, int svLastTNum, SvLoadLogRecord svLoadLogRecord, SvDebitLogRecord svDebitLogRecord) { this.svBalance = svBalance; this.svLastTNum = svLastTNum; // update logs, do not overwrite existing values (case of double reading) if (this.svLoadLogRecord == null) { this.svLoadLogRecord = svLoadLogRecord; } if (this.svDebitLogRecord == null) { this.svDebitLogRecord = svDebitLogRecord; } } /** * Gets the current SV balance * * @return the current SV balance value * @throws IllegalStateException if no SV Get command has been executed * @since 0.9 */ public final int getSvBalance() { if (svBalance == null) { throw new IllegalStateException("No SV Get command has been executed."); } return svBalance; } /** * Gets the last SV transaction number * * @return the last SV transaction number value * @throws IllegalStateException if no SV Get command has been executed * @since 0.9 */ public final int getSvLastTNum() { if (svBalance == null) { throw new IllegalStateException("No SV Get command has been executed."); } return svLastTNum; } /** * Gets the last SV load log record * * @return a last SV load log record object or null if not available * @throws NoSuchElementException if requested log is not found. * @since 0.9 */ public final SvLoadLogRecord getSvLoadLogRecord() { if (svLoadLogRecord == null) { // try to get it from the file data byte[] logRecord = getFileBySfi(CalypsoPoUtils.SV_RELOAD_LOG_FILE_SFI).getData().getContent(); svLoadLogRecord = new SvLoadLogRecord(logRecord, 0); } return svLoadLogRecord; } /** * Gets the last SV debit log record * * @return a last SV debit log record object or null if not available * @throws NoSuchElementException if requested log is not found. * @since 0.9 */ public final SvDebitLogRecord getSvDebitLogLastRecord() { if (svDebitLogRecord == null) { // try to get it from the file data List svDebitLogRecords = getSvDebitLogAllRecords(); svDebitLogRecord = svDebitLogRecords.get(0); } return svDebitLogRecord; } /** * Gets all available SV debit log records * * @return a list of SV debit log record objects or null if not available * @throws NoSuchElementException if requested log is not found. * @since 0.9 */ public final List getSvDebitLogAllRecords() { // get the logs from the file data SortedMap logRecords = getFileBySfi(CalypsoPoUtils.SV_DEBIT_LOG_FILE_SFI).getData().getAllRecordsContent(); List svDebitLogRecords = new ArrayList(); for (Map.Entry entry : logRecords.entrySet()) { svDebitLogRecords.add(new SvDebitLogRecord(entry.getValue(), 0)); } return svDebitLogRecords; } /** * (package-private)
* Sets the ratification status * * @param dfRatified true if the session was ratified * @since 0.9 */ final void setDfRatified(boolean dfRatified) { isDfRatified = dfRatified; } /** * The PO class is the ISO7816 class to be used with the current PO. * *

It determined from the PO revision * *

Two classes are possible: LEGACY and ISO. * * @return the PO class determined from the PO revision */ protected final PoClass getPoClass() { return poClass; } /** * Gets the DF metadata. * * @return null if is not set. * @since 0.9 */ public final DirectoryHeader getDirectoryHeader() { return directoryHeader; } /** * (package-private)
* Sets the DF metadata. * * @param directoryHeader the DF metadata (should be not null) * @return the current instance. */ final CalypsoPo setDirectoryHeader(DirectoryHeader directoryHeader) { this.directoryHeader = directoryHeader; return this; } /** * Gets a reference to the {@link ElementaryFile} that has the provided SFI value.
* Note that if a secure session is actually running, then the object contains all session * modifications, which can be canceled if the secure session fails. * * @param sfi the SFI to search * @return a not null reference. * @throws NoSuchElementException if requested EF is not found. * @since 0.9 */ public final ElementaryFile getFileBySfi(byte sfi) { ElementaryFile ef = efBySfi.get(sfi); if (ef == null) { throw new NoSuchElementException( "EF with SFI [0x" + Integer.toHexString(sfi & 0xFF) + "] is not found."); } return ef; } /** * Gets a reference to the {@link ElementaryFile} that has the provided LID value.
* Note that if a secure session is actually running, then the object contains all session * modifications, which can be canceled if the secure session fails. * * @param lid the LID to search * @return a not null reference. * @throws NoSuchElementException if requested EF is not found. * @since 0.9 */ public final ElementaryFile getFileByLid(short lid) { Byte sfi = sfiByLid.get(lid); if (sfi == null) { throw new NoSuchElementException( "EF with LID [" + Integer.toHexString(lid & 0xFFFF) + "] is not found."); } return efBySfi.get(sfi); } /** * Gets a reference to a map of all known Elementary Files by their associated SFI.
* Note that if a secure session is actually running, then the map contains all session * modifications, which can be canceled if the secure session fails. * * @return a not null reference (may be empty if no one EF is set). * @since 0.9 */ public final Map getAllFiles() { return efBySfi; } /** * (private)
* Gets or creates the EF having the provided SFI. * * @param sfi the SFI * @return a not null reference. */ private ElementaryFile getOrCreateFile(byte sfi) { ElementaryFile ef = efBySfi.get(sfi); if (ef == null) { ef = new ElementaryFile(sfi); efBySfi.put(sfi, ef); } return ef; } /** * Indicates if the PIN is blocked. The maximum number of incorrect PIN submissions has been * reached. * * @return true if the PIN status is blocked * @throws IllegalStateException if the PIN has not been checked * @since 0.9 */ public final boolean isPinBlocked() { return getPinAttemptRemaining() == 0; } /** * Gives the number of erroneous PIN presentations remaining before blocking. * * @return the number of remaining attempts * @throws IllegalStateException if the PIN has not been checked * @since 0.9 */ public final int getPinAttemptRemaining() { if (pinAttemptCounter == null) { throw new IllegalStateException("PIN status has not been checked."); } return pinAttemptCounter; } /** * (package-private)
* Sets the PIN attempts counter.
* The PIN attempt counter is interpreted to give the results of the methods {@link #isPinBlocked} * and {@link #getPinAttemptRemaining}. * * @param pinAttemptCounter the number of remaining attempts to present the PIN code */ final void setPinAttemptRemaining(int pinAttemptCounter) { this.pinAttemptCounter = pinAttemptCounter; } /** * (package-private)
* Sets the provided {@link FileHeader} to the EF having the provided SFI.
* If EF does not exist, then it is created. * * @param sfi the SFI * @param header the file header (should be not null) */ final void setFileHeader(byte sfi, FileHeader header) { ElementaryFile ef = getOrCreateFile(sfi); ef.setHeader(header); sfiByLid.put(header.getLid(), sfi); } /** * (package-private)
* Set or replace the entire content of the specified record #numRecord of the provided SFI by the * provided content.
* If EF does not exist, then it is created. * * @param sfi the SFI * @param numRecord the record number (should be {@code >=} 1) * @param content the content (should be not empty) */ final void setContent(byte sfi, int numRecord, byte[] content) { ElementaryFile ef = getOrCreateFile(sfi); ef.getData().setContent(numRecord, content); } /** * (package-private)
* Sets a counter value in record #1 of the provided SFI.
* If EF does not exist, then it is created. * * @param sfi the SFI * @param numCounter the counter number (should be {@code >=} 1) * @param content the counter value (should be not null and 3 bytes length) */ final void setCounter(byte sfi, int numCounter, byte[] content) { ElementaryFile ef = getOrCreateFile(sfi); ef.getData().setCounter(numCounter, content); } /** * (package-private)
* Set or replace the content at the specified offset of record #numRecord of the provided SFI by * a copy of the provided content.
* If EF does not exist, then it is created.
* If actual record content is not set or has a size {@code <} offset, then missing data will be * padded with 0. * * @param sfi the SFI * @param numRecord the record number (should be {@code >=} 1) * @param content the content (should be not empty) * @param offset the offset (should be {@code >=} 0) */ final void setContent(byte sfi, int numRecord, byte[] content, int offset) { ElementaryFile ef = getOrCreateFile(sfi); ef.getData().setContent(numRecord, content, offset); } /** * (package-private)
* Fill the content of the specified #numRecord of the provided SFI using a binary OR operation * with the provided content.
* If EF does not exist, then it is created.
* If actual record content is not set or has a size {@code <} content size, then missing data * will be completed by the provided content. * * @param sfi the SFI * @param numRecord the record number (should be {@code >=} 1) * @param content the content (should be not empty) */ final void fillContent(byte sfi, int numRecord, byte[] content) { ElementaryFile ef = getOrCreateFile(sfi); ef.getData().fillContent(numRecord, content); } /** * (package-private)
* Add cyclic content at record #1 by rolling previously all actual records contents (record #1 -> * record #2, record #2 -> record #3,...) of the provided SFI.
* This is useful for cyclic files. Note that records are infinitely shifted.
*
* If EF does not exist, then it is created. * * @param sfi the SFI * @param content the content (should be not empty) */ final void addCyclicContent(byte sfi, byte[] content) { ElementaryFile ef = getOrCreateFile(sfi); ef.getData().addCyclicContent(content); } /** * (package-private)
* Make a backup of the Elementary Files.
* This method should be used before starting a PO secure session. */ final void backupFiles() { copyMapFiles(efBySfi, efBySfiBackup); copyMapSfi(sfiByLid, sfiByLidBackup); } /** * (package-private)
* Restore the last backup of Elementary Files.
* This method should be used when SW of the PO close secure session command is unsuccessful or if * secure session is aborted. */ final void restoreFiles() { copyMapFiles(efBySfiBackup, efBySfi); copyMapSfi(sfiByLidBackup, sfiByLid); } /** * (private)
* Copy a map of ElementaryFile by SFI to another one by cloning each element. * * @param src the source (should be not null) * @param dest the destination (should be not null) */ private static void copyMapFiles(Map src, Map dest) { dest.clear(); for (Map.Entry entry : src.entrySet()) { dest.put(entry.getKey(), new ElementaryFile(entry.getValue())); } } /** * (private)
* Copy a map of SFI by LID to another one by cloning each element. * * @param src the source (should be not null) * @param dest the destination (should be not null) */ private static void copyMapSfi(Map src, Map dest) { dest.clear(); dest.putAll(src); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy