0

I''m trying to run the sample code from pdfbox examples but the code finishes with creating PDF with signature with exceptions below and not able to verify signature when I open it in Adobe PDF any help?

Exception in thread "main" java.lang.VerifyError: (class: org/bouncycastle/cms/CMSSignedGenerator, method: getAttributeSet signature: (Lorg/bouncycastle/asn1/cms/AttributeTable;)Lorg/bouncycastle/asn1/ASN1Set;) Incompatible argument to function at org.apache.pdfbox.examples.signature.CreateVisibleSignature.sign(CreateVisibleSignature.java:218) at org.apache.pdfbox.pdfwriter.COSWriter.doWriteSignature(COSWriter.java:784) at org.apache.pdfbox.pdfwriter.COSWriter.visitFromDocument(COSWriter.java:1171) at org.apache.pdfbox.cos.COSDocument.accept(COSDocument.java:568) at org.apache.pdfbox.pdfwriter.COSWriter.write(COSWriter.java:1517) at org.apache.pdfbox.pdmodel.PDDocument.saveIncremental(PDDocument.java:1391) at org.apache.pdfbox.examples.signature.CreateVisibleSignature.signPDF(CreateVisibleSignature.java:193) at org.apache.pdfbox.examples.signature.CreateVisibleSignature.main(CreateVisibleSignature.java:318)

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.pdfbox.examples.signature;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.List;

import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.exceptions.SignatureException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSigProperties;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSignDesigner;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSSignedGenerator;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

/**
 * <p>
 * This is an example for signing a pdf with bouncy castle.
 * </p>
 * <p>
 * And also you can create visible signature too
 * </p>
 * <p>
 * A keystore can be created with the java keytool (e.g. keytool -genkeypair
 * -storepass 123456 -storetype pkcs12 -alias test -validity 365 -v -keyalg RSA
 * -keystore keystore.p12 )
 * </p>
 * 
 * @author Vakhtang koroghlishvili (Gogebashvili)
 */
public class CreateVisibleSignature implements SignatureInterface {

    private static BouncyCastleProvider provider = new BouncyCastleProvider();

    private PrivateKey privKey;

    private Certificate[] cert;

    private SignatureOptions options;


    // statically add provider, if it is not already there
    private static final boolean firstProvider = true;  
    static {
            if(Security.getProvider("BC") == null) {
                BouncyCastleProvider bcProv = new BouncyCastleProvider();
                if(firstProvider) {
                    Security.insertProviderAt(bcProv, 1);
                } else {
                    Security.addProvider(bcProv);
                }
            }
        }

    /**
     * Initialize the signature creator with a keystore (pkcs12) and pin that
     * should be used for the signature.
     * 
     * @param keystore
     *            is a pkcs12 keystore.
     * @param pin
     *            is the pin for the keystore / private key
     */
    public CreateVisibleSignature(KeyStore keystore, char[] pin) {
        try {
            /*
             * grabs the first alias from the keystore and get the private key.
             * An alternative method or constructor could be used for setting a
             * specific alias that should be used.
             */
            Enumeration<String> aliases = keystore.aliases();
            String alias = null;
            if (aliases.hasMoreElements()) {
                alias = aliases.nextElement();
            } else {
                throw new RuntimeException("Could not find alias");
            }
            privKey = (PrivateKey) keystore.getKey(alias, pin);
            cert = keystore.getCertificateChain(alias);
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            System.err.println("Could not extract private key.");
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            System.err.println("Unknown algorithm.");
            e.printStackTrace();
        }
    }

    /**
     * Signs the given pdf file.
     * 
     * @param document
     *            is the pdf document
     * @param signatureProperties
     * @return the signed pdf document
     * @throws IOException
     * @throws COSVisitorException
     * @throws SignatureException
     */
    public File signPDF(File document,
            PDVisibleSigProperties signatureProperties) throws IOException,
            COSVisitorException, SignatureException {
        byte[] buffer = new byte[8 * 1024];
        if (document == null || !document.exists()) {
            new RuntimeException("Document for signing does not exist");
        }

        // creating output document and prepare the IO streams.
        String name = document.getName();
        String substring = name.substring(0, name.lastIndexOf("."));

        File outputDocument = new File(document.getParent(), substring
                + "_signed.pdf");
        FileInputStream fis = new FileInputStream(document);
        FileOutputStream fos = new FileOutputStream(outputDocument);

        int c;
        while ((c = fis.read(buffer)) != -1) {
            fos.write(buffer, 0, c);
        }
        fis.close();
        fis = new FileInputStream(outputDocument);

        // load document
        PDDocument doc = PDDocument.load(document);

        // create signature dictionary
        PDSignature signature = new PDSignature();
        signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE); // default filter
        // subfilter for basic and PAdES Part 2 signatures
        signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
        signature.setName("signer name");
        signature.setLocation("signer location");
        signature.setReason("reason for signature");

