javaxmlxades4jgemalto

How to sign an xml with XADES4j, certificate store windows and Smart Card + PIN Code


I'm trying to sign an xml file using the XADES4j. I also use the smart card certification (will be loaded from the windows store).

Is there an example that meet my search because i'm new with XML signature and smart cards. I searched a fix for few weeks without success.

There are others example about it but it's not very clear :

Example1 Example2

I found this demonstration at https://github.com/luisgoncalves/xades4j/wiki/DefiningKeyingData, but I don't know how to set the function PKCS11KeyStoreKeyingDataProvider to apply the Windows certificate parameters and their pin code:

    KeyingDataProvider kp = new PKCS11KeyStoreKeyingDataProvider(
              "path/to/native/lib",
               "MS SABRI", // CERTIFICATE NAME
               new FirstCertificateSelector(),
               null, 
               null,false);, 

My code:

          try {

     // >>> TEST N°1
     // KeyingDataProvider kp = new DirectKeyingDataProvider((X509Certificate) certExemple, PrivateKEY);

      // >>> TEST N°2
      KeyingDataProvider kp = new PKCS11KeyStoreKeyingDataProvider(
              "path/to/native/lib",
               "name", // CERTIFICATE NAME
               new FirstCertificateSelector(),
               new DirectPasswordProvider("123456"), // PIN CODE
               new DirectPasswordProvider("123456"), // PIN CODE
               false);



      // XADES
      XadesSigningProfile p = new XadesBesSigningProfile(kp);
      XadesSigner signer    = p.newSigner();

      javax.xml.parsers.DocumentBuilderFactory factory = javax.xml.parsers.DocumentBuilderFactory.newInstance();
      factory.setNamespaceAware(true);
      javax.xml.parsers.DocumentBuilder builder = null;
      builder = factory.newDocumentBuilder();


      // XML FILE TO BE SIGNED
      Document doc1 = builder.parse(new File("FileNotSigned.xml"));

      // NODE
      Node parentElement            = doc1.getDocumentElement();
      Node nodeToSign               = doc1.getDocumentElement().getFirstChild();
      Node nodeToAttachSignature    = doc1.getDocumentElement();


      IndividualDataObjsTimeStampProperty dataObjsTimeStamp = new IndividualDataObjsTimeStampProperty();
      AllDataObjsCommitmentTypeProperty globalCommitment    = AllDataObjsCommitmentTypeProperty.proofOfApproval();
      CommitmentTypeProperty commitment                     = CommitmentTypeProperty.proofOfCreation();   

      // XPATH STRING
      String xpathHeader    ="/InvoiceHeader";
      String xpathBody      ="/InvoiceBody";

      // OBJECT
      DataObjectDesc obj1 = new DataObjectReference("");
      obj1.withTransform(XPath2Filter.intersect( xpathHeader ).intersect(xpathBody));
      SignedDataObjects dataObjs = new SignedDataObjects( obj1 );

      // SIGN
      signer.sign(dataObjs, nodeToAttachSignature);

      // TRANSFORMER
      Transformer transformer = TransformerFactory.newInstance().newTransformer();

      // XML SIGNED
      Result output = new StreamResult(new File("FileSigned.xml"));
      Source input  = new DOMSource(doc1);
      transformer.transform(input, output);

Solution

  • I'm not sure what you mean by "Windows store + smart card" as both seem exclusive. Anyway, ff you want to use a smart card, you code is almost OK.

    Smart cards usually have a native library that is installed on the host OS. On the first argument of PKCS11KeyStoreKeyingDataProvider you should pass the path to that library. The second parameter (name) is just the name to register the instance of the provider. Since the smart card usually handles the PIN to access the key, you usually can supply null for the keyStorePasswordProvider and entryPasswordProvider arguments.

    On the library unit tests you can find an example using the Portuguese citizen card.

    Hope this helps.