All Downloads are FREE. Search and download functionalities are using the official Maven repository.

no.difi.asic.XadesAsicManifest Maven / Gradle / Ivy

Go to download

Generic implementation of ASiC-E archives in accordance with ETSI 102 918 v1.3.1.

There is a newer version: 1.0.0
Show newest version
package no.difi.asic;

import com.google.common.hash.Hashing;
import org.etsi.uri._01903.v1_3.*;
import org.etsi.uri._02918.v1_2.ObjectFactory;
import org.etsi.uri._02918.v1_2.XAdESSignaturesType;
import org.w3._2000._09.xmldsig_.*;

import javax.xml.bind.*;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.util.GregorianCalendar;

import org.etsi.uri._02918.v1_2.ObjectFactory;

class XadesAsicManifest extends AbstractAsicManifest {

    private static JAXBContext jaxbContext; // Thread safe
    private static ObjectFactory objectFactory1_2 = new ObjectFactory();
    private static org.etsi.uri._01903.v1_3.ObjectFactory objectFactory1_3 = new org.etsi.uri._01903.v1_3.ObjectFactory();

    static {
        try {
            jaxbContext = JAXBContext.newInstance(XAdESSignaturesType.class, X509DataType.class, QualifyingPropertiesType.class);
        } catch (JAXBException e) {
            throw new IllegalStateException(String.format("Unable to create JAXBContext: %s ", e.getMessage()), e);
        }
    }

    // \XAdESSignature\Signature\SignedInfo
    private SignedInfoType signedInfo;
    // \XAdESSignature\Signature\Object\QualifyingProperties\SignedProperties\SignedDataObjectProperties
    private SignedDataObjectPropertiesType signedDataObjectProperties = new SignedDataObjectPropertiesType();

    public XadesAsicManifest(MessageDigestAlgorithm messageDigestAlgorithm) {
        super(messageDigestAlgorithm);

        // \XAdESSignature\Signature\SignedInfo
        signedInfo = new SignedInfoType();

        // \XAdESSignature\Signature\SignedInfo\CanonicalizationMethod
        CanonicalizationMethodType canonicalizationMethod = new CanonicalizationMethodType();
        canonicalizationMethod.setAlgorithm("http://www.w3.org/2006/12/xml-c14n11");
        signedInfo.setCanonicalizationMethod(canonicalizationMethod);

        // \XAdESSignature\Signature\SignedInfo\SignatureMethod
        SignatureMethodType signatureMethod = new SignatureMethodType();
        signatureMethod.setAlgorithm(messageDigestAlgorithm.getUri());
        signedInfo.setSignatureMethod(signatureMethod);
    }

    @Override
    public void add(String filename, MimeType mimeType) {
        String id = String.format("ID_%s", signedInfo.getReference().size());

        {
            // \XAdESSignature\Signature\SignedInfo\Reference
            ReferenceType reference = new ReferenceType();
            reference.setId(id);
            reference.setURI(filename);
            reference.setDigestValue(messageDigest.digest());

            // \XAdESSignature\Signature\SignedInfo\Reference\DigestMethod
            DigestMethodType digestMethodType = new DigestMethodType();
            digestMethodType.setAlgorithm(messageDigestAlgorithm.getUri());
            reference.setDigestMethod(digestMethodType);

            signedInfo.getReference().add(reference);
        }

        {
            // \XAdESSignature\Signature\Object\QualifyingProperties\SignedProperties\SignedDataObjectProperties\DataObjectFormat
            DataObjectFormatType dataObjectFormatType = new DataObjectFormatType();
            dataObjectFormatType.setObjectReference(String.format("#%s", id));
            dataObjectFormatType.setMimeType(mimeType.toString());

            signedDataObjectProperties.getDataObjectFormat().add(dataObjectFormatType);
        }
    }

    XAdESSignaturesType getCreateXAdESSignatures(SignatureHelper signatureHelper) {
        // \XAdESSignature
        XAdESSignaturesType xAdESSignaturesType = new XAdESSignaturesType();

        // \XAdESSignature\Signature
        SignatureType signatureType = new SignatureType();
        signatureType.setId("Signature");
        signatureType.setSignedInfo(signedInfo);
        xAdESSignaturesType.getSignature().add(signatureType);

        // \XAdESSignature\Signature\KeyInfo
        KeyInfoType keyInfoType = new KeyInfoType();
        keyInfoType.getContent().add(getX509Data(signatureHelper));
        signatureType.setKeyInfo(keyInfoType);

        // \XAdESSignature\Signature\Object
        ObjectType objectType = new ObjectType();
        objectType.getContent().add(getQualifyingProperties(signatureHelper));
        signatureType.getObject().add(objectType);

        // \XAdESSignature\Signature\Object\SignatureValue
        signatureType.setSignatureValue(getSignature());

        return xAdESSignaturesType;
    }

