maven引入依赖

<dependency>
    <groupId>repository_personal.com.lowagie</groupId>
    <artifactId>itext</artifactId>
    <version>1.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.itextpdf/itextpdf -->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.10</version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.itextpdf/itext-asian -->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext-asian</artifactId>
    <version>5.2.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on -->
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk15on</artifactId>
    <version>1.60</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.60</version>
</dependency>

工具类

//PDF盖章
void ImageStamp(){
    //创建PdfDocument对象,加载PDF测试文档
    PdfDocument doc = new PdfDocument();
    doc.loadFromFile("E://浏览器//test1.pdf");

    //获取文档第3页
    PdfPageBase page = doc.getPages().get(0);

    //加载印章图片
    PdfImage image = PdfImage.fromFile("E://浏览器//qs.png");
    //获取印章图片的宽度和高度
    int width = image.getWidth();
    int height = image.getHeight();

    //创建PdfTemplate对象
    PdfTemplate template = new PdfTemplate(width, height);
    //将图片绘制到模板
    template.getGraphics().drawImage(image, 0, 0, width, height);

    //创建PdfRubebrStampAnnotation对象,指定大小和位置
    Rectangle2D rect = new Rectangle2D.Float((float) (page.getActualSize().getWidth() - width - 10), (float) (page.getActualSize().getHeight() - height - 60), width, height);
    PdfRubberStampAnnotation stamp = new PdfRubberStampAnnotation(rect);

    //创建PdfAppearance对象
    PdfAppearance pdfAppearance = new PdfAppearance(stamp);
    //将模板应用为PdfAppearance的一般状态
    pdfAppearance.setNormal(template);
    //将PdfAppearance 应用为图章的样式
    stamp.setAppearance(pdfAppearance);

    //添加图章到PDF
    page.getAnnotationsWidget().add(stamp);

    //保存文档
    doc.saveToFile("E://浏览器//ImageStamp.pdf",FileFormat.PDF);
}
//PDF签字
@Test
void TextStamp() throws IOException, DocumentException {
    // 要输出的pdf文件
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("E://浏览器//TextStamp.pdf")));
    // 将pdf文件先加水印然后输出

    PdfReader reader = new PdfReader("E://浏览器//ImageStamp.pdf");
    PdfStamper stamper = new PdfStamper(reader, bos);

    // 获取总页数 +1, 下面从1开始遍历
    int total = reader.getNumberOfPages() + 1;
    // 使用classpath下面的字体库
    BaseFont base = null;
    try {
        base = BaseFont.createFont("E://浏览器//方正楷体.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
    } catch (Exception e) {
        // 日志处理
        e.printStackTrace();
    }

    // 设置水印透明度
    PdfGState gs = new PdfGState();
    gs.setFillOpacity(0.4f);
    gs.setStrokeOpacity(0.4f);

    PdfContentByte content = null;
    for (int i = 1; i < total; i++) {
        // 在内容上方加水印
        content = stamper.getOverContent(i);
        // 在内容下方加水印
        // content = stamper.getUnderContent(i);
        content.saveState();
        content.setGState(gs);

        // 设置字体和字体大小
        content.beginText();
        content.setFontAndSize(base, 10);

        // 设置字体样式
        float ta = 1F, tb = 0F, tc = 0F, td = 1F, tx = 0F, ty = 0F;
        // 设置加粗(加粗)
        ta += 0.25F;
        td += 0.05F;
        ty -= 0.2F;
        // 设置倾斜(倾斜程序自己改)
        tc += 0.8F;
        content.setTextMatrix(ta, tb, tc, td, tx, ty);

        // 设置相对于左下角位置(向右为x,向上为y)
        content.moveText(300F, 50F);
        // 显示text
        content.showText("青莳");

        content.endText();
        content.stroke();
        content.restoreState();
    }

    // 关流
    stamper.close();
    reader.close();
}

//CA签名认证工具类
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.security.*;

import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.security.cert.Certificate;

public class KeystoreUtils {

    /**
     *
     * @param src 需要签章的pdf文件路径
     * @param dest 签完章的pdf文件路径
     * @param chain 证书链
     * @param img 印章图片
     * @param pk 签名私钥
     * @param digestAlgorithm 摘要算法名称,例如SHA-1
     * @param provider  密钥算法提供者,可以为null
     * @param subfilter 数字签名格式,itext有2种
     * @param reason 签名的原因,显示在pdf签名属性中
     * @param location 签名的地点,显示在pdf签名属性中
     * @throws GeneralSecurityException
     * @throws IOException
     * @throws DocumentException
     */
    public void sign(String src, String dest,String img, Certificate[] chain, PrivateKey pk, String digestAlgorithm, String provider,
                     MakeSignature.CryptoStandard subfilter, String reason, String location) throws GeneralSecurityException, IOException, DocumentException {

        PdfReader pdfReader = new PdfReader(src);
        FileOutputStream fileOutputStream = new FileOutputStream(dest);

        /**
         * 1 参数依次为:文件名、文件输入流、文件版本号、临时文件、是否可以追加签名
         *  1.1 false的话,pdf文件只允许被签名一次,多次签名,最后一次有效
         *  1.2 true的话,pdf可以被追加签名,验签工具可以识别出每次签名之后文档是否被修改
         */
        PdfStamper stamper = PdfStamper.createSignature(pdfReader, fileOutputStream, '\0', null, false);
        // 获取数字签章属性对象,设定数字签章的属性
        PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
        appearance.setReason(reason);
        appearance.setLocation(location);
        /**
         * 签名的大小以及位置
         * 1 三个参数依次为:设置签名的位置、页码、签名域名称,多次追加签名的时候,签名域名称不能一样
         *  1.1 签名的位置四个参数:印章左下角的X、Y轴坐标,印章右上角的X、Y轴坐标,
         *        这个位置是相对于PDF页面的位置坐标,即该坐标距PDF当前页左下角的坐标
         */
        appearance.setVisibleSignature(new Rectangle(100, 100, 200, 200), 1, "sign");

        /**
         * 用于盖章的印章图片,引包的时候要引入itext包的image
         */
        Image image = Image.getInstance(img);
        appearance.setSignatureGraphic(image);

        /**
         * 设置认证等级,共4种,分别为:
         *  NOT_CERTIFIED、CERTIFIED_NO_CHANGES_ALLOWED、
         *  CERTIFIED_FORM_FILLING 和 CERTIFIED_FORM_FILLING_AND_ANNOTATIONS
         *
         * 需要用哪一种根据业务流程自行选择
         */
        appearance.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);

        /**
         * 印章的渲染方式,同样有4种:
         *  DESCRIPTION、NAME_AND_DESCRIPTION,
         *  GRAPHIC_AND_DESCRIPTION,GRAPHIC;
         * 这里选择只显示印章
         */
        appearance.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);

        /**
         * 算法主要为:RSA、DSA、ECDSA
         * 摘要算法,这里的itext提供了2个用于签名的接口,可以自己实现
         */
        ExternalDigest digest = new BouncyCastleDigest();
        /**
         * 签名算法,参数依次为:证书秘钥、摘要算法名称,例如MD5 | SHA-1 | SHA-2.... 以及 提供者
         */
        ExternalSignature signature = new PrivateKeySignature(pk, digestAlgorithm, null);
        /**
         * 最重要的来了,调用itext签名方法完成pdf签章
         */
        MakeSignature.signDetached(appearance, digest, signature, chain, null, null, null, 0, subfilter);
    }
}

//测试CA签名认证
@Test
void KeystoreTest(){
    String KEYSTORE = "E:\\浏览器\\android.keystore";
    // 之前生成的keystory密码
    char[] PASSWORD = "123456".toCharArray();
    // 需要签名的PDF路径
    String SRC = "E://浏览器//test1.pdf";
    // 完成签名的PDF路径
    String OUTPUT_SRC = "E://浏览器//ImageStamp.pdf";
    String IMG = "E://浏览器//qs.png";
    try {
        //读取keystore ,获得私钥和证书链
        KeyStore keyStore = KeyStore.getInstance("JKS");
        keyStore.load(new FileInputStream(KEYSTORE), PASSWORD);
        String alias = (String)keyStore.aliases().nextElement();
        PrivateKey PrivateKey = (PrivateKey) keyStore.getKey(alias, PASSWORD);
        Certificate[] chain = keyStore.getCertificateChain(alias);

        KeystoreUtils keystoreUtils = new KeystoreUtils();
        keystoreUtils.sign(SRC, String.format(OUTPUT_SRC, 3),IMG, chain, PrivateKey, DigestAlgorithms.SHA1, null, MakeSignature.CryptoStandard.CMS, "Test", "Ghent");
    } catch (Exception e) {
        JOptionPane.showMessageDialog(null, e.getMessage());
        e.printStackTrace();
    }
}