/****************************************************************************
* Copyright (C) 2012 ecsec GmbH.
* All rights reserved.
* Contact: ecsec GmbH (info@ecsec.de)
*
* This file is part of the Open eCard App.
*
* GNU General Public License Usage
* This file may be used under the terms of the GNU General Public
* License version 3.0 as published by the Free Software Foundation
* and appearing in the file LICENSE.GPL included in the packaging of
* this file. Please review the following information to ensure the
* GNU General Public License version 3.0 requirements will be met:
* http://www.gnu.org/copyleft/gpl.html.
*
* Other Usage
* Alternatively, this file may be used in accordance with the terms
* and conditions contained in a signed written agreement between
* you and ecsec GmbH.
*
***************************************************************************/
package org.openecard.sal.protocol.eac.actions;
import iso.std.iso_iec._24727.tech.schema.DIDAuthenticationDataType;
import iso.std.iso_iec._24727.tech.schema.EstablishChannel;
import iso.std.iso_iec._24727.tech.schema.EstablishChannelResponse;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.openecard.common.ECardConstants;
import org.openecard.common.WSHelper;
import org.openecard.common.WSHelper.WSException;
import org.openecard.common.anytype.AuthDataMap;
import org.openecard.common.anytype.AuthDataResponse;
import org.openecard.common.interfaces.Dispatcher;
import org.openecard.common.interfaces.DispatcherException;
import org.openecard.common.util.ByteUtils;
import org.openecard.gui.StepResult;
import org.openecard.gui.definition.PasswordField;
import org.openecard.gui.definition.Step;
import org.openecard.gui.executor.ExecutionResults;
import org.openecard.gui.executor.StepAction;
import org.openecard.gui.executor.StepActionResult;
import org.openecard.gui.executor.StepActionResultStatus;
import org.openecard.sal.protocol.eac.EACData;
import org.openecard.sal.protocol.eac.anytype.PACEInputType;
import org.openecard.sal.protocol.eac.anytype.PasswordID;
import org.openecard.sal.protocol.eac.gui.PINStep;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* StepAction for capturing the user PIN on the EAC GUI.
*
* @author Tobias Wich <tobias.wich@ecsec.de>
*/
public class PINStepAction extends StepAction {
private static final Logger logger = LoggerFactory.getLogger(PINStepAction.class);
private final EACData eacData;
private final boolean capturePin;
private final byte[] slotHandle;
private final Dispatcher dispatcher;
private int retryCounter;
public PINStepAction(EACData eacData, boolean capturePin, byte[] slotHandle, Dispatcher dispatcher, Step step) {
super(step);
this.eacData = eacData;
this.capturePin = capturePin;
this.slotHandle = slotHandle;
this.dispatcher = dispatcher;
this.retryCounter = 0;
}
@Override
public StepActionResult perform(Map<String, ExecutionResults> oldResults, StepResult result) {
if (result.isBack()) {
return new StepActionResult(StepActionResultStatus.BACK);
}
// Create PACEInputType
DIDAuthenticationDataType protoData = eacData.didRequest.getAuthenticationProtocolData();
AuthDataMap paceAuthMap;
try {
paceAuthMap = new AuthDataMap(protoData);
} catch (ParserConfigurationException ex) {
logger.error("Failed to read EAC Protocol data.", ex);
return new StepActionResult(StepActionResultStatus.CANCEL);
}
AuthDataResponse paceInputMap = paceAuthMap.createResponse(protoData);
if (capturePin) {
ExecutionResults executionResults = oldResults.get(getStepID());
PasswordField p = (PasswordField) executionResults.getResult(PINStep.PIN_FIELD);
String pin = p.getValue();
// let the user enter the pin again, when there is none entered
// TODO: check pin length and possibly allowed charset with CardInfo file
if (pin.isEmpty()) {
return new StepActionResult(StepActionResultStatus.REPEAT);
} else {
paceInputMap.addElement(PACEInputType.PIN, pin);
}
}
// perform PACE
paceInputMap.addElement(PACEInputType.PIN_ID, PasswordID.parse(eacData.pinID).getByteAsString());
paceInputMap.addElement(PACEInputType.CHAT, eacData.selectedCHAT.toString());
String certDesc = ByteUtils.toHexString(eacData.rawCertificateDescription);
paceInputMap.addElement(PACEInputType.CERTIFICATE_DESCRIPTION, certDesc);
// EstablishChannel
EstablishChannel establishChannel = new EstablishChannel();
establishChannel.setSlotHandle(slotHandle);
establishChannel.setAuthenticationProtocolData(paceInputMap.getResponse());
establishChannel.getAuthenticationProtocolData().setProtocol(ECardConstants.Protocol.PACE);
try {
EstablishChannelResponse establishChannelResponse = (EstablishChannelResponse) dispatcher.deliver(establishChannel);
WSHelper.checkResult(establishChannelResponse);
eacData.paceResponse = establishChannelResponse;
// PACE completed successfully, proceed with next step
return new StepActionResult(StepActionResultStatus.NEXT);
} catch (WSException ex) {
if (capturePin) {
// repeat until retry counter is reached
// TODO: replace 3 by a number determined in the pin management
// TODO: retrycounter 3 does not work with the nPA, because it also needs the CAN after the second time
if (retryCounter < 2) {
retryCounter++;
logger.info("Wrong PIN entered, trying again (try number {}).", retryCounter);
// TODO: replace this dialog with a version displaying the retry counter
return new StepActionResult(StepActionResultStatus.REPEAT);
} else {
logger.warn("Wrong PIN entered {} times.", retryCounter + 1);
return new StepActionResult(StepActionResultStatus.CANCEL);
}
} else {
logger.warn("PIN not entered successfully in terminal.");
return new StepActionResult(StepActionResultStatus.CANCEL);
}
} catch (DispatcherException ex) {
logger.error("Failed to dispatch EstablishChannelCommand.", ex);
return new StepActionResult(StepActionResultStatus.CANCEL);
} catch (InvocationTargetException ex) {
logger.error("Failed to dispatch EstablishChannelCommand.", ex);
return new StepActionResult(StepActionResultStatus.CANCEL);
}
}
}