java - PDFbox 异常 - 线程 "main"java.lang.VerifyError 中出现异常

标签 java apache bouncycastle pdfbox jce

我正在尝试运行 pdfbox 示例中的示例代码,但代码最终创建了带签名的 PDF,但有以下异常(exception)情况,并且当我在 Adob​​e PDF 中打开它时无法验证签名,有什么帮助吗?

线程“main”中的异常 java.lang.VerifyError: (类: org/bouncycaSTLe/cms/CMSSignedGenerator, 方法: getAttributeSet 签名: (Lorg/bouncycaSTLe/asn1/cms/AttributeTable;)Lorg/bouncycaSTLe/asn1/ASN1Set ;) 函数参数不兼容 在 org.apache.pdfbox.examples.signature.CreateVisibleSignature.sign(CreateVisibleSignature.java:218) 在 org.apache.pdfbox.pdfwriter.COSWriter.doWriteSignature(COSWriter.java:784) 在 org.apache.pdfbox.pdfwriter.COSWriter.visitFromDocument (COSWriter.java:1171) 在 org.apache.pdfbox.cos.COSDocument.accept(COSDocument.java:568) 在 org.apache.pdfbox.pdfwriter.COSWriter.write(COSWriter.java:1517) 在org.apache.pdfbox.pdmodel.PDDocument.saveIncremental(PDDocument.java:1391) 在 org.apache.pdfbox.examples.signature.CreateVisibleSignature.signPDF(CreateVisibleSignature.java:193) 在 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>");
    }
}

最佳答案

使用 Bouncy CaSTLe 库的 1.44 版本,如下所述: https://pdfbox.apache.org/dependencies.html

Bouncy CaSTLe 库通常不向后兼容,这就是原因。

关于java - PDFbox 异常 - 线程 "main"java.lang.VerifyError 中出现异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27472708/

相关文章:

apache - 虚拟主机重定向不存在的子域并删除 www

mysql - 如何解决 Linode 上奇怪的 CPU 峰值问题

Windows 上的 PHP 5.6 和 Apache, block 分解并将输出发送到其他请求

java - PBKDF2-HMAC-SHA256 for JAVA 的可靠实现

java - 如何创建 Maven 可分发

java - play框架中的公共(public)缓冲区

java - 如何导出IntelliJ IDEA项目以便在没有IntelliJ IDEA的另一台机器上编译

java - 死锁情况

java - 不支持的 SignatureMethod 算法,但该算法被 BC-Provider 列为可用服务

c# - 在 C# 中的 BouncyCaSTLe 内存中 PGP 加密