From 6336eb94021158575a15abd0efb8f3089197d0ab Mon Sep 17 00:00:00 2001 From: Andreas Fitzek Date: Wed, 8 Oct 2014 17:54:06 +0200 Subject: Introduced PDF-AS-MOA --- pdf-as-moa/src/main/java/META-INF/MANIFEST.MF | 3 + .../at.gv.egiz.pdfas.lib.impl.verify.IVerifier | 1 + .../java/at/gv/egiz/pdfas/moa/MOAConnector.java | 220 +++++++++++++++++++++ .../java/at/gv/egiz/pdfas/moa/MOAVerifier.java | 197 ++++++++++++++++++ .../src/main/resources/wsdl/MOA-SPSS-1.5.2.wsdl | 128 ++++++++++++ 5 files changed, 549 insertions(+) create mode 100644 pdf-as-moa/src/main/java/META-INF/MANIFEST.MF create mode 100644 pdf-as-moa/src/main/java/META-INF/services/at.gv.egiz.pdfas.lib.impl.verify.IVerifier create mode 100644 pdf-as-moa/src/main/java/at/gv/egiz/pdfas/moa/MOAConnector.java create mode 100644 pdf-as-moa/src/main/java/at/gv/egiz/pdfas/moa/MOAVerifier.java create mode 100644 pdf-as-moa/src/main/resources/wsdl/MOA-SPSS-1.5.2.wsdl (limited to 'pdf-as-moa/src/main') diff --git a/pdf-as-moa/src/main/java/META-INF/MANIFEST.MF b/pdf-as-moa/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 00000000..5e949512 --- /dev/null +++ b/pdf-as-moa/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + diff --git a/pdf-as-moa/src/main/java/META-INF/services/at.gv.egiz.pdfas.lib.impl.verify.IVerifier b/pdf-as-moa/src/main/java/META-INF/services/at.gv.egiz.pdfas.lib.impl.verify.IVerifier new file mode 100644 index 00000000..1ace6960 --- /dev/null +++ b/pdf-as-moa/src/main/java/META-INF/services/at.gv.egiz.pdfas.lib.impl.verify.IVerifier @@ -0,0 +1 @@ +at.gv.egiz.pdfas.moa.MOAVerifier #MOA Verifier \ No newline at end of file diff --git a/pdf-as-moa/src/main/java/at/gv/egiz/pdfas/moa/MOAConnector.java b/pdf-as-moa/src/main/java/at/gv/egiz/pdfas/moa/MOAConnector.java new file mode 100644 index 00000000..1b4064a5 --- /dev/null +++ b/pdf-as-moa/src/main/java/at/gv/egiz/pdfas/moa/MOAConnector.java @@ -0,0 +1,220 @@ +/******************************************************************************* + * 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.moa; + +import iaik.x509.X509Certificate; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.cert.CertificateException; + +import javax.xml.ws.BindingProvider; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.e_government.reference.namespace.moa._20020822.CMSContentBaseType; +import at.gv.e_government.reference.namespace.moa._20020822.CMSDataObjectInfoType.DataObject; +import at.gv.e_government.reference.namespace.moa._20020822.CreateCMSSignatureRequest; +import at.gv.e_government.reference.namespace.moa._20020822.CreateCMSSignatureRequestType.SingleSignatureInfo; +import at.gv.e_government.reference.namespace.moa._20020822.CreateCMSSignatureRequestType.SingleSignatureInfo.DataObjectInfo; +import at.gv.e_government.reference.namespace.moa._20020822.CreateCMSSignatureResponseType; +import at.gv.e_government.reference.namespace.moa._20020822.ErrorResponseType; +import at.gv.e_government.reference.namespace.moa._20020822.MetaInfoType; +import at.gv.e_government.reference.namespace.moa._20020822_.MOAFault; +import at.gv.e_government.reference.namespace.moa._20020822_.SignatureCreationPortType; +import at.gv.e_government.reference.namespace.moa._20020822_.SignatureCreationService; +import at.gv.egiz.pdfas.common.exceptions.PdfAsException; +import at.gv.egiz.pdfas.common.exceptions.PdfAsMOAException; +import at.gv.egiz.pdfas.common.exceptions.PdfAsSignatureException; +import at.gv.egiz.pdfas.common.exceptions.PdfAsWrappedIOException; +import at.gv.egiz.pdfas.common.settings.ISettings; +import at.gv.egiz.pdfas.common.utils.StreamUtils; +import at.gv.egiz.pdfas.lib.api.Configuration; +import at.gv.egiz.pdfas.lib.api.IConfigurationConstants; +import at.gv.egiz.pdfas.lib.api.sign.SignParameter; +import at.gv.egiz.pdfas.lib.api.verify.VerifyResult; +import at.gv.egiz.pdfas.lib.impl.status.RequestedSignature; +import at.gv.egiz.pdfas.lib.util.SignatureUtils; +import at.gv.egiz.sl.util.ISignatureConnector; + +public class MOAConnector implements ISignatureConnector, + IConfigurationConstants { + + private static final Logger logger = LoggerFactory + .getLogger(MOAConnector.class); + + 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); + + if (certificateValue.startsWith("http")) { + logger.info("Loading certificate from url: " + certificateValue); + + try { + URL certificateURL = new URL(certificateValue); + + this.certificate = new X509Certificate(certificateURL.openStream()); + } catch(MalformedURLException e) { + logger.error(certificateValue + + " is not a valid url but!"); + throw new PdfAsWrappedIOException(new PdfAsException( + certificateValue + + " is not a valid url but!")); + } + } else { + + File certFile = new File(certificateValue); + if (!certFile.isAbsolute()) { + certificateValue = settings.getWorkingDirectory() + "/" + + config.getValue(MOA_SIGN_CERTIFICATE); + certFile = new File(certificateValue); + } + + logger.info("Loading certificate from file: " + 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; + } + + public byte[] sign(byte[] input, int[] byteRange, SignParameter parameter, + RequestedSignature requestedSignature) throws PdfAsException { + + logger.info("signing with MOA @ " + this.moaEndpoint); + URL moaUrl; + try { + moaUrl = new URL(this.moaEndpoint); + } catch (MalformedURLException e1) { + throw new PdfAsException("Invalid MOA endpoint!", e1); + } + SignatureCreationService service = new SignatureCreationService(moaUrl); + + SignatureCreationPortType creationPort = service.getSignatureCreationPort(); + BindingProvider provider = (BindingProvider) creationPort; + provider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, this.moaEndpoint); + + CreateCMSSignatureRequest request = new CreateCMSSignatureRequest(); + request.setKeyIdentifier(this.keyIdentifier.trim()); + SingleSignatureInfo sigInfo = new SingleSignatureInfo(); + sigInfo.setSecurityLayerConformity(Boolean.TRUE); + DataObjectInfo dataObjectInfo = new DataObjectInfo(); + dataObjectInfo.setStructure("detached"); + DataObject dataObject = new DataObject(); + MetaInfoType metaInfoType = new MetaInfoType(); + + metaInfoType.setMimeType("application/pdf"); + + dataObject.setMetaInfo(metaInfoType); + + CMSContentBaseType content = new CMSContentBaseType(); + content.setBase64Content(input); + + dataObject.setContent(content); + + dataObjectInfo.setDataObject(dataObject); + sigInfo.setDataObjectInfo(dataObjectInfo); + request.getSingleSignatureInfo().add(sigInfo); + + CreateCMSSignatureResponseType response; + try { + response = creationPort.createCMSSignature(request); + } catch (MOAFault e) { + logger.error("MOA signing failed!", e); + if(e.getFaultInfo() != null) { + throw new PdfAsMOAException(e.getFaultInfo().getErrorCode().toString(), + e.getFaultInfo().getInfo(), + "", ""); + } else { + throw new PdfAsMOAException("", + e.getMessage(), + "", ""); + } + } + + if(response.getCMSSignatureOrErrorResponse().size() != 1) { + throw new PdfAsException("Invalid Response Count [" + response.getCMSSignatureOrErrorResponse().size() + + "] from MOA!"); + } + + Object resp = response.getCMSSignatureOrErrorResponse().get(0); + if(resp instanceof byte[]) { + // done the signature! + byte[] cmsSignatureData = (byte[])resp; + + VerifyResult verifyResult = SignatureUtils + .verifySignature(cmsSignatureData, input); + + if (!StreamUtils.dataCompare(requestedSignature + .getCertificate().getFingerprintSHA(), + ((X509Certificate) verifyResult + .getSignerCertificate()) + .getFingerprintSHA())) { + throw new PdfAsSignatureException( + "Certificates missmatch!"); + } + + return cmsSignatureData; + } else if(resp instanceof ErrorResponseType) { + ErrorResponseType err = (ErrorResponseType) resp; + + throw new PdfAsMOAException("", "", + err.getInfo(), err.getErrorCode().toString()); + + } else { + throw new PdfAsException("MOA response is not byte[] nor error but: " + resp.getClass().getName()); + } + } +} diff --git a/pdf-as-moa/src/main/java/at/gv/egiz/pdfas/moa/MOAVerifier.java b/pdf-as-moa/src/main/java/at/gv/egiz/pdfas/moa/MOAVerifier.java new file mode 100644 index 00000000..42af02f7 --- /dev/null +++ b/pdf-as-moa/src/main/java/at/gv/egiz/pdfas/moa/MOAVerifier.java @@ -0,0 +1,197 @@ +package at.gv.egiz.pdfas.moa; + +import iaik.x509.X509Certificate; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.List; + +import javax.xml.bind.JAXBElement; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; +import javax.xml.ws.BindingProvider; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3._2000._09.xmldsig.KeyInfoType; +import org.w3._2000._09.xmldsig.X509DataType; + +import com.sun.org.apache.xerces.internal.dom.ElementNSImpl; + +import at.gv.e_government.reference.namespace.moa._20020822.CMSContentBaseType; +import at.gv.e_government.reference.namespace.moa._20020822.CMSDataObjectOptionalMetaType; +import at.gv.e_government.reference.namespace.moa._20020822.CheckResultType; +import at.gv.e_government.reference.namespace.moa._20020822.MetaInfoType; +import at.gv.e_government.reference.namespace.moa._20020822.VerifyCMSSignatureRequest; +import at.gv.e_government.reference.namespace.moa._20020822.VerifyCMSSignatureResponseType; +import at.gv.e_government.reference.namespace.moa._20020822_.SignatureVerificationPortType; +import at.gv.e_government.reference.namespace.moa._20020822_.SignatureVerificationService; +import at.gv.egiz.pdfas.common.exceptions.PdfAsException; +import at.gv.egiz.pdfas.lib.api.Configuration; +import at.gv.egiz.pdfas.lib.api.verify.VerifyParameter.SignatureVerificationLevel; +import at.gv.egiz.pdfas.lib.api.verify.VerifyResult; +import at.gv.egiz.pdfas.lib.impl.verify.IVerifier; +import at.gv.egiz.pdfas.lib.impl.verify.SignatureCheckImpl; +import at.gv.egiz.pdfas.lib.impl.verify.VerifyResultImpl; + +public class MOAVerifier implements IVerifier { + + private static final Logger logger = LoggerFactory + .getLogger(MOAVerifier.class); + + private static final String MOA_VERIFY_URL = "moa.verify.url"; + private static final String MOA_VERIFY_TRUSTPROFILE = "moa.verify.TrustProfileID"; + + private String moaEndpoint; + private String moaTrustProfile; + + + public List verify(byte[] signature, byte[] signatureContent, + Date verificationTime) throws PdfAsException { + List resultList = new ArrayList(); + try { + logger.info("verification with MOA @ " + this.moaEndpoint); + URL moaUrl = new URL(this.moaEndpoint); + + SignatureVerificationService service = new SignatureVerificationService(moaUrl); + + SignatureVerificationPortType verificationPort = service.getSignatureVerificationPort(); + BindingProvider provider = (BindingProvider) verificationPort; + provider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, this.moaEndpoint); + VerifyCMSSignatureRequest verifyCMSSignatureRequest = new VerifyCMSSignatureRequest(); + verifyCMSSignatureRequest.setTrustProfileID(this.moaTrustProfile); + verifyCMSSignatureRequest.setCMSSignature(signature); + CMSDataObjectOptionalMetaType metaDataType = new CMSDataObjectOptionalMetaType(); + + MetaInfoType metaInfoType = new MetaInfoType(); + metaInfoType.setDescription("PDF Document"); + metaInfoType.setMimeType("application/pdf"); + metaDataType.setMetaInfo(metaInfoType); + + CMSContentBaseType contentBase = new CMSContentBaseType(); + contentBase.setBase64Content(signatureContent); + metaDataType.setContent(contentBase); + + verifyCMSSignatureRequest.setDataObject(metaDataType); + + if (verificationTime != null) { + GregorianCalendar c = new GregorianCalendar(); + c.setTime(verificationTime); + XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c); + verifyCMSSignatureRequest.setDateTime(date2); + } + + VerifyCMSSignatureResponseType response = verificationPort + .verifyCMSSignature(verifyCMSSignatureRequest); + + logger.debug("Got Verify Response from MOA"); + + List> verifySequence = response.getSignerInfoAndSignatureCheckAndCertificateCheck(); + + VerifyResultImpl result = new VerifyResultImpl(); + + result.setCertificateCheck(new SignatureCheckImpl(1,"")); + result.setValueCheckCode(new SignatureCheckImpl(1,"")); + result.setVerificationDone(true); + result.setSignatureData(signatureContent); + + for (int i = 0; i < verifySequence.size(); i++) { + // + + JAXBElement element = verifySequence.get(i); + + logger.debug(" ---------------------- "); + logger.debug("Name: " + element.getName().getLocalPart()); + logger.debug("Class: " + element.getValue().getClass().getName()); + + if(element.getName().getLocalPart().equals("SignerInfo")) { + if(!(element.getValue() instanceof KeyInfoType)) { + // TODO throw Exception + } + KeyInfoType keyInfo = (KeyInfoType)element.getValue(); + + for(Object obj : keyInfo.getContent()) { + logger.debug("KeyInfo: " + obj.getClass().toString()); + if(obj instanceof JAXBElement) { + JAXBElement ele = (JAXBElement)obj; + logger.debug("KeyInfo: " + ele.getName().getLocalPart()); + logger.debug("KeyInfo: " + ele.getValue().getClass().getName()); + if(ele.getName().getLocalPart().equals("X509Data") && + ele.getValue() instanceof X509DataType) { + X509DataType x509Data = (X509DataType)ele.getValue(); + for(Object o : x509Data.getX509IssuerSerialOrX509SKIOrX509SubjectName()) { + logger.debug("X509 class: " + o.getClass().getName()); + if(o instanceof JAXBElement) { + JAXBElement e = (JAXBElement)o; + logger.debug("X509 class CHILD: " + e.getName().getLocalPart()); + logger.debug("X509 class CHILD: " + e.getValue().getClass().getName()); + if(e.getName().getLocalPart().equals("X509Certificate")) { + if(e.getValue() instanceof byte[]) { + X509Certificate signerCertificate = new X509Certificate((byte[])e.getValue()); + result.setSignerCertificate(signerCertificate); + } + } + } /*else if(o instanceof ElementNSImpl) { + logger.debug("ElementNSImpl name: " + ((ElementNSImpl) o).getNodeValue()); + for(int j = 0; j < ((ElementNSImpl) o).getAttributes().getLength(); j++) { + + //logger.debug("ElementNSImpl name: " + ((ElementNSImpl) o).getAttributes().item(j)..getTextContent()); + } + }*/ + } + } + } + } + + } else if(element.getName().getLocalPart().equals("SignatureCheck")) { + + if(!(element.getValue() instanceof CheckResultType)) { + // TODO throw Exception + } + + CheckResultType checkResult = (CheckResultType)element.getValue(); + + result.setValueCheckCode(new SignatureCheckImpl( + checkResult.getCode().intValue(), + (checkResult.getInfo() != null) ? + checkResult.getInfo().toString() : "" + )); + + } else if(element.getName().getLocalPart().equals("CertificateCheck")) { + + if(!(element.getValue() instanceof CheckResultType)) { + // TODO throw Exception + } + + CheckResultType checkResult = (CheckResultType)element.getValue(); + + result.setCertificateCheck(new SignatureCheckImpl( + checkResult.getCode().intValue(), + (checkResult.getInfo() != null) ? + checkResult.getInfo().toString() : "" + )); + } + + logger.debug(" ---------------------- "); + } + resultList.add(result); + } catch (Throwable e) { + logger.error("Verification failed", e); + throw new PdfAsException("error.pdf.verify.02", e); + } + return resultList; + } + + public void setConfiguration(Configuration config) { + this.moaEndpoint = config.getValue(MOA_VERIFY_URL); + this.moaTrustProfile = config.getValue(MOA_VERIFY_TRUSTPROFILE); + } + + @Override + public SignatureVerificationLevel getLevel() { + return SignatureVerificationLevel.FULL_VERIFICATION; + } + +} diff --git a/pdf-as-moa/src/main/resources/wsdl/MOA-SPSS-1.5.2.wsdl b/pdf-as-moa/src/main/resources/wsdl/MOA-SPSS-1.5.2.wsdl new file mode 100644 index 00000000..0554ecaf --- /dev/null +++ b/pdf-as-moa/src/main/resources/wsdl/MOA-SPSS-1.5.2.wsdl @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3