Ejemplo de firma Detached - gdiazs/MITyCLib GitHub Wiki
El objetivo de este ejemplo es mostrar los pasos necesarios para realizar una firma XAdES Detached. Por simplificar, el formato usado será XAdES-BES en su versión 1.3.2. En este tipo de firmas, el elemento que se firma es un recurso externo que estará referenciado por una URI externa (del tipo file:/...).
Una firma XAdES-BES Detached tiene el siguiente aspecto:
<?xml version="1.0" encoding="UTF-8"?>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:etsi="http://uri.etsi.org/01903/v1.3.2#" Id="Signature504735">
<ds:SignedInfo Id="Signature-SignedInfo1024952">
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference Id="SignedPropertiesID429729" Type="http://uri.etsi.org/01903#SignedProperties" URI="#Signature504735-SignedProperties48056">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue><!-- Digest del elemento referenciado en Base64 --></ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#Certificate1237555">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue><!-- Digest del elemento referenciado en Base64 --></ds:DigestValue>
</ds:Reference>
<ds:Reference Id="Reference-ID-200615" URI="file:/C:/Temp/ExampleToSign.xml>">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue><!-- Digest del elemento referenciado en Base64 --></ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue Id="SignatureValue552465">
<!-- Valor de la firma en Base64 -->
</ds:SignatureValue>
<ds:KeyInfo Id="Certificate1237555">
<ds:X509Data>
<ds:X509Certificate>
<!-- Certificado firmante en Base64 -->
</ds:X509Certificate>
</ds:X509Data>
<ds:KeyValue>
<ds:RSAKeyValue>
<ds:Modulus><!-- Módulo de la clave RSA en Base64 --></ds:Modulus>
<ds:Exponent><!-- Exponente de la clave RSA en Base64 --></ds:Exponent>
</ds:RSAKeyValue>
</ds:KeyValue>
</ds:KeyInfo>
<ds:Object Id="Signature504735-Object873466">
<etsi:QualifyingProperties Target="#Signature504735">
<etsi:SignedProperties Id="Signature504735-SignedProperties48056">
<etsi:SignedSignatureProperties>
<etsi:SigningTime><!-- Fecha y hora de la firma --></etsi:SigningTime>
<etsi:SigningCertificate>
<etsi:Cert>
<etsi:CertDigest>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue><!-- Digest del certificado en Base64 --></ds:DigestValue>
</etsi:CertDigest>
<etsi:IssuerSerial>
<ds:X509IssuerName><!-- Nombre de emisión del certificado firmante --></ds:X509IssuerName>
<ds:X509SerialNumber><!-- Número de serie del certificado firmante --></ds:X509SerialNumber>
</etsi:IssuerSerial>
</etsi:Cert>
</etsi:SigningCertificate>
</etsi:SignedSignatureProperties>
<etsi:SignedDataObjectProperties>
<etsi:DataObjectFormat ObjectReference="#Reference-ID-200615">
<etsi:Description><!-- Descripcion del objeto firmado ---></etsi:Description>
<etsi:MimeType><!-- Tipo MIME del objeto firmado --></etsi:MimeType>
</etsi:DataObjectFormat>
</etsi:SignedDataObjectProperties>
</etsi:SignedProperties>
</etsi:QualifyingProperties>
</ds:Object>
</ds:Signature>
En la firma anterior, el documento que realmente se está firmando se corresponde con la URL file:/C:/Temp/ExampleToSign.xml, es decir, un fichero local en la ubicación C:/Temp/ExampleToSign.xml
El programa de ejemplo extiende el ejemplo de firma genérica implementando aquellos métodos abstractos que lo hacen específico para el tipo de firma Detached. El código completo del ejemplo se puede ver aquí. También se puede ver el Javadoc asociado al ejemplo aquí.
La implementación del método abstracto createDataToSign() de la clase GenericXMLSignature es la siguiente:
@Override
protected DataToSign createDataToSign() {
DataToSign dataToSign = new DataToSign();
dataToSign.setXadesFormat(EnumFormatoFirma.XAdES_BES);
dataToSign.setEsquema(XAdESSchemas.XAdES_132);
dataToSign.setXMLEncoding("UTF-8");
dataToSign.setEnveloped(false);
URL resourceToSign = this.getClass().getResource(RESOURCE_TO_SIGN);
dataToSign.addObject(new ObjectToSign(new ExternFileToSign(new File(resourceToSign.getFile()), "#"), "Documento de ejemplo", null, "text/xml", null));
return dataToSign;
}
Los pasos para crear los datos a firmar son los siguientes:
-
Crear un objeto DataToSign.
DataToSign dataToSign = new DataToSign();`
-
Asignar el formato, en este caso XAdES-BES, mediante el valor XAdES_BES del enumerado EnumFormatoFirma.
dataToSign.setXadesFormat(EnumFormatoFirma.XAdES_BES);
-
Asignar el esquema, en este caso el 1.3.2 (actualmente la última versión de XAdES), mediante el valor XAdES_132 del enumerado XAdESSchemas.
dataToSign.setEsquema(XAdESSchemas.XAdES_132);
-
Establecer la codificación del XML a firmar. El estándar recomienda que sea UTF-8:
dataToSign.setXMLEncoding("UTF-8");
-
Puesto que queremos que la firma sea el nodo raíz del XML resultante, se lo decimos al objeto DataToSign de la siguiente forma:
dataToSign.setEnveloped(false);
Si quisiéramos que la firma estuviera contenida en un elemento de un documento XML determinado, se haría de la siguiente forma:
dataToSign.setEnveloped(true); dataToSign.setDocument(document); dataToSign.setParentSignNode(idParentNode);
Donde document es un documento XML definido por la interfaz org.w3c.dom.Document e idParentNode sería el valor del Id del nodo en el que se desea insertar la firma.
-
Por último, habría que indicar que es lo que se quiere firmar:
URL resourceToSign = this.getClass().getResource(RESOURCE_TO_SIGN); dataToSign.addObject(new ObjectToSign(new ExternFileToSign(new File(resourceToSign.getFile()), "#"), "Documento de ejemplo", null, "text/xml", null));
Mediante el método addObject se podrían añadir tantos objetos a firmar (en este caso cada objeto se correspondería con un fichero) como se deseen. El constructor ObjectToSign recibe los siguientes parámetros:
- El objeto a firmar. En el ejemplo, puesto que se está haciendo una firma Detached, se usa el objeto ExternFileToSign para indicar que el objeto a firmar es un fichero externo, cuyo constructor recibe dos parámetros:
- El primer parámetro se corresponde con el archivo a firmar. Como se puede ver, el documento a firmar aparece referenciado por la constante RESOURCE_TO_SIGN, que apunta a un recurso del Classpath que se desea firmar. A partir de ese recurso se obtendrá el objeto java.io.File que se va a firmar. El objeto File se podría obtener de cualquier otra forma (seleccionándolo interactivamente, por fichero de configuración, etc.).
- El segundo parámetro se corresponde con la URI base que se va a utilizar en el documento XML firmado.
- Descripción del objeto a firmar. Se trata de un valor opcional para aportar información extra.
- Objeto identificador del objeto descrito. Actualmente no se está usando. Se permite para total compatibilidad con el formato XAdES.
- Tipo MIME del objeto descrito: En este caso, puesto que estamos firmando un documento XML se usa "text/xml".
- Codificación del objeto firmado. En el caso de que se estuviera firmando un documento binario que está codificado en Base64 se podría usar la constante URI_BASE_64 de la clase ConstantesXADES. En el ejemplo, puesto que se esta firmando el propio XML este parámetro recibe el valor null
- El objeto a firmar. En el ejemplo, puesto que se está haciendo una firma Detached, se usa el objeto ExternFileToSign para indicar que el objeto a firmar es un fichero externo, cuyo constructor recibe dos parámetros:
En cuanto al método createDataToSign() de la clase GenericXMLSignature no es necesario sobrescribirlo puesto que con la implementación original es suficiente.