/******************************************************************************* * Copyright 2014 by E-Government Innovation Center EGIZ, Graz, Austria * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a * joint initiative of the Federal Chancellery Austria and Graz University of * Technology. * * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. * * This product combines work with different licenses. See the "NOTICE" text * file for details on the various modules and licenses. * The "NOTICE" text file is part of the distribution. Any derivative works * that you distribute must include a readable copy of the "NOTICE" text file. ******************************************************************************/ package at.gv.egiz.pdfas.web.helper; import iaik.x509.X509Certificate; import java.awt.Image; import java.awt.image.RenderedImage; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.security.cert.CertificateException; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.imageio.ImageIO; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.xml.bind.JAXBElement; import javax.xml.ws.WebServiceException; import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringEscapeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import at.gv.egiz.pdfas.api.ws.PDFASSignParameters; import at.gv.egiz.pdfas.api.ws.PDFASSignParameters.Connector; import at.gv.egiz.pdfas.api.ws.PDFASSignResponse; import at.gv.egiz.pdfas.api.ws.PDFASVerificationResponse; import at.gv.egiz.pdfas.common.exceptions.PDFASError; import at.gv.egiz.pdfas.lib.api.ByteArrayDataSource; import at.gv.egiz.pdfas.lib.api.Configuration; import at.gv.egiz.pdfas.lib.api.IConfigurationConstants; import at.gv.egiz.pdfas.lib.api.PdfAs; import at.gv.egiz.pdfas.lib.api.PdfAsFactory; import at.gv.egiz.pdfas.lib.api.StatusRequest; import at.gv.egiz.pdfas.lib.api.sign.IPlainSigner; import at.gv.egiz.pdfas.lib.api.sign.SignParameter; import at.gv.egiz.pdfas.lib.api.sign.SignResult; import at.gv.egiz.pdfas.lib.api.verify.VerifyParameter; import at.gv.egiz.pdfas.lib.api.verify.VerifyParameter.SignatureVerificationLevel; import at.gv.egiz.pdfas.lib.api.verify.VerifyResult; import at.gv.egiz.pdfas.moa.MOAConnector; import at.gv.egiz.pdfas.sigs.pades.PAdESSigner; import at.gv.egiz.pdfas.sigs.pades.PAdESSignerKeystore; import at.gv.egiz.pdfas.web.config.WebConfiguration; import at.gv.egiz.pdfas.web.exception.PdfAsWebException; import at.gv.egiz.pdfas.web.servlets.UIEntryPointServlet; import at.gv.egiz.pdfas.web.stats.StatisticEvent; import at.gv.egiz.sl.schema.CreateCMSSignatureResponseType; import at.gv.egiz.sl.schema.InfoboxAssocArrayPairType; import at.gv.egiz.sl.schema.InfoboxReadRequestType; import at.gv.egiz.sl.schema.InfoboxReadResponseType; import at.gv.egiz.sl.schema.ObjectFactory; import at.gv.egiz.sl.util.BKUSLConnector; import at.gv.egiz.sl.util.RequestPackage; import at.gv.egiz.sl.util.SLMarschaller; public class PdfAsHelper { private static final String PDF_CONFIG = "PDF_CONFIG"; private static final String PDF_STATUS = "PDF_STATUS"; private static final String PDF_OUTPUT = "PDF_OUTPUT"; private static final String PDF_SL_CONNECTOR = "PDF_SL_CONNECTOR"; private static final String PDF_STATISTICS = "PDF_STATISTICS"; private static final String PDF_SIGNER = "PDF_SIGNER"; private static final String PDF_SL_INTERACTIVE = "PDF_SL_INTERACTIVE"; private static final String PDF_SIGNED_DATA = "PDF_SIGNED_DATA"; private static final String PDF_SIGNED_DATA_CREATED = "PDF_SIGNED_DATA_CREATED"; private static final String PDF_LOCALE = "PDF_LOCALE"; private static final String PDF_ERR_MESSAGE = "PDF_ERR_MESSAGE"; private static final String PDF_ERR_THROWABLE = "PDF_ERR_THROWABLE"; private static final String PDF_ERROR_PAGE = "/ErrorPage"; private static final String PDF_PROVIDE_PAGE = "/ProvidePDF"; private static final String PDF_PDFDATA_PAGE = "/PDFData"; private static final String PDF_DATAURL_PAGE = "/DataURL"; private static final String PDF_USERENTRY_PAGE = "/userentry"; private static final String PDF_ERR_URL = "PDF_ERR_URL"; private static final String PDF_FILE_NAME = "PDF_FILE_NAME"; private static final String PDF_SIGNER_CERT = "PDF_SIGNER_CERT"; private static final String PDF_VER_LEVEL = "PDF_VER_LEVEL"; private static final String PDF_VER_RESP = "PDF_VER_RESP"; private static final String PDF_INVOKE_URL = "PDF_INVOKE_URL"; private static final String PDF_INVOKE_TARGET = "PDF_INVOKE_TARGET"; private static final String REQUEST_FROM_DU = "REQ_DATA_URL"; private static final String SIGNATURE_DATA_HASH = "SIGNATURE_DATA_HASH"; private static final String SIGNATURE_ACTIVE = "SIGNATURE_ACTIVE"; private static final String VERIFICATION_RESULT = "VERIFICATION_RESULT"; private static final String QRCODE_CONTENT = "QR_CONT"; private static final Logger logger = LoggerFactory .getLogger(PdfAsHelper.class); private static PdfAs pdfAs; private static ObjectFactory of = new ObjectFactory(); private static Configuration pdfAsConfig; static { reloadConfig(); } public static void init() { logger.info("PDF-AS Helper initialized"); } public static synchronized void reloadConfig() { logger.info("Creating PDF-AS"); pdfAs = PdfAsFactory.createPdfAs(new File(WebConfiguration .getPdfASDir())); pdfAsConfig = pdfAs.getConfiguration(); logger.info("Creating PDF-AS done"); } public static Configuration getPdfAsConfig() { return pdfAsConfig; } private static void validatePdfSize(HttpServletRequest request, HttpServletResponse response, byte[] pdfData) throws PdfAsWebException { // Try to check num-bytes String pdfSizeString = PdfAsParameterExtractor.getNumBytes(request); if (pdfSizeString != null) { long pdfSize = -1; try { pdfSize = Long.parseLong(pdfSizeString); } catch (NumberFormatException e) { throw new PdfAsWebException( PdfAsParameterExtractor.PARAM_NUM_BYTES + " parameter has to be a positiv number!", e); } if (pdfSize <= 0) { throw new PdfAsWebException( "Invalid PDF Size! Has to bigger than zero!"); } if (pdfData.length != pdfSize) { throw new PdfAsWebException("Signature Data Size and " + PdfAsParameterExtractor.PARAM_NUM_BYTES + " missmatch!"); } } } public static String buildPosString(HttpServletRequest request, HttpServletResponse response) throws PdfAsWebException { String posP = PdfAsParameterExtractor.getSigPosP(request); String posX = PdfAsParameterExtractor.getSigPosX(request); String posY = PdfAsParameterExtractor.getSigPosY(request); String posW = PdfAsParameterExtractor.getSigPosW(request); String posR = PdfAsParameterExtractor.getSigPosR(request); String posF = PdfAsParameterExtractor.getSigPosF(request); if (posP == null && posW == null && posX == null && posY == null && posR == null && posF == null) { return null; } StringBuilder sb = new StringBuilder(); if (posX != null) { try { Float.parseFloat(posX); } catch (NumberFormatException e) { if (!posX.equalsIgnoreCase("auto")) { throw new PdfAsWebException( PdfAsParameterExtractor.PARAM_SIG_POS_X + " has invalid value!", e); } else { sb.append("x:auto;"); } } sb.append("x:" + posX.trim() + ";"); } else { sb.append("x:auto;"); } if (posY != null) { try { Float.parseFloat(posY); } catch (NumberFormatException e) { if (!posY.equalsIgnoreCase("auto")) { throw new PdfAsWebException( PdfAsParameterExtractor.PARAM_SIG_POS_Y + " has invalid value!", e); } else { sb.append("y:auto;"); } } sb.append("y:" + posY.trim() + ";"); } else { sb.append("y:auto;"); } if (posW != null) { try { Float.parseFloat(posW); } catch (NumberFormatException e) { if (!posW.equalsIgnoreCase("auto")) { throw new PdfAsWebException( PdfAsParameterExtractor.PARAM_SIG_POS_W + " has invalid value!", e); } else { sb.append("w:auto;"); } } sb.append("w:" + posW.trim() + ";"); } else { sb.append("w:auto;"); } if (posP != null) { if (!(posP.equals("auto") || posP.equals("new"))) { try { Integer.parseInt(posP); } catch (NumberFormatException e) { throw new PdfAsWebException( PdfAsParameterExtractor.PARAM_SIG_POS_P + " has invalid value! (auto | new )"); } } sb.append("p:" + posP.trim() + ";"); } else { sb.append("p:auto;"); } if (posR != null) { try { Float.parseFloat(posR); } catch (NumberFormatException e) { if (!posR.equalsIgnoreCase("auto")) { throw new PdfAsWebException( PdfAsParameterExtractor.PARAM_SIG_POS_R + " has invalid value!", e); } } sb.append("r:" + posR.trim() + ";"); } else { sb.append("r:0;"); } if (posF != null) { try { Float.parseFloat(posF); } catch (NumberFormatException e) { if (!posF.equalsIgnoreCase("auto")) { throw new PdfAsWebException( PdfAsParameterExtractor.PARAM_SIG_POS_F + " has invalid value!", e); } else { sb.append("f:0;"); } } sb.append("f:" + posF.trim() + ";"); } else { sb.append("f:0;"); } return sb.toString(); } public static List synchornousVerify( HttpServletRequest request, HttpServletResponse response, byte[] pdfData) throws Exception { String signidxString = PdfAsParameterExtractor.getSigIdx(request); int signIdx = -1; if (signidxString != null) { try { signIdx = Integer.parseInt(signidxString); } catch (Throwable e) { logger.warn("Failed to parse Signature Index: " + signidxString); } } logger.debug("Verifing Signature index: " + signIdx); Configuration config = pdfAs.getConfiguration(); ByteArrayDataSource dataSource = new ByteArrayDataSource(pdfData); VerifyParameter verifyParameter = PdfAsFactory.createVerifyParameter( config, dataSource); verifyParameter.setDataSource(dataSource); verifyParameter.setConfiguration(config); verifyParameter.setWhichSignature(signIdx); List results = pdfAs.verify(verifyParameter); return results; } public static List synchornousVerify(byte[] pdfData, int signIdx, SignatureVerificationLevel lvl, Map preProcessor) throws Exception { logger.debug("Verifing Signature index: " + signIdx); Configuration config = pdfAs.getConfiguration(); ByteArrayDataSource dataSource = new ByteArrayDataSource(pdfData); VerifyParameter verifyParameter = PdfAsFactory.createVerifyParameter( config, dataSource); verifyParameter.setPreprocessorArguments(preProcessor); verifyParameter.setSignatureVerificationLevel(lvl); verifyParameter.setDataSource(dataSource); verifyParameter.setConfiguration(config); verifyParameter.setWhichSignature(signIdx); List results = pdfAs.verify(verifyParameter); return results; } /** * Create synchronous PDF Signature * * @param request * The Web request * @param response * The Web response * @param pdfData * The pdf data * @return The signed pdf data * @throws Exception */ public static byte[] synchornousSignature(HttpServletRequest request, HttpServletResponse response, byte[] pdfData) throws Exception { validatePdfSize(request, response, pdfData); Configuration config = pdfAs.getConfiguration(); Map configOverwrite = PdfAsParameterExtractor.getOverwriteMap(request); ConfigurationOverwrite.overwriteConfiguration(configOverwrite, config); ByteArrayOutputStream baos = new ByteArrayOutputStream(); // Generate Sign Parameter SignParameter signParameter = PdfAsFactory.createSignParameter(config, new ByteArrayDataSource(pdfData), baos); // Get Connector String connector = PdfAsParameterExtractor.getConnector(request); if (!connector.equals("moa") && !connector.equals("jks")) { throw new PdfAsWebException("Invalid connector (moa | jks)"); } IPlainSigner signer; if (connector.equals("moa")) { String keyIdentifier = PdfAsParameterExtractor .getKeyIdentifier(request); if (keyIdentifier != null) { if (!WebConfiguration.isMoaEnabled(keyIdentifier)) { throw new PdfAsWebException("MOA connector [" + keyIdentifier + "] disabled or not existing."); } String url = WebConfiguration.getMoaURL(keyIdentifier); String keyId = WebConfiguration.getMoaKeyID(keyIdentifier); String certificate = WebConfiguration .getMoaCertificate(keyIdentifier); config.setValue(IConfigurationConstants.MOA_SIGN_URL, url); config.setValue(IConfigurationConstants.MOA_SIGN_KEY_ID, keyId); config.setValue(IConfigurationConstants.MOA_SIGN_CERTIFICATE, certificate); } else { if (!WebConfiguration.getMOASSEnabled()) { throw new PdfAsWebException("MOA connector disabled."); } } signer = new PAdESSigner(new MOAConnector(config)); } else if (connector.equals("jks")) { String keyIdentifier = PdfAsParameterExtractor .getKeyIdentifier(request); boolean ksEnabled = false; String ksFile = null; String ksAlias = null; String ksPass = null; String ksKeyPass = null; String ksType = null; if (keyIdentifier != null) { ksEnabled = WebConfiguration.getKeystoreEnabled(keyIdentifier); ksFile = WebConfiguration.getKeystoreFile(keyIdentifier); ksAlias = WebConfiguration.getKeystoreAlias(keyIdentifier); ksPass = WebConfiguration.getKeystorePass(keyIdentifier); ksKeyPass = WebConfiguration.getKeystoreKeyPass(keyIdentifier); ksType = WebConfiguration.getKeystoreType(keyIdentifier); } else { ksEnabled = WebConfiguration.getKeystoreDefaultEnabled(); ksFile = WebConfiguration.getKeystoreDefaultFile(); ksAlias = WebConfiguration.getKeystoreDefaultAlias(); ksPass = WebConfiguration.getKeystoreDefaultPass(); ksKeyPass = WebConfiguration.getKeystoreDefaultKeyPass(); ksType = WebConfiguration.getKeystoreDefaultType(); } if (!ksEnabled) { if (keyIdentifier != null) { throw new PdfAsWebException("JKS connector [" + keyIdentifier + "] disabled or not existing."); } else { throw new PdfAsWebException( "DEFAULT JKS connector disabled."); } } if (ksFile == null || ksAlias == null || ksPass == null || ksKeyPass == null || ksType == null) { if (keyIdentifier != null) { throw new PdfAsWebException("JKS connector [" + keyIdentifier + "] not correctly configured."); } else { throw new PdfAsWebException( "DEFAULT JKS connector not correctly configured."); } } signer = new PAdESSignerKeystore(ksFile, ksAlias, ksPass, ksKeyPass, ksType); } else { throw new PdfAsWebException("Invalid connector (moa | jks)"); } signParameter.setPlainSigner(signer); String profileId = PdfAsParameterExtractor.getSigType(request); String qrCodeContent = PdfAsHelper.getQRCodeContent(request); if (qrCodeContent != null) { if (profileId == null) { // get default Profile profileId = config.getValue("sig_obj.type.default"); } if (profileId == null) { logger.warn("Failed to determine default profile! Using hard coded!"); profileId = "SIGNATURBLOCK_SMALL_DE"; } ByteArrayOutputStream qrbaos = new ByteArrayOutputStream(); try { String key = "sig_obj." + profileId + ".value.SIG_LABEL"; QRCodeGenerator.generateQRCode(qrCodeContent, qrbaos, 200); String value = Base64.encodeBase64String(qrbaos.toByteArray()); config.setValue(key, value); } finally { IOUtils.closeQuietly(qrbaos); } } // set Signature Profile (null use default ...) signParameter.setSignatureProfileId(profileId); // set Signature Position signParameter.setSignaturePosition(buildPosString(request, response)); @SuppressWarnings("unused") SignResult result = pdfAs.sign(signParameter); return baos.toByteArray(); } /** * Create synchronous PDF Signature * * @param params * The Web request * @param pdfData * The pdf data * @return The signed pdf data * @throws Exception */ public static PDFASSignResponse synchornousServerSignature(byte[] pdfData, PDFASSignParameters params) throws Exception { Configuration config = pdfAs.getConfiguration(); if (WebConfiguration.isAllowExtOverwrite() && params.getOverrides() != null) { ConfigurationOverwrite.overwriteConfiguration(params.getOverrides().getMap(), config); } ByteArrayOutputStream baos = new ByteArrayOutputStream(); // Generate Sign Parameter SignParameter signParameter = PdfAsFactory.createSignParameter(config, new ByteArrayDataSource(pdfData), baos); // Get Connector IPlainSigner signer; if (params.getConnector().equals(Connector.MOA)) { String keyIdentifier = params.getKeyIdentifier(); if (keyIdentifier != null) { if (!WebConfiguration.isMoaEnabled(keyIdentifier)) { throw new PdfAsWebException("MOA connector [" + keyIdentifier + "] disabled or not existing."); } String url = WebConfiguration.getMoaURL(keyIdentifier); String keyId = WebConfiguration.getMoaKeyID(keyIdentifier); String certificate = WebConfiguration .getMoaCertificate(keyIdentifier); config.setValue(IConfigurationConstants.MOA_SIGN_URL, url); config.setValue(IConfigurationConstants.MOA_SIGN_KEY_ID, keyId); config.setValue(IConfigurationConstants.MOA_SIGN_CERTIFICATE, certificate); } else { if (!WebConfiguration.getMOASSEnabled()) { throw new PdfAsWebException("MOA connector disabled."); } } signer = new PAdESSigner(new MOAConnector(config)); } else if (params.getConnector().equals(Connector.JKS)) { String keyIdentifier = params.getKeyIdentifier(); boolean ksEnabled = false; String ksFile = null; String ksAlias = null; String ksPass = null; String ksKeyPass = null; String ksType = null; if (keyIdentifier != null) { ksEnabled = WebConfiguration.getKeystoreEnabled(keyIdentifier); ksFile = WebConfiguration.getKeystoreFile(keyIdentifier); ksAlias = WebConfiguration.getKeystoreAlias(keyIdentifier); ksPass = WebConfiguration.getKeystorePass(keyIdentifier); ksKeyPass = WebConfiguration.getKeystoreKeyPass(keyIdentifier); ksType = WebConfiguration.getKeystoreType(keyIdentifier); } else { ksEnabled = WebConfiguration.getKeystoreDefaultEnabled(); ksFile = WebConfiguration.getKeystoreDefaultFile(); ksAlias = WebConfiguration.getKeystoreDefaultAlias(); ksPass = WebConfiguration.getKeystoreDefaultPass(); ksKeyPass = WebConfiguration.getKeystoreDefaultKeyPass(); ksType = WebConfiguration.getKeystoreDefaultType(); } if (!ksEnabled) { if (keyIdentifier != null) { throw new PdfAsWebException("JKS connector [" + keyIdentifier + "] disabled or not existing."); } else { throw new PdfAsWebException( "DEFAULT JKS connector disabled."); } } if (ksFile == null || ksAlias == null || ksPass == null || ksKeyPass == null || ksType == null) { if (keyIdentifier != null) { throw new PdfAsWebException("JKS connector [" + keyIdentifier + "] not correctly configured."); } else { throw new PdfAsWebException( "DEFAULT JKS connector not correctly configured."); } } signer = new PAdESSignerKeystore(ksFile, ksAlias, ksPass, ksKeyPass, ksType); } else { throw new PdfAsWebException("Invalid connector (moa | jks)"); } signParameter.setPlainSigner(signer); String profile = params.getProfile(); // PdfAsHelper.getQRCodeContent(request); // Get QR Code Content form param String qrCodeContent = params.getQRCodeContent(); if (qrCodeContent != null) { if (profile == null) { // get default Profile profile = config.getValue("sig_obj.type.default"); } if (profile == null) { logger.warn("Failed to determine default profile! Using hard coded!"); profile = "SIGNATURBLOCK_SMALL_DE"; } ByteArrayOutputStream qrbaos = new ByteArrayOutputStream(); try { String key = "sig_obj." + profile + ".value.SIG_LABEL"; QRCodeGenerator.generateQRCode(qrCodeContent, qrbaos, 200); String value = Base64.encodeBase64String(qrbaos.toByteArray()); config.setValue(key, value); } finally { IOUtils.closeQuietly(qrbaos); } } // set Signature Profile (null use default ...) signParameter.setSignatureProfileId(profile); // set Signature Position signParameter.setSignaturePosition(params.getPosition()); // Set Preprocessor if (params.getPreprocessor() != null) { signParameter.setPreprocessorArguments(params.getPreprocessor() .getMap()); } SignResult signResult = pdfAs.sign(signParameter); PDFASSignResponse signResponse = new PDFASSignResponse(); signResponse.setSignedPDF(baos.toByteArray()); PDFASVerificationResponse verResponse = new PDFASVerificationResponse(); verResponse.setSignerCertificate(signResult.getSignerCertificate() .getEncoded()); signResponse.setVerificationResponse(verResponse); return signResponse; } public static void startSignatureJson(HttpServletRequest request, HttpServletResponse response, ServletContext context, byte[] pdfData, String connector, String position, String transactionId, String profile, Map preProcessor, Map overwrite) throws Exception { // TODO: Protect session so that only one PDF can be signed during one // session /* * if(PdfAsHelper.isSignatureActive(request)) { throw new * PdfAsException("Signature is active in this session"); } * * PdfAsHelper.setSignatureActive(request, true); */ validatePdfSize(request, response, pdfData); HttpSession session = request.getSession(); logger.info("Starting signature in session: " + session.getId()); Configuration config = pdfAs.getConfiguration(); session.setAttribute(PDF_CONFIG, config); ConfigurationOverwrite.overwriteConfiguration(overwrite, config); ByteArrayOutputStream baos = new ByteArrayOutputStream(); session.setAttribute(PDF_OUTPUT, baos); // Generate Sign Parameter SignParameter signParameter = PdfAsFactory.createSignParameter(config, new ByteArrayDataSource(pdfData), baos); logger.info("Setting TransactionID: " + transactionId); signParameter.setTransactionId(transactionId); IPlainSigner signer; if (connector.equals("bku") || connector.equals("onlinebku") || connector.equals("mobilebku")) { BKUSLConnector conn = new BKUSLConnector(config); // conn.setBase64(true); signer = new PAdESSigner(conn); session.setAttribute(PDF_SL_CONNECTOR, conn); } else { throw new PdfAsWebException( "Invalid connector (bku | onlinebku | mobilebku | moa | jks)"); } signParameter.setPreprocessorArguments(preProcessor); signParameter.setPlainSigner(signer); session.setAttribute(PDF_SIGNER, signer); session.setAttribute(PDF_SL_INTERACTIVE, connector); String qrCodeContent = PdfAsHelper.getQRCodeContent(request); if (qrCodeContent != null) { if (profile == null) { // get default Profile profile = config.getValue("sig_obj.type.default"); } if (profile == null) { logger.warn("Failed to determine default profile! Using hard coded!"); profile = "SIGNATURBLOCK_SMALL_DE"; } ByteArrayOutputStream qrbaos = new ByteArrayOutputStream(); try { String key = "sig_obj." + profile + ".value.SIG_LABEL"; QRCodeGenerator.generateQRCode(qrCodeContent, qrbaos, 200); String value = Base64.encodeBase64String(qrbaos.toByteArray()); config.setValue(key, value); } finally { IOUtils.closeQuietly(qrbaos); } } // set Signature Profile (null use default ...) signParameter.setSignatureProfileId(profile); // set Signature Position signParameter.setSignaturePosition(position); StatusRequest statusRequest = pdfAs.startSign(signParameter); session.setAttribute(PDF_STATUS, statusRequest); } public static void startSignature(HttpServletRequest request, HttpServletResponse response, ServletContext context, byte[] pdfData, String connector, String position, String transactionId, String profile, Map preProcessor, Map overwrite) throws Exception { // TODO: Protect session so that only one PDF can be signed during one // session /* * if(PdfAsHelper.isSignatureActive(request)) { throw new * PdfAsException("Signature is active in this session"); } * * PdfAsHelper.setSignatureActive(request, true); */ validatePdfSize(request, response, pdfData); HttpSession session = request.getSession(); logger.info("Starting signature in session: " + session.getId()); Configuration config = pdfAs.getConfiguration(); session.setAttribute(PDF_CONFIG, config); ConfigurationOverwrite.overwriteConfiguration(overwrite, config); ByteArrayOutputStream baos = new ByteArrayOutputStream(); session.setAttribute(PDF_OUTPUT, baos); // Generate Sign Parameter SignParameter signParameter = PdfAsFactory.createSignParameter(config, new ByteArrayDataSource(pdfData), baos); logger.info("Setting TransactionID: " + transactionId); signParameter.setTransactionId(transactionId); IPlainSigner signer; if (connector.equals("bku") || connector.equals("onlinebku") || connector.equals("mobilebku")) { BKUSLConnector conn = new BKUSLConnector(config); // conn.setBase64(true); signer = new PAdESSigner(conn); session.setAttribute(PDF_SL_CONNECTOR, conn); } else { throw new PdfAsWebException( "Invalid connector (bku | onlinebku | mobilebku | moa | jks)"); } signParameter.setPreprocessorArguments(preProcessor); signParameter.setPlainSigner(signer); session.setAttribute(PDF_SIGNER, signer); session.setAttribute(PDF_SL_INTERACTIVE, connector); String qrCodeContent = PdfAsHelper.getQRCodeContent(request); if (qrCodeContent != null) { if (profile == null) { // get default Profile profile = config.getValue("sig_obj.type.default"); } if (profile == null) { logger.warn("Failed to determine default profile! Using hard coded!"); profile = "SIGNATURBLOCK_SMALL_DE"; } ByteArrayOutputStream qrbaos = new ByteArrayOutputStream(); try { String key = "sig_obj." + profile + ".value.SIG_LABEL"; QRCodeGenerator.generateQRCode(qrCodeContent, qrbaos, 200); String value = Base64.encodeBase64String(qrbaos.toByteArray()); config.setValue(key, value); } finally { IOUtils.closeQuietly(qrbaos); } } // set Signature Profile (null use default ...) signParameter.setSignatureProfileId(profile); // set Signature Position signParameter.setSignaturePosition(position); StatusRequest statusRequest = pdfAs.startSign(signParameter); session.setAttribute(PDF_STATUS, statusRequest); PdfAsHelper.process(request, response, context); } private static byte[] getCertificate( InfoboxReadResponseType infoboxReadResponseType) { byte[] data = null; if (infoboxReadResponseType.getAssocArrayData() != null) { List pairs = infoboxReadResponseType .getAssocArrayData().getPair(); Iterator pairIterator = pairs.iterator(); while (pairIterator.hasNext()) { InfoboxAssocArrayPairType pair = pairIterator.next(); if (pair.getKey().equals("SecureSignatureKeypair")) { return pair.getBase64Content(); } } } // SecureSignatureKeypair return data; } public static byte[] generateVisualBlock(String profile, int resolution) throws IOException, CertificateException, PDFASError { X509Certificate cert = new X509Certificate( PdfAsHelper.class.getResourceAsStream("/qualified.cer")); Configuration config = pdfAs.getConfiguration(); SignParameter parameter = PdfAsFactory.createSignParameter(config, null, null); parameter.setSignatureProfileId(profile); Image img = pdfAs.generateVisibleSignaturePreview(parameter, cert, resolution); if (img == null) { return null; } ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write((RenderedImage) img, "png", baos); baos.close(); return baos.toByteArray(); } public static boolean checkDataUrlAccess(HttpServletRequest request) throws Exception { HttpSession session = request.getSession(false); if(session != null) { Object statusObject = session .getAttribute(PDF_STATUS); if(statusObject != null && statusObject instanceof StatusRequest) { StatusRequest statusRequest = (StatusRequest)statusObject; if(statusRequest.needCertificate() || statusRequest.needSignature()) { return true; } } } return false; } public static void injectCertificate(HttpServletRequest request, HttpServletResponse response, InfoboxReadResponseType infoboxReadResponseType, ServletContext context) throws Exception { HttpSession session = request.getSession(); StatusRequest statusRequest = (StatusRequest) session .getAttribute(PDF_STATUS); if (statusRequest == null) { throw new PdfAsWebException("No Signature running in session:" + session.getId()); } statusRequest.setCertificate(getCertificate(infoboxReadResponseType)); statusRequest = pdfAs.process(statusRequest); session.setAttribute(PDF_STATUS, statusRequest); PdfAsHelper.process(request, response, context); } public static void injectSignature(HttpServletRequest request, HttpServletResponse response, CreateCMSSignatureResponseType createCMSSignatureResponseType, ServletContext context) throws Exception { logger.debug("Got CMS Signature Response"); HttpSession session = request.getSession(); StatusRequest statusRequest = (StatusRequest) session .getAttribute(PDF_STATUS); if (statusRequest == null) { throw new PdfAsWebException("No Signature running in session:" + session.getId()); } statusRequest.setSigature(createCMSSignatureResponseType .getCMSSignature()); statusRequest = pdfAs.process(statusRequest); session.setAttribute(PDF_STATUS, statusRequest); PdfAsHelper.process(request, response, context); } public static void logAccess(HttpServletRequest request) { HttpSession session = request.getSession(); logger.info("Access to " + request.getServletPath() + " in Session: " + session.getId()); } public static JSONStartResponse startJsonProcess(HttpServletRequest request, HttpServletResponse response, ServletContext context) throws Exception { HttpSession session = request.getSession(); StatusRequest statusRequest = (StatusRequest) session .getAttribute(PDF_STATUS); // IPlainSigner plainSigner = (IPlainSigner) session // .getAttribute(PDF_SIGNER); String connector = (String) session.getAttribute(PDF_SL_INTERACTIVE); if (connector.equals("bku") || connector.equals("onlinebku") || connector.equals("mobilebku")) { BKUSLConnector bkuSLConnector = (BKUSLConnector) session .getAttribute(PDF_SL_CONNECTOR); if (statusRequest.needCertificate()) { logger.debug("Needing Certificate from BKU"); // build SL Request to read certificate InfoboxReadRequestType readCertificateRequest = bkuSLConnector .createInfoboxReadRequest(statusRequest .getSignParameter()); JAXBElement readRequest = of .createInfoboxReadRequest(readCertificateRequest); String url = generateDataURL(request, response); String slRequest = SLMarschaller.marshalToString(readRequest); String template = getTemplateSL(); String locale = getLocale(request, response); String bkuURL = generateBKUURL(connector); return new JSONStartResponse(url, slRequest, template, locale, bkuURL); } } return null; } public static void process(HttpServletRequest request, HttpServletResponse response, ServletContext context) throws Exception { HttpSession session = request.getSession(); StatusRequest statusRequest = (StatusRequest) session .getAttribute(PDF_STATUS); // IPlainSigner plainSigner = (IPlainSigner) session // .getAttribute(PDF_SIGNER); String connector = (String) session.getAttribute(PDF_SL_INTERACTIVE); if (connector.equals("bku") || connector.equals("onlinebku") || connector.equals("mobilebku")) { BKUSLConnector bkuSLConnector = (BKUSLConnector) session .getAttribute(PDF_SL_CONNECTOR); if (statusRequest.needCertificate()) { logger.debug("Needing Certificate from BKU"); // build SL Request to read certificate InfoboxReadRequestType readCertificateRequest = bkuSLConnector .createInfoboxReadRequest(statusRequest .getSignParameter()); JAXBElement readRequest = of .createInfoboxReadRequest(readCertificateRequest); String url = generateDataURL(request, response); String slRequest = SLMarschaller.marshalToString(readRequest); String template = getTemplateSL(); String locale = getLocale(request, response); template = template.replace("##BKU##", generateBKUURL(connector)); template = template.replace("##XMLRequest##", StringEscapeUtils.escapeHtml4(slRequest)); template = template.replace("##DataURL##", url); template = template.replace("##LOCALE##", locale); if (statusRequest.getSignParameter().getTransactionId() != null) { template = template.replace( "##ADDITIONAL##", ""); } else { template = template.replace("##ADDITIONAL##", ""); } response.getWriter().write(template); // TODO: set content type of response!! response.setContentType("text/html"); response.getWriter().close(); } else if (statusRequest.needSignature()) { logger.debug("Needing Signature from BKU"); // build SL Request for cms signature RequestPackage pack = bkuSLConnector.createCMSRequest( statusRequest.getSignatureData(), statusRequest.getSignatureDataByteRange(), statusRequest.getSignParameter()); String slRequest = SLMarschaller .marshalToString(of .createCreateCMSSignatureRequest(pack .getRequestType())); logger.trace("SL Request: " + slRequest); response.setContentType("text/xml"); response.getWriter().write(slRequest); response.getWriter().close(); } else if (statusRequest.isReady()) { // TODO: store pdf document redirect to Finish URL logger.debug("Document ready!"); SignResult result = pdfAs.finishSign(statusRequest); ByteArrayOutputStream baos = (ByteArrayOutputStream) session .getAttribute(PDF_OUTPUT); baos.close(); PDFASVerificationResponse verResponse = new PDFASVerificationResponse(); List verResults = PdfAsHelper.synchornousVerify( baos.toByteArray(), -2, PdfAsHelper.getVerificationLevel(request), null); if (verResults.size() != 1) { throw new WebServiceException( "Document verification failed!"); } VerifyResult verifyResult = verResults.get(0); verResponse.setCertificateCode(verifyResult .getCertificateCheck().getCode()); verResponse.setValueCode(verifyResult.getValueCheckCode() .getCode()); PdfAsHelper.setPDFASVerificationResponse(request, verResponse); PdfAsHelper.setSignedPdf(request, response, baos.toByteArray()); PdfAsHelper.gotoProvidePdf(context, request, response); String signerCert = Base64.encodeBase64String(result .getSignerCertificate().getEncoded()); PdfAsHelper.setSignerCertificate(request, signerCert); } else { throw new PdfAsWebException("Invalid state!"); } } else { throw new PdfAsWebException("Invalid connector: " + connector); } } private static String getTemplateSL() throws IOException { String xml = FileUtils.readFileToString(FileUtils .toFile(PdfAsHelper.class.getResource("/template_sl.html"))); return xml; } public static String getErrorRedirectTemplateSL() throws IOException { String xml = FileUtils.readFileToString(FileUtils .toFile(PdfAsHelper.class .getResource("/template_error_redirect.html"))); return xml; } public static String getProvideTemplate() throws IOException { String xml = FileUtils .readFileToString(FileUtils.toFile(PdfAsHelper.class .getResource("/template_provide.html"))); return xml; } public static String getErrorTemplate() throws IOException { String xml = FileUtils.readFileToString(FileUtils .toFile(PdfAsHelper.class.getResource("/template_error.html"))); return xml; } public static String getGenericTemplate() throws IOException { String xml = FileUtils.readFileToString(FileUtils .toFile(PdfAsHelper.class .getResource("/template_generic_param.html"))); return xml; } public static String getInvokeRedirectTemplateSL() throws IOException { String xml = FileUtils.readFileToString(FileUtils .toFile(PdfAsHelper.class .getResource("/template_invoke_redirect.html"))); return xml; } public static boolean isSignedDataExpired(HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(); Object signedData = session.getAttribute(PDF_SIGNED_DATA_CREATED); if (signedData == null) { logger.warn("Cannot find signed data created timestamp in session."); return true; } if (signedData instanceof Long) { long created = ((Long)signedData).longValue(); long now = System.currentTimeMillis(); long validUntil = created + 300000; logger.debug("Checking signed data valid until {} now is {}", validUntil, now); return validUntil < now; } logger.warn("PDF_SIGNED_DATA_CREATED in session is not a long type!"); return true; } public static byte[] getSignedPdf(HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(); Object signedData = session.getAttribute(PDF_SIGNED_DATA); if (signedData == null) { return null; } if (signedData instanceof byte[]) { return (byte[]) signedData; } logger.warn("PDF_SIGNED_DATA in session is not a byte[] type!"); return null; } public static void setSignedPdf(HttpServletRequest request, HttpServletResponse response, byte[] signedData) { HttpSession session = request.getSession(); session.setAttribute(PDF_SIGNED_DATA, signedData); session.setAttribute(PDF_SIGNED_DATA_CREATED, Long.valueOf(System.currentTimeMillis())); } public static void setStatisticEvent(HttpServletRequest request, HttpServletResponse response, StatisticEvent event) { HttpSession session = request.getSession(); session.setAttribute(PDF_STATISTICS, event); } public static StatisticEvent getStatisticEvent(HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(); return (StatisticEvent) session.getAttribute(PDF_STATISTICS); } public static void setLocale(HttpServletRequest request, HttpServletResponse response, String locale) { HttpSession session = request.getSession(); session.setAttribute(PDF_LOCALE, locale); } public static String getLocale(HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(); Object obj = session.getAttribute(PDF_LOCALE); return obj == null ? "DE" : obj.toString(); } public static void setSessionException(HttpServletRequest request, HttpServletResponse response, String message, Throwable e) { HttpSession session = request.getSession(); session.setAttribute(PDF_ERR_MESSAGE, message); session.setAttribute(PDF_ERR_THROWABLE, e); } public static String getSessionErrMessage(HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(); Object obj = session.getAttribute(PDF_ERR_MESSAGE); return obj == null ? null : obj.toString(); } public static Throwable getSessionException(HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(); Object obj = session.getAttribute(PDF_ERR_THROWABLE); if (obj == null) { return null; } if (obj instanceof Throwable) { return (Throwable) obj; } logger.warn("PDF_ERR_THROWABLE in session is not a throwable type!"); return null; } public static void gotoError(ServletContext context, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (PdfAsHelper.getFromDataUrl(request)) { response.sendRedirect(generateErrorURL(request, response)); } else { RequestDispatcher dispatcher = context .getRequestDispatcher(PDF_ERROR_PAGE); dispatcher.forward(request, response); } } public static void gotoProvidePdf(ServletContext context, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (PdfAsHelper.getFromDataUrl(request)) { response.sendRedirect(generateProvideURL(request, response)); } else { RequestDispatcher dispatcher = context .getRequestDispatcher(PDF_PROVIDE_PAGE); dispatcher.forward(request, response); } } public static void setErrorURL(HttpServletRequest request, HttpServletResponse response, String url) { HttpSession session = request.getSession(); logger.debug("[" + session.getId() + "]: Setting Error URL to: " + url); session.setAttribute(PDF_ERR_URL, url); } public static String getErrorURL(HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(); Object obj = session.getAttribute(PDF_ERR_URL); return obj == null ? null : obj.toString(); } public static void setInvokeURL(HttpServletRequest request, HttpServletResponse response, String url) { HttpSession session = request.getSession(); logger.debug("[" + session.getId() + "]: Setting Invoke URL to: " + url); session.setAttribute(PDF_INVOKE_URL, url); } public static String getInvokeURL(HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(); Object obj = session.getAttribute(PDF_INVOKE_URL); return obj == null ? null : obj.toString(); } public static void setInvokeTarget(HttpServletRequest request, HttpServletResponse response, String url) { HttpSession session = request.getSession(); session.setAttribute(PDF_INVOKE_TARGET, url); logger.debug("External Invoke TARGET: " + url); } public static String getInvokeTarget(HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(); Object obj = session.getAttribute(PDF_INVOKE_TARGET); return obj == null ? null : obj.toString(); } private static String generateURL(HttpServletRequest request, HttpServletResponse response, String Servlet) { HttpSession session = request.getSession(); String publicURL = WebConfiguration.getPublicURL(); String dataURL = null; if (publicURL != null) { dataURL = publicURL + Servlet + ";jsessionid=" + session.getId(); } else { if ((request.getScheme().equals("http") && request.getServerPort() == 80) || (request.getScheme().equals("https") && request .getServerPort() == 443)) { dataURL = request.getScheme() + "://" + request.getServerName() + request.getContextPath() + Servlet + ";jsessionid=" + session.getId(); } else { dataURL = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + Servlet + ";jsessionid=" + session.getId(); } } logger.debug("Generated URL: " + dataURL); return dataURL; } public static void regenerateSession(HttpServletRequest request) { request.getSession(false).invalidate(); request.getSession(true); } public static String generateDataURL(HttpServletRequest request, HttpServletResponse response) { return generateURL(request, response, PDF_DATAURL_PAGE); } public static String generateProvideURL(HttpServletRequest request, HttpServletResponse response) { return generateURL(request, response, PDF_PROVIDE_PAGE); } public static String generateErrorURL(HttpServletRequest request, HttpServletResponse response) { return generateURL(request, response, PDF_ERROR_PAGE); } public static String generatePdfURL(HttpServletRequest request, HttpServletResponse response) { return generateURL(request, response, PDF_PDFDATA_PAGE); } public static String generateUserEntryURL(String storeId) { String publicURL = WebConfiguration.getPublicURL(); if (publicURL == null) { logger.error("To use this functionality " + WebConfiguration.PUBLIC_URL + " has to be configured in the web configuration"); return null; } String baseURL = publicURL + PDF_USERENTRY_PAGE; try { return baseURL + "?" + UIEntryPointServlet.REQUEST_ID_PARAM + "=" + URLEncoder.encode(storeId, "UTF-8"); } catch (UnsupportedEncodingException e) { logger.warn("Encoding not supported for URL encoding", e); } return baseURL + "?" + UIEntryPointServlet.REQUEST_ID_PARAM + "=" + storeId; } public static String generateBKUURL(String connector) { if (connector.equals("bku")) { return WebConfiguration.getLocalBKUURL(); } else if (connector.equals("onlinebku")) { return WebConfiguration.getOnlineBKUURL(); } else if (connector.equals("mobilebku")) { return WebConfiguration.getHandyBKUURL(); } return WebConfiguration.getLocalBKUURL(); } public static void setFromDataUrl(HttpServletRequest request) { request.setAttribute(REQUEST_FROM_DU, (Boolean) true); } public static boolean getFromDataUrl(HttpServletRequest request) { Object obj = request.getAttribute(REQUEST_FROM_DU); if (obj != null) { if (obj instanceof Boolean) { return ((Boolean) obj).booleanValue(); } } return false; } public static void setSignatureDataHash(HttpServletRequest request, String value) { HttpSession session = request.getSession(); session.setAttribute(SIGNATURE_DATA_HASH, value); } public static String getSignatureDataHash(HttpServletRequest request) { HttpSession session = request.getSession(); Object obj = session.getAttribute(SIGNATURE_DATA_HASH); if (obj != null) { return obj.toString(); } return ""; } public static void setQRCodeContent(HttpServletRequest request, String value) { HttpSession session = request.getSession(); session.setAttribute(QRCODE_CONTENT, value); } public static String getQRCodeContent(HttpServletRequest request) { HttpSession session = request.getSession(); Object obj = session.getAttribute(QRCODE_CONTENT); if (obj != null) { return obj.toString(); } return null; } public static void setPDFFileName(HttpServletRequest request, String value) { HttpSession session = request.getSession(); session.setAttribute(PDF_FILE_NAME, value); } public static String getPDFFileName(HttpServletRequest request) { HttpSession session = request.getSession(); Object obj = session.getAttribute(PDF_FILE_NAME); if (obj != null) { return obj.toString(); } return "document.pdf"; } public static void setSignerCertificate(HttpServletRequest request, String value) { HttpSession session = request.getSession(); session.setAttribute(PDF_SIGNER_CERT, value); } public static String getSignerCertificate(HttpServletRequest request) { HttpSession session = request.getSession(); Object obj = session.getAttribute(PDF_SIGNER_CERT); if (obj != null) { return obj.toString(); } return null; } public static void setVerificationLevel(HttpServletRequest request, SignatureVerificationLevel lvl) { HttpSession session = request.getSession(); session.setAttribute(PDF_VER_LEVEL, lvl); } public static SignatureVerificationLevel getVerificationLevel( HttpServletRequest request) { HttpSession session = request.getSession(); Object obj = session.getAttribute(PDF_VER_LEVEL); if (obj != null && obj instanceof SignatureVerificationLevel) { return (SignatureVerificationLevel) obj; } return SignatureVerificationLevel.INTEGRITY_ONLY_VERIFICATION; } public static void setPDFASVerificationResponse(HttpServletRequest request, PDFASVerificationResponse resp) { HttpSession session = request.getSession(); session.setAttribute(PDF_VER_RESP, resp); } public static PDFASVerificationResponse getPDFASVerificationResponse( HttpServletRequest request) { HttpSession session = request.getSession(); Object obj = session.getAttribute(PDF_VER_RESP); if (obj != null && obj instanceof PDFASVerificationResponse) { return (PDFASVerificationResponse) obj; } return null; } public static void setVerificationResult(HttpServletRequest request, List value) { HttpSession session = request.getSession(); session.setAttribute(VERIFICATION_RESULT, value); } @SuppressWarnings("unchecked") public static List getVerificationResult( HttpServletRequest request) { HttpSession session = request.getSession(); Object obj = session.getAttribute(VERIFICATION_RESULT); if (obj != null) { try { if (!(obj instanceof List)) { logger.warn("Invalid object type"); return null; } return (List) obj; } catch (Throwable e) { logger.warn("Invalid object type"); } } return null; } public static void setSignatureActive(HttpServletRequest request, boolean value) { HttpSession session = request.getSession(); session.setAttribute(SIGNATURE_ACTIVE, new Boolean(value)); } public static boolean isSignatureActive(HttpServletRequest request) { HttpSession session = request.getSession(); Object obj = session.getAttribute(SIGNATURE_ACTIVE); if (obj != null) { if (obj instanceof Boolean) { return ((Boolean) obj).booleanValue(); } } return false; } public static String getVersion() { return PdfAsFactory.getVersion(); } public static String getSCMRevision() { return PdfAsFactory.getSCMRevision(); } }