petek, 25. september 2015

FURS - Finančni urad Republike Slovenije - podpisovanje XML datotek v Javi - davčno potrjevanje računov

"Državni zbor RS je 15. julija 2015 sprejel  Zakon o davčnem potrjevanju računov, ki se bo začel uporabljati 2. januarja 2016.
Sprejet je sistem, v katerem bodo blagajne zavezancev preko spleta povezane s centralnim informacijskim sistemom Finančne uprave RS. Finančna uprava bo potrdila in shranila podatke o računih pri gotovinskem poslovanju v postopku njihove izdaje v realnem času. Postopek davčnega potrjevanja računov skupaj z veljavnima členoma 38. in 31. a  Zakona o davčnem postopku tvori sistem, ki bo omogočal sledljivost in učinkovitost nadzora nad izdanimi računi ter omejil sivo ekonomijo.
Zavezanec bo moral ob vsaki dobavi blaga in storitev za plačilo z gotovino izdati račun prek elektronske naprave, ki izpolnjuje predpisane pogoje in omogoča izvedbo postopka potrjevanja računa, in ga izročiti kupcu blaga oziroma naročniku storitve. Račun bo moral izdati najpozneje, ko je opravljena dobava in prejeto plačilo z gotovino."

Pri podpisovanju sem uporabil Java 1.6 verzijo, saj moram podpisovanje XML dokumentov omogočiti v podatkovni bazi Oracle preko Java stored procedur.

Za podpisovanje dokumenta je potrebno pridobiti testni nato pa produkcijski certifikat.
FURS na zahtevo izda testni certifikat v obliki p12.

!!! Opozorilo !!! V kolikor boste izhodni xml pregledovali v orodju kot je xmlspy ter ga nato poslali preko orodja soapui na FURS bo po vsej verjetnosti prišlo do napake ujemanja digitalnega potrdila. Zato je najbolje, da vzamete xml, ki nastane v izhodni datoteki  ter to pošljete preko SOAP-ui-ja.



import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.net.URL;

import java.security.*;
import java.security.cert.X509Certificate;
import java.util.*;
import javax.xml.XMLConstants;


import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.crypto.dsig.spec.*;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.w3c.dom.*;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;


public class SignFileExample {

    
    

    public static void main(String[] args) throws Exception {
        String referenceURI = null;
        List transforms = null;

        String xml = "Tukaj vnesite vaš xml "
        String outputFile = "c:/podpisan.xml";

        // Instantiate the document to be signed
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        dbFactory.setNamespaceAware(true);
        Document doc = (Document) dbFactory.newDocumentBuilder().parse(new ByteArrayInputStream(xml.getBytes()));

        //podpišemo le določen node znotraj XML-ja
        Node node = doc.getElementsByTagName("fu:BusinessPremiseRequest").item(0);
     
        KeyStore p12 = KeyStore.getInstance("pkcs12");
        //iz diska naložimo certifikat v p12 obliki 
        p12.load(new FileInputStream("c:/cert/certifikatfursa.p12"), "GESLO".toCharArray());
        Enumeration e = p12.aliases();
        String alias = (String) e.nextElement();
        System.out.println("Alias certifikata:" + alias);
        Key privateKey = p12.getKey(alias, "GESLO".toCharArray());

        KeyStore.PrivateKeyEntry keyEntry
                = (KeyStore.PrivateKeyEntry) p12.getEntry(alias, new KeyStore.PasswordProtection("GESLO".toCharArray()));

        X509Certificate cert = (X509Certificate) keyEntry.getCertificate();

        PublicKey publicKey = cert.getPublicKey();

        final XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM");
        Referenciramo se na Id="#data", ki je v <fu:BusinessPremiseRequest>
        Reference ref = sigFactory.newReference("#data",
                sigFactory.newDigestMethod(DigestMethod.SHA256, null),
                Collections.singletonList(sigFactory.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)),
                null,
                null);
        SignedInfo si = sigFactory.newSignedInfo(sigFactory.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null), sigFactory.newSignatureMethod("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", null), Collections.singletonList(ref));

        // Create a KeyValue containing the RSA PublicKey 
        KeyInfoFactory keyInfoFactory = sigFactory.getKeyInfoFactory();
        X509IssuerSerial x509IssuerSerial = keyInfoFactory.newX509IssuerSerial(cert.getSubjectX500Principal().getName(), cert.getSerialNumber());

        List x509Content = new ArrayList();

        x509Content.add(cert.getSubjectX500Principal().getName());
        x509Content.add(x509IssuerSerial);

        KeyValue keyValue = keyInfoFactory.newKeyValue(publicKey);
        X509Data xd = keyInfoFactory.newX509Data(x509Content);

        KeyInfo keyInfo = keyInfoFactory.newKeyInfo(Collections.singletonList(xd));

        DOMSignContext dsc = new DOMSignContext(
                privateKey,
                node
        );

        XMLSignature signature = sigFactory.newXMLSignature(si, keyInfo);

        signature.sign(dsc);

        
        OutputStream os = new FileOutputStream(outputFile);
        Transformer trans = TransformerFactory.newInstance()
                .newTransformer();
        trans.transform(new DOMSource(doc), new StreamResult(os));
       

    }

    private static void usage() {
        System.out.println("Usage: java SignFile   [id|path|whole]");
    }
}

1 komentar: