use of org.openecard.common.interfaces.DispatcherException in project open-ecard by ecsec.
the class MessageDispatcher method deliver.
@Override
public Object deliver(Object req) throws DispatcherException, InvocationTargetException {
EventDispatcher disp = environment.getEventDispatcher();
// send API CALL STARTED event
ConnectionHandleType handle = HandlerUtils.extractHandle(req);
if (disp != null && req instanceof RequestType) {
ApiCallEventObject startEvt = new ApiCallEventObject(handle, (RequestType) req);
LOG.debug("Sending API_CALL_STARTED event.");
disp.notify(EventType.API_CALL_STARTED, startEvt);
}
try {
Class<?> reqClass = req.getClass();
Service s = getService(reqClass);
Object serviceImpl = getServiceImpl(s);
LOG.debug("Delivering message of type: {}", req.getClass().getName());
Object result = s.invoke(serviceImpl, req);
// send API CALL FINISHED event
if (disp != null && req instanceof RequestType && result instanceof ResponseType) {
ApiCallEventObject finEvt = new ApiCallEventObject(handle, (RequestType) req);
finEvt.setResponse((ResponseType) result);
LOG.debug("Sending API_CALL_FINISHED event.");
disp.notify(EventType.API_CALL_FINISHED, finEvt);
}
return result;
} catch (IllegalAccessException | IllegalArgumentException ex) {
throw new DispatcherException(ex);
}
}
use of org.openecard.common.interfaces.DispatcherException in project open-ecard by ecsec.
the class Service method invoke.
/**
* Invokes the webservice method related to the request object in the given webservice class instance.
*
* @param ifaceImpl The instance implementing the webservice interface this instance is responsible for.
* @param req The request object to dispatch.
* @return The result of the method invocation.
* @throws DispatcherException In case an error happens in the reflections part of the dispatcher.
* @throws InvocationTargetException In case the dispatched method throws en exception.
*/
public Object invoke(Object ifaceImpl, Object req) throws DispatcherException, InvocationTargetException {
try {
MessageLogger l = getLogger(ifaceImpl);
Class<?> reqClass = req.getClass();
Method m = getMethod(reqClass.getName());
// invoke method
l.logRequest(req);
Object res = m.invoke(ifaceImpl, req);
l.logResponse(res);
return res;
} catch (IllegalAccessException | NoSuchMethodException | IllegalArgumentException ex) {
throw new DispatcherException(ex);
}
}
use of org.openecard.common.interfaces.DispatcherException in project open-ecard by ecsec.
the class PACEStep method perform.
@Override
public DIDAuthenticateResponse perform(DIDAuthenticate request, Map<String, Object> internalData) {
// get context to save values in
DynamicContext dynCtx = DynamicContext.getInstance(TR03112Keys.INSTANCE_KEY);
DIDAuthenticate didAuthenticate = request;
DIDAuthenticateResponse response = new DIDAuthenticateResponse();
ConnectionHandleType conHandle = (ConnectionHandleType) dynCtx.get(TR03112Keys.CONNECTION_HANDLE);
try {
ObjectSchemaValidator valid = (ObjectSchemaValidator) dynCtx.getPromise(EACProtocol.SCHEMA_VALIDATOR).deref();
boolean messageValid = valid.validateObject(request);
if (!messageValid) {
String msg = "Validation of the EAC1InputType message failed.";
LOG.error(msg);
dynCtx.put(EACProtocol.AUTHENTICATION_FAILED, true);
response.setResult(WSHelper.makeResultError(ECardConstants.Minor.App.INCORRECT_PARM, msg));
return response;
}
} catch (ObjectValidatorException ex) {
String msg = "Validation of the EAC1InputType message failed due to invalid input data.";
LOG.error(msg, ex);
dynCtx.put(EACProtocol.AUTHENTICATION_FAILED, true);
response.setResult(WSHelper.makeResultError(ECardConstants.Minor.App.INT_ERROR, msg));
return response;
} catch (InterruptedException ex) {
String msg = "Thread interrupted while waiting for schema validator instance.";
LOG.error(msg, ex);
dynCtx.put(EACProtocol.AUTHENTICATION_FAILED, true);
response.setResult(WSHelper.makeResultError(ECardConstants.Minor.App.INT_ERROR, msg));
return response;
}
if (!ByteUtils.compare(conHandle.getSlotHandle(), didAuthenticate.getConnectionHandle().getSlotHandle())) {
String msg = "Invalid connection handle given in DIDAuthenticate message.";
Result r = WSHelper.makeResultError(ECardConstants.Minor.SAL.UNKNOWN_HANDLE, msg);
response.setResult(r);
dynCtx.put(EACProtocol.AUTHENTICATION_FAILED, true);
return response;
}
byte[] slotHandle = conHandle.getSlotHandle();
dynCtx.put(EACProtocol.SLOT_HANDLE, slotHandle);
dynCtx.put(EACProtocol.DISPATCHER, dispatcher);
try {
EAC1InputType eac1Input = new EAC1InputType(didAuthenticate.getAuthenticationProtocolData());
EAC1OutputType eac1Output = eac1Input.getOutputType();
AuthenticatedAuxiliaryData aad = new AuthenticatedAuxiliaryData(eac1Input.getAuthenticatedAuxiliaryData());
byte pinID = PasswordID.valueOf(didAuthenticate.getDIDName()).getByte();
final String passwordType = PasswordID.parse(pinID).getString();
// determine PACE capabilities of the terminal
boolean nativePace = genericPACESupport(conHandle);
dynCtx.put(EACProtocol.IS_NATIVE_PACE, nativePace);
// Certificate chain
CardVerifiableCertificateChain certChain = new CardVerifiableCertificateChain(eac1Input.getCertificates());
byte[] rawCertificateDescription = eac1Input.getCertificateDescription();
CertificateDescription certDescription = CertificateDescription.getInstance(rawCertificateDescription);
// put CertificateDescription into DynamicContext which is needed for later checks
dynCtx.put(TR03112Keys.ESERVICE_CERTIFICATE_DESC, certDescription);
// according to BSI-INSTANCE_KEY-7 we MUST perform some checks immediately after receiving the eService cert
Result activationChecksResult = performChecks(certDescription, dynCtx);
if (!ECardConstants.Major.OK.equals(activationChecksResult.getResultMajor())) {
response.setResult(activationChecksResult);
dynCtx.put(EACProtocol.AUTHENTICATION_FAILED, true);
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);
dynCtx.put(EACProtocol.PACE_MARKER, paceMarker);
// 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
CHAT taCHAT = taCert.getCHAT();
// an other role.
if (taCHAT.getRole() != CHAT.Role.AUTHENTICATION_TERMINAL) {
String msg = "Unsupported terminal type in Terminal Certificate referenced. Refernced terminal type is " + taCHAT.getRole().toString() + ".";
response.setResult(WSHelper.makeResultError(ECardConstants.Minor.App.INCORRECT_PARM, msg));
dynCtx.put(EACProtocol.AUTHENTICATION_FAILED, true);
return response;
}
CHATVerifier.verfiy(taCHAT, requiredCHAT);
// remove overlapping values from optional chat
optionalCHAT.restrictAccessRights(taCHAT);
// Prepare data in DIDAuthenticate for GUI
final EACData eacData = new EACData();
eacData.didRequest = didAuthenticate;
eacData.certificate = certChain.getTerminalCertificate();
eacData.certificateDescription = certDescription;
eacData.rawCertificateDescription = rawCertificateDescription;
eacData.transactionInfo = eac1Input.getTransactionInfo();
eacData.requiredCHAT = requiredCHAT;
eacData.optionalCHAT = optionalCHAT;
eacData.selectedCHAT = requiredCHAT;
eacData.aad = aad;
eacData.pinID = pinID;
eacData.passwordType = passwordType;
dynCtx.put(EACProtocol.EAC_DATA, eacData);
// get initial pin status
InputAPDUInfoType input = new InputAPDUInfoType();
input.setInputAPDU(new byte[] { (byte) 0x00, (byte) 0x22, (byte) 0xC1, (byte) 0xA4, (byte) 0x0F, (byte) 0x80, (byte) 0x0A, (byte) 0x04, (byte) 0x00, (byte) 0x7F, (byte) 0x00, (byte) 0x07, (byte) 0x02, (byte) 0x02, (byte) 0x04, (byte) 0x02, (byte) 0x02, (byte) 0x83, (byte) 0x01, (byte) 0x03 });
input.getAcceptableStatusCode().addAll(EacPinStatus.getCodes());
Transmit transmit = new Transmit();
transmit.setSlotHandle(slotHandle);
transmit.getInputAPDUInfo().add(input);
TransmitResponse pinCheckResponse = (TransmitResponse) dispatcher.safeDeliver(transmit);
WSHelper.checkResult(pinCheckResponse);
byte[] output = pinCheckResponse.getOutputAPDU().get(0);
CardResponseAPDU outputApdu = new CardResponseAPDU(output);
byte[] status = outputApdu.getStatusBytes();
dynCtx.put(EACProtocol.PIN_STATUS, EacPinStatus.fromCode(status));
// define GUI depending on the PIN status
final UserConsentDescription uc = new UserConsentDescription(LANG.translationForKey(TITLE));
final CardMonitor cardMon;
uc.setDialogType("EAC");
// create GUI and init executor
cardMon = new CardMonitor();
CardRemovedFilter filter = new CardRemovedFilter(conHandle.getIFDName(), conHandle.getSlotIndex());
eventDispatcher.add(cardMon, filter);
CVCStep cvcStep = new CVCStep(eacData);
cvcStep.setBackgroundTask(cardMon);
CVCStepAction cvcStepAction = new CVCStepAction(cvcStep);
cvcStep.setAction(cvcStepAction);
uc.getSteps().add(cvcStep);
uc.getSteps().add(CHATStep.createDummy());
uc.getSteps().add(PINStep.createDummy(passwordType));
ProcessingStep procStep = new ProcessingStep();
ProcessingStepAction procStepAction = new ProcessingStepAction(procStep);
procStep.setAction(procStepAction);
uc.getSteps().add(procStep);
Thread guiThread = new Thread(new Runnable() {
@Override
public void run() {
try {
// get context here because it is thread local
DynamicContext dynCtx = DynamicContext.getInstance(TR03112Keys.INSTANCE_KEY);
if (!uc.getSteps().isEmpty()) {
UserConsentNavigator navigator = gui.obtainNavigator(uc);
dynCtx.put(TR03112Keys.OPEN_USER_CONSENT_NAVIGATOR, navigator);
ExecutionEngine exec = new ExecutionEngine(navigator);
ResultStatus guiResult = exec.process();
dynCtx.put(EACProtocol.GUI_RESULT, guiResult);
if (guiResult == ResultStatus.CANCEL) {
Promise<Object> pPaceSuccessful = dynCtx.getPromise(EACProtocol.PACE_EXCEPTION);
if (!pPaceSuccessful.isDelivered()) {
pPaceSuccessful.deliver(WSHelper.createException(WSHelper.makeResultError(ECardConstants.Minor.SAL.CANCELLATION_BY_USER, "User canceled the PACE dialog.")));
}
}
}
} finally {
if (cardMon != null) {
eventDispatcher.del(cardMon);
}
}
}
}, "EAC-GUI");
guiThread.start();
// wait for PACE to finish
Promise<Object> pPaceException = dynCtx.getPromise(EACProtocol.PACE_EXCEPTION);
Object pPaceError = pPaceException.deref();
if (pPaceError != null) {
if (pPaceError instanceof WSHelper.WSException) {
response.setResult(((WSHelper.WSException) pPaceError).getResult());
return response;
} else if (pPaceError instanceof DispatcherException | pPaceError instanceof InvocationTargetException) {
String msg = "Internal error while PACE authentication.";
Result r = WSHelper.makeResultError(ECardConstants.Minor.App.INT_ERROR, msg);
response.setResult(r);
return response;
} else {
String msg = "Unknown error while PACE authentication.";
Result r = WSHelper.makeResultError(ECardConstants.Minor.App.UNKNOWN_ERROR, msg);
response.setResult(r);
return response;
}
}
// get challenge from card
TerminalAuthentication ta = new TerminalAuthentication(dispatcher, slotHandle);
byte[] challenge = ta.getChallenge();
// prepare DIDAuthenticationResponse
DIDAuthenticationDataType data = eacData.paceResponse.getAuthenticationProtocolData();
AuthDataMap paceOutputMap = new AuthDataMap(data);
// int retryCounter = Integer.valueOf(paceOutputMap.getContentAsString(PACEOutputType.RETRY_COUNTER));
byte[] efCardAccess = paceOutputMap.getContentAsBytes(PACEOutputType.EF_CARD_ACCESS);
byte[] currentCAR = paceOutputMap.getContentAsBytes(PACEOutputType.CURRENT_CAR);
byte[] previousCAR = paceOutputMap.getContentAsBytes(PACEOutputType.PREVIOUS_CAR);
byte[] idpicc = paceOutputMap.getContentAsBytes(PACEOutputType.ID_PICC);
// Store SecurityInfos
SecurityInfos securityInfos = SecurityInfos.getInstance(efCardAccess);
internalData.put(EACConstants.IDATA_SECURITY_INFOS, securityInfos);
// Store additional data
internalData.put(EACConstants.IDATA_AUTHENTICATED_AUXILIARY_DATA, aad);
internalData.put(EACConstants.IDATA_CERTIFICATES, certChain);
internalData.put(EACConstants.IDATA_CURRENT_CAR, currentCAR);
internalData.put(EACConstants.IDATA_PREVIOUS_CAR, previousCAR);
internalData.put(EACConstants.IDATA_CHALLENGE, challenge);
// Create response
// eac1Output.setRetryCounter(retryCounter);
eac1Output.setCHAT(eacData.selectedCHAT.toByteArray());
eac1Output.setCurrentCAR(currentCAR);
eac1Output.setPreviousCAR(previousCAR);
eac1Output.setEFCardAccess(efCardAccess);
eac1Output.setIDPICC(idpicc);
eac1Output.setChallenge(challenge);
response.setResult(WSHelper.makeResultOK());
response.setAuthenticationProtocolData(eac1Output.getAuthDataType());
} catch (CertificateException ex) {
LOG.error(ex.getMessage(), ex);
String msg = ex.getMessage();
response.setResult(WSHelper.makeResultError(ECardConstants.Minor.SAL.EAC.DOC_VALID_FAILED, msg));
dynCtx.put(EACProtocol.AUTHENTICATION_FAILED, true);
} catch (WSHelper.WSException e) {
LOG.error(e.getMessage(), e);
response.setResult(e.getResult());
dynCtx.put(EACProtocol.AUTHENTICATION_FAILED, true);
} catch (ElementParsingException ex) {
LOG.error(ex.getMessage(), ex);
response.setResult(WSHelper.makeResultError(ECardConstants.Minor.App.INCORRECT_PARM, ex.getMessage()));
dynCtx.put(EACProtocol.AUTHENTICATION_FAILED, true);
} catch (Exception e) {
LOG.error(e.getMessage(), e);
response.setResult(WSHelper.makeResultUnknownError(e.getMessage()));
dynCtx.put(EACProtocol.AUTHENTICATION_FAILED, true);
}
return response;
}
use of org.openecard.common.interfaces.DispatcherException in project open-ecard by ecsec.
the class TCTokenHandler method processBinding.
/**
* Performs the actual PAOS procedure.
* Connects the given card, establishes the HTTP channel and talks to the server. Afterwards disconnects the card.
*
* @param token The TCToken containing the connection parameters.
* @param connectionHandle The handle of the card that will be used.
* @return A TCTokenResponse indicating success or failure.
* @throws DispatcherException If there was a problem dispatching a request from the server.
* @throws PAOSException If there was a transport error.
*/
private TCTokenResponse processBinding(TCTokenRequest tokenRequest, @Nullable ConnectionHandleType connectionHandle) throws PAOSException, DispatcherException {
TCToken token = tokenRequest.getTCToken();
try {
TCTokenResponse response = new TCTokenResponse();
response.setTCToken(token);
response.setResult(WSHelper.makeResultOK());
String binding = token.getBinding();
switch(binding) {
case "urn:liberty:paos:2006-08":
{
// send StartPAOS
connectionHandle = ensureHandleIsUsable(connectionHandle);
List<String> supportedDIDs = getSupportedDIDs();
PAOSTask task = new PAOSTask(dispatcher, connectionHandle, supportedDIDs, tokenRequest, gui, evManager);
FutureTask<StartPAOSResponse> paosTask = new FutureTask<>(task);
Thread paosThread = new Thread(paosTask, "PAOS");
paosThread.start();
if (!tokenRequest.isTokenFromObject()) {
// wait for computation to finish
waitForTask(paosTask);
}
response.setBindingTask(paosTask);
break;
}
case "urn:ietf:rfc:2616":
{
// no actual binding, just connect via tls and authenticate the user with that connection
connectionHandle = ensureHandleIsUsable(connectionHandle);
HttpGetTask task = new HttpGetTask(dispatcher, connectionHandle, tokenRequest);
FutureTask<StartPAOSResponse> tlsTask = new FutureTask<>(task);
Thread tlsThread = new Thread(tlsTask, "TLS Auth");
tlsThread.start();
waitForTask(tlsTask);
response.setBindingTask(tlsTask);
break;
}
default:
// unknown binding
throw new RuntimeException("Unsupported binding in TCToken.");
}
return response;
} catch (WSException ex) {
String msg = "Failed to connect to card.";
LOG.error(msg, ex);
throw new DispatcherException(msg, ex);
}
}
use of org.openecard.common.interfaces.DispatcherException in project open-ecard by ecsec.
the class PAOS method sendStartPAOS.
/**
* Sends start PAOS and answers all successor messages to the server associated with this instance.
* Messages are exchanged until the server replies with a {@code StartPAOSResponse} message.
*
* @param message The StartPAOS message which is sent in the first message.
* @return The {@code StartPAOSResponse} message from the server.
* @throws DispatcherException In case there errors with the message conversion or the dispatcher.
* @throws PAOSException In case there were errors in the transport layer.
* @throws PAOSConnectionException
*/
public StartPAOSResponse sendStartPAOS(StartPAOS message) throws DispatcherException, PAOSException, PAOSConnectionException {
Object msg = message;
StreamHttpClientConnection conn = null;
HttpContext ctx = new BasicHttpContext();
HttpRequestExecutor httpexecutor = new HttpRequestExecutor();
DefaultConnectionReuseStrategy reuse = new DefaultConnectionReuseStrategy();
boolean connectionDropped = false;
ResponseBaseType lastResponse = null;
try {
// loop and send makes a computer happy
while (true) {
// set up connection to PAOS endpoint
// if this one fails we may not continue
conn = openHttpStream();
boolean isReusable;
// send as long as connection is valid
try {
do {
// save the last message we sent to the eID-Server.
if (msg instanceof ResponseBaseType) {
lastResponse = (ResponseBaseType) msg;
}
// prepare request
String resource = tlsHandler.getResource();
BasicHttpEntityEnclosingRequest req = new BasicHttpEntityEnclosingRequest("POST", resource);
HttpRequestHelper.setDefaultHeader(req, tlsHandler.getServerAddress());
req.setHeader(HEADER_KEY_PAOS, headerValuePaos);
req.setHeader("Accept", "text/xml, application/xml, application/vnd.paos+xml");
ContentType reqContentType = ContentType.create("application/vnd.paos+xml", "UTF-8");
HttpUtils.dumpHttpRequest(LOG, "before adding content", req);
String reqMsgStr = createPAOSResponse(msg);
StringEntity reqMsg = new StringEntity(reqMsgStr, reqContentType);
req.setEntity(reqMsg);
req.setHeader(reqMsg.getContentType());
req.setHeader("Content-Length", Long.toString(reqMsg.getContentLength()));
// send request and receive response
LOG.debug("Sending HTTP request.");
HttpResponse response = httpexecutor.execute(req, conn, ctx);
LOG.debug("HTTP response received.");
int statusCode = response.getStatusLine().getStatusCode();
try {
checkHTTPStatusCode(statusCode);
} catch (PAOSConnectionException ex) {
// response with error. So check the status of our last response to the eID-Server
if (lastResponse != null) {
WSHelper.checkResult(lastResponse);
}
throw ex;
}
conn.receiveResponseEntity(response);
HttpEntity entity = response.getEntity();
byte[] entityData = FileUtils.toByteArray(entity.getContent());
HttpUtils.dumpHttpResponse(LOG, response, entityData);
// consume entity
Object requestObj = processPAOSRequest(new ByteArrayInputStream(entityData));
// break when message is startpaosresponse
if (requestObj instanceof StartPAOSResponse) {
StartPAOSResponse startPAOSResponse = (StartPAOSResponse) requestObj;
// an ok.
if (lastResponse != null) {
WSHelper.checkResult(lastResponse);
}
WSHelper.checkResult(startPAOSResponse);
return startPAOSResponse;
}
// send via dispatcher
msg = dispatcher.deliver(requestObj);
// check if connection can be used one more time
isReusable = reuse.keepAlive(response, ctx);
connectionDropped = false;
} while (isReusable);
} catch (IOException ex) {
if (!connectionDropped) {
connectionDropped = true;
LOG.warn("PAOS server closed the connection. Trying to connect again.");
} else {
String errMsg = "Error in the link to the PAOS server.";
LOG.error(errMsg);
throw new PAOSException(DELIVERY_FAILED, ex);
}
}
}
} catch (HttpException ex) {
throw new PAOSException(DELIVERY_FAILED, ex);
} catch (SOAPException ex) {
throw new PAOSException(SOAP_MESSAGE_FAILURE, ex);
} catch (MarshallingTypeException ex) {
throw new PAOSDispatcherException(MARSHALLING_ERROR, ex);
} catch (InvocationTargetException ex) {
throw new PAOSDispatcherException(DISPATCHER_ERROR, ex);
} catch (TransformerException ex) {
throw new DispatcherException(ex);
} catch (WSException ex) {
throw new PAOSException(ex);
} finally {
try {
if (conn != null) {
conn.close();
}
} catch (IOException ex) {
// throw new PAOSException(ex);
}
}
}
Aggregations