use of org.openecard.common.apdu.common.CardResponseAPDU in project open-ecard by ecsec.
the class AbstractTerminal method verifyUser.
public VerifyUserResponse verifyUser(VerifyUser verify) throws SCIOException, IFDException {
byte[] handle = verify.getSlotHandle();
// get capabilities
getCapabilities();
// check if is possible to perform PinCompare protocol
List<String> protoList = this.capabilities.getSlotCapability().get(0).getProtocol();
if (!protoList.contains(ECardConstants.Protocol.PIN_COMPARE)) {
throw new IFDException("PinCompare protocol is not supported by this IFD.");
}
// get values from requested command
InputUnitType inputUnit = verify.getInputUnit();
AltVUMessagesType allMsgs = getMessagesOrDefaults(verify.getAltVUMessages());
BigInteger firstTimeout = verify.getTimeoutUntilFirstKey();
firstTimeout = (firstTimeout == null) ? BigInteger.valueOf(60000) : firstTimeout;
BigInteger otherTimeout = verify.getTimeoutAfterFirstKey();
otherTimeout = (otherTimeout == null) ? BigInteger.valueOf(15000) : otherTimeout;
final byte[] template = verify.getTemplate();
VerifyUserResponse response;
Result result;
// check which type of authentication to perform
if (inputUnit.getBiometricInput() != null) {
// TODO: implement
String msg = "Biometric authentication not supported by IFD.";
IFDException ex = new IFDException(ECardConstants.Minor.IFD.IO.UNKNOWN_INPUT_UNIT, msg);
LOG.warn(ex.getMessage(), ex);
throw ex;
} else if (inputUnit.getPinInput() != null) {
final PinInputType pinInput = inputUnit.getPinInput();
// we have a sophisticated card reader
if (terminalInfo.supportsPinCompare()) {
// create custom pinAction to submit pin to terminal
NativePinStepAction pinAction = new NativePinStepAction("enter-pin", pinInput, channel, terminalInfo, template);
// display message instructing user what to do
UserConsentDescription uc = pinUserConsent("action.changepin.userconsent.pinstep.title", pinAction);
UserConsentNavigator ucr = gui.obtainNavigator(uc);
ExecutionEngine exec = new ExecutionEngine(ucr);
// run gui
ResultStatus status = exec.process();
if (status == ResultStatus.CANCEL) {
String msg = "PIN entry cancelled by user.";
LOG.warn(msg);
result = WSHelper.makeResultError(ECardConstants.Minor.IFD.CANCELLATION_BY_USER, msg);
response = WSHelper.makeResponse(VerifyUserResponse.class, result);
} else if (pinAction.exception != null) {
LOG.warn(pinAction.exception.getMessage(), pinAction.exception);
result = WSHelper.makeResultError(ECardConstants.Minor.IFD.AUTHENTICATION_FAILED, pinAction.exception.getMessage());
response = WSHelper.makeResponse(VerifyUserResponse.class, result);
} else {
// input by user
byte[] verifyResponse = pinAction.response;
// evaluate result
result = checkNativePinVerify(verifyResponse);
response = WSHelper.makeResponse(VerifyUserResponse.class, result);
response.setResponse(verifyResponse);
}
return response;
} else if (isVirtual()) {
// software method
// get pin, encode and send
int minLength = pinInput.getPasswordAttributes().getMinLength().intValue();
int maxLength = pinInput.getPasswordAttributes().getMaxLength().intValue();
UserConsentDescription uc = pinUserConsent("action.changepin.userconsent.pinstep.title", minLength, maxLength);
UserConsentNavigator ucr = gui.obtainNavigator(uc);
ExecutionEngine exec = new ExecutionEngine(ucr);
ResultStatus status = exec.process();
if (status == ResultStatus.CANCEL) {
String msg = "PIN entry cancelled by user.";
LOG.warn(msg);
result = WSHelper.makeResultError(ECardConstants.Minor.IFD.CANCELLATION_BY_USER, msg);
response = WSHelper.makeResponse(VerifyUserResponse.class, result);
return response;
}
char[] rawPIN = getPinFromUserConsent(exec);
PasswordAttributesType attributes = pinInput.getPasswordAttributes();
Transmit verifyTransmit;
try {
verifyTransmit = PINUtils.buildVerifyTransmit(rawPIN, attributes, template, handle);
} catch (UtilException e) {
String msg = "Failed to create the verifyTransmit message.";
LOG.error(msg, e);
result = WSHelper.makeResultError(ECardConstants.Minor.IFD.UNKNOWN_ERROR, msg);
response = WSHelper.makeResponse(VerifyUserResponse.class, result);
return response;
} finally {
Arrays.fill(rawPIN, ' ');
}
// send to reader
TransmitResponse transResp;
try {
transResp = ifd.transmit(verifyTransmit);
} finally {
// blank PIN APDU
for (InputAPDUInfoType apdu : verifyTransmit.getInputAPDUInfo()) {
byte[] rawApdu = apdu.getInputAPDU();
if (rawApdu != null) {
Arrays.fill(rawApdu, (byte) 0);
}
}
}
// produce messages
if (transResp.getResult().getResultMajor().equals(ECardConstants.Major.ERROR)) {
if (transResp.getOutputAPDU().isEmpty()) {
result = WSHelper.makeResultError(ECardConstants.Minor.IFD.AUTHENTICATION_FAILED, transResp.getResult().getResultMessage().getValue());
response = WSHelper.makeResponse(VerifyUserResponse.class, result);
return response;
} else {
response = WSHelper.makeResponse(VerifyUserResponse.class, transResp.getResult());
response.setResponse(transResp.getOutputAPDU().get(0));
// TODO: move this code to the PIN Compare protocol
if (response.getResponse() != null) {
CardResponseAPDU resApdu = new CardResponseAPDU(response.getResponse());
byte[] statusBytes = resApdu.getStatusBytes();
boolean isMainStatus = statusBytes[0] == (byte) 0x63;
boolean isMinorStatus = (statusBytes[1] & (byte) 0xF0) == (byte) 0xC0;
int triesLeft = statusBytes[1] & 0x0F;
if (isMainStatus && isMinorStatus && triesLeft > 0) {
LOG.info("PIN not entered successful. There are {} tries left.", statusBytes[1] & 0x0F);
return verifyUser(verify);
}
}
return response;
}
} else {
response = WSHelper.makeResponse(VerifyUserResponse.class, transResp.getResult());
response.setResponse(transResp.getOutputAPDU().get(0));
return response;
}
} else {
IFDException ex = new IFDException("No input unit available to perform PinCompare protocol.");
LOG.warn(ex.getMessage(), ex);
throw ex;
}
} else {
String msg = "Unsupported authentication input method requested.";
IFDException ex = new IFDException(ECardConstants.Minor.IFD.IO.UNKNOWN_INPUT_UNIT, msg);
LOG.warn(ex.getMessage(), ex);
throw ex;
}
}
use of org.openecard.common.apdu.common.CardResponseAPDU in project open-ecard by ecsec.
the class SingleThreadChannel method transmit.
@Nonnull
@Override
public byte[] transmit(@Nonnull byte[] input, @Nonnull List<byte[]> responses) throws TransmitException, SCIOException, IllegalStateException {
byte[] inputAPDU = input;
if (isSM()) {
LOG.debug("Apply secure messaging to APDU: {}", ByteUtils.toHexString(inputAPDU, true));
inputAPDU = smProtocol.applySM(inputAPDU);
}
LOG.debug("Send APDU: {}", ByteUtils.toHexString(inputAPDU, true));
CardResponseAPDU rapdu = transmit(inputAPDU);
byte[] result = rapdu.toByteArray();
LOG.debug("Receive APDU: {}", ByteUtils.toHexString(result, true));
if (isSM()) {
result = smProtocol.removeSM(result);
LOG.debug("Remove secure messaging from APDU: {}", ByteUtils.toHexString(result, true));
}
// get status word
byte[] sw = new byte[2];
sw[0] = result[result.length - 2];
sw[1] = result[result.length - 1];
// return without validation when no expected results given
if (responses.isEmpty()) {
return result;
}
// verify result
for (byte[] expected : responses) {
// AcceptableStatusCode-elements containing only one byte match all status codes starting with this byte
if (ByteUtils.isPrefix(expected, sw)) {
return result;
}
}
// not an expected result
String msg = "The returned status code is not in the list of expected status codes. The returned code is:\n";
TransmitException tex = new TransmitException(result, msg + CardCommandStatus.getMessage(sw));
throw tex;
}
use of org.openecard.common.apdu.common.CardResponseAPDU in project open-ecard by ecsec.
the class NFCCardChannel method transmit.
@Override
public int transmit(ByteBuffer command, ByteBuffer response) throws SCIOException {
CardResponseAPDU cra = transmit(command.array());
byte[] data = cra.toByteArray();
response.put(data);
return data.length;
}
use of org.openecard.common.apdu.common.CardResponseAPDU in project open-ecard by ecsec.
the class TinySAL method dataSetSelect.
/**
* The DataSetSelect function selects a data set in a card application.
* See BSI-TR-03112-4, version 1.1.2, section 3.4.3.
*
* @param request DataSetSelect
* @return DataSetSelectResponse
*/
@Publish
@Override
public DataSetSelectResponse dataSetSelect(DataSetSelect request) {
DataSetSelectResponse response = WSHelper.makeResponse(DataSetSelectResponse.class, WSHelper.makeResultOK());
try {
ConnectionHandleType connectionHandle = SALUtils.getConnectionHandle(request);
CardStateEntry cardStateEntry = SALUtils.getCardStateEntry(states, connectionHandle);
byte[] applicationID = connectionHandle.getCardApplication();
String dataSetName = request.getDataSetName();
Assert.assertIncorrectParameter(dataSetName, "The parameter DataSetName is empty.");
CardInfoWrapper cardInfoWrapper = cardStateEntry.getInfo();
DataSetInfoType dataSetInfo = cardInfoWrapper.getDataSet(dataSetName, applicationID);
Assert.assertNamedEntityNotFound(dataSetInfo, "The given DataSet cannot be found.");
Assert.securityConditionDataSet(cardStateEntry, applicationID, dataSetName, NamedDataServiceActionName.DATA_SET_SELECT);
byte[] fileID = dataSetInfo.getDataSetPath().getEfIdOrPath();
byte[] slotHandle = connectionHandle.getSlotHandle();
CardResponseAPDU result = CardUtils.selectFileWithOptions(env.getDispatcher(), slotHandle, fileID, null, CardUtils.FCP_RESPONSE_DATA);
FCP fcp = null;
if (result != null && result.getData().length > 0) {
try {
fcp = new FCP(result.getData());
} catch (TLVException ex) {
LOG.warn("Invalid FCP received.");
}
}
if (fcp == null) {
LOG.info("Using fake FCP.");
fcp = new FCP(createFakeFCP(Arrays.copyOfRange(fileID, fileID.length - 2, fileID.length)));
}
cardStateEntry.setFCPOfSelectedEF(fcp);
} catch (ECardException e) {
response.setResult(e.getResult());
} catch (Exception e) {
LOG.error(e.getMessage(), e);
throwThreadKillException(e);
response.setResult(WSHelper.makeResult(e));
}
return response;
}
use of org.openecard.common.apdu.common.CardResponseAPDU in project open-ecard by ecsec.
the class TinySAL method cardApplicationConnect.
/**
* The CardApplicationConnect function establishes an unauthenticated connection between the client
* application and the card application.
* See BSI-TR-03112-4, version 1.1.2, section 3.2.1.
*
* @param request CardApplicationConnect
* @return CardApplicationConnectResponse
*/
@Override
public CardApplicationConnectResponse cardApplicationConnect(CardApplicationConnect request) {
CardApplicationConnectResponse response = WSHelper.makeResponse(CardApplicationConnectResponse.class, WSHelper.makeResultOK());
try {
CardApplicationPathType cardAppPath = request.getCardApplicationPath();
Assert.assertIncorrectParameter(cardAppPath, "The parameter CardAppPathRequest is empty.");
Set<CardStateEntry> cardStateEntrySet = states.getMatchingEntries(cardAppPath, false);
Assert.assertIncorrectParameter(cardStateEntrySet, "The given ConnectionHandle is invalid.");
/*
* [TR-03112-4] If the provided path fragments are valid for more than one card application
* the eCard-API-Framework SHALL return any of the possible choices.
*/
CardStateEntry cardStateEntry = cardStateEntrySet.iterator().next();
byte[] applicationID = cardAppPath.getCardApplication();
if (applicationID == null) {
if (cardStateEntry.getImplicitlySelectedApplicationIdentifier() != null) {
applicationID = cardStateEntry.getImplicitlySelectedApplicationIdentifier();
} else {
applicationID = MF;
}
}
Assert.securityConditionApplication(cardStateEntry, applicationID, ConnectionServiceActionName.CARD_APPLICATION_CONNECT);
// Connect to the card
ConnectionHandleType handle = cardStateEntry.handleCopy();
cardStateEntry = cardStateEntry.derive(handle);
Connect connect = new Connect();
connect.setContextHandle(handle.getContextHandle());
connect.setIFDName(handle.getIFDName());
connect.setSlot(handle.getSlotIndex());
ConnectResponse connectResponse = (ConnectResponse) env.getDispatcher().safeDeliver(connect);
WSHelper.checkResult(connectResponse);
// Select the card application
CardCommandAPDU select;
// TODO: proper determination of path, file and app id
if (applicationID.length == 2) {
select = new Select.File(applicationID);
List<byte[]> responses = new ArrayList<>();
responses.add(TrailerConstants.Success.OK());
responses.add(TrailerConstants.Error.WRONG_P1_P2());
CardResponseAPDU resp = select.transmit(env.getDispatcher(), connectResponse.getSlotHandle(), responses);
if (Arrays.equals(resp.getTrailer(), TrailerConstants.Error.WRONG_P1_P2())) {
select = new Select.AbsolutePath(applicationID);
select.transmit(env.getDispatcher(), connectResponse.getSlotHandle());
}
} else {
select = new Select.Application(applicationID);
select.transmit(env.getDispatcher(), connectResponse.getSlotHandle());
}
cardStateEntry.setCurrentCardApplication(applicationID);
cardStateEntry.setSlotHandle(connectResponse.getSlotHandle());
// reset the ef FCP
cardStateEntry.unsetFCPOfSelectedEF();
states.addEntry(cardStateEntry);
response.setConnectionHandle(cardStateEntry.handleCopy());
response.getConnectionHandle().setCardApplication(applicationID);
} catch (ECardException e) {
response.setResult(e.getResult());
}
return response;
}
Aggregations