ENI (7) ENI Expedient for Sedipualba: Signing content

0. Introduction

In a previous post we saw how to create the "Expediente" in ENI format. But the signature of the content was not accepted by Valide 

After analyzing the ENI format of the "Expedient" generated in Sedipualba that has no problem with Valide  there are some differences in the signature:

  • Sedipualba uses the TF03 signatures format (XAdES Enveloped)
  • Sedipualba does not use the binary FirmaBase64 field. Sedipualba uses ds:Signature field instead.
So our steps are:
  1. Marshall the content("indice.indiceContenido" attribute) of the "Expedient" into an XML file (for instance contenidoYEAR.xml where YEAR is the year of the resolutions for instance 2022).
  2. Use Autofirma and sign the previous XML file in XAdES Enveloped format
  3. Get the "xadesEnveloped.xsd" schema from this URL from Liquid Technologies  and adapt the schema
  4. Get the class eni.xades.enveloped.IndiceContenido
  5. Unmarshall the signature obtained by Autofirma into the previous class and extract the Signature class.
  6. Assign this Signature class to the nested attribute "indice.firmas.firma.contenidoFirma.firmaConCertificado.signature" of the class "TipoExpediente" 
  7. Marshall the "Expediente" object whose class is "TipoExpediente"

1. Marshalling the "indice.indiceContenido" field

We need a class for marshalling and unmarshalling. This class uses these dependencies:

  • 'javax.xml.bind:jaxb-api:2.4.0-b180830.0359'

  • 'org.glassfish:javax.xml.bind:10.0-b28


1.1 A Marshalling utility class JAXBEduImp.class

package openadmin.utils.jaxb;

import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;


import org.apache.commons.io.IOUtils;
import org.xml.sax.SAXException;

import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBElement;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;
import jakarta.xml.bind.Unmarshaller;
import openadmin.utils.jackson.IJacksonEdu;


public class JAXBEduImp implements IJacksonEdu{
    
    public JAXBEduImp() {
        
    }
    
    public Marshaller getMarshaller(Class myClass) throws JAXBException {
        JAXBContext context = JAXBContext.newInstance(myClass);
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        return m;
    }
    
    public Unmarshaller getUnmarshaller(Class myClass) throws JAXBException {
        JAXBContext context = JAXBContext.newInstance(myClass);
        Unmarshaller jaxbUnmarshaller = context.createUnmarshaller();  
        return jaxbUnmarshaller;
    }
    
    public String ObjectToString (Object obj) throws Exception {
        Marshaller m = getMarshaller(obj.getClass());
        StringWriter sw = new StringWriter();
        m.marshal(obj, sw);
        String result = sw.toString();
        return result;
    }
    
    
    public void ObjectToFile (Object obj, String fileName) throws Exception {
        Marshaller m = getMarshaller(obj.getClass());
        m.marshal(obj, new FileOutputStream(fileName));
    }
    
    public StringWriter ObjectToStringWriter (Object obj) throws Exception {
        Marshaller m = getMarshaller(obj.getClass());
        StringWriter sw = new StringWriter();
        m.marshal(obj, sw);
        return sw;
    }
    
    public InputStream ObjectToIputStream(Object obj) throws Exception {
        return IOUtils.toInputStream(this.ObjectToString(obj), "UTF-8");
    }
    
    public <T extends Object> T InputStreamToObject(InputStream in, Class<T> valueType) throws Exception {
        Unmarshaller unM = getUnmarshaller(valueType);
        T obj = (T) unM.unmarshal(in);
        return obj;
        //JAXBElement<T> root = (JAXBElement<T>) unM.unmarshal(in);
        //return root.getValue();
    }
    
    public <T extends Object> T StringToObject (String content, Class<T> valueType) throws Exception  {
        Unmarshaller unM = getUnmarshaller(valueType);
        StringReader reader = new StringReader(content);
        T obj = (T) unM.unmarshal(reader);
        return obj;
        //JAXBElement<T> root = (JAXBElement<T>) unM.unmarshal(reader);
        //return root.getValue();
    }
    
