Digital Signer library it's a Java library which allows using smart cards for data signing in CAdES format. You can also do Client Certificate Authentication with this library.
When you look at source code, I use the term hardware
instead of smart card
because it's more generic.
This library has been tested with Bit4Id smart cards. These are my tests: On Windows it does only work under a 32bit JVM, because of the implementation of the smart card library. On Linux it works on both 32bit and 64bit machines as expected. On MacOS, I tested only on 64Bit machines (running Sierra).
Currently, it has been tested with the Italian CNS (Carta Nazionale dei Servizi) and DS (Digital Signer) cards, provided by Bit4Id®. Other developers can request modifications to make this library work with their cards.
On Windows, using Bit4Id smart cards, if you disconnect, then reconnect the hardware, calling signData
method will give you an exception. This does not happen on Linux, nor MacOS.
This library depends on BouncyCastle. It requires both Provider and S/MIME API provided by the 1.6 version, specifically. Other versions will not work correctly, because some functions have been deprecated.
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.45</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcmail-jdk16</artifactId>
<version>1.45</version>
</dependency>
</dependencies>
First of all, this library is designed with a singleton pattern. So, we get the singleton istance
DigitalSigner digitalSigner = DigitalSigner.getSingleton();
If you want to see debugging informations by both library and PKCS#11 implementation, we can enable or disable debug logging:
digitalSigner.setDebugEnabled(true);
Then we must set the library path, which contains the PKCS#11 implementation and the password to access the hardware:
digitalSigner.setLibPath("C:/Some/Path/pkcs11.dll");
Finally, we have to set the password for the hardware:
digitalSigner.setPassword("12345678");
Optionally, we can set the slot unit (in string format). By default, its value is 0:
digitalSigner.setSlot("0");
The library is pretty straightforward.
You can extract the content from a CAdES signed content (in P7M format, presumably) via this function:
byte[] originalContent = digitalSigner.extractSignedContent(myContentInByteFormat);
You can sign, or countersign, in CAdES format any data you want, via this function:
byte[] signedContent = digitalSigner.sign(myContentInByteFormat);
You can verify CAdES signed data, via this function. The code is pretty self-explanatory:
VerifySignature vs = digitalSigner.verify(signedContent);
boolean isSignatureValid = vs.isVerified();
ArrayList<ArrayList<String[]>> subjects = getSubjects();
ArrayList<ArrayList<String[]>> issuers = getIssuers();
Methods getSubjects
and getIssuers
will return an ArrayList
, where each row contains another ArrayList
, containing a list of String
array, which has always two elements. They are like a key/value pair, where the key is a certificate field.
Here's an example:
- Array of subjects / issuers
- First Row
- { "DN", "James Brown" }
- { "C", "USA" }
- { "CN", "james@email.com" }
- etc...
- Second Row
- { "DN", "John Connor" }
- { "C", "United Kingdom" }
- { "CN", "john@email.com" }
- etc...
- etc...
- First Row
- etc...
You can get the long field name by doing:
String name = VerifySignature.getFieldName("DN");
// name is equal to "Distinguished Name".
You can get the KeyStore, respecting the PKCS#11 standard, via this function:
KeyStore myKeyStore = digitalSigner.loadKeyStorePKCS11();
The method below is designed specifically for Italian cards, which can have multiple certificates, one for signing and another one for accessing public online services.
String alias = digitalSigner.getAliasForCNS();
You can use SSLContext
to achieve Client Certificate Authentication, and X509KeyManager
to choose the certificate to be used, by defining its alias. Take a look at the ClientCertAuth.java
class for further information about the process.