The Digital Patrol
Menu
  • Home
  • Blog
  • Contact
Menu

Digital Signing with JDigiDoc

Posted on November 4, 2013May 3, 2025 by Shazia Javed

Here at Mindware OÜ, we are extensively relying on JDigiDoc for authentication, encryption, and decryption. JDigiDoc is Estonia‘s Java based library for digitally signing documents using national ID card, (software) token, smart card, or HSM device. The current version supports both DIGIDOC-XML 1.3 and BDOC 2.1 formats. The library also provides functionality for data encryption, and decryption, all in just few simple steps.

In this post I illustrate the simple steps for digitally signing documents in DIGIDOC-XML 1.3 format with the help of functional code snippets. The code snippets are not from the official project implementation, and can be downloaded from Github. The source code file also includes utility methods for reading and writing files, and printing signature information from the signed document on console.

Example: Digital Signing with JDigiDoc

Before we can sign a document, we need to initialize JDigiDoc by reading configuration data. This is important because JDigiDoc needs to know the location of driver and CA certificates among other parameters. We can do the initialization by providing the path of configuration file to ConfigManager:

ConfigManager.init(configFilePath);

Once the JDigiDoc library is initialized, we need to create the SignedDoc object which will hold the payload data. In this example we will create a SignedDoc object for DIGIDOC-XML 1.3 data format:

SignedDoc signedDocument = new SignedDoc("DIGIDOC-XML", "1.3");

For BDOC 2.1 format, the input parameters will change to “BDOC” and “2.1”.

Next we would like to add a data file to DigiDoc container because it is possible to add a signature only if there is at least one data file in the container. The container should be unsigned and it shouldn’t already have any existing data file with the same name. For DIGIDOC-XML 1.3 data format, the data file can be added to DigiDoc container by embedding data in base64 encoding: DataFile.CONTENT_EMBEDDED_BASE64.

The setBody method assigns the in-memory byte[] data to DataFile object and uses it for further processing. It is useful when you have your data in database and/or you don’t want the data to be read from hard disk.

DataFile dataFile = new DataFile(signedDocument.getNewDataFileId(), DataFile.CONTENT_EMBEDDED_BASE64, "", "text/xml", signedDocument);
dataFile.setBody(document, "UTF-8");
signedDocument.addDataFile(dataFile);

Signing the data file requires signer’s certificate which is referenced by the signature. Here we are using PKCS#11 driver for accessing identity token. We pass 0 as the slot number and pin as the identity token pin to the getCertificate method. Please note that the slot number is the sequence number for certificates on an identity token. Also, the slot number for the certificate on Estonian ID card is 0.

PKCS11SignatureFactory signatureFactory = new PKCS11SignatureFactory();
signatureFactory.init();
X509Certificate certificate = signatureFactory.getCertificate(0, pin);

Now we compute the data file’s hashcode and create a signature object. Please note that the second and third parameter are optional in the prepareSignature method. The role can only be that of signer’s, and can be specified along with resolution as “role/resolution”. Resolution alone can be specified. If specified, the value is written to a single xml element in the file.

String[] roles = null;
SignatureProductionPlace address = new SignatureProductionPlace("Tartu", "Tartumaa", "Eesti Vabariik", "51009");
Signature signature = signedDocument.prepareSignature(certificate, roles, address);

In order to complete signature, we need to calculate final hash value (SHA-1 in case of DIGIDOC-XML 1.3). In case of PKCS#11 driver, we use this final hash value in sign method to calculate RSA signature value.

byte[] sidigest = signature.calculateSignedInfoDigest();
byte[] sigval = signatureFactory.sign(sidigest, 0, pin, signature);
signature.setSignatureValue(sigval);

Call getConfirmation to add OCSP confirmation. This completes the signature and provides long term proof of the signed data. Please note that only one OCSP confirmation is allowed for a signature.

signature.getConfirmation();

This concludes the required code for digitally signing data using PKCS#11 driver for identity token. Please feel free to use the reference code, ask questions, and/or suggest revisions.

    Recent Posts

    • Digital Signing with JDigiDoc
    • Email Management on InferatoFS; An Application of Integrative Graph File System

    Recent Comments

    No comments to show.

    Archives

    • November 2013
    • January 2012

    Categories

    • Engineering Notes
    • Feature Walkthroughs
    ⓒ 2025 The Digital Patrol