    public <T extends Object> T ByteArrayToObject (byte[] content, Class<T> valueType) throws Exception{
        Unmarshaller unM = getUnmarshaller(valueType);
        InputStream inStrm = new ByteArrayInputStream(content);
        T obj = (T) unM.unmarshal(inStrm);
        return obj;
        //JAXBElement<T> root = (JAXBElement<T>) unM.unmarshal(inStrm);
        //return root.getValue();
    }
    
    public <T extends Object> T FileToObject (File src, Class<T> valueType) throws Exception  {
        Unmarshaller unM = getUnmarshaller(valueType);
        //T obj= (T) unM.unmarshal(src);  //Peta!!
        //return obj;
        JAXBElement<T> root = (JAXBElement<T>) unM.unmarshal(src);
        return root.getValue();
    }
    
    public <T extends Object> T FileToObject (InputStream src, Class<T> valueType) throws Exception {
        Unmarshaller unM = getUnmarshaller(valueType);
        T obj = (T) unM.unmarshal(src);
        return obj;
        //T obj= (T) unM.unmarshal(src);  
        //return obj;
    }
    
    
    
    /**
     * 
     * @param xmlFile
     * @param schemaFile is relative from resource folder
     * @return
     */
    public boolean validateXML(String xmlFile, String schemaFile) {
        SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = null;
        try {
            try {
                schema = schemaFactory.newSchema(
                    new File(Thread.currentThread().getContextClassLoader().getResource(schemaFile).getPath()));
            } catch (Exception e1) {
                schema = schemaFactory.newSchema(new File(schemaFile));
            }
            Validator validator = schema.newValidator();
            validator.validate(new StreamSource(new File(xmlFile)));
            return true;
            
        } catch (SAXException | IOException e) {
            e.printStackTrace();
            return false;
        }
    }
    
    public static void main (String[] args) {
        boolean ok= new JAXBEduImp().validateXML(
        "/mnt/NASDADES_DOCS/X19-DOCS-ESSENCIALS/LlibreDecrets/ENI2019/0ES_L01462384_2019_EXP_LLIBRE_RESOLUCIONS.ENI.xml",
        "/home/eduard/WORKSPACES/WS_GRDL05/Ajuntament/A10-xsd2Pojo/src/main/resources/xsd/expedienteEni.xsd");

        /*
        boolean ok= new JAXBEduImp().validateXML(
                "/home/eduard/SEGRA2022/0ES_L01462384_2022_EXP_LLIBRE_RESOLUCIONS.ENI.xml",
                "/home/eduard/WORKSPACES/WS_GRDL05/Ajuntament/A10-xsd2Pojo/src/main/resources/xsd/expedienteEni.xsd");

        
        boolean ok= new JAXBEduImp().validateXML("/home/eduard/DOCUMENTACIO/INSIDE/DECRETS_SENSE_EXPEDIENT/ES_L01462384_2023_EXP_1355414W_638136030389984806/ES_L01462384_2023_EXP_1355414W.xml",
                 "/home/eduard/WORKSPACES/WS_GRDL05/Ajuntament/A10-xsd2Pojo/src/main/resources/xsd/TipoExpedienteInsideConMAdicionales.xsd");
        
        boolean ok= new JAXBEduImp().validateXML("/home/eduard/SEGRA2022/ES_L01462384_2022_DOC_RESOLUCIO_00005_17557433.xml",
                "/home/eduard/WORKSPACES/WS_GRDL05/Ajuntament/A10-xsd2Pojo/src/main/resources/xsd/documentoEni.xsd");
        
        
        ok= new JAXBEduImp().validateXML("/home/eduard/prova_decrets/V1/2021/0ES_L01462384_2021_EXP_LLIBRE_RESOLUCIONS.ENI.xml",
                "/home/eduard/WORKSPACES/WS_GRDL01/Ajuntament/A10-xsd2Pojo/src/main/resources/xsd/expedienteEni.xsd");
        
        
        boolean ok= new JAXBEduImp().validateXML("/home/eduard/prova_decrets/V1/2021/ES_L01462384_2021_DOC_RESOLUCIO_0005_ENI.xml",
                "/home/eduard/WORKSPACES/WS_GRDL01/Ajuntament/A10-xsd2Pojo/src/main/resources/xsd/documentoEni.xsd");
        
        
        boolean ok1= new JAXBEduImp().validateXML("/home/eduard/Baixades/ES_L01462384_2022_DOC_12473165_0000_Pressupostampl.xml",
                "/home/eduard/WORKSPACES/WS_GRDL01/Ajuntament/A10-xsd2Pojo/src/main/resources/xsd/documentoEni.xsd");
        */
        
        if (ok) System.out.println("OK");
        else System.out.println("ERROR!");
    }
    
    
}    

1.2 Marshalling its "indice.indiceContenido" attribute from TIpoExpediente class

Imagine we have the class TipoExpediente named "expEni" fully completed except for the content signature.
To unmarshal it

JAXBEduImp xmlMapper= new JAXBEduImp();
String expContenidoFileName=outputFolder+"/contenido"+YEAR+".xml";
xmlMapper.ObjectToFile(expENI.getIndice().getIndiceContenido(),expContenidoFileName );
        

2. Signing the content with Autofirma using XAdES enveloped

Open AutoFirma, go to the top menu and select "Herramientas>Preferencias". Select the "Firmas XAdES" tab and select "Formato de firma": "XAdES Enveloped"


 
Now select the file to sign (contenido2020.xml) and wait some minutes! And save the signature to the file "contenido2022.xml_signed.xsig.xades.enveloped.xml" file

3. Getting the xadesEnveloped.xsd schema from LiquidTechmologies URL

Maybe you have a lot of "resolutions" in this file. So, make a copy of the contenido2020.xml file and leave only 3 instances of the elements with tag <DocumentoIndizado> and delete the rest as this URL rejects big XML files.
Copy the resulting simplified XML file and get the main schema xsd


Copy it to the src/main/resources/xsd folder and name it xasdesEnveloped.xsd

Change the line

<xs:import schemaLocation="schema1.xsd" namespace="http://www.w3.org/2000/09/xmldsig#" />

with 

<xs:import schemaLocation="xmldsig-core-schema.xsd" namespace="http://www.w3.org/2000/09/xmldsig#" />

