/* DigiDoc4J library
*
* This software is released under either the GNU Library General Public
* License (see LICENSE.LGPL).
*
* Note that the only valid version of the LGPL license as far as this
* project is concerned is the original GNU Library General Public License
* Version 2.1, February 1999
*/
package org.digidoc4j.signers;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.security.cert.X509Certificate;
import java.util.List;
import javax.xml.bind.DatatypeConverter;
import org.digidoc4j.Container;
import org.digidoc4j.ContainerBuilder;
import org.digidoc4j.DigestAlgorithm;
import org.digidoc4j.Signature;
import org.digidoc4j.SignatureBuilder;
import org.digidoc4j.SignatureToken;
import org.digidoc4j.impl.DigiDoc4JTestHelper;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import eu.europa.esig.dss.token.DSSPrivateKeyEntry;
import eu.europa.esig.dss.token.PasswordInputCallback;
import eu.europa.esig.dss.token.PrefilledPasswordCallback;
@Ignore("Requires a physical smart card for testing. Smart card issuer is TEST of ESTEID-SK 2015 and and CN is Igor Ž. Certificate serial 169229412855358073476555321630882129183. Document nr AS0013055")
public class PKCS11SignatureTokenTest extends DigiDoc4JTestHelper {
static final byte[] dataToSign = new byte[]{60, 100, 115, 58, 83, 105, 103, 110, 101, 100, 73, 110, 102, 111, 32, 120, 109, 108, 110, 115, 58, 100, 115, 61, 34, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47, 50, 48, 48, 48, 47, 48, 57, 47, 120, 109, 108, 100, 115, 105, 103, 35, 34, 62, 60, 100, 115, 58, 67, 97, 110, 111, 110, 105, 99, 97, 108, 105, 122, 97, 116, 105, 111, 110, 77, 101, 116, 104, 111, 100, 32, 65, 108, 103, 111, 114, 105, 116, 104, 109, 61, 34, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47, 50, 48, 48, 49, 47, 49, 48, 47, 120, 109, 108, 45, 101, 120, 99, 45, 99, 49, 52, 110, 35, 34, 62, 60, 47, 100, 115, 58, 67, 97, 110, 111, 110, 105, 99, 97, 108, 105, 122, 97, 116, 105, 111, 110, 77, 101, 116, 104, 111, 100, 62, 60, 100, 115, 58, 83, 105, 103, 110, 97, 116, 117, 114, 101, 77, 101, 116, 104, 111, 100, 32, 65, 108, 103, 111, 114, 105, 116, 104, 109, 61, 34, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47, 50, 48, 48, 49, 47, 48, 52, 47, 120, 109, 108, 100, 115, 105, 103, 45, 109, 111, 114, 101, 35, 114, 115, 97, 45, 115, 104, 97, 50, 53, 54, 34, 62, 60, 47, 100, 115, 58, 83, 105, 103, 110, 97, 116, 117, 114, 101, 77, 101, 116, 104, 111, 100, 62, 60, 100, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 32, 73, 100, 61, 34, 114, 45, 105, 100, 45, 49, 34, 32, 84, 121, 112, 101, 61, 34, 34, 32, 85, 82, 73, 61, 34, 116, 101, 115, 116, 46, 116, 120, 116, 34, 62, 60, 100, 115, 58, 68, 105, 103, 101, 115, 116, 77, 101, 116, 104, 111, 100, 32, 65, 108, 103, 111, 114, 105, 116, 104, 109, 61, 34, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47, 50, 48, 48, 49, 47, 48, 52, 47, 120, 109, 108, 101, 110, 99, 35, 115, 104, 97, 50, 53, 54, 34, 62, 60, 47, 100, 115, 58, 68, 105, 103, 101, 115, 116, 77, 101, 116, 104, 111, 100, 62, 60, 100, 115, 58, 68, 105, 103, 101, 115, 116, 86, 97, 108, 117, 101, 62, 82, 113, 68, 113, 116, 113, 105, 51, 114, 84, 115, 87, 106, 48, 55, 114, 114, 87, 99, 53, 107, 65, 84, 65, 90, 73, 119, 55, 84, 49, 88, 72, 80, 47, 78, 80, 76, 67, 70, 48, 53, 82, 85, 61, 60, 47, 100, 115, 58, 68, 105, 103, 101, 115, 116, 86, 97, 108, 117, 101, 62, 60, 47, 100, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 62, 60, 100, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 32, 84, 121, 112, 101, 61, 34, 104, 116, 116, 112, 58, 47, 47, 117, 114, 105, 46, 101, 116, 115, 105, 46, 111, 114, 103, 47, 48, 49, 57, 48, 51, 35, 83, 105, 103, 110, 101, 100, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 85, 82, 73, 61, 34, 35, 120, 97, 100, 101, 115, 45, 105, 100, 45, 100, 101, 97, 97, 53, 101, 52, 98, 101, 97, 97, 55, 102, 48, 97, 102, 49, 102, 100, 52, 99, 55, 101, 51, 49, 100, 100, 55, 50, 52, 57, 50, 34, 62, 60, 100, 115, 58, 84, 114, 97, 110, 115, 102, 111, 114, 109, 115, 62, 60, 100, 115, 58, 84, 114, 97, 110, 115, 102, 111, 114, 109, 32, 65, 108, 103, 111, 114, 105, 116, 104, 109, 61, 34, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47, 50, 48, 48, 49, 47, 49, 48, 47, 120, 109, 108, 45, 101, 120, 99, 45, 99, 49, 52, 110, 35, 34, 62, 60, 47, 100, 115, 58, 84, 114, 97, 110, 115, 102, 111, 114, 109, 62, 60, 47, 100, 115, 58, 84, 114, 97, 110, 115, 102, 111, 114, 109, 115, 62, 60, 100, 115, 58, 68, 105, 103, 101, 115, 116, 77, 101, 116, 104, 111, 100, 32, 65, 108, 103, 111, 114, 105, 116, 104, 109, 61, 34, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47, 50, 48, 48, 49, 47, 48, 52, 47, 120, 109, 108, 101, 110, 99, 35, 115, 104, 97, 50, 53, 54, 34, 62, 60, 47, 100, 115, 58, 68, 105, 103, 101, 115, 116, 77, 101, 116, 104, 111, 100, 62, 60, 100, 115, 58, 68, 105, 103, 101, 115, 116, 86, 97, 108, 117, 101, 62, 73, 114, 117, 116, 56, 49, 75, 108, 75, 115, 117, 97, 112, 69, 115, 57, 70, 85, 118, 52, 86, 43, 71, 72, 117, 76, 101, 118, 74, 53, 47, 66, 47, 83, 117, 52, 50, 48, 104, 98, 84, 48, 56, 61, 60, 47, 100, 115, 58, 68, 105, 103, 101, 115, 116, 86, 97, 108, 117, 101, 62, 60, 47, 100, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 62, 60, 47, 100, 115, 58, 83, 105, 103, 110, 101, 100, 73, 110, 102, 111, 62};
static final String expectedSignatureinHex = "49D438E821F1AD841D275DD890FBCB74748BE4F979BF81FBEE83CC4606F09E23189EAA6BBDF4E9D8F1CE0021EC9D97E35044D5B9D8B816EA59F06BD0F923CE9F351CFDC2A3A7DC4F0A77D08A0E7E158AD15FE0420D994B984731EF04C98CDE6CB0CA34001332EF157F27747797897531758B1B8E31BEF3D7A89B1ACF4D28E44B1734A51D31E325CF7E076D2DC29AAECF9303F3DFE3D137F21638219896CC978E3D3E26433DAB592FA773B2EFD461ABABAD4D8E70D62EBE7529AD672B3FB1A30A3658196326E61B6919B3FC2F466559ECE75A8E4E4EE751CDF1C3B55388B6DC1A35C219B52AD120481879800124A84A98BAAB92C31A7DF3B0E09B2C8D718C5C55";
static final String expectedSignatureinHexWithSha512 = "81128BA4FE29966B614416BFC54B8E6BF18B75B51A7AC8528EC3A1452872B3EA8914DF0E787CCFF5D3ABAA9D363CDD4891ED3B35C6FAFD3E42C1A6D6BA4769FC721B514B98FC1708A4ECB0AADAB9FF89A017D9C2156839E4E85E059E7B3FCBAAF225480093BE897B6E6FEB5F26638223AF5C4AD0B8DCCB96B2A000E517D8543EA4F2C1817FF4450F47D14D00C8333BDB40F7E408948DDBB1663AF364340F8FB44080ED9B731A2BDD28FA2C6FB55E993F33079B7C57FDDC3C6B345D1360D82F5242A857F27EA71DC3012EA1B069100824AF6729F1C878A29C6C81F83101B711B03707CA4D5F7A54952443F7F80CE5B5FCC88174249B303E50B48C5F30A952D865";
private SignatureToken signatureToken;
@Before
public void setUp() throws Exception {
signatureToken = new PKCS11SignatureToken("/usr/local/lib/opensc-pkcs11.so", "22975".toCharArray(), 2);
}
@Test
public void signContainerWithSmartCard() throws Exception {
Container container = createSignedContainer(ContainerBuilder.BDOC_CONTAINER_TYPE, DigestAlgorithm.SHA256);
assertTrue(container.validate().isValid());
}
@Test
public void signDDocContainerWithSmartCard() throws Exception {
Container container = createSignedContainer(ContainerBuilder.DDOC_CONTAINER_TYPE, DigestAlgorithm.SHA1);
assertTrue(container.validate().isValid());
}
@Test
public void fetchCertificateFromSmartCard() throws Exception {
X509Certificate certificate = signatureToken.getCertificate();
assertNotNull(certificate);
assertThat(certificate.getSubjectDN().getName(), containsString("CN"));
}
@Test
public void signHashWithSmartCard() throws Exception {
signHashAndAssertSignature(DigestAlgorithm.SHA256, dataToSign, expectedSignatureinHex);
}
@Test
public void signSha512HashWithSmartCard() throws Exception {
signHashAndAssertSignature(DigestAlgorithm.SHA512, dataToSign, expectedSignatureinHexWithSha512);
}
@Test
public void selectPrivateKeyAndSignHash() throws Exception {
PKCS11SignatureToken token = (PKCS11SignatureToken) signatureToken;
List<DSSPrivateKeyEntry> privateKeyEntries = token.getPrivateKeyEntries();
DSSPrivateKeyEntry keyEntry = privateKeyEntries.get(0);
token.usePrivateKeyEntry(keyEntry);
signHashAndAssertSignature(token, DigestAlgorithm.SHA256, dataToSign, expectedSignatureinHex);
}
@Test
public void selectCertificateWithPasswordCallback() throws Exception {
PasswordInputCallback passwordCallback = new PrefilledPasswordCallback("22975".toCharArray());
PKCS11SignatureToken signatureToken = new PKCS11SignatureToken("/usr/local/lib/opensc-pkcs11.so", passwordCallback, 2);
List<DSSPrivateKeyEntry> privateKeyEntries = signatureToken.getPrivateKeyEntries();
assertNotNull(privateKeyEntries);
assertFalse(privateKeyEntries.isEmpty());
signHashAndAssertSignature(signatureToken, DigestAlgorithm.SHA256, dataToSign, expectedSignatureinHex);
}
private Container createSignedContainer(String containerType, DigestAlgorithm digestAlgorithm) {
Container container = ContainerBuilder.
aContainer(containerType).
withDataFile("testFiles/test.txt", "text/plain").
build();
Signature signature = SignatureBuilder.
aSignature(container).
withSignatureToken(signatureToken).
withSignatureDigestAlgorithm(digestAlgorithm).
invokeSigning();
container.addSignature(signature);
return container;
}
private void signHashAndAssertSignature(DigestAlgorithm digestAlgorithm, byte[] dataToSign, String expectedSignatureinHex) {
signHashAndAssertSignature(signatureToken, digestAlgorithm, dataToSign, expectedSignatureinHex);
}
private void signHashAndAssertSignature(SignatureToken signatureToken, DigestAlgorithm digestAlgorithm, byte[] dataToSign, String expectedSignatureinHex) {
byte[] signatureValue = signatureToken.sign(digestAlgorithm, dataToSign);
assertNotNull(signatureValue);
String signatureInHex = DatatypeConverter.printHexBinary(signatureValue);
assertEquals(expectedSignatureinHex, signatureInHex);
}
}