【问题标题】:Verify if a PDF is digitally signed with iText验证 PDF 是否使用 iText 进行数字签名
【发布时间】:2013-07-01 01:04:36
【问题描述】:

正如标题所说,我想知道给定的 PDF 文件是否已经过数字签名。

我使用 iText 对其进行了签名,但我无法知道它是否已经签名以最终退出或执行其他操作。

有没有办法简单地做到这一点(可能使用 iText)?

【问题讨论】:

    标签: java pdf itext digital-signature


    【解决方案1】:

    使用 iText:

    PdfReader reader = new PdfReader(...);
    AcroFields acroFields = reader.getAcroFields();
    List<String> signatureNames = acroFields.getSignatureNames();
    

    现在signatureNames 包含所有包含签名的可达签名字段的名称,参见。 JavaDoc:

    /**
     * Gets the field names that have signatures and are signed.
     *
     * @return the field names that have signatures and are signed
     */
    public ArrayList<String> getSignatureNames()
    

    【讨论】:

      【解决方案2】:

      这里有一个例子

          public static final String verifSign(PdfReader pdfReader)
      {
          KeyStore kall = PdfPKCS7.loadCacertsKeyStore();
          AcroFields acroFields = pdfReader.getAcroFields();
          List<String> signatureNames = acroFields.getSignatureNames();
          if (signatureNames.isEmpty())
          {
              return ("El documento no tiene ni una firma registrada");
          }
          for(String name : signatureNames)
          {
              if (!acroFields.signatureCoversWholeDocument(name))
              {
                  return ("la firma: "+name+" does not covers the whole document.");
              }
              PdfPKCS7 pk = acroFields.verifySignature(name);
              Certificate[] certificates = pk.getCertificates();
              Calendar cal = pk.getSignDate();
              //System.out.println("Document modified: " + !pk.verify());
              Object fails[] = PdfPKCS7.verifyCertificates(certificates, kall, null, cal);
              if (fails == null)
              {
                  // Documento PDF firmado correctamente
              }
              else
              {
                  return ("Firma no válida");
              }
          }
          // Todo firmado correctamente
          return null;
      

      }

      http://www.berthou.com/us/2009/07/01/verify-pdf-signature-with-itext/

      【讨论】:

        【解决方案3】:

        如果您使用较新的 iText 版本,如 5.5.x,这里有一个完整的工作示例,您可以如何检查数字签名的 PDF(自 2.1.7 版以来,iText 已经进行了许多有用的开发和更改):

        import com.itextpdf.text.pdf.AcroFields;
        import com.itextpdf.text.pdf.PdfReader;
        import com.itextpdf.text.pdf.security.PdfPKCS7;
        import java.io.IOException;
        import java.io.InputStream;
        import java.security.GeneralSecurityException;
        import java.security.Principal;
        import java.security.cert.X509Certificate;
        import java.util.Calendar;
        import java.util.List;
        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;
        
        public class DigitalSignatureCheck {
        
            private static final Logger LOGGER = LoggerFactory.getLogger(DigitalSignatureCheck.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)) {
                            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;
            }
        
            private static void validate(String name)
                    throws IOException, GeneralSecurityException {
                InputStream is = DigitalSignatureCheck.class.getClassLoader()
                                 .getResourceAsStream(name);
                PdfReader reader = new PdfReader(is);
                boolean ok = verifySignature(reader);
                LOGGER.info("'{}' is {}signed", name, ok ? "" : "NOT ");
            }
        
            public static void main(String[] args) throws Exception {
                validate("any.pdf"); // if placed in resources' root
            }
        }
        

        使用LOGGER只是为了显示结果。

        【讨论】:

        • 即使okfalse,文档很可能已经签名(只是没有对文档有效的签名),签名只是不涉及嵌入的文档,可能是由于后来的变化。
        • 我的目的是仅举一个最新 iText 库的示例(我目前还有一项任务是探索签名的 PDF 文档)当然你是对的,这就是为什么我包含了一些附加属性作为好吧。您可以检查签名的许多不同方面,您可以做出适合您的决定。这是一个简单的交易,只需返回 verify() 方法的结果并说是或否。
        • 操作者想知道给定的 PDF 文件是否已经过数字签名,而不是现有的签名是否有效等等。因此,虽然很高兴提到可以使用当前的 iText 版本检索大量属性,但这个问题的答案应该在实际问题的上下文中特别有意义。
        • 我不明白,如果附加的签名无效或文档在签名后被更改,如何证明文档是数字签名的。我认为在这两种情况下,我们都不能说文档是经过数字签名的。曾经是,但现在更改后并没有真正签名。这是我的看法。我再次阅读了最初的问题,但我仍然觉得我的理解还不错。我检查了您的个人资料,发现您在 PDF 安全方面的经验比我多,但我觉得我的回答对@lgr 有帮助。我希望。
        • OP 说 “我使用 iText 对其进行签名,但我无法知道它是否已经签名以最终辞职或执行其他操作。” 并询问“有没有办法简单地做到这一点?” 在我看来,这意味着 OP 只对确定文档中是否有数字签名感兴趣,他不想确定其有效性或任何其他属性。
        【解决方案4】:

        我有类似的问题,但我使用的是 itext 7 并且没有

        PdfReader reader = new PdfReader(...);
        AcroFields acroFields = reader.getAcroFields();
        

        在当前版本中。

        所以我使用了这个解决方案[更新]

        private boolean hasSignatures(final PdfDocument pdfDocument) {
            final List<String> signatureNames = new SignatureUtil(pdfDocument).getSignatureNames();
            return !signatureNames.isEmpty();
        }
        

        【讨论】:

        • 请注意,您只是从一个声称有签名的标志字段中测试一个标志,而不检查是否真的有任何签名。如果您使用 iText 7 SignatureUtil,您可以获得一个实际检查填写的签名字段的解决方案,就像这里接受的答案一样。
        • @mkl 谢谢你的评论。我已更改解决方案以使用 SignatureUtil
        猜你喜欢
        • 1970-01-01
        • 2018-03-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多