Then enter the URL of the namespace of the replacement (http://www.w3.org/2000/09/xmldsig#) and save the xml content to the file xmldsig-core-schema.xsd in  the src/main/resources/xsd folder.

Here are the two schemas

3.1 xadesEnveloped.xml


<?xml version="1.0" encoding="utf-8"?>
<!-- Created with Liquid Technologies Online Tools 1.0 (https://www.liquid-technologies.com) -->
<xs:schema 
  xmlns:ds="http://www.w3.org/2000/09/xmldsig#" 
  xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" 
  attributeFormDefault="unqualified" 
  elementFormDefault="qualified" 
  targetNamespace="http://administracionelectronica.gob.es/ENI/XSD/v1.0/expediente-e/indice-e/contenido" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema">
  
  <!-- <xs:import schemaLocation="schema1.xsd" namespace="http://www.w3.org/2000/09/xmldsig#" />-->
  <xs:import schemaLocation="xmldsig-core-schema.xsd" namespace="http://www.w3.org/2000/09/xmldsig#" />
  
  <xs:element name="IndiceContenido">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="FechaIndiceElectronico" type="xs:dateTime" />
        <xs:element maxOccurs="unbounded" name="DocumentoIndizado">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="IdentificadorDocumento" type="xs:string" />
              <xs:element name="ValorHuella" type="xs:string" />
              <xs:element name="FuncionResumen" type="xs:string" />
              <xs:element name="FechaIncorporacionExpediente" type="xs:dateTime" />
              <xs:element name="OrdenDocumentoExpediente" type="xs:unsignedByte" />
            </xs:sequence>
            <xs:attribute name="Id" type="xs:string" use="required" />
          </xs:complexType>
        </xs:element>
        <xs:element ref="ds:Signature" />
      </xs:sequence>
      <xs:attribute name="Id" type="xs:string" use="required" />
    </xs:complexType>
  </xs:element>
</xs:schema>

3.2 xxmldsig-core-schema.xsd


<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE schema
  PUBLIC "-//W3C//DTD XMLSchema 200102//EN" "http://www.w3.org/2001/XMLSchema.dtd"
 [
   <!ATTLIST schema 
     xmlns:ds CDATA #FIXED "http://www.w3.org/2000/09/xmldsig#">
   <!ENTITY dsig 'http://www.w3.org/2000/09/xmldsig#'>
   <!ENTITY % p ''>
   <!ENTITY % s ''>
  ]>

<!-- Schema for XML Signatures
    http://www.w3.org/2000/09/xmldsig#
    $Revision: 1.2 $ on $Date: 2013-04-16 12:48:49 $ by $Author: denis $

    Copyright 2001 The Internet Society and W3C (Massachusetts Institute
    of Technology, Institut National de Recherche en Informatique et en
    Automatique, Keio University). All Rights Reserved.
    http://www.w3.org/Consortium/Legal/

    This document is governed by the W3C Software License [1] as described
    in the FAQ [2].

    [1] http://www.w3.org/Consortium/Legal/copyright-software-19980720
    [2] http://www.w3.org/Consortium/Legal/IPR-FAQ-20000620.html#DTD
-->


<schema xmlns="http://www.w3.org/2001/XMLSchema"
        xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
        targetNamespace="http://www.w3.org/2000/09/xmldsig#"
        version="0.1" elementFormDefault="qualified"> 

<!-- Basic Types Defined for Signatures -->

<simpleType name="CryptoBinary">
  <restriction base="base64Binary">
  </restriction>
</simpleType>

<!-- Start Signature -->

<element name="Signature" type="ds:SignatureType"/>
<complexType name="SignatureType">
  <sequence> 
    <element ref="ds:SignedInfo"/> 
    <element ref="ds:SignatureValue"/> 
    <element ref="ds:KeyInfo" minOccurs="0"/> 
    <element ref="ds:Object" minOccurs="0" maxOccurs="unbounded"/> 
  </sequence>  
  <attribute name="Id" type="ID" use="optional"/>
</complexType>

  <element name="SignatureValue" type="ds:SignatureValueType"/> 
  <complexType name="SignatureValueType">
    <simpleContent>
      <extension base="base64Binary">
        <attribute name="Id" type="ID" use="optional"/>
      </extension>
    </simpleContent>
  </complexType>

<!-- Start SignedInfo -->

<element name="SignedInfo" type="ds:SignedInfoType"/>
<complexType name="SignedInfoType">
  <sequence> 
    <element ref="ds:CanonicalizationMethod"/> 
    <element ref="ds:SignatureMethod"/> 
    <element ref="ds:Reference" maxOccurs="unbounded"/> 
  </sequence>  
  <attribute name="Id" type="ID" use="optional"/> 
</complexType>

  <element name="CanonicalizationMethod" type="ds:CanonicalizationMethodType"/> 
  <complexType name="CanonicalizationMethodType" mixed="true">
    <sequence>
      <any namespace="##any" minOccurs="0" maxOccurs="unbounded"/>
      <!-- (0,unbounded) elements from (1,1) namespace -->
    </sequence>
    <attribute name="Algorithm" type="anyURI" use="required"/> 
  </complexType>

  <element name="SignatureMethod" type="ds:SignatureMethodType"/>
  <complexType name="SignatureMethodType" mixed="true">
    <sequence>
      <element name="HMACOutputLength" minOccurs="0" type="ds:HMACOutputLengthType"/>
      <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
      <!-- (0,unbounded) elements from (1,1) external namespace -->
    </sequence>
    <attribute name="Algorithm" type="anyURI" use="required"/> 
  </complexType>

<!-- Start Reference -->

<element name="Reference" type="ds:ReferenceType"/>
<complexType name="ReferenceType">
  <sequence> 
    <element ref="ds:Transforms" minOccurs="0"/> 
    <element ref="ds:DigestMethod"/> 
    <element ref="ds:DigestValue"/> 
  </sequence>
  <attribute name="Id" type="ID" use="optional"/> 
  <attribute name="URI" type="anyURI" use="optional"/> 
  <attribute name="Type" type="anyURI" use="optional"/> 
</complexType>

  <element name="Transforms" type="ds:TransformsType"/>
  <complexType name="TransformsType">
    <sequence>
      <element ref="ds:Transform" maxOccurs="unbounded"/>  
    </sequence>
  </complexType>

  <element name="Transform" type="ds:TransformType"/>
  <complexType name="TransformType" mixed="true">
    <choice minOccurs="0" maxOccurs="unbounded"> 
      <any namespace="##other" processContents="lax"/>
      <!-- (1,1) elements from (0,unbounded) namespaces -->
      <element name="XPath" type="string"/> 
    </choice>
    <attribute name="Algorithm" type="anyURI" use="required"/> 
  </complexType>

<!-- End Reference -->

<element name="DigestMethod" type="ds:DigestMethodType"/>
<complexType name="DigestMethodType" mixed="true"> 
  <sequence>
    <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
  </sequence>    
  <attribute name="Algorithm" type="anyURI" use="required"/> 
</complexType>

<element name="DigestValue" type="ds:DigestValueType"/>
<simpleType name="DigestValueType">
  <restriction base="base64Binary"/>
</simpleType>

<!-- End SignedInfo -->

<!-- Start KeyInfo -->

<element name="KeyInfo" type="ds:KeyInfoType"/> 
<complexType name="KeyInfoType" mixed="true">
  <choice maxOccurs="unbounded">     
    <element ref="ds:KeyName"/> 
    <element ref="ds:KeyValue"/> 
    <element ref="ds:RetrievalMethod"/> 
    <element ref="ds:X509Data"/> 
    <element ref="ds:PGPData"/> 
    <element ref="ds:SPKIData"/>
    <element ref="ds:MgmtData"/>
    <any processContents="lax" namespace="##other"/>
    <!-- (1,1) elements from (0,unbounded) namespaces -->
  </choice>
  <attribute name="Id" type="ID" use="optional"/> 
</complexType>

  <element name="KeyName" type="string"/>
  <element name="MgmtData" type="string"/>

  <element name="KeyValue" type="ds:KeyValueType"/> 
  <complexType name="KeyValueType" mixed="true">
   <choice>
     <element ref="ds:DSAKeyValue"/>
     <element ref="ds:RSAKeyValue"/>
     <any namespace="##other" processContents="lax"/>
   </choice>
  </complexType>

  <element name="RetrievalMethod" type="ds:RetrievalMethodType"/> 
  <complexType name="RetrievalMethodType">
    <sequence>
      <element ref="ds:Transforms" minOccurs="0"/> 
    </sequence>  
    <attribute name="URI" type="anyURI"/>
    <attribute name="Type" type="anyURI" use="optional"/>
  </complexType>

<!-- Start X509Data -->

<element name="X509Data" type="ds:X509DataType"/> 
<complexType name="X509DataType">
  <sequence maxOccurs="unbounded">
    <choice>
      <element name="X509IssuerSerial" type="ds:X509IssuerSerialType"/>
      <element name="X509SKI" type="base64Binary"/>
      <element name="X509SubjectName" type="string"/>
      <element name="X509Certificate" type="base64Binary"/>
      <element name="X509CRL" type="base64Binary"/>
      <any namespace="##other" processContents="lax"/>
    </choice>
  </sequence>
</complexType>

<complexType name="X509IssuerSerialType"> 
  <sequence> 
    <element name="X509IssuerName" type="string"/> 
    <element name="X509SerialNumber" type="integer"/> 
  </sequence>
</complexType>

<!-- End X509Data -->

<!-- Begin PGPData -->

<element name="PGPData" type="ds:PGPDataType"/> 
<complexType name="PGPDataType"> 
  <choice>
    <sequence>
      <element name="PGPKeyID" type="base64Binary"/> 
      <element name="PGPKeyPacket" type="base64Binary" minOccurs="0"/> 
      <any namespace="##other" processContents="lax" minOccurs="0"
       maxOccurs="unbounded"/>
    </sequence>
    <sequence>
      <element name="PGPKeyPacket" type="base64Binary"/> 
      <any namespace="##other" processContents="lax" minOccurs="0"
       maxOccurs="unbounded"/>
    </sequence>
  </choice>
</complexType>

<!-- End PGPData -->

<!-- Begin SPKIData -->

<element name="SPKIData" type="ds:SPKIDataType"/> 
<complexType name="SPKIDataType">
  <sequence maxOccurs="unbounded">
    <element name="SPKISexp" type="base64Binary"/>
    <any namespace="##other" processContents="lax" minOccurs="0"/>
  </sequence>
</complexType> 

<!-- End SPKIData -->

<!-- End KeyInfo -->

<!-- Start Object (Manifest, SignatureProperty) -->

<element name="Object" type="ds:ObjectType"/> 
<complexType name="ObjectType" mixed="true">
  <sequence minOccurs="0" maxOccurs="unbounded">
    <any namespace="##any" processContents="lax"/>
  </sequence>
  <attribute name="Id" type="ID" use="optional"/> 
  <attribute name="MimeType" type="string" use="optional"/> <!-- add a grep facet -->
  <attribute name="Encoding" type="anyURI" use="optional"/> 
</complexType>

<element name="Manifest" type="ds:ManifestType"/> 
<complexType name="ManifestType">
  <sequence>
    <element ref="ds:Reference" maxOccurs="unbounded"/> 
  </sequence>
  <attribute name="Id" type="ID" use="optional"/> 
</complexType>

<element name="SignatureProperties" type="ds:SignaturePropertiesType"/> 
<complexType name="SignaturePropertiesType">
  <sequence>
    <element ref="ds:SignatureProperty" maxOccurs="unbounded"/> 
  </sequence>
  <attribute name="Id" type="ID" use="optional"/> 
</complexType>

   <element name="SignatureProperty" type="ds:SignaturePropertyType"/> 
   <complexType name="SignaturePropertyType" mixed="true">
     <choice maxOccurs="unbounded">
       <any namespace="##other" processContents="lax"/>
       <!-- (1,1) elements from (1,unbounded) namespaces -->
     </choice>
     <attribute name="Target" type="anyURI" use="required"/> 
     <attribute name="Id" type="ID" use="optional"/> 
   </complexType>

<!-- End Object (Manifest, SignatureProperty) -->

<!-- Start Algorithm Parameters -->

<simpleType name="HMACOutputLengthType">
  <restriction base="integer"/>
</simpleType>

<!-- Start KeyValue Element-types -->

<element name="DSAKeyValue" type="ds:DSAKeyValueType"/>
<complexType name="DSAKeyValueType">
  <sequence>
    <sequence minOccurs="0">
      <element name="P" type="ds:CryptoBinary"/>
      <element name="Q" type="ds:CryptoBinary"/>
    </sequence>
    <element name="G" type="ds:CryptoBinary" minOccurs="0"/>
    <element name="Y" type="ds:CryptoBinary"/>
    <element name="J" type="ds:CryptoBinary" minOccurs="0"/>
    <sequence minOccurs="0">
      <element name="Seed" type="ds:CryptoBinary"/>
      <element name="PgenCounter" type="ds:CryptoBinary"/>
    </sequence>
  </sequence>
</complexType>

<element name="RSAKeyValue" type="ds:RSAKeyValueType"/>
<complexType name="RSAKeyValueType">
  <sequence>
    <element name="Modulus" type="ds:CryptoBinary"/> 
    <element name="Exponent" type="ds:CryptoBinary"/> 
  </sequence>
</complexType> 

<!-- End KeyValue Element-types -->

<!-- End Signature -->

</schema>

4. Getting the class eni.xades.enveloped.IndiceContenido

Follow the instructions for creating a Gradle project as mentioned in this post and use this build.gradle file. Note that the purpose is creating the classes from xadesEnveloped.xsd schema into to package eni.xades.enveloped . Then build the project and the classes appear in the src/generated-sources folder. The class IndiceContenido is our aim. Copy the class IndiceContenido to the eni.exp package!!



4.1 build.gradle file


sourceCompatibility = 12
targetCompatibility = 12

configurations {
    jaxb
}

dependencies {
    
    jaxb (
        'com.sun.xml.bind:jaxb-xjc:4.0.1',
        'com.sun.xml.bind:jaxb-impl:4.0.1',
        'org.glassfish.jaxb:jaxb-runtime:4.0.1'
    )
    
    api libs.jakarta.xml.bind.api
    
    compileOnly             libs.lombok // use version catalog in the file "settings.gradle"
    annotationProcessor     libs.lombok // use version catalog in the file "settings.gradle"
    testCompileOnly         libs.lombok // use version catalog in the file "settings.gradle"
    testAnnotationProcessor libs.lombok // use version catalog in the file "settings.gradle"
       
}

task jaxb {
    System.setProperty('javax.xml.accessExternalSchema', 'all')
    def jaxbTargetDir = file("src/generated-sources/jaxb")
    doLast {
        jaxbTargetDir.mkdirs()
        ant.taskdef(
            name: 'xjc',
            classname: 'com.sun.tools.xjc.XJCTask',
            classpath: configurations.jaxb.asPath
        )
        ant.jaxbTargetDir = jaxbTargetDir
        ant.xjc(
            destdir: '${jaxbTargetDir}',
            //package: 'eni.documento',
            //package: 'eni.expediente',
            //package: 'eni.xmldsig',
            //package: 'eni.xades',
            //package: 'eni.afirma',
            //package: 'eni.inside',
            package: 'eni.xades.enveloped',
            
            //schema: 'src/main/resources/xsd/documentoEni.xsd'
            //schema: 'src/main/resources/xsd/expedienteEni.xsd'
            //schema: 'src/main/resources/xsd/xmldsig-core-schema.xsd'
            //schema: 'src/main/resources/xsd/xades.xsd'
            //schema: 'src/main/resources/xsd/TipoExpedienteInsideConMAdicionales.xsd'
            schema: 'src/main/resources/xsd/xadesEnveloped.xsd'
        )
    }
}

jar {   
    from sourceSets.main.allSource  //Include java sources
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
    
}
compileJava.dependsOn jaxb

5. Unmarshal the signature obtained by Autofirma into the previous class and extract the Signature class.

Just use this line of code

IndiceContenido indxContent=xmlMapper.FileToObject(new File(expContenidoFirmaFileNameXades),IndiceContenido.class);

where expContenidoFirmaFileNameXades is the name of the signature file obtained with AutoFirma.

6. Assign this Signature class to the nested attribute "indice.firmas.firma.contenidoFirma.firmaConCertificado.signature" of the class "TipoExpediente" 

use call the next function from this line of code

expENI=ENIExpSedipualba.firmarContenidoV2(expENI, indxContent.getSignature(), year, expContenidoFirmaFileNameXades);


    public static TipoExpediente firmarContenidoV2(TipoExpediente expENI, SignatureType firmaXsdesEnveloped, int any, String tipo)  {
        
        FirmaConCertificado unaFrmCCert= new FirmaConCertificado();
        //unaFrmCCert.setFirmaBase64(Base64.getEncoder().encodeToString(firmaContent));
        //unaFrmCCert.setReferenciaFirma(null); //
        unaFrmCCert.setSignature(firmaXsdesEnveloped);
        
        ContenidoFirma unContenido=new ContenidoFirma();
        unContenido.setFirmaConCertificado(unaFrmCCert);
        
        TipoFirmasElectronicas unaFirma=new TipoFirmasElectronicas();
        unaFirma.setId("Contenido_"+ any);
        unaFirma.setTipoFirma("TF03"); //Xades enveloped
        unaFirma.setContenidoFirma(unContenido);
        unaFirma.setRef("#"+getIdentificadorDocIndexContenido(any));
                
        expENI.getIndice().setFirmas(new Firmas());
        expENI.getIndice().getFirmas().getFirma().add(unaFirma);
        return expENI;
    }

7. Marshall the "Expediente" object whose class is "TipoExpediente"

Use this line of code

xmlMapper.ObjectToFile(expENI,expEniJaxbFNameSigned);


and you have got the desired ENI format of the "Expediente"

Comments

Popular posts from this blog

ORVE WS (Dynamic) (4) Jackson XML mapper

ENI (1) ENI Document OR the Spanish Electronic Administration Mafia

Creating a WS Client consumer