/**************************************************************************** * Copyright (C) 2013 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.addon.sal; import iso.std.iso_iec._24727.tech.schema.CardApplicationEndSession; import iso.std.iso_iec._24727.tech.schema.CardApplicationEndSessionResponse; import iso.std.iso_iec._24727.tech.schema.CardApplicationStartSession; import iso.std.iso_iec._24727.tech.schema.CardApplicationStartSessionResponse; import iso.std.iso_iec._24727.tech.schema.DIDAuthenticate; import iso.std.iso_iec._24727.tech.schema.DIDAuthenticateResponse; import iso.std.iso_iec._24727.tech.schema.DIDCreate; import iso.std.iso_iec._24727.tech.schema.DIDCreateResponse; import iso.std.iso_iec._24727.tech.schema.DIDDelete; import iso.std.iso_iec._24727.tech.schema.DIDDeleteResponse; import iso.std.iso_iec._24727.tech.schema.DIDUpdate; import iso.std.iso_iec._24727.tech.schema.DIDUpdateResponse; import iso.std.iso_iec._24727.tech.schema.Decipher; import iso.std.iso_iec._24727.tech.schema.DecipherResponse; import iso.std.iso_iec._24727.tech.schema.Encipher; import iso.std.iso_iec._24727.tech.schema.EncipherResponse; import iso.std.iso_iec._24727.tech.schema.GetRandom; import iso.std.iso_iec._24727.tech.schema.GetRandomResponse; import iso.std.iso_iec._24727.tech.schema.Hash; import iso.std.iso_iec._24727.tech.schema.HashResponse; import iso.std.iso_iec._24727.tech.schema.RequestType; import iso.std.iso_iec._24727.tech.schema.ResponseType; import iso.std.iso_iec._24727.tech.schema.Sign; import iso.std.iso_iec._24727.tech.schema.SignResponse; import iso.std.iso_iec._24727.tech.schema.VerifyCertificate; import iso.std.iso_iec._24727.tech.schema.VerifyCertificateResponse; import iso.std.iso_iec._24727.tech.schema.VerifySignature; import iso.std.iso_iec._24727.tech.schema.VerifySignatureResponse; import java.util.ArrayList; import java.util.EnumMap; import java.util.Map; import java.util.TreeMap; import javax.annotation.Nonnull; import javax.annotation.Nullable; import oasis.names.tc.dss._1_0.core.schema.Result; import org.openecard.common.ECardConstants; import org.openecard.common.WSHelper; /** * Basic implementation of a SAL protocol.<br/> * Some protocols may need to override this implementation in order to control Secure Messaging or * provide a customized protocol flow. * * @author Tobias Wich <tobias.wich@ecsec.de> */ public abstract class SALProtocolBaseImpl implements SALProtocol { /** Object map to transport protocol specific parameters. Used when executing ProtocolStep. */ protected final TreeMap<String, Object> internalData; /** List of ProtocolSteps, which are per default executed in order. */ protected final ArrayList<ProtocolStep<?, ?>> steps; protected final Map<FunctionType, ProtocolStep<?, ?>> statelessSteps; /** Index marking current step in the step list. */ protected int curStep = 0; protected SALProtocolBaseImpl() { this.internalData = new TreeMap<String, Object>(); this.steps = new ArrayList<ProtocolStep<?, ?>>(); this.statelessSteps = new EnumMap<FunctionType, ProtocolStep<?, ?>>(FunctionType.class); } @Override public TreeMap<String, Object> getInternalData() { return internalData; } private boolean hasNextStep() { return steps.size() > curStep; } private boolean hasNextProcessStep(FunctionType functionName) { if (hasNextStep()) { if (steps.get(curStep).getFunctionType() == functionName) { return true; } else { return false; } } else { return false; } } private boolean hasStatelessStep(FunctionType functionName) { return statelessSteps.containsKey(functionName); } @Override public boolean hasNextStep(FunctionType functionName) { if (hasStatelessStep(functionName)) { return true; } // check for a step in the process order return hasNextProcessStep(functionName); } @Override public boolean isFinished() { return ! hasNextStep(); } protected @Nonnull ProtocolStep<?, ?> addOrderStep(@Nonnull ProtocolStep<?, ?> step) { steps.add(step); return step; } /** * Adds the given step to the stateless steps of this protocol. * * @param step The protocol step to add to the map. * @return The previously associated step, or null if there was no previous association. */ protected @Nullable ProtocolStep<?, ?> addStatelessStep(@Nonnull ProtocolStep<?, ?> step) { return statelessSteps.put(step.getFunctionType(), step); } /** * Get next step and advance counter. * @return next step or null if none exists. */ private ProtocolStep<? extends RequestType, ? extends ResponseType> next(FunctionType functionName) { // process order step takes precedence over stateless steps if (hasNextProcessStep(functionName)) { ProtocolStep<?, ?> step = steps.get(curStep); curStep++; return step; } else { return statelessSteps.get(functionName); // returns null if nothing found } } private static <Req extends RequestType> ResponseType perform(Class<? extends ResponseType> responseClass, ProtocolStep step, Req request, TreeMap<String, Object> internalData) { // return not implemented result first if (step == null) { String msg = "There is no applicable protocol step at this point in the protocol flow."; Result r = WSHelper.makeResultError(ECardConstants.Minor.SAL.INAPPROPRIATE_PROTOCOL_FOR_ACTION, msg); return WSHelper.makeResponse(responseClass, r); } else { return step.perform(request, internalData); } } @Override public CardApplicationStartSessionResponse cardApplicationStartSession(CardApplicationStartSession param) { ProtocolStep<?, ?> s = next(FunctionType.CardApplicationStartSession); Class<? extends ResponseType> c = CardApplicationStartSessionResponse.class; return (CardApplicationStartSessionResponse) perform(c, s, param, internalData); } @Override public CardApplicationEndSessionResponse cardApplicationEndSession(CardApplicationEndSession param) { ProtocolStep<?, ?> s = next(FunctionType.CardApplicationEndSession); Class<? extends ResponseType> c = CardApplicationEndSessionResponse.class; return (CardApplicationEndSessionResponse) perform(c, s, param, internalData); } @Override public EncipherResponse encipher(Encipher param) { ProtocolStep<?, ?> s = next(FunctionType.Encipher); return (EncipherResponse) perform(EncipherResponse.class, s, param, internalData); } @Override public DecipherResponse decipher(Decipher param) { ProtocolStep<?, ?> s = next(FunctionType.Decipher); return (DecipherResponse) perform(DecipherResponse.class, s, param, internalData); } @Override public GetRandomResponse getRandom(GetRandom param) { ProtocolStep<?, ?> s = next(FunctionType.GetRandom); return (GetRandomResponse) perform(GetRandomResponse.class, s, param, internalData); } @Override public HashResponse hash(Hash param) { ProtocolStep<?, ?> s = next(FunctionType.Hash); return (HashResponse) perform(HashResponse.class, s, param, internalData); } @Override public SignResponse sign(Sign param) { ProtocolStep<?, ?> s = next(FunctionType.Sign); return (SignResponse) perform(SignResponse.class, s, param, internalData); } @Override public VerifySignatureResponse verifySignature(VerifySignature param) { ProtocolStep<?, ?> s = next(FunctionType.VerifySignature); return (VerifySignatureResponse) perform(VerifySignatureResponse.class, s, param, internalData); } @Override public VerifyCertificateResponse verifyCertificate(VerifyCertificate param) { ProtocolStep<?, ?> s = next(FunctionType.VerifyCertificate); return (VerifyCertificateResponse) perform(VerifyCertificateResponse.class, s, param, internalData); } @Override public DIDCreateResponse didCreate(DIDCreate param) { ProtocolStep<?, ?> s = next(FunctionType.DIDCreate); return (DIDCreateResponse) perform(DIDCreateResponse.class, s, param, internalData); } @Override public DIDUpdateResponse didUpdate(DIDUpdate param) { ProtocolStep<?, ?> s = next(FunctionType.DIDUpdate); return (DIDUpdateResponse) perform(DIDUpdateResponse.class, s, param, internalData); } @Override public DIDDeleteResponse didDelete(DIDDelete param) { ProtocolStep<?, ?> s = next(FunctionType.DIDDelete); return (DIDDeleteResponse) perform(DIDDeleteResponse.class, s, param, internalData); } @Override public DIDAuthenticateResponse didAuthenticate(DIDAuthenticate param) { ProtocolStep<?, ?> s = next(FunctionType.DIDAuthenticate); return (DIDAuthenticateResponse) perform(DIDAuthenticateResponse.class, s, param, internalData); } /// /// Secure Messaging functions /// Overwrite in subclass when needed /// @Override public boolean needsSM() { return false; } @Override public byte[] applySM(byte[] commandAPDU) { return commandAPDU; } @Override public byte[] removeSM(byte[] responseAPDU) { return responseAPDU; } }