如何检查pdf的签名
首先这里有一个已经签名的pdf文件,通过pdf软件可以看到文件的数字签名。
下面就是如何代码检查这里pdf文件的签名
1.引入依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/com.itextpdf/itextpdf -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.3</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>
- 编写检查签名的方法
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.security.PdfPKCS7;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.Principal;
import java.security.Provider;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.List;
/**
* pdf文件签名检查
*/
public class PdfDigitalSignatureCheck {
private static final Logger LOGGER = LoggerFactory.getLogger(PdfDigitalSignatureCheck.class);
public static final boolean verifySignature(PdfReader pdfReader)
throws GeneralSecurityException, IOException {
boolean valid = false;
AcroFields acroFields = pdfReader.getAcroFields();
List<String> signatureNames = acroFields.getSignatureNames();
if (!signatureNames.isEmpty()) {
for (String name : signatureNames) {
if (acroFields.signatureCoversWholeDocument(name)) {
//设定签名提供者
Provider provider=Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
if(provider==null){
provider=new BouncyCastleProvider();
Security.addProvider(provider);
}
PdfPKCS7 pkcs7 = acroFields.verifySignature(name);
valid = pkcs7.verify();
String reason = pkcs7.getReason();
Calendar signedAt = pkcs7.getSignDate();
X509Certificate signingCertificate = pkcs7.getSigningCertificate();
Principal issuerDN = signingCertificate.getIssuerDN();
Principal subjectDN = signingCertificate.getSubjectDN();
LOGGER.info("valid = {}, date = {}, reason = '{}', issuer = '{}', subject = '{}'",
valid, signedAt.getTime(), reason, issuerDN, subjectDN);
break;
}
}
}
return valid;
}
/**
* 验证签名
*
* @param name
* @return
* @throws IOException
* @throws GeneralSecurityException
*/
public static boolean validate(String name)
throws IOException, GeneralSecurityException {
PdfReader reader = new PdfReader(name);
boolean isSign = verifySignature(reader);
return isSign;
}
}
- 编写测试用例,并执行,可以看到数字证书相关信息。
如果有多个签名,则会显示多个签名
@Test
void pdfDigitalSignatureCheck() throws IOException, GeneralSecurityException {
System.out.println("-----------数字签名检查------------");
String[] files = {"D:\\test3\\test1_sign.pdf", "D:\\test3\\test1.pdf"};
for (String file : files) {
boolean validate = PdfDigitalSignatureCheck.validate(file);
log.info("{} 是否签名:{}", file, validate);
}
}
遇到的问题
签名设定
如果你的签入使用的BouncyCastleProvider,那么你的签名检查也应该使用BouncyCastleProvider,否则可能会报错。