/****************************************************************************
* 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.ifd.protocol.pace;
import iso.std.iso_iec._24727.tech.schema.EstablishChannel;
import iso.std.iso_iec._24727.tech.schema.EstablishChannelResponse;
import java.io.UnsupportedEncodingException;
import org.openecard.common.ECardConstants;
import org.openecard.common.WSHelper;
import org.openecard.common.apdu.utils.CardUtils;
import org.openecard.common.ifd.Protocol;
import org.openecard.common.ifd.anytype.PACEInputType;
import org.openecard.common.ifd.anytype.PACEOutputType;
import org.openecard.common.ifd.protocol.exception.ProtocolException;
import org.openecard.common.interfaces.Dispatcher;
import org.openecard.crypto.common.asn1.eac.PACESecurityInfos;
import org.openecard.crypto.common.asn1.eac.SecurityInfos;
import org.openecard.crypto.common.asn1.eac.ef.EFCardAccess;
import org.openecard.gui.UserConsent;
import org.openecard.ifd.protocol.pace.gui.GUIContentMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Moritz Horsch <horsch@cdc.informatik.tu-darmstadt.de>
*/
public class PACEProtocol implements Protocol {
private static final Logger logger = LoggerFactory.getLogger(PACEProtocol.class.getName());
private SecureMessaging sm;
@Override
public EstablishChannelResponse establish(EstablishChannel req, Dispatcher dispatcher, UserConsent gui) {
EstablishChannelResponse response = new EstablishChannelResponse();
try {
// Get parameters for the PACE protocol
PACEInputType paceInput = new PACEInputType(req.getAuthenticationProtocolData());
byte[] pin;
byte pinID = paceInput.getPINID();
byte[] chat = paceInput.getCHAT();
if (paceInput.getPIN() == null || paceInput.getPIN().isEmpty()) {
// GUI request
GUIContentMap content = new GUIContentMap();
content.add(GUIContentMap.ELEMENT.PIN_ID, pinID);
PACEUserConsent paceUserConsent = new PACEUserConsent(gui);
paceUserConsent.show(content);
pin = ((String) content.get(GUIContentMap.ELEMENT.PIN)).getBytes(PACEConstants.PIN_CHARSET);
} else {
pin = paceInput.getPIN().getBytes(PACEConstants.PIN_CHARSET);
}
if (pin == null || pin.length == 0) {
response.setResult(WSHelper.makeResultError(
ECardConstants.Minor.IFD.CANCELLATION_BY_USER,
"No PIN was entered."));
return response;
}
// Read EF.CardAccess from card
byte[] slotHandle = req.getSlotHandle();
byte[] efcadata = CardUtils.readFile(dispatcher, slotHandle, PACEConstants.EF_CARDACCESS_FID);
// Parse SecurityInfos and get PACESecurityInfos
SecurityInfos sis = SecurityInfos.getInstance(efcadata);
EFCardAccess efca = new EFCardAccess(sis);
PACESecurityInfos psi = efca.getPACESecurityInfos();
// Start PACE
PACEImplementation pace = new PACEImplementation(dispatcher, slotHandle, psi);
pace.execute(pin, pinID, chat);
// Establish Secure Messaging channel
sm = new SecureMessaging(pace.getKeyMAC(), pace.getKeyENC());
// Create AuthenticationProtocolData (PACEOutputType)
PACEOutputType paceOutput = paceInput.getOutputType();
paceOutput.setEFCardAccess(efcadata);
paceOutput.setCurrentCAR(pace.getCurrentCAR());
paceOutput.setPreviousCAR(pace.getPreviousCAR());
paceOutput.setIDPICC(pace.getIDPICC());
paceOutput.setRetryCounter(pace.getRetryCounter());
// Create EstablishChannelResponse
response.setResult(WSHelper.makeResultOK());
response.setAuthenticationProtocolData(paceOutput.getAuthDataType());
} catch (UnsupportedEncodingException ex) {
logger.error(ex.getMessage(), ex);
response.setResult(WSHelper.makeResultError(
ECardConstants.Minor.IFD.IO.UNKNOWN_PIN_FORMAT,
"Cannot encode the PIN in " + PACEConstants.PIN_CHARSET + " charset."));
} catch (ProtocolException ex) {
logger.error(ex.getMessage(), ex);
response.setResult(WSHelper.makeResult(ex));
} catch (Throwable ex) {
logger.error(ex.getMessage(), ex);
response.setResult(WSHelper.makeResult(ex));
}
return response;
}
@Override
public byte[] applySM(byte[] commandAPDU) {
try {
if (sm != null) {
return sm.encrypt(commandAPDU);
} else {
throw new RuntimeException("No established Secure Messaging channel available");
}
} catch (Exception ex) {
sm = null;
logger.error(ex.getMessage(), ex);
throw new RuntimeException(ex);
}
}
@Override
public byte[] removeSM(byte[] responseAPDU) {
try {
if (sm != null) {
return sm.decrypt(responseAPDU);
} else {
throw new RuntimeException("No established Secure Messaging channel available");
}
} catch (Exception ex) {
sm = null;
logger.error(ex.getMessage(), ex);
throw new RuntimeException(ex);
}
}
}