aboutsummaryrefslogtreecommitdiff
path: root/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/tasks/FirstBKAMobileAuthTask.java
diff options
context:
space:
mode:
Diffstat (limited to 'id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/tasks/FirstBKAMobileAuthTask.java')
-rw-r--r--id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/tasks/FirstBKAMobileAuthTask.java247
1 files changed, 244 insertions, 3 deletions
diff --git a/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/tasks/FirstBKAMobileAuthTask.java b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/tasks/FirstBKAMobileAuthTask.java
index 66112edc5..43043ddd6 100644
--- a/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/tasks/FirstBKAMobileAuthTask.java
+++ b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/tasks/FirstBKAMobileAuthTask.java
@@ -22,16 +22,56 @@
*/
package at.gv.egovernment.moa.id.auth.modules.bkamobileauthtests.tasks;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.security.cert.CertificateException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
+import org.bouncycastle.cms.CMSSignedData;
+import org.joda.time.DateTime;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonParser;
+
+import at.gv.egovernment.moa.id.auth.invoke.SignatureVerificationInvoker;
import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask;
import at.gv.egovernment.moa.id.auth.modules.TaskExecutionException;
-import at.gv.egovernment.moa.id.auth.servlet.GeneralProcessEngineSignalController;
+import at.gv.egovernment.moa.id.auth.parser.IdentityLinkAssertionParser;
+import at.gv.egovernment.moa.id.commons.api.AuthConfiguration;
+import at.gv.egovernment.moa.id.commons.api.IRequest;
+import at.gv.egovernment.moa.id.commons.api.data.IAuthenticationSession;
+import at.gv.egovernment.moa.id.commons.api.data.IIdentityLink;
+import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;
import at.gv.egovernment.moa.id.process.api.ExecutionContext;
+import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants;
import at.gv.egovernment.moa.logging.Logger;
+import at.gv.egovernment.moa.spss.api.cmsverify.VerifyCMSSignatureRequest;
+import at.gv.egovernment.moa.spss.api.cmsverify.VerifyCMSSignatureResponse;
+import at.gv.egovernment.moa.spss.api.cmsverify.VerifyCMSSignatureResponseElement;
+import at.gv.egovernment.moa.spss.api.common.SignerInfo;
+import at.gv.egovernment.moa.spss.api.impl.VerifyCMSSignatureRequestImpl;
+import at.gv.egovernment.moa.util.Base64Utils;
+import at.gv.egovernment.moa.util.MiscUtil;
/**
@@ -41,6 +81,20 @@ import at.gv.egovernment.moa.logging.Logger;
@Component("FirstBKAMobileAuthTask")
public class FirstBKAMobileAuthTask extends AbstractAuthServletTask {
+ private static final String CONF_MOASPSS_TRUSTPROFILE = "modules.bkamobileAuth.verify.trustprofile";
+ private static final String CONF_SIGNING_TIME_JITTER = "modules.bkamobileAuth.verify.time.jitter";
+ private static final String CONF_EID_TOKEN_ENCRYPTION_KEY = "modules.bkamobileAuth.eIDtoken.encryption.pass";
+
+ private static final String EIDCONTAINER_KEY_SALT = "salt";
+ private static final String EIDCONTAINER_KEY_IV = "iv";
+ private static final String EIDCONTAINER_EID = "eid";
+ private static final String EIDCONTAINER_KEY_IDL = "idl";
+ private static final String EIDCONTAINER_KEY_BINDINGCERT = "cert";
+
+ public static final String REQ_PARAM_eID_BLOW = "eidToken";
+
+ @Autowired(required=true) private AuthConfiguration authConfig;
+
/* (non-Javadoc)
* @see at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask#execute(at.gv.egovernment.moa.id.process.api.ExecutionContext, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@@ -48,9 +102,196 @@ public class FirstBKAMobileAuthTask extends AbstractAuthServletTask {
public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response)
throws TaskExecutionException {
- Logger.info("Redirect to Second BKA Mobile Auth task");
- performRedirectToItself(pendingReq, response, GeneralProcessEngineSignalController.ENDPOINT_GENERIC);
+ try {
+ String eIDBlobRawB64 = request.getParameter(REQ_PARAM_eID_BLOW);
+ if (MiscUtil.isEmpty(eIDBlobRawB64)) {
+ //TODO: add dummy-auth functionality
+
+ Logger.warn("NO eID data blob included!");
+ throw new MOAIDException("NO eID data blob included!", null);
+ }
+
+ parseDemoValuesIntoMOASession(pendingReq, pendingReq.getMOASession(), eIDBlobRawB64);
+
+ } catch (MOAIDException e) {
+ throw new TaskExecutionException(pendingReq, e.getMessage(), e);
+
+ } catch (Exception e) {
+ throw new TaskExecutionException(pendingReq, e.getMessage(), e);
+
+ }
+
+ //Logger.info("Redirect to Second BKA Mobile Auth task");
+ //performRedirectToItself(pendingReq, response, GeneralProcessEngineSignalController.ENDPOINT_GENERIC);
+
+ }
+
+ /**
+ * @param pendingReq
+ * @param moaSession
+ * @param eIDBlobRaw
+ * @throws MOAIDException
+ * @throws IOException
+ */
+ private void parseDemoValuesIntoMOASession(IRequest pendingReq, IAuthenticationSession moaSession, String eIDBlobRawB64) throws MOAIDException, IOException {
+ Logger.debug("Check eID blob signature ... ");
+ byte[] eIDBlobRaw = Base64Utils.decode(eIDBlobRawB64.trim(), false);
+
+ VerifyCMSSignatureResponse cmsResp = SignatureVerificationInvoker.getInstance().verifyCMSSignature(
+ createCMSVerificationReq(eIDBlobRaw));
+
+ if (cmsResp.getResponseElements().isEmpty()) {
+ Logger.warn("No CMS signature-verification response");
+ throw new MOAIDException("Signature verification FAILED: No response", null);
+
+ }
+ VerifyCMSSignatureResponseElement sigVerifyResp = (VerifyCMSSignatureResponseElement) cmsResp.getResponseElements().get(0);
+ analyseCMSSignatureVerificationResponse(sigVerifyResp);
+
+
+ Logger.info("eID blob signature is VALID!");
+ byte[] decRawEidBlob = null;
+ byte[] signedData = null;
+ try {
+ Logger.debug("Starting eID information extraction ... ");
+ CMSSignedData cmsContent = new CMSSignedData(eIDBlobRaw);
+ signedData = (byte[])cmsContent.getSignedContent().getContent();
+ if (!cmsContent.getSignedContent().getContentType().equals(CMSObjectIdentifiers.data)) {
+ Logger.warn("Signature contains NO 'data' OID 1.2.840.113549.1.7.1");
+ throw new MOAIDException("Signature contains NO 'data' OID 1.2.840.113549.1.7.1", null);
+ }
+ if (signedData == null) {
+ Logger.warn("CMS SignedData is empty or null");
+ throw new MOAIDException("CMS SignedData is empty or null", null);
+ }
+ Logger.info("Signed content extracted");
+
+
+ Logger.debug("Starting signed content decryption ... ");
+ JsonParser parser = new JsonParser();
+ JsonObject signedDataJson = (JsonObject) parser.parse(new String(signedData, "UTF-8"));
+ byte[] salt = Base64Utils.decode(signedDataJson.get(EIDCONTAINER_KEY_SALT).getAsString(), false);
+ byte[] ivraw = Base64Utils.decode(signedDataJson.get(EIDCONTAINER_KEY_IV).getAsString(), false);
+ byte[] encRawEidBlob = Base64Utils.decode(signedDataJson.get(EIDCONTAINER_EID).getAsString(), false);
+ SecretKey seckey = generateDecryptionKey(salt);
+ IvParameterSpec iv = new IvParameterSpec(ivraw);
+ Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ cipher.init(Cipher.DECRYPT_MODE, seckey, iv);
+ decRawEidBlob = cipher.doFinal(encRawEidBlob);
+ Logger.info("eID data decryption completed");
+
+
+ Logger.debug("Starting eID-blob parsing ...");
+ JsonObject eIDBlobJson = (JsonObject) parser.parse(new String(decRawEidBlob, "UTF-8"));
+ String idlB64 = eIDBlobJson.get(
+ EIDCONTAINER_KEY_IDL).getAsString();
+ String bindingCertB64 = eIDBlobJson.get(
+ EIDCONTAINER_KEY_BINDINGCERT).getAsString();
+ javax.security.cert.X509Certificate bindingCert = javax.security.cert.X509Certificate.getInstance(Base64Utils.decode(bindingCertB64, false));
+ if (!sigVerifyResp.getSignerInfo().getSignerCertificate().equals(bindingCert)) {
+ Logger.error("eID-blob signing certificate DOES NOT match to binding certificate included in eID blob!");
+ Logger.info("BindingCert: " + bindingCert.toString());
+ Logger.info("SigningCert: " + sigVerifyResp.getSignerInfo().getSignerCertificate().toString());
+ throw new MOAIDException("eID-blob signing certificate DOES NOT match to binding certificate included in eID blob!", null);
+
+ }
+ Logger.info("eID-blob parsing completed");
+
+
+ Logger.debug("Parse eID information into MOA-Session ...");
+ byte[] rawIDL = Base64Utils.decode(idlB64, false);
+ IIdentityLink identityLink = new IdentityLinkAssertionParser(new ByteArrayInputStream(rawIDL)).parseIdentityLink();
+ moaSession.setIdentityLink(identityLink);
+ moaSession.setUseMandates(false);
+ moaSession.setForeigner(false);
+ moaSession.setBkuURL("http://egiz.gv.at/BKA_MobileAuthTest");
+ moaSession.setQAALevel(PVPConstants.STORK_QAA_1_3);
+ Logger.info("Session Restore completed");
+
+
+ } catch (MOAIDException e) {
+ throw e;
+
+ } catch (JsonParseException e) {
+ if (decRawEidBlob != null)
+ Logger.error("eID-blob parse error! blob: " + new String(decRawEidBlob, "UTF-8"), e);
+
+ if (signedData != null)
+ Logger.error("eID-blob parse error! blob: " + new String(signedData, "UTF-8"), e);
+
+ if (decRawEidBlob == null && signedData == null)
+ Logger.error("eID-blob parse error!", e);
+
+ throw new MOAIDException("eID-blob parse error!", null);
+
+ } catch (org.bouncycastle.cms.CMSException e) {
+ Logger.error("Can not parse CMS signature.", e);
+ throw new MOAIDException("Can not parse CMS signature.", null, e);
+
+ } catch (InvalidAlgorithmParameterException| NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
+ Logger.error("Can not decrypte eID data.", e);
+ throw new MOAIDException("Can not decrypte eID data", null, e);
+ } catch (CertificateException e) {
+ Logger.error("Can not extract mobile-app binding-certificate from eID blob.", e);
+ throw new MOAIDException("Can not extract mobile-app binding-certificate from eID blob.", null, e);
+
+ } finally {
+
+ }
+
+ }
+
+ private SecretKey generateDecryptionKey(byte[] salt) throws MOAIDException {
+ String decryptionPassPhrase = authConfig.getBasicMOAIDConfiguration(CONF_EID_TOKEN_ENCRYPTION_KEY, "DEFAULTPASSWORD");
+ try {
+ SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
+ KeySpec spec = new PBEKeySpec(decryptionPassPhrase.toCharArray(), salt, 2000, 128);
+ SecretKey derivedKey = factory.generateSecret(spec);
+ SecretKeySpec symKeySpec = new SecretKeySpec(derivedKey.getEncoded(), "AES");
+ return symKeySpec;
+
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+ Logger.error("Mobile-Auth Module has an internal errror.", e);
+ throw new MOAIDException("Mobile-Auth Module has an internal errror.", null, e);
+
+ }
+ }
+
+ /**
+ * @throws MOAIDException
+ *
+ */
+ private void analyseCMSSignatureVerificationResponse(VerifyCMSSignatureResponseElement verifySigResult) throws MOAIDException {
+ //validate CMS signature verification response
+ if (verifySigResult.getSignatureCheck().getCode() != 0) {
+ Logger.warn("CMS signature verification FAILED with StatusCode: " + verifySigResult.getSignatureCheck().getCode());
+ throw new MOAIDException("CMS signature verification FAILED with StatusCode: " + verifySigResult.getSignatureCheck().getCode(), null);
+
+ }
+ if (verifySigResult.getCertificateCheck().getCode() != 0) {
+ Logger.warn("CMS certificate verification FAILED with StatusCode: " + verifySigResult.getCertificateCheck().getCode());
+ throw new MOAIDException("CMS certificate verification FAILED with StatusCode: " + verifySigResult.getCertificateCheck().getCode(), null);
+
+ }
+ SignerInfo signerInfos = verifySigResult.getSignerInfo();
+ DateTime date = new DateTime(signerInfos.getSigningTime().getTime());
+ Integer signingTimeJitter = Integer.valueOf(authConfig.getBasicMOAIDConfiguration(CONF_SIGNING_TIME_JITTER, "5"));
+ if (date.plusMinutes(signingTimeJitter).isBeforeNow()) {
+ Logger.warn("CMS signature-time is before: " + date.plusMinutes(signingTimeJitter));
+ throw new MOAIDException("CMS signature-time is before: " + date.plusMinutes(signingTimeJitter), null);
+
+ }
+
}
+ private VerifyCMSSignatureRequest createCMSVerificationReq(byte[] eIDBlobRaw) {
+ VerifyCMSSignatureRequestImpl cmsSigVerifyReq = new VerifyCMSSignatureRequestImpl();
+ cmsSigVerifyReq.setSignatories(VerifyCMSSignatureRequestImpl.ALL_SIGNATORIES);
+ cmsSigVerifyReq.setExtended(false);
+ cmsSigVerifyReq.setPDF(false);
+ cmsSigVerifyReq.setTrustProfileId(authConfig.getBasicMOAIDConfiguration(CONF_MOASPSS_TRUSTPROFILE, "!!NOT SET!!!"));
+ cmsSigVerifyReq.setCMSSignature(new ByteArrayInputStream(eIDBlobRaw));
+ return cmsSigVerifyReq;
+ }
}