Trying to sign pdf with a smart card

2019-08-04 14:24发布

问题:

I am trying to sign pdf with a smart card. I use the following code:

public class SC {
    public static final String SRC = "src/test.pdf";
    public static final String DEST = "src/test_smartCard.pdf";

    public void sign(String src, String dest,
            Certificate[] chain, PrivateKey pk,
            String digestAlgorithm, String provider, CryptoStandard subfilter,
            String reason, String location,
            Collection<CrlClient> crlList,
            OcspClient ocspClient,
            TSAClient tsaClient,
            int estimatedSize)
                    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(new Rectangle(36, 748, 144, 780), 1, "sig");
        // Creating the signature
        ExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
        ExternalDigest digest = new BouncyCastleDigest();
        MakeSignature.signDetached(appearance, digest, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
    }

    public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException {
        LoggerFactory.getInstance().setLogger(new SysoLogger());

        BouncyCastleProvider providerBC = new BouncyCastleProvider();
        Security.addProvider(providerBC);
        SunMSCAPI providerMSCAPI = new SunMSCAPI();
        Security.addProvider(providerMSCAPI);
        KeyStore ks = KeyStore.getInstance("Windows-MY");
        ks.load(null, null);
        String alias = (String)ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey)ks.getKey(alias, null);
        Certificate[] chain = ks.getCertificateChain(alias);
        //OcspClient ocspClient = new OcspClientBouncyCastle();
        TSAClient tsaClient = null;

        for (int i = 0; i < chain.length; i++) {
            X509Certificate cert = (X509Certificate)chain[i];
            String tsaUrl = CertificateUtil.getTSAURL(cert);
            if (tsaUrl != null) {
                tsaClient = new TSAClientBouncyCastle(tsaUrl);
                break;
            }
        }

        List<CrlClient> crlList = new ArrayList<CrlClient>();
        crlList.add(new CrlClientOnline(chain));
        SC app = new SC();
        app.sign(SRC, DEST, chain, pk, DigestAlgorithms.SHA256, providerMSCAPI.getName(), CryptoStandard.CMS, "Test", "London",
                null, null, tsaClient, 0);
    }
}

I get a little confused with this external signing process. I have my card reader installed, my card inserted, as I see it I am using Windows-MY key store..so i can call out certificates on the card from that key store as long as the card is inserted. When I check the certs via internet explorer I can see my certs that I got for free from internet and the ones that are on the card. I can't export the ones from the smart card with a private key, I know that is the whole point of the smart card so the process would be done externally.

My problem lies in that that with the code I wrote I get the document signed with a cert that I have already made and not with the ones from the card, how do I sign it with a cert from the card, one more thing is that I am never asked for my smart card PIN number.

Can anyone help me out, I am trying really hard to tackle this digital signature thing, I know that the next thing is doing it with PKCS11 and dll file but I am not there yet.Thanks

added:

Thanks for the answer Robert. You were right. I enumerated the alises in WINDOWS-MY keystore and I did in fact sign the document with the first alias that was listed and it was my non-smartcard cert/key pair. Obviously that is not what i want to do, how would I go about signing it with different cert/key, in my case with one that belongs to a smart card. Thanks again

回答1:

The certificate/key for signing the PDF is selected by it's alias.

In your code you are using the first available alias:

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

Looks like this alias belongs to the non-smartcard cert/key pair. You should enumerate through the list of available aliases (and the assigned certificates) and see if one belongs to your smartcard certificate. If the smart card is not visible in this list you have to access your smartcard via PKCS#11. Note that PKCS#11 are often 32bit - in this case you also have to use a 32bit JRE.