2017-09-20 16 views
0

Je suis en train de signer un pdf avec horodatage et LTV activé de sorte qu'il est montré comme celui-ci dans Adobe Reader:Comment signer un PDF avec horodatage intégré et LTV activé?

Correct signing

En anglais, cela signifie que « la signature inclut un horodatage intégré » et « la la signature est activée par LTV ". Voici le code que je utilise:

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); 

Basé sur this answer, je besoin d'un moyen d'obtenir LCR pour le certificat TSA au CrlList, mais .. comment puis-je obtenir le certificat TSA? Dois-je faire une demande timestamp-query à la TSA et lire la réponse, puis l'ajouter à CrlList? Notez que cela est déjà fait dans MakeSignature.signDetached lorsqu'il appelle sgn.getEncodedPKCS7. Notez que j'utilise un serveur TSA gratuit.

C'est ce qui est montré dans Adobe Reader avec le code ci-dessus. détails Signature: enter image description here

détails Timestamp: enter image description here

TSA Détails du certificat: enter image description here


MISE À JOUR

Comme il était un serveur TSA gratuit, je viens d'avoir ajouter le certificat de serveur TSA dans les certificats approuvés par Adobe et maintenant cela fonctionne. Mais, je l'ai fait un autre test à l'aide d'une carte à puce pour signer un document et voici ce que je suis arrivé (je l'ai ajouté le cert racine aux certificats de confiance dans Adobe):

détails Signature:

enter image description here

détails du certificat de signature:

enter image description here

Basé sur this link, LTV a permis signifie que toutes les informations nécessaires à valider le fichier (moins certs racine) est contenu dans le PDF. Ainsi, le PDF est activé LTV s'il est signé correctement et contient tous les certificats nécessaires et une réponse CRL ou OSCP valide pour chaque certificat, et s'il inclut des signatures sur les listes CRL et OCSP, pas seulement le certificat de signature. On dirait que j'ai toutes ces exigences ou est-ce qu'il me manque quelque chose? Si oui, comment puis-je savoir ce qui manque pour obtenir un pdf compatible LTV?

+1

* "Notez que j'utilise un serveur TSA gratuit." * - avez-vous vérifié si Adobe approuve ce serveur gratuit? – mkl

+0

Ajout à la liste des certificats de confiance dans Adobe travaillé. Mais .. est-il possible de le faire via le code? – lucasdc

+1

* "Y at-il un moyen de le faire via le code?" * - Il ne devrait pas y avoir. C'est à propos de qui l'utilisateur fait confiance. Par défaut, l'utilisateur délègue la maintenance des ancrages de confiance principalement à Adobe. Ainsi, seul l'utilisateur (en éditant les paramètres de sécurité) et Adobe (en fournissant des mises à jour de sécurité) devrait pouvoir modifier ces paramètres. – mkl

Répondre

1

En premier lieu, basé sur le commentaire @mkl, j'ai ajouté le certificat de serveur TSA aux Adobe certificats de confiance pour que le message

la signature inclut un horodatage intégré, mais il ne pouvait pas être vérifiée

est devenu

la signature inclut un horodatage intégré

Et pour résoudre

Signature n'est pas LTV activé et expirera après (...)

je pourrais noter que l'utilisation

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

il y avait une LCR (certains des certificats avaient plus d'un point de distribution) n'étant pas ajoutés - rendant le pdf LTV non activé. Pour le résoudre, j'ai fait ce chemin:

// 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; 
}