代码之家  ›  专栏  ›  技术社区  ›  lucasdc

如何签署嵌入时间戳并启用LTV的PDF?

  •  4
  • lucasdc  · 技术社区  · 7 年前

    Correct signing

    在英语中,它表示“签名包括嵌入的时间戳”和“签名启用LTV”。以下是我使用的代码:

    PrivateKey pk = // get pk from an encrypting certificate created using encrypting file system
    Certificate[] chain = ks.getCertificateChain(alias);
    
    PdfReader reader = new PdfReader(src);
    FileOutputStream fout = new FileOutputStream(dest);
    PdfStamper stp = PdfStamper.createSignature(reader, fout, '\0');
    
    PdfSignatureAppearance sap = stp.getSignatureAppearance();
    
    ExternalSignature signature = new PrivateKeySignature(pk, "SHA-512", "SunMSCAPI");
    TSAClient tsc = null;
    String url = // TSA URL
    tsc = new TSAClientBouncyCastle(url, null, null, 4096, "SHA-512");
    
    List<CrlClient> crlList = new ArrayList<>();
    crlList.add(new CrlClientOnline(chain));
    
    ExternalDigest digest = new BouncyCastleDigest();
    MakeSignature.signDetached(sap, digest, signature, chain, crlList, null, tsc, 0, CryptoStandard.CMS);
    

    基于 this answer ,我需要一种方法将TSA证书的CRL获取到 CrlList 但是我如何获得TSA证书?我需要做一个 timestamp-query 请求TSA并读取响应,然后将其添加到 CrlList公司 MakeSignature.signDetached 当它呼叫时 sgn.getEncodedPKCS7 . 注意,我使用的是免费的TSA服务器。

    enter image description here

    时间戳详细信息: enter image description here

    enter image description here


    更新

    由于它是一个免费的TSA服务器,我只需要在Adobe Trusted Certificates中添加TSA服务器证书,现在它可以工作了。

    签名详细信息:

    enter image description here

    enter image description here

    基于 this link 启用LTV意味着验证文件所需的所有信息(减去根证书)都包含在PDF中。因此,如果PDF签名正确,并且包含所有必要的证书和每个证书的有效CRL或OSCP响应,并且如果它包括CRL和OCSP上的签名,而不仅仅是签名证书,则PDF启用LTV。看起来我满足了所有这些要求,还是我遗漏了什么?如果是这样,我怎么知道缺少什么来获得支持LTV的pdf?

    1 回复  |  直到 7 年前
        1
  •  1
  •   lucasdc    7 年前

    首先,基于@mkl注释,我将TSA服务器证书添加到Adobe Trusted Certificates中,以便消息

    已证实的

    签名包括嵌入的时间戳

    签名未启用LTV,将在(…)后过期

    我注意到使用

    List<CrlClient> crlList = new ArrayList<>();
    crlList.add(new CrlClientOnline(chain));
    

    // long term validation (LTV)
    List<CrlClient> crlList = new ArrayList<>();
    
    for(Certificate cert : chain) {
        X509Certificate c = (X509Certificate)cert;
        List<String> crls = this.getCrlDistributionPoints(c);
        if(crls != null && !crls.isEmpty()) {
            crlList.add(new CrlClientOnline(crls.toArray(new String[crls.size()])));
        }
    }
    
    private List<String> getCrlDistributionPoints(final X509Certificate cert) throws Exception {
        final byte[] crldpExt = cert.getExtensionValue(X509Extension.cRLDistributionPoints.getId());
        if (crldpExt == null) {
            final List<String> emptyList = new ArrayList<String>();
            return emptyList;
        }
        ASN1InputStream oAsnInStream = null;
        ASN1InputStream oAsnInStream2 = null;
        List<String> crlUrls = new ArrayList<String>();
    
        try { 
            oAsnInStream = new ASN1InputStream(new ByteArrayInputStream(crldpExt));
            final ASN1Object derObjCrlDP = oAsnInStream.readObject();
            final DEROctetString dosCrlDP = (DEROctetString) derObjCrlDP;
            final byte[] crldpExtOctets = dosCrlDP.getOctets();
            oAsnInStream2 = new ASN1InputStream(new ByteArrayInputStream(crldpExtOctets));
            final ASN1Object derObj2 = oAsnInStream2.readObject();
            final CRLDistPoint distPoint = CRLDistPoint.getInstance(derObj2);
            for (final DistributionPoint dp : distPoint.getDistributionPoints()) {
                final DistributionPointName dpn = dp.getDistributionPoint();
                // Look for URIs in fullName
                if (dpn != null) {
                    if (dpn.getType() == DistributionPointName.FULL_NAME) {
                        final GeneralName[] genNames = GeneralNames.getInstance(dpn.getName()).getNames();
                        // Look for an URI
                        for (int j = 0; j < genNames.length; j++) {
                            if (genNames[j].getTagNo() == GeneralName.uniformResourceIdentifier) {
                                final String url = DERIA5String.getInstance(genNames[j].getName()).getString();
                                crlUrls.add(url);
                            }
                        }
                    }
                }
            }
        } catch(IOException e) {
            throw new Exception(e.getMessage(), e);
        } finally {
            IOUtils.closeQuietly(oAsnInStream);
            IOUtils.closeQuietly(oAsnInStream2);
        }
    
        return crlUrls;
    }