Cómo firmar un documento PDF desde C# con iTextSharp

Jueves, 24 jun, 2010 @ 18:40 | Por Gustavo Cantero (The Wolf) | .NET Framework, Certificados Digitales, Seguridad

Muchas veces tenemos que firmar un PDF utilizando un certificado X.509, y el iTextSharp (una excelente librería) nos puede ayudar a realizar esta tarea. Para esto les dejo un método que utilizo para hacer esto, que seguramente les va a ser de utilidad.

Para poder utilizar este código deben bajarse la librería iTextSharp (http://sourceforge.net/projects/itextsharp), y referenciar esta DLL y “System.Security” desde su proyecto.

A continuación les dejo el código:

using System;
using System.Collections;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.Pkcs;
using iTextSharp.text;
using iTextSharp.text.pdf;
using Org.BouncyCastle.X509;
using SysX509 = System.Security.Cryptography.X509Certificates;

/// <summary>
/// Helper para el firmado de PDFs con la librería iTextSharp
/// </summary>
public static class PDF
{
    /// <summary>
    /// Firma un documento
    /// </summary>
    /// <param name="Source">Documento origen</param>
    /// <param name="Target">Documento destino</param>
    /// <param name="Certificate">Certificado a utilizar</param>
    /// <param name="Reason">Razón de la firma</param>
    /// <param name="Location">Ubicación</param>
    /// <param name="AddVisibleSign">Establece si hay que agregar la firma visible al documento</param>
    public static void SignHashed(string Source, string Target, SysX509.X509Certificate2 Certificate, string Reason, string Location, bool AddVisibleSign)
    {
        X509CertificateParser objCP = new X509CertificateParser();
        X509Certificate[] objChain = new X509Certificate[] { objCP.ReadCertificate(Certificate.RawData) };

        PdfReader objReader = new PdfReader(Source);
        PdfStamper objStamper = PdfStamper.CreateSignature(objReader, new FileStream(Target, FileMode.Create), '\0');
        PdfSignatureAppearance objSA = objStamper.SignatureAppearance;

        if (AddVisibleSign)
            objSA.SetVisibleSignature(new Rectangle(100, 100, 300, 200), 1, null);

        objSA.SignDate = DateTime.Now;
        objSA.SetCrypto(null, objChain, null, null);
        objSA.Reason = Reason;
        objSA.Location = Location;
        objSA.Acro6Layers = true;
        objSA.Render = PdfSignatureAppearance.SignatureRender.NameAndDescription;
        PdfSignature objSignature = new PdfSignature(PdfName.ADOBE_PPKMS, PdfName.ADBE_PKCS7_SHA1);
        objSignature.Date = new PdfDate(objSA.SignDate);
        objSignature.Name = PdfPKCS7.GetSubjectFields(objChain[0]).GetField("CN");
        if (objSA.Reason != null)
            objSignature.Reason = objSA.Reason;
        if (objSA.Location != null)
            objSignature.Location = objSA.Location;
        objSA.CryptoDictionary = objSignature;
        int intCSize = 4000;
        Hashtable objTable = new Hashtable();
        objTable[PdfName.CONTENTS] = intCSize * 2 + 2;
        objSA.PreClose(objTable);

        HashAlgorithm objSHA1 = new SHA1CryptoServiceProvider();

        Stream objStream = objSA.RangeStream;
        int intRead = 0;
        byte[] bytBuffer = new byte[8192];
        while ((intRead = objStream.Read(bytBuffer, 0, 8192)) > 0)
            objSHA1.TransformBlock(bytBuffer, 0, intRead, bytBuffer, 0);
        objSHA1.TransformFinalBlock(bytBuffer, 0, 0);

        byte[] bytPK = SignMsg(objSHA1.Hash, Certificate, false);
        byte[] bytOut = new byte[intCSize];

        PdfDictionary objDict = new PdfDictionary();

        Array.Copy(bytPK, 0, bytOut, 0, bytPK.Length);

        objDict.Put(PdfName.CONTENTS, new PdfString(bytOut).SetHexWriting(true));
        objSA.Close(objDict);
    }

    /// <summary>
    /// Crea la firma CMS/PKCS #7
    /// </summary>
    private static byte[] SignMsg(byte[] Message, SysX509.X509Certificate2 SignerCertificate, bool Detached)
    {
        //Creamos el contenedor
        ContentInfo contentInfo = new ContentInfo(Message);

        //Instanciamos el objeto SignedCms con el contenedor
        SignedCms objSignedCms = new SignedCms(contentInfo, Detached);

        //Creamos el "firmante"
        CmsSigner objCmsSigner = new CmsSigner(SignerCertificate);

        // Include the following line if the top certificate in the
        // smartcard is not in the trusted list.
        objCmsSigner.IncludeOption = SysX509.X509IncludeOption.EndCertOnly;

        //  Sign the CMS/PKCS #7 message. The second argument is
        //  needed to ask for the pin.
        objSignedCms.ComputeSignature(objCmsSigner, false);

        //Encodeamos el mensaje CMS/PKCS #7
        return objSignedCms.Encode();
    }
}

Descargar proyecto de ejemploAquí les dejo un proyecto de ejemplo donde se pide un PDF a firmar, luego donde escribir PDF firmado y toma el primer certificado personal que posea clave privada y lo utiliza para firmar el PDF.

Espero que este código les sea de utilidad.
Suerte!

Artículos relacionados

VN:F [1.7.3_972]
Rating: 10.0/10 (1 voto cast)


Reciente

Obtener lista de contactos de Gmail

16 jun, 2010 por Gustavo Cantero (The Wolf) en Interconexión y redes sociales

Pósters de tecnologías y productos de Microsoft

08 jun, 2010 por Gustavo Cantero (The Wolf) en .NET Framework, Visual Studio

Parámetros opcionales en C# 4.0

24 may, 2010 por Gustavo Cantero (The Wolf) en .NET Framework

Enlace via código de grillas en ASP.NET

03 may, 2010 por Dario Krapp en ASP.NET

Poster con las clases de .NET Framework 4.0

27 abr, 2010 por Gustavo Cantero (The Wolf) en .NET Framework

Especificación de los lenguajes C# 4.0 y Visual Basic 10.0

20 abr, 2010 por Gustavo Cantero (The Wolf) en .NET Framework

Tamaño de los parámetros en string.Format

17 abr, 2010 por Gustavo Cantero (The Wolf) en .NET Framework