public class CLITest
extends java.lang.Object
A command line interface program for testing the generation of a CMS signed message, using a pkcs11 token (usually a SmartCard). This is a complete example covering all aspects of digital signature, from token management to CMS message generation and verification.
Multiple signatures are permitted, each with different token types; the generated CMS message keeps signers informations at the same level (similar to a paper document with multiple signatures). I call this arrangement "combined signatures", in contrast with "nested signatures" (like a signed paper document put in a signed envelope). A hierarchical type of multiple signatures, ("CounterSignature", OID: 1.2.840.113549.1.9.6) is also contemplated by CMS standard in RFC 3852, but it is not currently supported.
The example adopts a special class for securing token PIN management
(Unfortunately the java language does not provide any standard method to hide
character input). This could cause some problem on IDEs, where the default
input - output streams are not the standard console, then password hiding can
be disabled.
After having signed, (or instead of signing, if the file to verify path is passed)
it is possible to perform a full verification,
with signer certificate check (certificate chain check, revocation through
the CRL distribution service specified in the signer certificate), CAdES
details checks, etc.
The configuration of the tests is specified in three properties file:
The verification policy conforms to the latest italian
regulations, see:
REGOLE PER IL RICONOSCIMENTO E LA VERIFICA DEL DOCUMENTO INFORMATICO.
These rules comply also to the electronic signature european regulation framework.
clitest.properties
which specify internal behavior and resources needed by the tests.conf.properties
for configuration and resources needed by the verification process.logging.properties
for logging (standard java.util.logging is used).
Modifier and Type | Class and Description |
---|---|
private class |
CLITest.Prompt |
Modifier and Type | Field and Description |
---|---|
private java.io.File |
crlDir |
private java.lang.String |
cryptokiLib |
private java.lang.String |
digestAlg |
(package private) java.security.cert.X509Certificate |
dsaOrigCert |
(package private) java.security.KeyPair |
dsaOrigKP |
(package private) java.security.cert.X509Certificate |
dsaSignCert |
(package private) java.security.KeyPair |
dsaSignKP |
private java.lang.String |
encAlg |
private java.lang.String |
filePath |
private java.lang.String |
fingerprintString |
private boolean |
forcingCryptoki |
private boolean |
makeDigestOnToken |
(package private) byte[] |
msgBytes |
(package private) java.security.cert.X509Certificate |
origCert |
(package private) java.lang.String |
origDN |
(package private) java.security.KeyPair |
origKP |
private static java.lang.String |
PROPERTIES_FILE |
(package private) java.security.cert.X509Certificate |
reciCert |
(package private) java.lang.String |
reciDN |
(package private) java.security.KeyPair |
reciKP |
(package private) java.security.cert.X509Certificate |
signCert |
(package private) java.lang.String |
signDN |
(package private) java.security.KeyPair |
signKP |
private static int |
WRAP_AFTER |
Constructor and Description |
---|
CLITest() |
CLITest(java.lang.String filePath)
CLITest constructor that takes a file path as argument.
|
Modifier and Type | Method and Description |
---|---|
private long |
algToMechanism(boolean digestOnToken,
java.lang.String digestAlg,
java.lang.String encryptionAlg) |
private byte[] |
applyDigest(java.lang.String digestAlg,
byte[] bytes) |
private byte[] |
applyPkcs1Padding(int resultLength,
byte[] srcBytes) |
static byte[] |
decodeHex(char[] data) |
private boolean |
detectCardAndCriptoki()
This triggers the PCSC wrapper stuff; a
PCSCHelper class is used
to detect reader and token presence, trying also to provide a candidate
PKCS#11 cryptoki for it. |
private byte[] |
encapsulateInDigestInfo(java.lang.String digestAlg,
byte[] digestBytes) |
java.lang.String |
formatAsString(byte[] bytes,
java.lang.String byteSeparator,
int wrapAfter)
Formats a byte[] as an hexadecimal String, interleaving bytes with a
separator string.
|
java.lang.String |
getCryptokiLib()
The cryptoki library currently used, as set in
detectCardAndCriptoki() method. |
java.lang.String |
getFilePath() |
(package private) ExternalSignatureSignerInfoGenerator |
getSignerInfoGenerator(org.bouncycastle.cms.CMSProcessable msg,
java.lang.String digestAlg,
java.lang.String encryptionAlg,
boolean digestOnToken,
java.util.ArrayList certList)
Implements a single signature, returning the
ExternalSignatureSignerInfoGenerator that encapsulates all signer
informations. |
boolean |
isForcingCryptoki() |
private void |
loadProperties() |
static void |
main(java.lang.String[] args)
the main method Adds BouncyCastle cryptographic provider, instantiates
the CLITest class, and launches the signature/verification process.
|
(package private) char[] |
readPassword()
Uses the
PasswordMasker class to securely read characters from the
console; it's a pity that java language does not includes this in its
standard set of features. |
private void |
setCryptokiLib(java.lang.String lib)
Sets th cryptoki library to use to access the current PKCS#11 token; This
method is used internally in
detectCardAndCriptoki() method. |
void |
testExternalSignature()
Tests (possibly multiple) digital signatures using PKCS#11 tokens.
|
void |
testFullVerification()
Performs full (signer certificate chain and revocation status)
verification of a CMS signed message.
|
protected static int |
toDigit(char ch,
int index) |
private java.lang.String cryptokiLib
private boolean forcingCryptoki
java.lang.String signDN
java.security.KeyPair signKP
java.security.cert.X509Certificate signCert
java.lang.String origDN
java.security.KeyPair origKP
java.security.cert.X509Certificate origCert
java.lang.String reciDN
java.security.KeyPair reciKP
java.security.cert.X509Certificate reciCert
java.security.KeyPair dsaSignKP
java.security.cert.X509Certificate dsaSignCert
java.security.KeyPair dsaOrigKP
java.security.cert.X509Certificate dsaOrigCert
byte[] msgBytes
private static int WRAP_AFTER
private boolean makeDigestOnToken
private java.lang.String digestAlg
private java.lang.String encAlg
private static java.lang.String PROPERTIES_FILE
private java.lang.String filePath
private java.lang.String fingerprintString
private java.io.File crlDir
public CLITest()
public CLITest(java.lang.String filePath)
filePath
- Currently this is assumed to be the path of a signed CMS file to verify;private void loadProperties()
public static void main(java.lang.String[] args)
the main method Adds BouncyCastle cryptographic provider, instantiates
the CLITest class, and launches the signature/verification process. The message to sign is the fixed word "CIAO".
A CMS signed file path can be provided as parameter; in that case the signature procedure is skipped,
and only verification is performed.
args
- public java.lang.String getFilePath()
public java.lang.String getCryptokiLib()
detectCardAndCriptoki()
method.private void setCryptokiLib(java.lang.String lib)
detectCardAndCriptoki()
method.lib
- private boolean detectCardAndCriptoki() throws java.io.IOException
PCSCHelper
class is used
to detect reader and token presence, trying also to provide a candidate
PKCS#11 cryptoki for it.java.io.IOException
public void testExternalSignature()
public void testFullVerification()
Requires a suitable conf
directory containing the signed
zipfile of qualified root CAs (and related files), and the fingerprint
value of signing certificate, provided in the
clitest.properties
file, for checking roots integrity.
The verification policy strictly follows current italian regulations (CAdES, SHA256 hashing ...).
See the README
file for more informations.
private long algToMechanism(boolean digestOnToken, java.lang.String digestAlg, java.lang.String encryptionAlg)
ExternalSignatureSignerInfoGenerator getSignerInfoGenerator(org.bouncycastle.cms.CMSProcessable msg, java.lang.String digestAlg, java.lang.String encryptionAlg, boolean digestOnToken, java.util.ArrayList certList)
ExternalSignatureSignerInfoGenerator
that encapsulates all signer
informations.msg
- the content to signcertList
- the list which the signer certificate is to be added to.ExternalSignatureSignerInfoGenerator
containing
all signer informations.public java.lang.String formatAsString(byte[] bytes, java.lang.String byteSeparator, int wrapAfter)
bytes
- the byte[] to format.byteSeparator
- the string to be used to separate bytes.char[] readPassword() throws java.io.IOException, java.lang.InterruptedException
PasswordMasker
class to securely read characters from the
console; it's a pity that java language does not includes this in its
standard set of features.java.io.IOException
java.lang.InterruptedException
private byte[] applyDigest(java.lang.String digestAlg, byte[] bytes) throws java.security.NoSuchAlgorithmException
java.security.NoSuchAlgorithmException
private byte[] encapsulateInDigestInfo(java.lang.String digestAlg, byte[] digestBytes) throws java.io.IOException
java.io.IOException
private byte[] applyPkcs1Padding(int resultLength, byte[] srcBytes)
public boolean isForcingCryptoki()
public static byte[] decodeHex(char[] data) throws java.lang.Exception
java.lang.Exception
protected static int toDigit(char ch, int index) throws java.lang.Exception
java.lang.Exception