        // the signing date, needed for valid signature
        signature.setSignDate(Calendar.getInstance());

        // register signature dictionary and sign interface

        if (signatureProperties != null
                && signatureProperties.isVisualSignEnabled()) {
            options = new SignatureOptions();
            options.setVisualSignature(signatureProperties);
            // options.setPage(signatureProperties.getPage());
            // options.setPreferedSignatureSize(signatureProperties.getPreferredSize());
            doc.addSignature(signature, this, options);
        } else {
            doc.addSignature(signature, this);
        }

        // write incremental (only for signing purpose)
        doc.saveIncremental(fis, fos);

        return outputDocument;
    }

    /**
     * <p>
     * SignatureInterface implementation.
     * </p>
     * <p>
     * This method will be called from inside of the pdfbox and create the pkcs7
     * signature. The given InputStream contains the bytes that are providen by
     * the byte range.
     * </p>
     * <p>
     * This method is for internal use only.
     * </p>
     * <p>
     * Here the user should use his favorite cryptographic library and implement
     * a pkcs7 signature creation.
     * </p>
     */
    public byte[] sign(InputStream content) throws SignatureException,
            IOException {
        CMSProcessableInputStream input = new CMSProcessableInputStream(content);
        CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
        // CertificateChain
        List<Certificate> certList = Arrays.asList(cert);

        CertStore certStore = null;
        try {
            certStore = CertStore.getInstance("Collection",
                    new CollectionCertStoreParameters(certList), provider);
            gen.addSigner(privKey, (X509Certificate) certList.get(0),
                    CMSSignedGenerator.DIGEST_SHA256);
            gen.addCertificatesAndCRLs(certStore);
            CMSSignedData signedData = gen.generate(input, false, provider);
            return signedData.getEncoded();
        } catch (Exception e) {
            // should be handled
            System.err.println("Error while creating pkcs7 signature.");
            e.printStackTrace();
        }
        throw new RuntimeException("Problem while preparing signature");
    }

    /**
     * Arguments are [0] key store [1] pin [2] document that will be signed [3]
     * image of visible signature
     */


    public static void main(String[] args) throws KeyStoreException,
            NoSuchAlgorithmException, CertificateException,
            FileNotFoundException, IOException, COSVisitorException,
            SignatureException {

        if(Security.getProvider("BC") != null) {
            System.out.printf("Bouncy Castle Added!!!");
        }else{
            System.out.printf("Bouncy Castle Not Found!!!!!!!!");
        }

        File ksFile = new File("keystore.p12");
        KeyStore keystore = KeyStore.getInstance("PKCS12", provider);
        char[] pin = "123456".toCharArray();
        keystore.load(new FileInputStream(ksFile), pin);

        File document = new File("doc.pdf");

        CreateVisibleSignature signing = new CreateVisibleSignature(
                keystore, pin.clone());

        FileInputStream image = new FileInputStream("sign.jpg");

        PDVisibleSignDesigner visibleSig = new PDVisibleSignDesigner(
                "doc.pdf", image, 1);
        visibleSig.xAxis(0).yAxis(0).zoom(-50)
                .signatureFieldName("signature");

        PDVisibleSigProperties signatureProperties = new PDVisibleSigProperties();

        signatureProperties.signerName("name").signerLocation("location")
                .signatureReason("Security").preferredSize(0).page(1)
                .visualSignEnabled(true).setPdVisibleSignature(visibleSig)
                .buildSignature();

        signing.signPDF(document, signatureProperties);

    }

    /**
     * This will print the usage for this program.
     */
    private static void usage() {
        System.err.println("Usage: java " + CreateSignature.class.getName()
                + " <pkcs12-keystore-file> <pin> <input-pdf> <sign-image>");
    }
}
realnumber
  • 2,124
  • 5
  • 25
  • 33
  • Whoa, that's a toolchain problem. Try re-downloading the library to ensure that you don't have a corrupted binary. – chrylis -cautiouslyoptimistic- Dec 14 '14 at 19:17
  • Please include in your question what version you are using. – Tilman Hausherr Dec 14 '14 at 21:58
  • Java Version java version "1.7.0_67" Java(TM) SE Runtime Environment (build 1.7.0_67-b01) Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode) PDFBox Version - 1.8.8, 1.8.7 (tried both) Boncy Castle - bcprov-ext-jdk15on-151.jar, bcprov-jdk15on-151.jar (tried both) – realnumber Dec 14 '14 at 23:48

1 Answers1

1

Use version 1.44 of the Bouncy Castle libs, as mentioned here: https://pdfbox.apache.org/dependencies.html

The Bouncy Castle libs are often not backwards compatible, that is why.

Tilman Hausherr
  • 17,731
  • 7
  • 58
  • 97