/******************************************************************************* * 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.sl.util; import iaik.x509.X509Certificate; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.StringReader; import java.security.cert.CertificateException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.codec.binary.Base64; import org.apache.http.HttpResponse; import org.apache.http.client.entity.EntityBuilder; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import at.gv.egiz.pdfas.common.exceptions.PdfAsException; import at.gv.egiz.pdfas.common.exceptions.PdfAsMOAException; import at.gv.egiz.pdfas.common.exceptions.PdfAsWrappedIOException; import at.gv.egiz.pdfas.common.settings.ISettings; import at.gv.egiz.pdfas.lib.api.Configuration; import at.gv.egiz.pdfas.lib.api.sign.SignParameter; public class MOAConnector implements ISignatureConnector { private static final Logger logger = LoggerFactory .getLogger(MOAConnector.class); private static final Logger moalogger = LoggerFactory.getLogger("at.knowcenter.wag.egov.egiz.sig.connectors.MOASSRepsonseLogger"); public static final String MOA_SIGN_URL = "moa.sign.url"; public static final String MOA_SIGN_KEY_ID = "moa.sign.KeyIdentifier"; public static final String MOA_SIGN_CERTIFICATE = "moa.sign.Certificate"; public static final String KEY_ID_PATTERN = "##KEYID##"; public static final String CONTENT_PATTERN = "##CONTENT##"; public static final String FAULTCODE = "faultcode"; public static final String FAULTSTRING = "faultstring"; public static final String ERRORRESPONSE = "ErrorResponse"; public static final String ERRORCODE = "ErrorCode"; public static final String CMSSIGNATURE = "CMSSignature"; public static final String CMS_REQUEST = "" + "" + KEY_ID_PATTERN + "" + "" + "application/pdf" + "" + CONTENT_PATTERN + "" + "" + ""; private X509Certificate certificate; private String moaEndpoint; private String keyIdentifier; public MOAConnector(Configuration config) throws CertificateException, FileNotFoundException, IOException { if(config.getValue(MOA_SIGN_CERTIFICATE) == null) { logger.error(MOA_SIGN_CERTIFICATE + " not configured for MOA connector"); throw new PdfAsWrappedIOException(new PdfAsException("Please configure: " + MOA_SIGN_CERTIFICATE + " to use MOA connector")); } if(!(config instanceof ISettings)) { logger.error("Configuration is no instance of ISettings"); throw new PdfAsWrappedIOException(new PdfAsException("Configuration is no instance of ISettings")); } ISettings settings = (ISettings)config; String certificateValue = config.getValue(MOA_SIGN_CERTIFICATE); File certFile = new File(certificateValue); if(!certFile.isAbsolute()) { certificateValue = settings.getWorkingDirectory() + "/" + config.getValue(MOA_SIGN_CERTIFICATE); certFile = new File(certificateValue); } logger.info("Loading certificate: " + certificateValue); this.certificate = new X509Certificate(new FileInputStream(certFile)); this.moaEndpoint = config.getValue(MOA_SIGN_URL); this.keyIdentifier = config.getValue(MOA_SIGN_KEY_ID); } public X509Certificate getCertificate(SignParameter parameter) throws PdfAsException { return this.certificate; } private CloseableHttpClient buildHttpClient() { HttpClientBuilder builder = HttpClientBuilder.create(); return builder.build(); } public byte[] sign(byte[] input, int[] byteRange, SignParameter parameter) throws PdfAsException { CloseableHttpClient client = null; try { client = buildHttpClient(); HttpPost post = new HttpPost(this.moaEndpoint); logger.info("signature with MOA [" + this.keyIdentifier + "] @ " + this.moaEndpoint); Base64 base64 = new Base64(); String content = base64.encodeAsString(input); String request = CMS_REQUEST; request = request.replace(CONTENT_PATTERN, content.trim()); request = request .replace(KEY_ID_PATTERN, this.keyIdentifier.trim()); // SOAPAction: "urn:CreateCMSSignatureAction" post.setHeader("SOAPAction", "urn:CreateCMSSignatureAction"); EntityBuilder entityBuilder = EntityBuilder.create(); entityBuilder.setContentType(ContentType.TEXT_XML); entityBuilder.setContentEncoding("UTF-8"); entityBuilder.setText(request); post.setEntity(entityBuilder.build()); moalogger.debug(">>> " + request); HttpResponse response = client.execute(post); BufferedReader rd = new BufferedReader(new InputStreamReader( response.getEntity().getContent())); StringBuffer result = new StringBuffer(); String line = ""; while ((line = rd.readLine()) != null) { result.append(line); } moalogger.debug("<<< " + result.toString()); DocumentBuilderFactory dbFactory = DocumentBuilderFactory .newInstance(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); Document doc = dBuilder.parse(new InputSource(new StringReader( result.toString()))); doc.getDocumentElement().normalize(); if (response.getStatusLine().getStatusCode() != 200) { String faultCode = ""; String faultString = ""; String errorResponse = ""; String errorCode = ""; NodeList nodeList = doc.getElementsByTagName("*"); for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { if (node.getNodeName().equals(FAULTCODE)) { faultCode = node.getTextContent(); } else if (node.getNodeName().equals(FAULTSTRING)) { faultString = node.getTextContent(); } else if (node.getNodeName().equals(ERRORCODE)) { errorCode = node.getTextContent(); } else if (node.getNodeName().equals(ERRORRESPONSE)) { errorResponse = node.getTextContent(); } } } throw new PdfAsMOAException(faultCode, faultString, errorResponse, errorCode); } else { String cmsSignature = null; NodeList nodeList = doc.getElementsByTagName("*"); for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { if (node.getNodeName().equals(CMSSIGNATURE)) { cmsSignature = node.getTextContent(); break; } } } if (cmsSignature != null) { try { return base64.decode(cmsSignature); } catch(Exception e) { throw new PdfAsException("error.pdf.io.07", e); } } else { throw new PdfAsException("error.pdf.io.07"); } } } catch (IllegalStateException e) { throw new PdfAsException("error.pdf.io.08", e); } catch (IOException e) { throw new PdfAsException("error.pdf.io.08", e); } catch (SAXException e) { throw new PdfAsException("error.pdf.io.08", e); } catch (ParserConfigurationException e) { throw new PdfAsException("error.pdf.io.08", e); } finally { if (client != null) { try { client.close(); } catch (IOException e) { logger.warn("Failed to close client", e); } } } } /* * public byte[] sign(byte[] input, int[] byteRange) throws PdfAsException { * try { * * SignatureCreationServiceStub signatureCreationService = new * SignatureCreationServiceStub( this.moaEndpoint); * * CreateCMSSignatureRequest createCMSSignatureRequest = new * CreateCMSSignatureRequest(); KeyIdentifierType keyId = new * KeyIdentifierType(); keyId.setKeyIdentifierType(keyIdentifier); * createCMSSignatureRequest.setKeyIdentifier(keyId); * * SingleSignatureInfo_type1 singleSignature = new * SingleSignatureInfo_type1(); DataObjectInfo_type1 dataObjectType = new * DataObjectInfo_type1(); * * dataObjectType.setStructure(Structure_type1.detached); * singleSignature.setDataObjectInfo(dataObjectType); DataObject_type1 * dataObject = new DataObject_type1(); MetaInfoType metaInfoType = new * MetaInfoType(); MimeTypeType mimeTypeType = new MimeTypeType(); * mimeTypeType.setMimeTypeType(new Token("application/pdf")); * metaInfoType.setMimeType(mimeTypeType); * dataObject.setMetaInfo(metaInfoType); * dataObjectType.setDataObject(dataObject); CMSContentBaseType cmsContent = * new CMSContentBaseType(); cmsContent.setBase64Content(new DataHandler( * new ByteArrayDataSource(input, "application/pdf"))); * * dataObject.setContent(cmsContent); * * createCMSSignatureRequest.addSingleSignatureInfo(singleSignature); * * CreateCMSSignatureResponse response = signatureCreationService * .createCMSSignature(createCMSSignatureRequest); * * InputStream is = response.getCreateCMSSignatureResponse() * .getCreateCMSSignatureResponseTypeChoice()[0] * .getCMSSignature().getInputStream(); * * byte[] signature = StreamUtils.inputStreamToByteArray(is); * * return signature; } catch (Exception e) { throw new * PdfAsException(e.getMessage()); } } */ }