0

Here is a scenario that I am having a hard time grappling with. We want to make it possible for our vendors to sign PDF documents with LTV signatures so that the documents' validity does not expire. I have read Bruno Lowagie's book iText in Action (2nd edition), his white paper Digital Signatures for PDF documents and looked at the PAdES profile documents (Digital Signatures for PDF documents).

The users sign the documents using their cell phones that have an electronic ID. The program basically sends a hash to a 3rd party service that signs it and sends back to us and we use that signature and place it in the PDF file. That works fine but this signature is only valid for three years or so.

How do we add a DSS and Timestamp to the PDF after we receive and add the signature to make the PDF conform to the PAdES LTV-Profile using iText. I have seen lots of examples for adding signatures and adding timestamps and OSCP information to them, but that is not quite the same.

Here is some code that gives a picture of what we are doing starting with the preSign and postSign methods. This works but where and how do I add code to add DSS and Timestamp information if that is possible at all:

    /// <summary>
    /// Creates signature infrastructure to use in the signing process. Start with calling this method in the signature process.
    /// </summary>
    /// <param name="inStream">Byte stream with the PDF document to be signed</param>
    /// <param name="reason">The reason for the signing</param>
    /// <param name="location">Signing location</param>
    /// <returns>Returns a hash of the signed data</returns>
    public void preSign(byte[] inStream, string reason, string location)
    {
        iTextSharp.text.Document document = new iTextSharp.text.Document();

        // Lesum inn PDF skjalið sem á að undirrita inn í iText reader
        PdfReader reader = new PdfReader(inStream);
        reader.Appendable = true;
        Rectangle pageSize = reader.GetPageSizeWithRotation(1); 

        // Tengjum output stream við iText stamper
        _outstream = new MemoryStream();
        PdfStamper stamper = PdfStamper.CreateSignature(reader, _outstream, '\0', null, true);
        stamper.InsertPage(reader.NumberOfPages + 1, reader.GetPageSize(reader.NumberOfPages));

        _sap = stamper.SignatureAppearance;

        float llx = pageSize.Width/2 - 350/2;
        float lly = pageSize.Height/2 - 150/2;
        float urx = llx + 350;
        float ury = lly + 150;
        _sap.SetVisibleSignature(new iTextSharp.text.Rectangle(llx, lly, urx, ury), reader.NumberOfPages, null);
        _sap.Reason = reason;
        _sap.Location = location;
        _transactionTime = DateTime.Now;
        _sap.SignDate = _transactionTime;

        iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance(AppDomain.CurrentDomain.BaseDirectory + "UndirskriftDemo.png");
        img.ScaleToFit(new Rectangle(350, 50));
        _sap.Image = img;

        _sap.Layer2Font = new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.TIMES_ROMAN, 10.0f, 0, iTextSharp.text.BaseColor.BLACK);
        _sap.Layer2Text = _userFullName + " undirritaði skjalið\nmeð rafrænum hætti \nþann " + _transactionTime.ToString("dd.MM.yyyy") + "\nStaður: " + location;
        _sap.LocationCaption = "Location caption";
        _sap.Contact = "Contact";

        _sap.ReasonCaption = "ReasonCaption";
        _sap.Layer4Text = "Layer 4 text";

        // Create signature infrastructure
        PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
        dic.Reason = _sap.Reason;
        dic.Location = _sap.Location;
        dic.Contact = _sap.Contact;
        dic.Date = new PdfDate(_sap.SignDate);
        _sap.CryptoDictionary = dic;

        Dictionary<PdfName, int> exc = new Dictionary<PdfName, int>();
        exc.Add(PdfName.CONTENTS, (15000 * 2) + 2); // TSA: Content estimated er 15000 í stað 8192

        //string tsa_url = ConfigurationManager.AppSettings["TSA_Url"];
        //TSAClientBouncyCastle tsc = new TSAClientBouncyCastle(tsa_url);
        //LtvTimestamp.Timestamp(_sap, tsc, null); // This can not be called here as then an exception will be thrown.

        _sap.PreClose(exc);

        Stream data = _sap.GetRangeStream();
        _hash = DigestAlgorithms.Digest(data, DigestAlgorithms.SHA1);
    }