    public byte[] toBytes(SignatureHelper signatureHelper) {

        try {
            Marshaller marshaller = jaxbContext.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            // TODO
            marshaller.marshal(objectFactory1_2.createXAdESSignatures(getCreateXAdESSignatures(signatureHelper)), baos);
            return baos.toByteArray();
        } catch (JAXBException e) {
            throw new IllegalStateException("Unable to marshall the XAdESSignature into string output", e);
        }

    }

    private JAXBElement getX509Data(SignatureHelper signatureHelper) {
        org.w3._2000._09.xmldsig_.ObjectFactory objectFactory = new org.w3._2000._09.xmldsig_.ObjectFactory();

        // \XAdESSignature\Signature\KeyInfo\X509Data
        X509DataType x509DataType = new X509DataType();

        for (Certificate certificate : signatureHelper.getCertificateChain()) {
            try {
                // \XAdESSignature\Signature\KeyInfo\X509Data\X509Certificate
                x509DataType.getX509IssuerSerialOrX509SKIOrX509SubjectName().add(objectFactory.createX509DataTypeX509Certificate(certificate.getEncoded()));
            } catch (CertificateEncodingException e) {
                throw new IllegalStateException("Unable to insert certificate.", e);
            }
        }

        return objectFactory.createX509Data(x509DataType);
    }

    private JAXBElement getQualifyingProperties(SignatureHelper signatureHelper) {
        // \XAdESSignature\Signature\Object\QualifyingProperties\SignedProperties\SignedSignatureProperties
        SignedSignaturePropertiesType signedSignaturePropertiesType = new SignedSignaturePropertiesType();
        try {
            // \XAdESSignature\Signature\Object\QualifyingProperties\SignedProperties\SignedSignatureProperties\SigningTime
            signedSignaturePropertiesType.setSigningTime(DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar()));
        } catch (DatatypeConfigurationException e) {
            throw new IllegalStateException("Unable to use current DatatypeFactory", e);
        }

        // \XAdESSignature\Signature\Object\QualifyingProperties\SignedProperties\SignedSignatureProperties\SigningCertificate
        CertIDListType certIDListType = new CertIDListType();
        signedSignaturePropertiesType.setSigningCertificate(certIDListType);

        // \XAdESSignature\Signature\Object\QualifyingProperties\SignedProperties\SignedSignatureProperties\SigningCertificate\Cert
        CertIDType cert = new CertIDType();
        certIDListType.getCert().add(cert);

        try {
            // \XAdESSignature\Signature\Object\QualifyingProperties\SignedProperties\SignedSignatureProperties\SigningCertificate\Cert\CertDigest
            DigestAlgAndValueType certDigest = new DigestAlgAndValueType();
            certDigest.setDigestValue(Hashing.sha1().hashBytes(signatureHelper.getX509Certificate().getEncoded()).asBytes());
            cert.setCertDigest(certDigest);

            // \XAdESSignature\Signature\Object\QualifyingProperties\SignedProperties\SignedSignatureProperties\SigningCertificate\Cert\CertDigest\DigestMethod
            DigestMethodType digestMethodType = new DigestMethodType();
            digestMethodType.setAlgorithm("http://www.w3.org/2000/09/xmldsig#sha1");
            certDigest.setDigestMethod(digestMethodType);
        } catch (CertificateEncodingException e) {
            throw new IllegalStateException("Unable to encode certificate.", e);
        }

        // \XAdESSignature\Signature\Object\QualifyingProperties\SignedProperties\SignedSignatureProperties\SigningCertificate\Cert\IssuerSerial
        X509IssuerSerialType issuerSerialType = new X509IssuerSerialType();
        issuerSerialType.setX509IssuerName(signatureHelper.getX509Certificate().getIssuerX500Principal().getName());
        issuerSerialType.setX509SerialNumber(signatureHelper.getX509Certificate().getSerialNumber());
        cert.setIssuerSerial(issuerSerialType);

        // \XAdESSignature\Signature\Object\QualifyingProperties\SignedProperties
        SignedPropertiesType signedPropertiesType = new SignedPropertiesType();
        signedPropertiesType.setId("SignedProperties");
        signedPropertiesType.setSignedSignatureProperties(signedSignaturePropertiesType);
        signedPropertiesType.setSignedDataObjectProperties(signedDataObjectProperties);

        // \XAdESSignature\Signature\Object\QualifyingProperties
        QualifyingPropertiesType qualifyingPropertiesType = new QualifyingPropertiesType();
        // qualifyingPropertiesType.setSignedProperties(signedPropertiesType);
        qualifyingPropertiesType.setTarget("#Signature");

        // Adding digest of SignedProperties into SignedInfo
        {
            // \XAdESSignature\Signature\SignedInfo\Reference
            ReferenceType reference = new ReferenceType();
            reference.setType("http://uri.etsi.org/01903#SignedProperties");
            reference.setURI("#SignedProperties");
            // TODO Generate digest

            // \XAdESSignature\Signature\SignedInfo\Reference\Transforms
            TransformsType transformsType = new TransformsType();
            reference.setTransforms(transformsType);

            // \XAdESSignature\Signature\SignedInfo\Reference\Transforms\Transform
            TransformType transformType = new TransformType();
            transformType.setAlgorithm("http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
            reference.getTransforms().getTransform().add(transformType);

            // \XAdESSignature\Signature\SignedInfo\Reference\DigestMethod
            DigestMethodType digestMethodType = new DigestMethodType();
            digestMethodType.setAlgorithm(messageDigestAlgorithm.getUri());
            reference.setDigestMethod(digestMethodType);

            signedInfo.getReference().add(reference);
        }

        return objectFactory1_3.createQualifyingProperties(qualifyingPropertiesType);
    }

    protected SignatureValueType getSignature() {
        // TODO Generate signature
        // http://stackoverflow.com/questions/30596933/xades-bes-detached-signedproperties-reference-wrong-digestvalue-java

        /*
        DigestMethod dm = fac.newDigestMethod(DigestMethod.SHA1, null);
        CanonicalizationMethod cn = fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS,(C14NMethodParameterSpec) null);

        List refs = new ArrayList();
        Reference ref1 = fac.newReference(pathName, dm,null,null,signedRefID,messageDigest2.digest(datax));
        refs.add(ref1);

        Canonicalizer cn14 = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N11_OMIT_COMMENTS);
        byte[] canon;
        canon = cn14.canonicalizeSubtree(SPElement);
        Reference ref2 = fac.newReference("#"+signedPropID,dm, null , sigProp , signedPropRefID,messageDigest2.digest(canon));
        refs.add(ref2);

        SignatureMethod sm = fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null);
        SignedInfo si = fac.newSignedInfo(cn, sm, refs);

        XMLSignature signature = fac.newXMLSignature(si, ki,objects,signatureID,null);

        signature.sign(dsc);
        */

        return new SignatureValueType();
    }

    @SuppressWarnings("unchecked")
    public static void extractAndVerify(String xml, ManifestVerifier manifestVerifier) {
        // Updating namespace
        xml = xml.replace("http://uri.etsi.org/02918/v1.1.1#", "http://uri.etsi.org/02918/v1.2.1#");
        xml = xml.replace("http://uri.etsi.org/2918/v1.2.1#", "http://uri.etsi.org/02918/v1.2.1#");
        xml = xml.replaceAll("http://www.w3.org/2000/09/xmldsig#sha", "http://www.w3.org/2001/04/xmlenc#sha");

        XAdESSignaturesType manifest;

        try {
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            manifest = unmarshaller.unmarshal(new StreamSource(new ByteArrayInputStream(xml.getBytes())), XAdESSignaturesType.class).getValue();
        } catch (Exception e) {
            throw new IllegalStateException("Unable to read content as XML", e);
        }

        for (SignatureType signature : manifest.getSignature()) {
            SignedInfoType signedInfoType = signature.getSignedInfo();

            for (ReferenceType reference : signedInfoType.getReference()) {
                if (!reference.getURI().startsWith("#"))
                    manifestVerifier.update(reference.getURI(), null, reference.getDigestValue(), reference.getDigestMethod().getAlgorithm(), null);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy