如何使用PDFBox获取数字签名中时间戳令牌的证书信息
使用PDFBox获取PDF签名时间戳令牌的证书信息
核心步骤说明
要提取PDF签名中嵌入的时间戳令牌证书信息,需通过PDFBox解析签名属性,再借助BouncyCastle解析CMS格式的时间戳令牌,具体流程如下:
加载PDF并获取签名列表
用PDDocument加载目标PDF文件,通过getSignatureDictionaries()方法获取文档中所有签名对象。定位时间戳令牌属性
签名的扩展属性存储在Prop_Build字典的Prop子字典中,时间戳令牌对应的PKCS#9属性OID为1.2.840.113549.1.9.16.2.14,通过该OID可提取时间戳的字节流数据。解析CMS格式时间戳令牌
时间戳令牌采用CMS(密码消息语法)格式,需用BouncyCastle的CMSSignedData类解析,从中提取证书存储和签名者信息,最终匹配出时间戳对应的证书。
完整代码示例
import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.cms.SignerInformation; import org.bouncycastle.cms.SignerInformationStore; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.util.Store; import java.io.ByteArrayInputStream; import java.io.File; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Collection; import java.util.List; public class TimestampCertExtractor { public static void main(String[] args) throws Exception { // 加载目标PDF文档 try (PDDocument document = PDDocument.load(new File("signed_document.pdf"))) { List<PDSignature> signatures = document.getSignatureDictionaries(); // 遍历每个签名 for (PDSignature signature : signatures) { COSDictionary sigPropDict = (COSDictionary) signature.getCOSObject().getDictionaryObject("Prop_Build"); if (sigPropDict == null) continue; COSDictionary propDict = (COSDictionary) sigPropDict.getDictionaryObject("Prop"); if (propDict == null) continue; // 根据OID获取时间戳令牌字节流 COSBase tsTokenBase = propDict.getDictionaryObject(new COSName("1.2.840.113549.1.9.16.2.14")); if (!(tsTokenBase instanceof COSString)) continue; byte[] tsTokenBytes = ((COSString) tsTokenBase).getBytes(); CMSSignedData cmsSignedData = new CMSSignedData(tsTokenBytes); // 提取证书存储和签名者信息 Store certStore = cmsSignedData.getCertificates(); SignerInformationStore signerStore = cmsSignedData.getSignerInfos(); Collection<SignerInformation> signers = signerStore.getSigners(); // 匹配并输出证书信息 for (SignerInformation signer : signers) { Collection<X509CertificateHolder> certHolders = certStore.getMatches(signer.getSID()); for (X509CertificateHolder certHolder : certHolders) { X509Certificate cert = (X509Certificate) CertificateFactory.getInstance("X.509") .generateCertificate(new ByteArrayInputStream(certHolder.getEncoded())); // 输出证书关键信息 System.out.println("=== 时间戳证书信息 ==="); System.out.println("颁发者DN: " + cert.getIssuerDN()); System.out.println("主体DN: " + cert.getSubjectDN()); System.out.println("序列号: " + cert.getSerialNumber()); System.out.println("有效期起始: " + cert.getNotBefore()); System.out.println("有效期截止: " + cert.getNotAfter()); } } } } } }
依赖说明
需引入以下依赖(以Maven为例):
<dependencies> <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>2.0.32</version> <!-- 建议使用最新稳定版 --> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> <version>1.70</version> </dependency> </dependencies>
内容的提问来源于stack exchange,提问作者Tanmay Sharma
相关产品推荐
相关产品推荐

