2016-11-21 3 views
1

Je suis en train d'écrire une preuve de concept pour ajouter des signatures électroniques à des fichiers PDF existants. Je rencontre un problème étrange que je n'obtiens pas. Il semble que l'ajout de la signature à certains documents fonctionne correctement, alors que l'ajout d'une signature à d'autres ne fonctionne pas et qu'un fichier corrompu est généré et que Adobe Reader ne peut pas ouvrir.La signature d'un document PDF existant provoque parfois un fichier corrompu

Voici mon code:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using iText; 
using iText.Kernel.Pdf; 
using System.IO; 
using iText.Layout; 
using iText.Layout.Element; 
using iText.Kernel.Geom; 
using Org.BouncyCastle.Crypto.Tls; 
using iText.Signatures; 
using System.Collections.ObjectModel; 
using Org.BouncyCastle.Pkcs; 
using System.Security.Cryptography.X509Certificates; 
using Org.BouncyCastle.Crypto; 
using System.Security.Cryptography; 
using Org.BouncyCastle.Crypto.Parameters; 
using Org.BouncyCastle.Math; 
using iText.IO.Image; 

namespace LTVSkilrikjaDemo 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string welcomeText = "Welcome to LTVSkilríkjaDemotolid!"; 
      string pressEnterToTry = "Commands: 's' - sign, 'stop' - stops the programme"; 
      Console.WriteLine(welcomeText); 
      Console.WriteLine(pressEnterToTry); 

      // Base directory prepared 
      string basedir = AppDomain.CurrentDomain.BaseDirectory; 
      int index = basedir.IndexOf(@"bin\"); 
      basedir = basedir.Remove(index); 

      string readString = Console.ReadLine().ToLower(); 

      while(!readString.Equals("stop")) 
      { 
       if(readString.Equals("c")) 
       { 
        string inFile = "Infile2.pdf"; 
        string outFile = "Outfile2.pdf"; 

        // Open PDF document and decide where to write the new document 
        PdfWorker worker = new PdfWorker(); 
        worker.ReadPdf(basedir + "App_Data\\InFiles\\" + inFile, basedir + "App_Data\\OutFiles\\" + outFile); 

        // Start working on certificate 
        X509Store store = new X509Store("My"); 

        store.Open(OpenFlags.ReadOnly); 

        Collection<Org.BouncyCastle.X509.X509Certificate> xcertificates = new Collection<Org.BouncyCastle.X509.X509Certificate>(); 

        foreach (X509Certificate2 mCert in store.Certificates) 
        { 
         if (mCert.Subject.IndexOf("CN=Róbert") > -1) 
         { 
          xcertificates.Add(Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(mCert)); 
         } 
        } 

        Org.BouncyCastle.X509.X509Certificate[] certificatesProcessed = new Org.BouncyCastle.X509.X509Certificate[xcertificates.Count]; 
        for(int i = 0; i < xcertificates.Count; i++) 
        { 
         certificatesProcessed[i] = xcertificates[i]; 
        } 

        var pk = Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(store.Certificates[5].PrivateKey).Private; 

        try 
        { 
         worker.Sign(certificatesProcessed, pk, DigestAlgorithms.SHA1, PdfSigner.CryptoStandard.CADES, "No apparent raisin!", "Lost in Iceland", null, null, null, 0, true, basedir); 
        } 
        catch(Exception ex) 
        { 
         Console.ForegroundColor = ConsoleColor.Red; 
         Console.WriteLine("Error! " + ex.Message + "\n\r" + ex.StackTrace); 
         if(ex.InnerException != null) 
         { 
          Console.WriteLine("Inner exception: " + ex.InnerException.Message); 
         } 
         Console.ForegroundColor = ConsoleColor.Gray;      
        } 
       } 
       else if(!readString.Equals("stop")) 
       { 
        Console.WriteLine("Command not understood. Understand only 's' and 'stop'."); 
       } 

       readString = Console.ReadLine(); 
      } 

      Console.WriteLine("Goodbye!"); 
      System.Threading.Thread.Sleep(500); 

     } 
    } 

    public class PdfWorker 
    { 
     private PdfDocument _document; 
     private string _source; 
     private string _dest; 

     public void ReadPdf(string source, string dest) 
     { 
      _source = source; 
      _dest = dest; 
     } 

     public void Sign(Org.BouncyCastle.X509.X509Certificate[] chain, Org.BouncyCastle.Crypto.ICipherParameters pk, 
      string digestAlgorithm, PdfSigner.CryptoStandard subfilter, string reason, 
      string location, Collection<ICrlClient> crlList, IOcspClient ocspClient, ITSAClient tsaClient, 
      int estimatedSize, bool initial, string baseDir) 
     { 
      File.Copy(_source, _dest, true); 
      FileStream f = new FileStream(_dest, FileMode.Append); 
      try 
      { 

       PdfSigner signer = new PdfSigner(new PdfReader(_source), f, true); 
       _document = signer.GetDocument(); 
       _document.AddNewPage(); 

       // Work the last page 
       Rectangle pageSize = _document.GetLastPage().GetPageSizeWithRotation(); 
       //PdfWriter w = _document.GetWriter(); 
       //long currentPos = w.GetCurrentPos(); 
       float llx = pageSize.GetWidth() - 350 - 20; //pageSize.GetWidth()/2 - 350/2; 
       float lly = pageSize.GetHeight() - 50 - 20; // pageSize.GetHeight()/2 - 150/2; 
       float urx = 350; //llx + 350; 
       float ury = 50; //lly + 150; 
       PdfSignatureAppearance appearance = signer.GetSignatureAppearance(); 
       appearance.SetPageRect(new Rectangle(llx, lly, urx, ury)); 
       appearance.SetReason(reason); 
       appearance.SetLocation(location); 

       byte[] imagebytes = File.ReadAllBytes(baseDir + "App_Data\\UndirskriftDemo.png"); 
       // It is not possible to use the path as it contains Icelandic characters 
       // which itext chokes on. We use byte array instead 
       ImageData imgData = ImageDataFactory.Create(imagebytes); 
       Image img = new Image(imgData); 
       img = img.ScaleToFit(350.0f, 50.0f); 
       appearance.SetImage(imgData); 

       int pageCount = _document.GetNumberOfPages(); 

       // Creating the appearance 
       if(initial == true) 
       { 
        signer.SetCertificationLevel(PdfSigner.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS); 
       } 

       appearance.SetPageNumber(pageCount); 
       Rectangle rect = new Rectangle(10, 50, 350, 50); 
       appearance.SetPageRect(rect).SetPageNumber(pageCount); 
       appearance.SetRenderingMode(PdfSignatureAppearance.RenderingMode.NAME_AND_DESCRIPTION); 
       signer.SetFieldName(signer.GetNewSigFieldName()); 

       // Creating the signature 
      IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm); 

       signer.SignDetached(pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter); 

       Console.WriteLine("Signing successful!"); 
      } 
      catch(Exception ex) 
      { 
       throw ex; 
      } 
      finally 
      { 
       _document.Close(); 
       f.Close(); 
      } 
     } 
    } 
} 