Then postSign:

    public void PostSign(byte[] signatureData)
    {
        PdfSignatureAppearance sap = _sap;

        byte[] paddedSig = new byte[15000];
        System.Array.Copy(signatureData, 0, paddedSig, 0, signatureData.Length);

        PdfDictionary dic = new PdfDictionary();
        dic.Put(PdfName.CONTENTS, new PdfString(paddedSig).SetHexWriting(true));

        sap.Close(dic);
    }

And these methods are called like this:

      // Sign the document
      SignatureHelper signatureHelper = new SignatureHelper(itemID, employeeItemID, oUser.UserName, oUser.FullName);
      signatureHelper.preSign(pdfBytes, "Undirritun til að staðfesta uppruna", "Reykjavík");
      byte[] signatureData = signatureHelper.SignFile(pdfBytes, phoneNumber, itemID);
      signatureHelper.PostSign(signatureData);
      ro.ByteStream = signatureHelper.OutStream;
rbadi76
  • 21
  • 8
  • **A** Does that signing service you use also provide certificate revocation information via CRLs or OCSPs? **B** You want *to make the PDF conform to the PAdES LTV-Profile*; which *PAdES LTV-Profile* exactly do you mean? The *Profile for PAdES-LTV* according to [ETSI TS 102 778-4](http://www.etsi.org/deliver/etsi_ts/102700_102799/10277804/01.01.01_60/ts_10277804v010101p.pdf)? Or PAdES Baseline Profiles like *LT-Level* or *LTA-Level* conformance according to [ETSI TS 103 172](http://www.etsi.org/deliver/etsi_ts/103100_103199/103172/02.01.01_60/ts_103172v020101p.pdf)? – mkl Mar 15 '16 at 16:35
  • A: The signing service provides a link to CRLs (i.e. under Certificate Viewer details in Acrobat Reader I see "CRL distribution points: URI = http://crl.audkenni.is/fullgiltaudkenni/latest.crl".) B: ETSI TS 102 778-4 v.1.1.2 – rbadi76 Mar 16 '16 at 09:38
  • Sorry, actually when I create a PdfPKCS7 object from the bytes returned from the service I get CRLs = "Count = 0" and Ocsp = null. (as you can see I am a bit of a newbie) :) – rbadi76 Mar 16 '16 at 10:02
  • Please share a sample PDF signed using your code and PKI. – mkl Mar 18 '16 at 10:51
  • Here it is: [Sample PDF](https://app.box.com/s/2anucnu49rs4rd0ffblppqtgnyzqz0js) – rbadi76 Mar 18 '16 at 14:17
  • ETSI TS 102 778-4 specifies where to put extra LTV information and which LTV information *should* be put there, not *shall*, i.e. it is recommending, not requiring there. So strictly speaking your PDFs are conform to that TS even if you add *no LTV information* at all! Thus, you may want to decide to go for a PAdES Baseline Profile according to ETSI TS 103 172, [ETSI EN 319 142-1](http://www.etsi.org/deliver/etsi_en/319100_319199/31914201/01.01.01_60/en_31914201v010101p.pdf), or [ETSI EN 319 142-2](http://www.etsi.org/deliver/etsi_en/319100_319199/31914202/01.01.01_60/en_31914202v010101p.pdf). – mkl May 01 '16 at 09:56
  • That been said, your use of the `PdfName.ADBE_PKCS7_DETACHED` sub-filter restricts you somewhat as most of the newer norms expect the signature to use `PdfName.ETSI_CADES_DETACHED`; there are hints to the legacy form, though, indicating how to add validation information to legacy sub-filter signatures. And finally, your task to implement things *so that the documents' validity does not expire* is not possible as such, even the various LT forms do require time stamps to be added every once in a while in time before the validity of the already included validation related information runs out. – mkl May 01 '16 at 10:05

0 Answers0