DigiDoc4j 6.0.0-RC.1 API
digidoc4j is a library for integrating digital signatures (XAdES/ASiC based) into applications and services built with Java technology.
The development of digidoc4j is organized by Estonian Information System Authority and executed by several companies, including AS Sertifitseerimiskeskus and CGI Eesti AS. For inquiries about participating in the development please e-mail eid at ria.ee
This document provides the following information on digidoc4j:
- Supported functionality
- Architecture
- API overview
- Utility program overview
Supported functionality
This section gives overview of the main functional features offered by digidoc4j. For more detailed information about the functions (including functionality that is planned for later releases), see the digidoc4j project's Pivotal Tracker.
The digidoc4j utility program digidoc4j-util*.jar can be used for testing a subset of the supported functionality, the program is accessible from the digidoc4j download area.
Creating and handling signature containers
digidoc4j enables handling signature containers compliant to ETSI TS 102 918 standard called Associated Signature Containers (ASiC). By default, the digidoc4j implementation uses containers in BDOC 2.1 format, which is a subset of ASiC standard.
Note: additionally, an older DIGIDOC-XML 1.3 container format is supported via JDigiDoc base library.
The main use cases regarding signature containers are:
- Creating a new container
- Adding and removing data files
- Extracting data files from container
- Using temporary cache files for storing the data file's contents in file system
- Adding and removing signatures
- Input/output operations with containers
- Timestamping an ASiCS container
See also: org.digidoc4j.ContainerBuilder
and Container
Creating and handling digital signatures
digidoc4j enables handling digital signatures based on ETSI TS 101 903 standard called XML Advanced Electronic Signatures (XAdES). By default, the digidoc4j implementation uses signatures in BDOC 2.1 format, which is a subset of XAdES standard.
Note: additionally, an older XAdES-based DIGIDOC-XML 1.3 signature format is supported via JDigiDoc base library.
The main use cases regarding digital signatures are:
- Creating the signature's XAdES-based XML contents
- Adding meta-data to the signature: e.g. signature creation location and signer's role
- Calculating the hash to be signed - e.g. for calculating the raw signature value with a plug-in in browser
- Calculating the raw RSA or ECDSA signature value
- Adding a raw signature value that is calculated in an external system (e.g. with plugin when signing in browser) to the signature's XML content
- Adding long term validation data according to the signature profile: either time-mark or time-stamp and OCSP confirmation*
* There are two XAdES-LT level compliant signature profiles supported:
- LT - XAdES-LT signature with time-stamp - long term validation data is added to the signature in the form of a RFC3161 compliant time-stamp and RFC6960 compliant OCSP confirmation. The profile can be used in case of BDOC 2.1 format.
- LT_TM - XAdES-LT signature with time-mark - long term validation data is added to the signature in the form of a time-mark (RFC6960 compliant OCSP confirmation with a special nonce value). The profile can be used in case of BDOC 2.1 and DIGIDOC-XML 1.3 formats.
See also: org.digidoc4j.SignatureBuilder
, Signature
, ContainerBuilder
and Container
Validating signature container and all of its contents
The signature validation process is based on ETSI TS 102 853 standard called Signature validation procedures and policies.
The main use cases regarding validation are:
- Validating a single digital signature. See also:
org.digidoc4j.Signature.validateSignature
- Validating a signature container and all of its contents. See also:
org.digidoc4j.Container.validate
- Generating validation report in XML format.
- Enabling configuration of signature validation policies according to ETSI TR 102 038 standard XML format for signature policies.
See also: org.digidoc4j.ValidationResult
Using TSL lists as trust anchors
TSL (Trust Service status List) list is a signed XML document that provides information about the status of trust services. The format is based on ETSI 119 612 standard.
digidoc4j uses TSL lists for checking the trustworthiness of the certificates that are used in the signature. The European Commission's TSL list is used as the List Of Trusted List (LOTL) (accessible from: https://ec.europa.eu/tools/lotl/eu-lotl.xml).
The main use case regarding TSL lists usage is:
- Using TSL lists for checking the trustworthiness of the signer's certificate, OCSP service and time-stamping service certificates during signature creation and validation processes.
Supported cryptographic tokens
- PKCS#12 token (software token)
- PKCS#11 token (hardware token)
See also: org.digidoc4j.SignatureToken
, org.digidoc4j.signers.PKCS12SignatureToken
and org.digidoc4j.signers.PKCS11SignatureToken
Architecture
Component diagram
The component diagram above depicts the high level components of digidoc4j library, their internal and external interfaces.
The components in the diagram are divided into notional packages according to their owner:
- RIA - Estonian Information System Authority
- EC - European Commission
The components are further described in the following table:
Component | Description | Owner |
---|---|---|
digidoc4j | Open source software library for integrating digital signatures (XAdES/ASiC based) into applications and services built with Java technology.
|
RIA |
digidoc4j utility program | Small command line application that enables accessing the main functionality of digidoc4j library via a command line interface. Used for testing purposes. Can also be used as a source for sample client code for using digidoc4j API. Can be downloaded from digidoc4j download area.
|
RIA |
JDigiDoc | Open source Java software library that enables handling documents in BDOC 2.1 and DIGIDOC-XML 1.3 formats and encryption/decryption in ENCDOC-XML 1.0 (CDOC) format. See also:
|
RIA |
DSS | Digital Signature Service - open source Java framework created in order to assist EU Member States with the implementation of the Decision 2011/130/EU. Supports several forms AdES digital signatures and ASiC signature containers. See also:
|
European Commission |
TSL repository | Repository for the European Commission's central TSL list with links to the locations where the trusted lists are published as notified by EU Member States, accessible from https://ec.europa.eu/tools/lotl/eu-lotl.xml.
|
European Commission |
OCSP service | RFC2560/RTF6960 based OCSP service. Also offered by SK for Estonian and a number of foreign certificates.
|
Any OCSP service provider |
Time-stamping service | RFC3161-based time-stamping service. Also offered by SK.
|
Any time-stamping service provider |
API overview
The digidoc4j source code's compliance to Java development best practices is periodically checked with automated code review, executed with Checkstyle configuration file checkstyle.xml that is included in the digidoc4j source package.
The Checkstyle source code analyzer enables to ensure that the code has been written according to "Code conventions for the Java programming language" and has been documented according to JavaDoc best practices, described in "How to write doc comments for the JavaDoc tool".
Sample of using digidoc4j API
In the following subsections, a sample BDOC 2.1 signature creation use case is implemented with digidoc4j API classes and methods.
Configuration
It is possible switch between testing and production environment by using Configuration
class or digidoc4j.mode
system property.
Default environment is production.
More detailed configuration can be modified in the digidoc4j.yaml
file.
Configuration
configuration = new Configuration
(Configuration.Mode.TEST
);
The example above creates a configuration with test environment for using test OCSP, Time Stamp etc servers. The same can
be achieved by setting the system property digidoc4j.mode
with value "TEST"
.
It is a good idea to use only a single configuration object for all the containers so the operation times would be faster. For example, TSL is cached within a configuration object and TSL loading is a time consuming operation.
The default configuration object is a singelton, meaning that all the containers will use the same configuration object
(unless specified otherwise). The default singelton configuration object can be accessed by
Configuration
configuration = Configuration
.getInstance()
;
Creating a container
Container
container = ContainerBuilder
.
aContainer
("BDOC"). // Supported types are BDOC, ASICE, ASICS and DDOC. Default is BDOC
withConfiguration
(configuration). // Configuration
settings
withDataFile
("testFiles/legal_contract_1.txt", "text/plain"). // Adding a document from a hard drive
withDataFile
(inputStream, "legal_contract_2.txt", "text/plain"). // Adding a document from a stream
build()
;
You can use ContainerBuilder.aContainer()
to create a new container builder,
populate the builder with data and finally call build()
to create the container with the populated data.
In the example above, a container builder is used to create a BDOC container with specific configuration parameters and two data files: one from hard drive (legal_contract_1.txt) and other from input stream (legal_contract_2.txt).
ContainerBuilder.aContainer(String containerType)
can be used
for creating a container of a particular type. Currently supported types are BDOC, ASiCE, ASiCS and DDOC. Default is BDOC 2.1 if no type is provided.
Adding data files
A data file can be added by reading it from the file system or from an input stream (needed if the data is already in memory, e.g. read from database). The following example shows the case when the file is read from file system:
containerBuilder.withDataFile
("<input_file_name_and_path>", "<mime_type>");
Reading and writing containers
A created container can be written to the file system as follows:
container.
saveAsFile
("<output_file_name_and_path>");
An existing container can be read as follows:
Container
container = ContainerBuilder
.
aContainer()
.
fromExistingFile
("<input_file_name_and_path>").
build()
;
Adding signatures
A signature can be added to the container by determining a class that implements communication with the signature token,
i.e. a subclass of
.
Currently, a PKCS#12 software token implementation is provided by digidoc4j in the
SignatureToken
PKCS12SignatureToken
class.
Using a signature token
String privateKeyPath = "testFiles/signout.p12";
char[] password = "test".toCharArray();
PKCS12SignatureToken
signatureToken = new PKCS12SignatureToken
(privateKeyPath, password);
In the sample above, the PKCS#12 token container's location and password is given as input parameters
to the
class. The private key is stored in the
PKCS12SignatureToken
"signout.p12"
file and the password is "test"
.
Creating a new signature
Next we create a new signature with the signature token.
Signature
signature = SignatureBuilder
.
aSignature
(container).
withSignatureDigestAlgorithm
(DigestAlgorithm.SHA256
).
withSignatureToken
(signatureToken).
invokeSigning()
;
Finally we add the signature to the container. Signature must be added to the container otherwise the signature remains detached from the container.
container.
addSignature
(signature);
Signing externally
It is possible to sign the container externally. A typical use case would be signing in the Web using a browser plugin:
- Create a container with data files
- Create SignedInfo data object what contains a digests of the data files to be signed
- Sign the SignedInfo data object externally (e.g. via browser plugin)
- Finalize the signature with the signature value, OCSP response etc
- Add the finalized signature to the container
Getting data to sign
First we need to get the signer's certificate that is used in signing (via browser plugin for example).
X509Certificate
signingCert = getSignerCertSomewhere();
Then we need to get the SignedInfo data object to be signed externally.
DataToSign
dataToSign = SignatureBuilder
.
aSignature
(container).
withSigningCertificate
(signingCert).
withSignatureDigestAlgorithm
(DigestAlgorithm.SHA256
).
buildDataToSign()
;
External signing
Now we have a data that can be used for external signing. DataToSign
class contains DataToSign.getDataToSign()
method
for getting data to be signed. DataToSign.getDigestAlgorithm()
method can be used for getting the digest algorithm to be used in the signing process.
byte[] data = dataToSign.
getDataToSign()
; //Get the SignedInfo data that should be signed
byte[] signatureValue = signDataSomewhereRemotely(data, DigestAlgorithm.SHA256); //Sign the SignedInfo data
Finalizing signature
Next we have to finalize the signature with the signature value (signatureValue
) we got from an external signing process.
Signature
signature = dataToSign.finalize
(signatureValue); //Finalize the signature with OCSP response etc
Finally we add the signature to the container. Signature must be added to the container otherwise the signature remains detached from the container.
container.
addSignature
(signature);
Using Time Mark signature profile
By default, the Time Stamp signature profile (referred to as "LT") is used in case of BDOC 2.1 documents.
It is possible to use use a different signature profile by using signature builder's SignatureBuilder.withSignatureProfile(org.digidoc4j.SignatureProfile)
method.
For signing a container using the Time Mark profile you need to set the signature profile as in the following example:
SignatureBuilder
signatureBuilder = SignatureBuilder
.
aSignature
(container).
withSignatureProfile
(SignatureProfile.LT_TM
); // Signature profile is Time Mark
Signer role and production place
We can add signer roles and production place to signature by using SignatureBuilder
.
SignatureBuilder
signatureBuilder = SignatureBuilder
.
aSignature
(container).
withCity
("San Pedro").
withStateOrProvince
("Puerto Vallarta").
withPostalCode
("13456").
withCountry
("Val Verde").
withRoles
("Manager", "Suspicious Fisherman");
The example above the signer is from the city of San Pedro, in the state of Puerto Vallarta, with postal code 13456 and from country called Val Verde. The signer's roles are Manager and Suspicious Fisherman.
Validation
Validation process of a container and all of its contents can be initiated as follows:
ValidationResult
result = container.validate()
;
Possible validation errors can be handled as follows:
if (!result.
isValid()
) {
for (DigiDoc4JException
error : result.getErrors()
) {
System.out.println(error.getMessage()
);
}
}
Exception handling
digidoc4j uses a generic exception class org.digidoc4j.exceptions.DigiDoc4JException
that is a subclass of java.lang.RuntimeException.
DigiDoc4JException
also wraps any possible exceptions that are thrown by the base libraries of digidoc4j.
The DigiDoc4JException
class itself is subclassed to enable better handling of a number of the most critical exceptions. See also package org.digidoc4j.exceptions
.
Utility program overview
The digidoc4j utility program is a command line tool that allows easy usage of several API's.
Setting up the utility
The utility is distributed as a zip file with the name digidoc4j-util-*.zip (where * is the actual version number). Unzip the file to a directory of your choice. From that directory you can now run it:
java -jar digidoc4j-util.jar
Sample of using the digidoc4j utility
In the following subsection some examples are provided for using the utility.
Creating a container
A valid BDOC container contains at least one document and is signed. To create such a container:
java -jar digidoc4j-util.jar -in "<output_file_name_and_path>" -add "<input_file_name_and_path>" "<mime_type>" -pkcs12 "<pkcs12_token_file>" "<pkcs12_token_password>"
Using the time-mark signature profile
To sign a container using the time-mark protocol you need to specify the signature profile using the -profile option LT_TM:
java -jar digidoc4j-util.jar -in "<output_file_name_and_path>" -add "<input_file_name_and_path>" "<mime_type>" -profile LT_TM -pkcs12 "<pkcs12_token_file>" "<pkcs12_token_password>"
Using the ID-card
java -jar digidoc4j-util.jar -in "<output_file_name_and_path>" -add "<input_file_name_and_path>" "<mime_type>" -profile LT_TM -pkcs11 "<pkcs11_module_path>" "<pkcs11_token_pin_password>" "<pkcs11_slot_index>"
When the client computer has only one smartcard reader then there are for Estonian ID-card usually two slots available:
- slot 0 - for authentication (PIN1)
- slot 1 - for signing (PIN2)
In case where computer has multiple smartcard readers the slot numbers are usable in pairs:
- slot 0 - reader 0, PIN1
- slot 1 - reader 0, PIN2
- slot 2 - reader 1, PIN1
- slot 3 - reader 1, PIN2
- etc
In order to investigate possibilities one can use OpenSC tools, for example:
pkcs11-tool -L --module /usr/local/lib/opensc-pkcs11.so
Example:
java -Ddigidoc4j.mode=TEST -jar digidoc4j-util.jar -in test.bdoc -add dds_acrobat.pdf application/pdf -pkcs11 /usr/local/lib/opensc-pkcs11.so 22975 1
Creating multiple signed containers
To create signatures of all the files within a directory, you need to specify the input directory containing data files, and output directory where the signed containers will be saved.
java -jar digidoc4j-util.jar -inputDir "<input_directory_path>" -mimeType "<mime_type (optional)>" -outputDir "<output_directory_path>" -pkcs11 "<pkcs11_module_path>" "<pkcs11_token_pin_password>" "<pkcs11_slot_index>"
e-tokens which are bought from SK are initialized in FIPS 140-2 or EAL4+ CC v3.1 rez mode.
Thanks to that PIN-code cannot be cached without adding PIN-caching to script. This means that you cannot use -inputDir
,
but can use only -in
parameter with those tokens.
Creating a timestamped ASiCS container
A valid ASiCS container contains only one document and is signed or timestamped.
To create such a container the output file extention must be .asics
or .scs.
In order to create ASiCS container with
timestamp the option -tst
or -timestamp
must be used:
java -jar digidoc4j-util.jar -in "<output_file_name_and_path>" -add "<input_file_name_and_path>" "<mime_type>" -tst
NB! For successful timestamping the user must have service agreement with TSA!
Validation
The utility performs validation when specifying the -v option. The output shows all signatures and their statuses as well as all errors:
java -jar digidoc4j-util.jar -in "<input_file_name_and_path>" -v
In order to see validation warnings in addition to the errors you must specify the -w option:
java -jar digidoc4j-util.jar -in "<input_file_name_and_path>" -v -w
In order to get validation reports in addition to the output on the screen you must specify the -r option:
java -jar digidoc4j-util.jar -in "<input_file_name_and_path>" -v -r "<report_files_path>"
Then you can find in given report directory following xml-files: validationReport.xml
, validationDiagnosticData*.xml
,
validationDetailReport*.xml
and validationSimpleReport*.xml
.
Verbose
For all tasks more details can be obtained using the -verbose option as in the next example:
java -jar digidoc4j-util.jar -in "<input_file_name_and_path>" -v -verbose
Test mode
It is possible to invoke the library in test mode by adding -Ddigidoc4j.mode=TEST
. This will use the test TSL and accepts test ID cards.
java -Ddigidoc4j.mode=TEST -jar digidoc4j-util.jar