S'il vous plaît voir les documents ici, alors. Infile1.pdf Je ne peux pas signer mais Infile2.pdf est signé bien. Outfile1.pdf est le fichier corrompu. https://app.box.com/s/52jqe8qirl80km6hunxucs00dntx70o5

Qu'est-ce qui cause cela? Y at-il quelque chose à propos du fichier PDF d'entrée ou du programme ci-dessus?

Répondre

0

Le problème est dans votre programme, plus exactement dans votre méthode PdfWorker.Sign:

File.Copy(_source, _dest, true); 
FileStream f = new FileStream(_dest, FileMode.Append); 
try 
{ 
    PdfSigner signer = new PdfSigner(new PdfReader(_source), f, true); 
    ... 

Vous copiez d'abord le fichier à signer à la destination, puis ajouter à la sortie il PdfSigner.

Mais cette sortie PdfSigner est le complet signé, c'est-à-dire la source plus une révision supplémentaire dans laquelle la signature est ajoutée. Ainsi, dans le fichier de destination, vous avez finalement deux copies de la source, puis quelques ajouts de signature générés sous l'hypothèse qu'une seule copie de la source précède. Pour résoudre ce problème, supprimez simplement l'opération File.Copy(_source, _dest, true) et n'ouvrez pas FileStream avec FileMode.Append.


Même après cette correction, la signature du fichier exemple de l'OP de « Infile1.PDF » crée encore un PDF cassé lors de la signature du fichier exemple « Infile2.pdf » maintenant réussit. La cause en est le bogue d'iText 7.0.0 expliqué en this answer qui (pour autant que je puisse le voir) est corrigé dans 7.0.1. Comme "Infile1.PDF" utilise des flux d'objets alors que "Infile2.pdf" ne le fait pas, seul l'ancien fichier est affecté.

+0

J'ai essayé de commenter la ligne avec File.Copy (...) mais j'ai toujours la même erreur lorsque j'essaie d'ouvrir le fichier de sortie. La raison pour laquelle j'ai copié le fichier est que j'ai pensé que le fichier d'origine serait modifié, ce que je ne voulais pas. De plus, je ne voulais pas créer de fichier temporaire et finalement le document final, tel qu'il semble, est fait dans un exemple que j'ai rencontré. – rbadi76

+0

* mais j'obtiens toujours la même erreur lorsque j'essaie d'ouvrir le fichier de sortie. * - Veuillez partager ce fichier aussi. Il peut afficher la même erreur mais pour une raison différente. – mkl

+0

@ rbadi76 ah, une chose supplémentaire, n'ouvrez pas le 'FileStream' avec' FileMode.Append': vous ne voulez pas ajouter la sortie 'PdfSigner' à n'importe quoi, pas plus à une ancienne sortie de test par hasard encore là ... – mkl