use of org.openecard.binding.tctoken.ex.SecurityViolationException in project open-ecard by ecsec.
the class TCTokenHandler method determineRefreshURL.
/**
* Follow the URL in the RefreshAddress and update it in the response.
* The redirect is followed as long as the response is a redirect (302, 303 or 307) AND is a
* https-URL AND the hash of the retrieved server certificate is contained in the CertificateDescrioption, else
* return 400. If the URL and the subjectURL in the CertificateDescription conform to the SOP we reached our final
* destination.
*
* @param request TCToken request used to determine which security checks to perform.
* @param response The TCToken response in which the original refresh address is defined and where it will be
* updated.
* @return Modified response with the final address the browser should be redirected to.
* @throws InvalidRedirectUrlException Thrown in case no redirect URL could be determined.
*/
private static TCTokenResponse determineRefreshURL(TCTokenRequest request, TCTokenResponse response) throws InvalidRedirectUrlException, SecurityViolationException {
try {
String endpointStr = response.getRefreshAddress();
URL endpoint = new URL(endpointStr);
DynamicContext dynCtx = DynamicContext.getInstance(TR03112Keys.INSTANCE_KEY);
// omit checks completely if this is an object tag activation
Object objectActivation = dynCtx.get(TR03112Keys.OBJECT_ACTIVATION);
if (objectActivation instanceof Boolean && ((Boolean) objectActivation) == true) {
return response;
}
// disable certificate checks according to BSI TR03112-7 in some situations
boolean redirectChecks = isPerformTR03112Checks(request);
RedirectCertificateValidator verifier = new RedirectCertificateValidator(redirectChecks);
ResourceContext ctx = ResourceContext.getStream(endpoint, verifier);
ctx.closeStream();
// using this verifier no result must be present, meaning no status code different than a redirect occurred
// if (result.p1 != null) {
// // TODO: this error is expected according the spec, handle it in a different way
// String msg = "Return-To-Websession yielded a non-redirect response.";
// throw new IOException(msg);
// }
// determine redirect
List<Pair<URL, TlsServerCertificate>> resultPoints = ctx.getCerts();
Pair<URL, TlsServerCertificate> last = resultPoints.get(resultPoints.size() - 1);
endpoint = last.p1;
dynCtx.put(TR03112Keys.IS_REFRESH_URL_VALID, true);
LOG.debug("Setting redirect address to '{}'.", endpoint);
response.setRefreshAddress(endpoint.toString());
return response;
} catch (MalformedURLException ex) {
throw new IllegalStateException(LANG_TR.translationForKey(REFRESH_URL_ERROR), ex);
} catch (ResourceException | InvalidAddressException | ValidationError | IOException ex) {
String code = ECardConstants.Minor.App.COMMUNICATION_ERROR;
String communicationErrorAddress = response.getTCToken().getComErrorAddressWithParams(code);
if (communicationErrorAddress != null && !communicationErrorAddress.isEmpty()) {
throw new SecurityViolationException(communicationErrorAddress, REFRESH_DETERMINATION_FAILED, ex);
}
throw new InvalidRedirectUrlException(REFRESH_DETERMINATION_FAILED, ex);
}
}
use of org.openecard.binding.tctoken.ex.SecurityViolationException in project open-ecard by ecsec.
the class TCTokenVerifier method assertSameChannel.
private void assertSameChannel(String name, String address) throws InvalidRedirectUrlException, InvalidTCTokenUrlException, SecurityViolationException {
// check that everything can be handled over the same channel
// TR-03124-1 does not mention that redirects on the TCToken address are possible and it also states that there
// are only two channels. So I guess we should force this here as well.
URL paosUrl = assertURL(name, address);
List<Pair<URL, TlsServerCertificate>> urls = ctx.getCerts();
for (Pair<URL, TlsServerCertificate> next : urls) {
if (!TR03112Utils.checkSameOriginPolicy(paosUrl, next.p1)) {
String minor = ResultMinor.COMMUNICATION_ERROR;
String errorUrl = token.getComErrorAddressWithParams(minor);
throw new SecurityViolationException(errorUrl, FAILED_SOP);
}
}
}
use of org.openecard.binding.tctoken.ex.SecurityViolationException in project open-ecard by ecsec.
the class TCTokenHandler method handleActivate.
/**
* Activates the client according to the received TCToken.
*
* @param request The activation request containing the TCToken.
* @return The response containing the result of the activation process.
* @throws InvalidRedirectUrlException Thrown in case no redirect URL could be determined.
* @throws SecurityViolationException
* @throws NonGuiException
*/
public TCTokenResponse handleActivate(TCTokenRequest request) throws InvalidRedirectUrlException, SecurityViolationException, NonGuiException {
TCToken token = request.getTCToken();
if (LOG.isDebugEnabled()) {
try {
WSMarshaller m = WSMarshallerFactory.createInstance();
LOG.debug("TCToken:\n{}", m.doc2str(m.marshal(token)));
} catch (TransformerException | WSMarshallerException ex) {
// it's no use
}
}
final DynamicContext dynCtx = DynamicContext.getInstance(TR03112Keys.INSTANCE_KEY);
boolean performChecks = isPerformTR03112Checks(request);
if (!performChecks) {
LOG.warn("Checks according to BSI TR03112 3.4.2, 3.4.4 (TCToken specific) and 3.4.5 are disabled.");
}
boolean isObjectActivation = request.getTCTokenURL() == null;
if (isObjectActivation) {
LOG.warn("Checks according to BSI TR03112 3.4.4 (TCToken specific) are disabled.");
}
dynCtx.put(TR03112Keys.TCTOKEN_CHECKS, performChecks);
dynCtx.put(TR03112Keys.OBJECT_ACTIVATION, isObjectActivation);
dynCtx.put(TR03112Keys.TCTOKEN_SERVER_CERTIFICATES, request.getCertificates());
ConnectionHandleType connectionHandle = null;
TCTokenResponse response = new TCTokenResponse();
response.setTCToken(token);
byte[] requestedContextHandle = request.getContextHandle();
String ifdName = request.getIFDName();
BigInteger requestedSlotIndex = request.getSlotIndex();
// we know exactly which card we want
ConnectionHandleType requestedHandle = new ConnectionHandleType();
requestedHandle.setContextHandle(requestedContextHandle);
requestedHandle.setIFDName(ifdName);
requestedHandle.setSlotIndex(requestedSlotIndex);
Set<CardStateEntry> matchingHandles = cardStates.getMatchingEntries(requestedHandle);
if (!matchingHandles.isEmpty()) {
connectionHandle = matchingHandles.toArray(new CardStateEntry[] {})[0].handleCopy();
}
if (connectionHandle == null) {
String msg = LANG_TOKEN.translationForKey("cancel");
LOG.error(msg);
response.setResult(WSHelper.makeResultError(ResultMinor.CANCELLATION_BY_USER, msg));
// fill in values, so it is usuable by the transport module
response = determineRefreshURL(request, response);
response.finishResponse(true);
return response;
}
try {
// process binding and follow redirect addresses afterwards
response = processBinding(request, connectionHandle);
// fill in values, so it is usuable by the transport module
response = determineRefreshURL(request, response);
response.finishResponse(isObjectActivation);
return response;
} catch (DispatcherException w) {
LOG.error(w.getMessage(), w);
response.setResultCode(BindingResultCode.INTERNAL_ERROR);
response.setResult(WSHelper.makeResultError(ResultMinor.CLIENT_ERROR, w.getMessage()));
showErrorMessage(w.getMessage());
throw new NonGuiException(response, w.getMessage(), w);
} catch (PAOSException w) {
LOG.error(w.getMessage(), w);
// find actual error to display to the user
Throwable innerException = w.getCause();
if (innerException == null) {
innerException = w;
} else if (innerException instanceof ExecutionException) {
innerException = innerException.getCause();
}
String errorMsg = innerException.getLocalizedMessage();
// fix NPE when null is returned instead of a message
errorMsg = errorMsg == null ? "" : errorMsg;
switch(errorMsg) {
case "The target server failed to respond":
errorMsg = LANG_TR.translationForKey(NO_RESPONSE_FROM_SERVER);
break;
case ECardConstants.Minor.App.INT_ERROR + " ==> Unknown eCard exception occurred.":
errorMsg = LANG_TR.translationForKey(UNKNOWN_ECARD_ERROR);
break;
case "Internal TLS error, this could be an attack":
errorMsg = LANG_TR.translationForKey(INTERNAL_TLS_ERROR);
break;
}
if (innerException instanceof WSException) {
WSException ex = (WSException) innerException;
errorMsg = createResponseFromWsEx(ex, response);
} else if (innerException instanceof PAOSConnectionException) {
response.setResult(WSHelper.makeResultError(ResultMinor.TRUSTED_CHANNEL_ESTABLISCHMENT_FAILED, w.getLocalizedMessage()));
} else {
errorMsg = createMessageFromUnknownError(w);
response.setResult(WSHelper.makeResultError(ResultMinor.CLIENT_ERROR, w.getMessage()));
}
showErrorMessage(errorMsg);
try {
// fill in values, so it is usuable by the transport module
response = determineRefreshURL(request, response);
response.finishResponse(true);
} catch (InvalidRedirectUrlException ex) {
LOG.error(ex.getMessage(), ex);
response.setResultCode(BindingResultCode.INTERNAL_ERROR);
response.setResult(WSHelper.makeResultError(ResultMinor.CLIENT_ERROR, ex.getLocalizedMessage()));
throw new NonGuiException(response, ex.getMessage(), ex);
} catch (SecurityViolationException ex) {
String msg2 = "The RefreshAddress contained in the TCToken is invalid. Redirecting to the " + "CommunicationErrorAddress.";
LOG.error(msg2, ex);
response.setResultCode(BindingResultCode.REDIRECT);
response.setResult(WSHelper.makeResultError(ResultMinor.COMMUNICATION_ERROR, msg2));
response.addAuxResultData(AuxDataKeys.REDIRECT_LOCATION, ex.getBindingResult().getAuxResultData().get(AuxDataKeys.REDIRECT_LOCATION));
}
return response;
}
}
Aggregations