Xades4j - How can I enter a hash for SHA256?

353 Views Asked by At

I need to sign xml files with XAdES-EPES enveloped, RSA-SHA256 with this hash: Quzn98x3PMbSHwbUzaj5f5KOpiH0u8bvmwbbbNkO9Es

I signed the XML but it is not valid because I don't know how to enter that Hash. This is my code:

public class Firma{

private static final String FOLDER = "C:/ECLIPSE/PRUEBAS_Firma/";
private static final String CERT = "SOLDISP_XXXXX.p12";// "Certificado de
                                                        // dispositivo
private static final String PASS = "xxxxxx";

private static final String DOCUMENT = "C:/ECLIPSE/PRUEBAS_Firma/Ejemplo_TicketBAI_B00000034_B2022_0101_SinFirma.xml";

public static void main(String[] args) throws Exception {
    System.setProperty("org.apache.xml.security.ignoreLineBreaks", "true");

    System.out.println(">>>>>>>>> Firmando XML");
    signEpes();
}

private static void signEpes() throws Exception {
    Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(DOCUMENT));
    Element elem = doc.getDocumentElement();
    DOMHelper.useIdAsXmlId(elem);

    KeyingDataProvider kdp = new FileSystemKeyStoreKeyingDataProvider("pkcs12", FOLDER + CERT,
            new FirstCertificateSelector(), new DirectPasswordProvider(PASS), new DirectPasswordProvider(PASS),
            true);
    // politica
    SignaturePolicyInfoProvider policyInfoProvider = new SignaturePolicyInfoProvider() {
        @Override
        public SignaturePolicyBase getSignaturePolicy() {
            return new SignaturePolicyIdentifierProperty(

                    new ObjectIdentifier(
                            "https://www.batuz.eus/fitxategiak/batuz/ticketbai/sinadura_elektronikoaren_zehaztapenak_especificaciones_de_la_firma_electronica_v1_0.pdf",
                            IdentifierType.URI, ""),
                    new ByteArrayInputStream(
                            "https://www.batuz.eus/fitxategiak/batuz/ticketbai/sinadura_elektronikoaren_zehaztapenak_especificaciones_de_la_firma_electronica_v1_0.pdf"
                                    .getBytes())

            );
        }
    };

    SignerEPES signer = (SignerEPES) new XadesEpesSigningProfile(kdp, policyInfoProvider).newSigner();

    new Enveloped(signer).sign(elem);

    outputDocument(doc, "Factura_firmada.xml");
}

protected static void outputDocument(Document doc, String fileName) throws Exception {
    TransformerFactory tf = TransformerFactory.newInstance();
    File outDir = ensureOutputDir();
    FileOutputStream out = new FileOutputStream(new File(outDir, fileName));
    tf.newTransformer().transform(new DOMSource(doc), new StreamResult(out));
    out.close();
}

private static File ensureOutputDir() {
    File dir = new File(toPlatformSpecificFilePath(FOLDER));
    dir.mkdir();
    return dir;
}

}

Please, can anyone help me??? Thanks in advance

1

There are 1 best solutions below

0
On

The hash must be calculated from source policy page Stream. The code below do what you want, change whatever you need to adapt your scenario. You can change the code when you creates the

SignaturePolicyInfoProvider

SignaturePolicyInfoProvider policyInfoProvider = new SignaturePolicyInfoProvider() {
                @Override
                public SignaturePolicyBase getSignaturePolicy() {
                    try {
                        //PolicyDocumentStream o PolicyDocumentData calculado a partir del contenido de la URL
                        URL url = new URL("https://www.batuz.eus/fitxategiak/batuz/ticketbai/sinadura_elektronikoaren_zehaztapenak_especificaciones_de_la_firma_electronica_v1_0.pdf");
                        if ("https".equals(url.getProtocol())) {
                            HttpsURLConnection.setDefaultSSLSocketFactory(getTrustAllClientSecureContext("TLS").getSocketFactory());
                            HttpsURLConnection.setDefaultHostnameVerifier(new TrustAllHostnameVerifier());
                        }
                        URLConnection urlConn = url.openConnection();
                        urlConn.setConnectTimeout(5000);
                        urlConn.setReadTimeout(60000);
                        //Dummy "User-Agent"
                        urlConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0");
                        return new SignaturePolicyIdentifierProperty(new ObjectIdentifier("https://www.batuz.eus/fitxategiak/batuz/ticketbai/sinadura_elektronikoaren_zehaztapenak_especificaciones_de_la_firma_electronica_v1_0.pdf", IdentifierType.URI), new BufferedInputStream(urlConn.getInputStream()))
                                .withLocationUrl("https://www.batuz.eus/fitxategiak/batuz/ticketbai/sinadura_elektronikoaren_zehaztapenak_especificaciones_de_la_firma_electronica_v1_0.pdf");
                    } catch (Exception ex) {
                        System.out.println("ERROR: SignaturePolicyInfoProvider...");
                        ex.printStackTrace();
                    }
                    return null;
                }
            };

Also I give you auxiliar code used for the https communication.

public SSLContext getTrustAllClientSecureContext(String secureSocketProtocol) {
        SSLContext context = null;
        if (secureSocketProtocol == null) {
            secureSocketProtocol = "TLS";
        }
        try {
            context = SSLContext.getInstance(secureSocketProtocol);
            context.init(null, new TrustManager[]{new TrustAllTrustManager()}, null);
        } catch (Exception e) {
            System.out.println("ERROR: " + e.getMessage());
        }
        return context;
    }

public class TrustAllTrustManager implements X509TrustManager {

    @Override
    public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {

    }

    @Override
    public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {

    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[0];
    }
}

public class TrustAllHostnameVerifier implements HostnameVerifier {

    @Override
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }

}

Of course the "allow all certificate" operation for connecting to the URL must be avoided in production, instead is better add the corresponding certificates to your certificate store.