Commit 2a3f3007 authored by Tobias Wich's avatar Tobias Wich
Browse files

Merge branch 'master' into java11

parents 4c421f54 36a7e65b
......@@ -5,7 +5,7 @@
<parent>
<groupId>org.openecard</groupId>
<artifactId>src-parent</artifactId>
<version>1.3.1-SNAPSHOT</version>
<version>1.4.0-rc.3-SNAPSHOT</version>
<relativePath>../src-parent/</relativePath>
</parent>
......
......@@ -5,7 +5,7 @@
<parent>
<groupId>org.openecard</groupId>
<artifactId>addons</artifactId>
<version>1.3.1-SNAPSHOT</version>
<version>1.4.0-rc.3-SNAPSHOT</version>
</parent>
<groupId>org.openecard.addons</groupId>
......
......@@ -5,7 +5,7 @@
<parent>
<groupId>org.openecard</groupId>
<artifactId>addons</artifactId>
<version>1.3.1-SNAPSHOT</version>
<version>1.4.0-rc.3-SNAPSHOT</version>
</parent>
<groupId>org.openecard.addons</groupId>
......
......@@ -5,7 +5,7 @@
<parent>
<groupId>org.openecard</groupId>
<artifactId>addons</artifactId>
<version>1.3.1-SNAPSHOT</version>
<version>1.4.0-rc.3-SNAPSHOT</version>
</parent>
<groupId>org.openecard.addons</groupId>
......
......@@ -5,7 +5,7 @@
<parent>
<groupId>org.openecard</groupId>
<artifactId>src-parent</artifactId>
<version>1.3.1-SNAPSHOT</version>
<version>1.4.0-rc.3-SNAPSHOT</version>
<relativePath>../src-parent/</relativePath>
</parent>
......
......@@ -5,7 +5,7 @@
<parent>
<groupId>org.openecard</groupId>
<artifactId>addons</artifactId>
<version>1.3.1-SNAPSHOT</version>
<version>1.4.0-rc.3-SNAPSHOT</version>
</parent>
<groupId>org.openecard.addons</groupId>
......
......@@ -5,7 +5,7 @@
<parent>
<groupId>org.openecard</groupId>
<artifactId>addons</artifactId>
<version>1.3.1-SNAPSHOT</version>
<version>1.4.0-rc.3-SNAPSHOT</version>
</parent>
<groupId>org.openecard.addons</groupId>
......
......@@ -234,6 +234,7 @@ public class TCTokenRequest {
if (usableCards == null) {
// user aborted the card insertion dialog
LOG.info("Waiting for cards has not returned a result, cancelling process.");
throw new UserCancellationException(null, LANG.translationForKey(CARD_INSERTION_ABORT));
}
......
......@@ -182,9 +182,6 @@ public class PACEStep implements ProtocolStep<DIDAuthenticate, DIDAuthenticateRe
return response;
}
CHAT requiredCHAT = new CHAT(eac1Input.getRequiredCHAT());
CHAT optionalCHAT = new CHAT(eac1Input.getOptionalCHAT());
// get the PACEMarker
CardStateEntry cardState = (CardStateEntry) internalData.get(EACConstants.IDATA_CARD_STATE_ENTRY);
PACEMarkerType paceMarker = getPaceMarker(cardState, passwordType);
......@@ -193,13 +190,16 @@ public class PACEStep implements ProtocolStep<DIDAuthenticate, DIDAuthenticateRe
// Verify that the certificate description matches the terminal certificate
CardVerifiableCertificate taCert = certChain.getTerminalCertificate();
CardVerifiableCertificateVerifier.verify(taCert, certDescription);
// Verify that the required CHAT matches the terminal certificate's CHAT
// get CHAT values
CHAT taCHAT = taCert.getCHAT();
CHAT requiredCHAT = new CHAT(eac1Input.getRequiredCHAT());
CHAT optionalCHAT = new CHAT(eac1Input.getOptionalCHAT());
// Check that we got an authentication terminal terminal certificate. We abort the process in case there is
// an other role.
if (taCHAT.getRole() != CHAT.Role.AUTHENTICATION_TERMINAL) {
String msg = "Unsupported terminal type in Terminal Certificate referenced. Refernced terminal type is " +
String msg = "Unsupported terminal type in Terminal Certificate referenced. Referenced terminal type is " +
taCHAT.getRole().toString() + ".";
response.setResult(WSHelper.makeResultError(ECardConstants.Minor.App.INCORRECT_PARM, msg));
dynCtx.put(EACProtocol.AUTHENTICATION_DONE, false);
......@@ -207,6 +207,8 @@ public class PACEStep implements ProtocolStep<DIDAuthenticate, DIDAuthenticateRe
}
CHATVerifier.verfiy(taCHAT, requiredCHAT);
// enable CAN_ALLOWED value, gets deleted by the restrict afterwards if not allowed
optionalCHAT.setSpecialFunctions(CHAT.SpecialFunction.CAN_ALLOWED, true);
// remove overlapping values from optional chat
optionalCHAT.restrictAccessRights(taCHAT);
......
/****************************************************************************
* Copyright (C) 2019 ecsec GmbH.
* All rights reserved.
* Contact: ecsec GmbH (info@ecsec.de)
*
* 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.gui;
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.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.openecard.binding.tctoken.TR03112Keys;
import org.openecard.common.DynamicContext;
import org.openecard.common.ECardConstants;
import org.openecard.common.anytype.AuthDataMap;
import org.openecard.common.anytype.AuthDataResponse;
import org.openecard.common.interfaces.Dispatcher;
import org.openecard.common.util.ByteUtils;
import org.openecard.gui.definition.PasswordField;
import org.openecard.gui.executor.ExecutionResults;
import org.openecard.gui.executor.StepAction;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Tobias Wich
*/
public abstract class AbstractPasswordStepAction extends StepAction {
private static final Logger LOG = LoggerFactory.getLogger(AbstractPasswordStepAction.class);
private static final String PIN_ID_CAN = "2";
protected final EACData eacData;
protected final boolean capturePin;
protected final byte[] slotHandle;
protected final Dispatcher dispatcher;
protected final PINStep step;
protected final DynamicContext ctx;
public AbstractPasswordStepAction(EACData eacData, boolean capturePin, byte[] slotHandle, Dispatcher dispatcher,
PINStep step) {
super(step);
this.eacData = eacData;
this.capturePin = capturePin;
this.slotHandle = slotHandle;
this.dispatcher = dispatcher;
this.step = step;
this.ctx = DynamicContext.getInstance(TR03112Keys.INSTANCE_KEY);
}
protected EstablishChannelResponse performPACEWithPIN(Map<String, ExecutionResults> oldResults) {
DIDAuthenticationDataType protoData = eacData.didRequest.getAuthenticationProtocolData();
AuthDataMap paceAuthMap;
try {
paceAuthMap = new AuthDataMap(protoData);
} catch (ParserConfigurationException ex) {
LOG.error("Failed to read EAC Protocol data.", ex);
return null;
}
AuthDataResponse paceInputMap = paceAuthMap.createResponse(protoData);
if (capturePin) {
ExecutionResults executionResults = oldResults.get(getStepID());
PasswordField p = (PasswordField) executionResults.getResult(PINStep.PIN_FIELD);
char[] pinIn = 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 (pinIn.length == 0) {
return null;
} else {
// NOTE: saving pin as string prevents later removal of the value from memory !!!
paceInputMap.addElement(PACEInputType.PIN, new String(pinIn));
}
}
// 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 eChannel = createEstablishChannelStructure(paceInputMap);
return (EstablishChannelResponse) dispatcher.safeDeliver(eChannel);
}
protected EstablishChannelResponse performPACEWithCAN(Map<String, ExecutionResults> oldResults) {
DIDAuthenticationDataType paceInput = new DIDAuthenticationDataType();
paceInput.setProtocol(ECardConstants.Protocol.PACE);
AuthDataMap tmp;
try {
tmp = new AuthDataMap(paceInput);
} catch (ParserConfigurationException ex) {
LOG.error("Failed to read empty Protocol data.", ex);
return null;
}
AuthDataResponse paceInputMap = tmp.createResponse(paceInput);
if (capturePin) {
ExecutionResults executionResults = oldResults.get(getStepID());
PasswordField canField = (PasswordField) executionResults.getResult(PINStep.CAN_FIELD);
String canValue = new String(canField.getValue());
if (canValue.length() != 6) {
// let the user enter the can again, when input verification failed
return null;
} else {
paceInputMap.addElement(PACEInputType.PIN, canValue);
}
}
paceInputMap.addElement(PACEInputType.PIN_ID, PIN_ID_CAN);
// perform PACE by EstablishChannelCommand
EstablishChannel eChannel = createEstablishChannelStructure(paceInputMap);
return (EstablishChannelResponse) dispatcher.safeDeliver(eChannel);
}
protected EstablishChannel createEstablishChannelStructure(AuthDataResponse paceInputMap) {
// EstablishChannel
EstablishChannel establishChannel = new EstablishChannel();
establishChannel.setSlotHandle(slotHandle);
establishChannel.setAuthenticationProtocolData(paceInputMap.getResponse());
establishChannel.getAuthenticationProtocolData().setProtocol(ECardConstants.Protocol.PACE);
return establishChannel;
}
}
/****************************************************************************
* Copyright (C) 2019 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.gui;
import iso.std.iso_iec._24727.tech.schema.EstablishChannelResponse;
import java.util.Map;
import org.openecard.common.ECardConstants;
import org.openecard.common.I18n;
import org.openecard.common.WSHelper;
import org.openecard.common.WSHelper.WSException;
import org.openecard.common.interfaces.Dispatcher;
import org.openecard.gui.StepResult;
import org.openecard.gui.executor.ExecutionResults;
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.EACProtocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* StepAction for capturing the user PIN on the EAC GUI.
*
* @author Tobias Wich
* @author Hans-Martin Haase
*/
public class CANStepAction extends AbstractPasswordStepAction {
private static final Logger LOG = LoggerFactory.getLogger(CANStepAction.class);
// Translation constants
private static final String ERROR_CARD_REMOVED = "action.error.card.removed";
private static final String ERROR_TITLE = "action.error.title";
private static final String ERROR_UNKNOWN = "action.error.unknown";
private final I18n lang = I18n.getTranslation("pace");
private final I18n langPin = I18n.getTranslation("pinplugin");
public CANStepAction(EACData eacData, boolean capturePin, byte[] slotHandle, Dispatcher dispatcher, PINStep step) {
super(eacData, capturePin, slotHandle, dispatcher, step);
}
@Override
public StepActionResult perform(Map<String, ExecutionResults> oldResults, StepResult result) {
try {
EstablishChannelResponse establishChannelResponse = performPACEWithPIN(oldResults);
if (establishChannelResponse.getResult().getResultMajor().equals(ECardConstants.Major.ERROR)) {
if (establishChannelResponse.getResult().getResultMinor().equals(ECardConstants.Minor.IFD.AUTHENTICATION_FAILED)) {
// repeat the step
LOG.info("Wrong CAN entered, trying again.");
return new StepActionResult(StepActionResultStatus.REPEAT);
} else {
WSHelper.checkResult(establishChannelResponse);
}
}
eacData.paceResponse = establishChannelResponse;
// PACE completed successfully, proceed with next step
ctx.put(EACProtocol.PACE_EXCEPTION, null);
return new StepActionResult(StepActionResultStatus.NEXT);
} catch (WSException ex) {
// This is for PIN Pad Readers in case the user pressed the cancel button on the reader.
if (ex.getResultMinor().equals(ECardConstants.Minor.IFD.CANCELLATION_BY_USER)) {
LOG.error("User canceled the authentication manually.", ex);
return new StepActionResult(StepActionResultStatus.CANCEL);
}
// for people which think they have to remove the card in the process
if (ex.getResultMinor().equals(ECardConstants.Minor.IFD.INVALID_SLOT_HANDLE)) {
LOG.error("The SlotHandle was invalid so probably the user removed the card or an reset occurred.", ex);
return new StepActionResult(StepActionResultStatus.REPEAT,
new ErrorStep(lang.translationForKey(ERROR_TITLE),
langPin.translationForKey(ERROR_CARD_REMOVED), ex));
}
// repeat the step
LOG.error("An unknown error occured while trying to verify the PIN.");
return new StepActionResult(StepActionResultStatus.REPEAT,
new ErrorStep(langPin.translationForKey(ERROR_TITLE),
langPin.translationForKey(ERROR_UNKNOWN), ex));
}
}
}
......@@ -44,6 +44,7 @@ import org.openecard.gui.executor.StepActionResultStatus;
import org.openecard.sal.protocol.eac.EACData;
import org.openecard.sal.protocol.eac.EACProtocol;
import org.openecard.sal.protocol.eac.anytype.PACEMarkerType;
import org.openecard.sal.protocol.eac.anytype.PasswordID;
/**
......@@ -86,27 +87,34 @@ public class CHATStepAction extends StepAction {
byte[] slotHandle = (byte[]) ctx.get(EACProtocol.SLOT_HANDLE);
Dispatcher dispatcher = (Dispatcher) ctx.get(EACProtocol.DISPATCHER);
Step pinStep;
Step nextStep;
assert(status != null);
switch (status) {
case BLOCKED:
pinStep = new ErrorStep(LANG.translationForKey("step_error_title_blocked", PIN),
nextStep = new ErrorStep(LANG.translationForKey("step_error_title_blocked", PIN),
LANG.translationForKey("step_error_pin_blocked", PIN, PIN, PUK, PIN),
WSHelper.createException(WSHelper.makeResultError(ECardConstants.Minor.IFD.PASSWORD_BLOCKED, "Password blocked.")));
break;
case DEACTIVATED:
pinStep = new ErrorStep(LANG.translationForKey("step_error_title_deactivated"),
nextStep = new ErrorStep(LANG.translationForKey("step_error_title_deactivated"),
LANG.translationForKey("step_error_pin_deactivated"),
WSHelper.createException(WSHelper.makeResultError(ECardConstants.Minor.IFD.PASSWORD_SUSPENDED, "Card deactivated.")));
break;
default:
pinStep = new PINStep(eacData, !nativePace, paceMarker, status);
PINStep pinStep = new PINStep(eacData, !nativePace, paceMarker, status);
nextStep = pinStep;
pinStep.setBackgroundTask(bTask);
StepAction pinAction = new PINStepAction(eacData, !nativePace, slotHandle, dispatcher, (PINStep) pinStep, status);
StepAction pinAction;
if (eacData.pinID == PasswordID.CAN.getByte()) {
pinStep.setStatus(EacPinStatus.RC3);
pinAction = new CANStepAction(eacData, !nativePace, slotHandle, dispatcher, pinStep);
} else {
pinAction = new PINStepAction(eacData, !nativePace, slotHandle, dispatcher, pinStep, status);
}
pinStep.setAction(pinAction);
}
return new StepActionResult(StepActionResultStatus.NEXT, pinStep);
return new StepActionResult(StepActionResultStatus.NEXT, nextStep);
} else {
// cancel can not happen, so only back is left to be handled
return new StepActionResult(StepActionResultStatus.BACK);
......@@ -142,6 +150,12 @@ public class CHATStepAction extends StepAction {
}
}
}
// change PIN ID to CAN if CAN ALLOWED is used
if (eacData.selectedCHAT.getSpecialFunctions().getOrDefault(CHAT.SpecialFunction.CAN_ALLOWED, Boolean.FALSE)) {
eacData.pinID = PasswordID.CAN.getByte();
eacData.passwordType = PasswordID.parse(eacData.pinID).getString();
}
}
/**
......
......@@ -29,6 +29,7 @@ import org.openecard.gui.definition.PasswordField;
import org.openecard.gui.definition.Step;
import org.openecard.gui.definition.Text;
import org.openecard.sal.protocol.eac.EACData;
import org.openecard.sal.protocol.eac.anytype.PasswordID;
/**
......@@ -38,7 +39,7 @@ import org.openecard.sal.protocol.eac.EACData;
* @author Tobias Wich
* @author Moritz Horsch
*/
public class PINStep extends Step {
public final class PINStep extends Step {
private static final I18n LANG_EAC = I18n.getTranslation("eac");
private static final I18n LANG_PACE = I18n.getTranslation("pace");
......@@ -60,6 +61,7 @@ public class PINStep extends Step {
private final String pinType;
private final PACEMarkerType paceMarker;
private final boolean hasAttemptsCounter;
private EacPinStatus status;
......@@ -67,6 +69,7 @@ public class PINStep extends Step {
super(STEP_ID, "Dummy-Title");
this.pinType = LANG_PACE.translationForKey(eacData.passwordType);
this.paceMarker = paceMarker;
this.hasAttemptsCounter = eacData.pinID != PasswordID.CAN.getByte();
setTitle(LANG_PACE.translationForKey(TITLE, pinType));
setDescription(LANG_PACE.translationForKey(STEP_DESCRIPTION));
setReversible(false);
......@@ -116,10 +119,12 @@ public class PINStep extends Step {
pinInputField.setMaxLength(paceMarker.getMaxLength());
getInputInfoUnits().add(pinInputField);
Text attemptCount = new Text();
attemptCount.setText(LANG_PACE.translationForKey("step_pin_retrycount", 3));
attemptCount.setID(PIN_ATTEMPTS_ID);
getInputInfoUnits().add(attemptCount);
if (hasAttemptsCounter) {
Text attemptCount = new Text();
attemptCount.setText(LANG_PACE.translationForKey("step_pin_retrycount", 3));
attemptCount.setID(PIN_ATTEMPTS_ID);
getInputInfoUnits().add(attemptCount);
}
Text notice = new Text();
notice.setText(LANG_EAC.translationForKey(NOTICE, pinType));
......@@ -136,10 +141,12 @@ public class PINStep extends Step {
notice.setText(LANG_EAC.translationForKey(NOTICE, pinType));
getInputInfoUnits().add(notice);
Text attemptCount = new Text();
attemptCount.setText(LANG_PACE.translationForKey("step_pin_retrycount", 3));
attemptCount.setID(PIN_ATTEMPTS_ID);
getInputInfoUnits().add(attemptCount);
if (hasAttemptsCounter) {
Text attemptCount = new Text();
attemptCount.setText(LANG_PACE.translationForKey("step_pin_retrycount", 3));
attemptCount.setID(PIN_ATTEMPTS_ID);
getInputInfoUnits().add(attemptCount);
}
}
protected void addCANEntry() {
......
/****************************************************************************
* Copyright (C) 2012-2018 ecsec GmbH.
* Copyright (C) 2012-2019 ecsec GmbH.
* All rights reserved.
* Contact: ecsec GmbH (info@ecsec.de)
*
......@@ -22,31 +22,19 @@
package org.openecard.sal.protocol.eac.gui;
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.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.openecard.binding.tctoken.TR03112Keys;
import org.openecard.common.DynamicContext;
import org.openecard.common.ECardConstants;
import org.openecard.common.I18n;
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.util.ByteUtils;
import org.openecard.gui.StepResult;
import org.openecard.gui.definition.PasswordField;
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.EACProtocol;
import org.openecard.sal.protocol.eac.anytype.PACEInputType;
import org.openecard.sal.protocol.eac.anytype.PasswordID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -57,12 +45,10 @@ import org.slf4j.LoggerFactory;
* @author Tobias Wich
* @author Hans-Martin Haase
*/
public class PINStepAction extends StepAction {
public class PINStepAction extends AbstractPasswordStepAction {
private static final Logger LOG = LoggerFactory.getLogger(PINStepAction.class);
private static final String PIN_ID_CAN = "2";
// Translation constants
private static final String ERROR_CARD_REMOVED = "action.error.card.removed";
private static final String ERROR_INTERNAL = "action.error.internal";
......@@ -73,26 +59,14 @@ public class PINStepAction extends StepAction {
private final String pin;
private final String puk;
private final EACData eacData;
private final boolean capturePin;
private final byte[] slotHandle;
private final Dispatcher dispatcher;
private final PINStep step;
private final I18n lang = I18n.getTranslation("pace");
private final I18n langPin = I18n.getTranslation("pinplugin");
private final DynamicContext ctx;
private int retryCounter;
public PINStepAction(EACData eacData, boolean capturePin, byte[] slotHandle, Dispatcher dispatcher, PINStep step,
EacPinStatus status) {
super(step);
this.eacData = eacData;
this.capturePin = capturePin;
this.slotHandle = slotHandle;
this.dispatcher = dispatcher;
this.step = step;
this.ctx = DynamicContext.getInstance(TR03112Keys.INSTANCE_KEY);
super(eacData, capturePin, slotHandle, dispatcher, step);
switch (status) {
case RC3:
......@@ -219,78 +193,4 @@ public class PINStepAction extends StepAction {
}
}
private EstablishC