I'd like to sign a pdf with itext and a smartcard. If I put the smartcard in the reader, automatically Windows adds two certificates in the store. I read Bruno Lowagie's book and I tried to make a sample adding an image and some other stuff:
public static void main(String[] args)
throws GeneralSecurityException, IOException, DocumentException {
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyStore ks = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
//KeyStore ks = KeyStore.getInstance("PKCS11");
ks.load(null, PASSWORD);
String alias = (String) ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain = ks.getCertificateChain(alias);
sign(SRC, String.format(DEST, 1), chain, pk, DigestAlgorithms.SHA256,
provider.getName(), CryptoStandard.CMS, "Test 1", "Ghent", "signHere");
sign(SRC, String.format(DEST, 2), chain, pk, DigestAlgorithms.SHA512,
provider.getName(), CryptoStandard.CMS, "Test 2", "Ghent", "signHere");
sign(SRC, String.format(DEST, 3), chain, pk, DigestAlgorithms.SHA256,
provider.getName(), CryptoStandard.CADES, "Test 3", "Ghent", "signHere");
sign(SRC, String.format(DEST, 4), chain, pk, DigestAlgorithms.RIPEMD160,
provider.getName(), CryptoStandard.CADES, "Test 4", "Ghent", "signHere");
}
public static void sign(String src, String dest, Certificate[] chain, PrivateKey pk,
String digestAlgorithm, String provider, CryptoStandard subfilter,
String reason, String location, String fieldToSign)
throws GeneralSecurityException, IOException, DocumentException {
// Creating the reader and the stamper
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
// Creating the appearance
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
appearance.setVisibleSignature(fieldToSign);
appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS);
appearance.setImage(Image.getInstance(Params.imgPath));
appearance.setImageScale(-1);
// Creating the signature
ExternalDigest digest = new BouncyCastleDigest();
ExternalSignature signature = new PrivateKeySignature(pk, digestAlgorithm, provider);
MakeSignature.signDetached(appearance, digest, signature, chain, null, null, null, 0, subfilter);
}
but what I get is a java.security.InvalidKeyException: Supplied key (sun.security.mscapi.RSAPrivateKey) is not a RSAPrivateKey instance
Why sun.security.mscapi.RSAPrivateKey is not a RSAPrivateKey instance? What I'm doing wrong here? I have this error both with BouncyCastle jars 1.49 and 1.50
The problem is the provider that you pass when you create the signature:
ExternalSignature signature = new PrivateKeySignature(pk, digestAlgorithm, provider);
The provider must be ks.getProvider().getName() (or "SunMSCAPI") and not BouncyCastleProvider.