2
votes

I trying create a signature in pdf using iText for JAVA and Portuguese Citizen Card (Smart Card). But when code execute MakeSignature class i receive always an error saying:

java.security.InvalidKeyException: Supplied key (sun.security.pkcs11.P11Key$P11PrivateKey) is not a RSAPrivateKey instance

I need some help here, can anyone help me?

 try {
        String pkcs11Config = "name=GemPC" + "\n" + "library=C:/WINDOWS/system32/pteidpkcs11.dll";
        ByteArrayInputStream configStream = new ByteArrayInputStream(pkcs11Config.getBytes());
        Provider pkcs11Provider = new sun.security.pkcs11.SunPKCS11(configStream);

        Security.addProvider(pkcs11Provider);
        CallbackHandler cmdLineHdlr = new DialogCallbackHandler();

        KeyStore.Builder builder = KeyStore.Builder.newInstance("PKCS11", pkcs11Provider,
                new KeyStore.CallbackHandlerProtection(cmdLineHdlr));

        KeyStore ks = builder.getKeyStore();

        PdfReader pdf = new PdfReader(filePath);
        FileOutputStream fos = new FileOutputStream(dest);
        PdfStamper stp = PdfStamper.createSignature(pdf, fos, '\0');
        PdfSignatureAppearance sap = stp.getSignatureAppearance();
        sap.setReason("I'm the author");

        String alias = (String) ks.aliases().nextElement();

        PrivateKey pk = (PrivateKey) ks.getKey("CITIZEN SIGNATURE CERTIFICATE", null);
        Certificate chain = ks.getCertificate(alias);

        X509Certificate x509 = (X509Certificate) chain;
        x509.checkValidity();

        ExternalSignature es = new PrivateKeySignature(pk, "SHA-1", "BC");
        ExternalDigest digest = new BouncyCastleDigest();
        Certificate[] certs = new Certificate[1];
        certs[0] = chain;

        MakeSignature.signDetached(sap, digest, es, certs, null, null, null, 0, CryptoStandard.CMS);
        return dest;
    } catch (CertificateExpiredException | CertificateNotYetValidException ex) {
        Logger.getLogger(Signer.class.getName()).log(Level.SEVERE, null, ex);
        return null;
    }
1
All the samples i see to implement this feature using Portuguese Citizen Card is made with null password. And this work with iText 5.2 but not work in iText5.5 because API changes. I tested with SHA1 hash algoritm because all samples use it.pedrofernandes
You're correct, I answered too quickly. The password is entered at a later stage with PKCS#11.Bruno Lowagie
SHA1 is the standard for Portuguese Citizen Card. It uses a SHA1 RSA encryption. I confirmed.pedrofernandes
It works with the Belgian card and I don't have a Portuguese card to test with, so I can't reproduce the problem. If I can't reproduce the problem, I can't help you. You'll have to ask somebody in Portugal to find out which encryption algorithm is supported by the smart card. According to the error message that is thrown by Java (not by iText), it's not an RSA key.Bruno Lowagie

1 Answers

4
votes

If you have your private key in a smartcard (PKCS11) you cannot wrapp this key in a java.security.interfaces.RSAPrivateKey because your key material is in a secure device.

So probably you must change the provider in your code:

 ExternalSignature es = new PrivateKeySignature(pk, "SHA-1", "BC");

for:

 ExternalSignature es = new PrivateKeySignature(pk, "SHA-1", pkcs11Provider.getName());

Hope this helps,