/**************************************************************************** * Copyright (C) 2012 HS Coburg. * 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.plugins.abc4trustplugin.gui; import iso.std.iso_iec._24727.tech.schema.DIDAuthenticationDataType; import iso.std.iso_iec._24727.tech.schema.DestroyChannel; import iso.std.iso_iec._24727.tech.schema.EstablishChannel; import iso.std.iso_iec._24727.tech.schema.EstablishChannelResponse; import iso.std.iso_iec._24727.tech.schema.Transmit; import iso.std.iso_iec._24727.tech.schema.TransmitResponse; import iso.std.iso_iec._24727.tech.schema.InputAPDUInfoType; import java.lang.reflect.InvocationTargetException; import java.lang.Character; import java.util.Map; import java.math.BigInteger; 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.ifd.anytype.PACEInputType; import org.openecard.common.interfaces.Dispatcher; import org.openecard.common.interfaces.DispatcherException; import org.openecard.common.util.StringUtils; 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.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.ByteBuffer; /** * StepAction for obtaining the administration PIN. * * @author Antonio de la Piedra <a.delapiedra@cs.ru.nl> */ public class PUKStepAction extends StepAction { private static final Logger logger = LoggerFactory.getLogger(PUKStepAction.class); private static final String PIN_ID_PUK = "4"; private static final byte[] credVerifyAPDU = StringUtils.toByteArray("0020000108"); private static final byte[] credListAPDU = StringUtils.toByteArray("803A0000"); private static final byte[] endAPDU = StringUtils.toByteArray("0000"); private final boolean capturePin; private final byte[] slotHandle; private final Dispatcher dispatcher; private String puk; private byte[] responseCredentials; /** * Create a new instance of PUKStepAction. * * @param capturePin True if the PIN has to be captured by software else false * @param slotHandle The unique SlotHandle for the card to use * @param step the step this action belongs to * @param dispatcher The Dispatcher to use */ public PUKStepAction(boolean capturePin, byte[] slotHandle, Dispatcher dispatcher, Step step) { super(step); this.capturePin = capturePin; this.slotHandle = slotHandle; this.dispatcher = dispatcher; } @Override public StepActionResult perform(Map<String, ExecutionResults> oldResults, StepResult result) { if (result.isBack()) { return new StepActionResult(StepActionResultStatus.BACK); } ExecutionResults executionResults = oldResults.get(getStepID()); verifyUserInput(executionResults); try { String pin_hex = String.format("%x", new BigInteger(1, puk.getBytes("UTF-8"))); int len = pin_hex.length(); byte[] pin_hex_byte = new byte[len / 2]; for (int i = 0; i < len; i += 2) pin_hex_byte[i / 2] = (byte) ((Character.digit(pin_hex.charAt(i), 16) << 4) + Character.digit(pin_hex.charAt(i+1), 16)); Transmit t = new Transmit(); t.setSlotHandle(slotHandle); InputAPDUInfoType inputAPDU = new InputAPDUInfoType(); byte[] combined = new byte[credVerifyAPDU.length + pin_hex_byte.length]; System.arraycopy(credVerifyAPDU, 0, combined, 0 , credVerifyAPDU.length); System.arraycopy(pin_hex_byte, 0, combined, credVerifyAPDU.length, pin_hex_byte.length); byte[] finalVerify = new byte[combined.length + endAPDU.length]; System.arraycopy(combined, 0, finalVerify, 0 , combined.length); System.arraycopy(endAPDU, 0, finalVerify, combined.length, endAPDU.length); inputAPDU.setInputAPDU(finalVerify); t.getInputAPDUInfo().add(inputAPDU); TransmitResponse response = (TransmitResponse) dispatcher.deliver(t); byte[] responseAPDU = response.getOutputAPDU().get(0); } catch (java.io.UnsupportedEncodingException e) { logger.error("The credential PIN cannot be parsed.", e); return null; } catch (Exception e) { logger.error("The credential PIN verification failed.", e); return null; } try { Transmit tr = new Transmit(); tr.setSlotHandle(slotHandle); InputAPDUInfoType inputAPDU = new InputAPDUInfoType(); inputAPDU.setInputAPDU(credListAPDU); tr.getInputAPDUInfo().add(inputAPDU); TransmitResponse response = (TransmitResponse) dispatcher.deliver(tr); this.responseCredentials = response.getOutputAPDU().get(0); } catch (DispatcherException e) { logger.error("Transmission of the get credentials APDU failed", e); return null; } catch (java.lang.reflect.InvocationTargetException e) { logger.error("Transmission of the get credentials APDU failed", e); return null; } return new StepActionResult(StepActionResultStatus.NEXT); } /** * Verify the input of the user (e.g. no empty mandatory fields, pin length, allowed charset). * * @param executionResults The results containing the OutputInfoUnits of interest. * @return True if the input of the user could be verified, else false */ private boolean verifyUserInput(ExecutionResults executionResults) { PasswordField pukField = (PasswordField) executionResults.getResult(UnblockPINDialog.PUK_FIELD); puk = pukField.getValue(); if (puk.isEmpty()) { return false; } return true; } public byte[] getCredentials() { return this.responseCredentials; } }