# Digital Signature

DsPdf is a Document Solutions product that offers a rich library to read, create, modify, and save PDF files without using any external tool.

## Content

DsPdf enables a user to digitally sign a PDF document to secure the authenticity of the content. The library supports digital signature in the PDF document using the [SignatureField](/document-solutions/dot-net-pdf-api/api/online/DS.Documents.Pdf/GrapeCity.Documents.Pdf.AcroForms.SignatureField.html) class. You can also add digital signatures with timestamps to mark the time and date of the signature in the PDF document. DsPdf supports legal stamps created by trustworthy authority like the Time Stamp Authority (TSA). DsPdf provides [Sign](/document-solutions/dot-net-pdf-api/api/online/DS.Documents.Pdf/GrapeCity.Documents.Pdf.GcPdfDocument.Sign.html) method to sign and save a document which by default updates the document incrementally. Alternatively, you can also set the [SaveMode](/document-solutions/dot-net-pdf-api/api/online/DS.Documents.Pdf/GrapeCity.Documents.Pdf.SaveMode.html) enumeration to **IncrementalUpdate** and pass it as a parameter to **Sign** method. Both these methods let you sign a document multiple times without invalidating the original signature and without changing its original content. DsPdf allows three levels of subsequent changes on a signed document:

* No changes
* Modify fields
* Modify fields and add annotations

Note that once a document has been signed, adding a new field invalidates the existing signature. Hence, a document must already have enough signature fields to accommodate all the subsequent signatures. Also, if you run a sample that uses a signed PDF without a valid license key of DsPdf, then the original signature in the generated PDF is invalidated. This happens because a license header is added to the PDF in such cases which changes the original signed document.
Further, DsPdf allows a user to reuse a signed PDF template by removing the signatures and keeping the Signature Field, or simply removing the Signature Field.

## Add Digital Signature

To add digital signature in a PDF document:

1. Use the [SignatureProperties](/document-solutions/dot-net-pdf-api/api/online/DS.Documents.Pdf/GrapeCity.Documents.Pdf.SignatureProperties.html) class to set up the certificate for digital signature.
2. Initialize the [SignatureField](/document-solutions/dot-net-pdf-api/api/online/DS.Documents.Pdf/GrapeCity.Documents.Pdf.AcroForms.SignatureField.html) class to hold the signature.
3. Add the signature field to the PDF document using the **Add** method.
4. Connect the signature field to signature properties.
5. Sign the document using the [Sign](/document-solutions/dot-net-pdf-api/api/online/DS.Documents.Pdf/GrapeCity.Documents.Pdf.GcPdfDocument.Sign.html) method of GcPdfDocument class. It also saves the document.

    ```csharp
    public static void CreatePDF(Stream stream)
    {
        GcPdfDocument doc = new GcPdfDocument();
        Page page = doc.NewPage();
        TextFormat tf = new TextFormat() { Font = StandardFonts.Times, FontSize = 14 };
        page.Graphics.DrawString(
            "Hello, World!\r\nSigned below by DsPdfWeb SignDoc sample." +
            "\r\n(Note that some browser built-in viewers may not show the signature.)",
            tf, new PointF(72, 72));
    
        // Initialize a test certificate:
        var pfxPath = Path.Combine("Resources", "Misc", "DsPdfTest.pfx");
        X509Certificate2 cert = new X509Certificate2(File.ReadAllBytes(pfxPath), "qq",
        X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet
        | X509KeyStorageFlags.Exportable);
        SignatureProperties sp = new SignatureProperties();
        sp.Certificate = cert;
        sp.Location = "DsPdfWeb Sample Browser";
        sp.SignerName = "DsPdfWeb";
        // Add timestamp            
        sp.TimeStamp = new TimeStamp("https://freetsa.org/tsr");
    
        // Initialize a signature field to hold the signature:
        SignatureField sf = new SignatureField();
        sf.Widget.Rect = new RectangleF(72, 72 * 2, 72 * 4, 36);
        sf.Widget.Page = page;
        sf.Widget.BackColor = Color.LightSeaGreen;
        sf.Widget.TextFormat.Font = StandardFonts.Helvetica;
        sf.Widget.ButtonAppearance.Caption = $"Signer: " +
            $"{sp.SignerName}\r\nLocation: {sp.Location}";
        // Add the signature field to the document:
        doc.AcroForm.Fields.Add(sf);
    
        // Connect the signature field and signature properties:
        sp.SignatureField = sf;
    
        // Sign and save the document:
        // NOTES:
        // - Signing and saving is an atomic operation, the two cannot be separated.
        // - The stream passed to the Sign() method must be readable.
        doc.Sign(sp, stream);
    
        // Rewind the stream to read the document just created 
        // into another GcPdfDocument and verify the signature:
        stream.Seek(0, SeekOrigin.Begin);
        GcPdfDocument doc2 = new GcPdfDocument();
        doc2.Load(stream);
        SignatureField sf2 = (SignatureField)doc2.AcroForm.Fields[0];
        if (!sf2.Value.VerifySignature())
            throw new Exception("Failed to verify the signature");
    
        // Done (the generated and signed document has already been saved to 'stream').
    }
    ```

## Remove Digital Signature

With DsPdf, it is easy to remove a digital signature from a PDF file. The library allows users to remove a signature from signature field, so that the contents of the PDF file can be used again.
![Pdf without a digital signature](https://cdn.mescius.io/document-site-files/images/884d2bfb-301b-49bc-8d90-656c5b910507/images/wihtout_signature1.png)
To remove the signature and keep the signature field in the PDF document, follow these steps:

1. Initialize an instance of [GcPdfDocument](/document-solutions/dot-net-pdf-api/api/online/DS.Documents.Pdf/GrapeCity.Documents.Pdf.GcPdfDocument.html) class and load the PDF file.
2. To remove all the signatures in the document, call a recursive method which loops through all the signature fields in the PDF file and set the [Value](/document-solutions/dot-net-pdf-api/api/online/DS.Documents.Pdf/GrapeCity.Documents.Pdf.AcroForms.SignatureField.Value.html) property of the [SignatureField](/document-solutions/dot-net-pdf-api/api/online/DS.Documents.Pdf/GrapeCity.Documents.Pdf.AcroForms.SignatureField.html) class to null.
3. Save the document.

    ```csharp
    var doc = new GcPdfDocument();
    using (var fs = new FileStream( "TimeSheet.pdf", FileMode.Open, FileAccess.Read))
    {
        doc.Load(fs);
    
        // Fields can be children of other fields, so we use
        // a recursive method to iterate through the whole tree:
        removeSignatures(doc.AcroForm.Fields);
    
        doc.Save("TimeSheet_NoSign.pdf"); //Save the document
    
        void removeSignatures(FieldCollection fields)
        {
            foreach (var f in fields)
            {
                if (f is SignatureField sf)
                    sf.Value = null; //removes the signatures from the document
                removeSignatures(f.Children);
            }
        }
    }
    ```

## Extract Signature Properties

DsPdf allows you to extract signature information from a digital signature in a PDF document by using **[Content](/document-solutions/dot-net-pdf-api/api/online/DS.Documents.Pdf/GrapeCity.Documents.Pdf.Security.Signature.Contents.html)**[ ](/document-solutions/dot-net-pdf-api/api/online/DS.Documents.Pdf/GrapeCity.Documents.Pdf.Security.Signature.Contents.html)property of [Signature ](/document-solutions/dot-net-pdf-api/api/online/DS.Documents.Pdf/GrapeCity.Documents.Pdf.Security.Signature.html)class. The signature information provides necessary details about the signature which can be used to verify its validity. Some of the information fields which can be extracted from a signature are Issuer, IssuerName, SerialNumber, Subject, Thumbprint, NotAfter, NotBefore, SignatureAlgorithm etc.
To extract signature information from a digital signature in PDF document, follow these steps:

1. Load the signed document and get the signature using [Fields ](/document-solutions/dot-net-pdf-api/api/online/DS.Documents.Pdf/GrapeCity.Documents.Pdf.AcroForms.AcroForm.Fields.html)property of [AcroForm](/document-solutions/dot-net-pdf-api/api/online/DS.Documents.Pdf/GrapeCity.Documents.Pdf.AcroForms.AcroForm.html) class.
2. Use the **Content** property of Signature class to get the additional information about the signature.

    ```csharp
    MemoryStream ms = new MemoryStream(File.ReadAllBytes(@"AdobePDFWithEmptySignatureField.pdf"));
    GcPdfDocument doc = new GcPdfDocument();
    doc.Load(ms);
    
    //initialize a certificate
    X509Certificate2 cert = new X509Certificate2(@"User.pfx", "User12");
    SignatureProperties sp = new SignatureProperties();
    sp.Location = "MACHINE";
    sp.SignerName = "USER";
    sp.SigningDateTime = null;
    sp.SignatureField = doc.AcroForm.Fields["EmptySignatureField"];
    
    using (MemoryStream ms2 = new MemoryStream())
    {
        //sign document
        doc.Sign(sp, ms2, false);
        ms2.Seek(0, SeekOrigin.Begin);
    
        //load signed document
        GcPdfDocument doc2 = new GcPdfDocument();
        doc2.Load(ms2);
    
        //get signature field and signature
        SignatureField sf2 = (SignatureField)doc2.AcroForm.Fields["EmptySignatureField"];
        var sk = sf2.Value.Content;
    
        //get certificate and print its props
        var sc = sk.SigningCertificate;
        Console.WriteLine($"Subject: {sc.Subject}");
        Console.WriteLine($"Issuer: {sc.Issuer}");
        Console.WriteLine($"GetEffectiveDateString: {sc.GetEffectiveDateString()}");
        Console.WriteLine($"GetExpirationDateString: {sc.GetExpirationDateString()}");
    }
    ```

## Custom Implementation of Digital Signature

DsPdf provides **ISignatureBuilder** and **IPkcs7SignatureGenerator** interfaces which can be used to achieve the custom implementation of digital signatures. The **Pkcs7SignatureBuilder** class implements the **ISignatureBuilder** interface and provides various methods and properties such as:

* **Pkcs7SignatureBuilder.Format** property which can be set to **SignatureFormat** enumeration values such as **adbe\_pkcs7\_detached**, **ETSI\_CAdES\_detached** and **adbe\_pkcs7\_sha1** to create the respective signatures
* **Pkcs7SignatureBuilder.Crls** property which can be used to embed certificate revocation lists into the signature
* **Pkcs7SignatureBuilder.IncludeOcsp** property which can be used to embed OCPS information into the signature
* **Pkcs7SignatureBuilder.CertificateChain** property which can be used to embed full chain of certificates into the signature

Some of the custom signature implementations are described below:

### Sign Document using Certificate from .p12 file

To sign a document using certificate from .p12 file, follow these steps:

1. Instantiate **SignatureProperties** class and use its object to initialize **Pkcs7SignatureBuilder** class.
2. Build a chain of certificates by passing a .p12 filename and its password to **GetCertificateChain** method of **SecurityUtils** class.
3. Add the signature field to the document using **Fields** property of **AcroForm** class.
4. Sign and save the PDF document using **Sign** method of GcPdfDocument class.

    ```csharp
    using (FileStream fs = new FileStream(@"AdobePDFWithEmptySignatureField.pdf", FileMode.Open))
    {
        GcPdfDocument doc = new GcPdfDocument();
        doc.Load(fs);
    
        SignatureProperties sp = new SignatureProperties();
        sp.SignatureBuilder = new Pkcs7SignatureBuilder()
        {
            CertificateChain = SecurityUtils.GetCertificateChain("1571753451.p12", "test"),
        };
        sp.SignatureField = doc.AcroForm.Fields[0];
        doc.Sign(sp, "signed.pdf");
    }
    ```

### Sign Document using USB Token

You can sign a document using a USB token with a valid certificate. For details, please refer to this [demo](https://developer.mescius.com/documents-api-pdf/demos/features/signatures/sign-usb-token/pdf-cs).

### Sign Document using Certificate from Azure Key Vault

You can sign a document using a certificate stored in Azure Key Vault. For details, please refer to this [demo](https://developer.mescius.com/documents-api-pdf/demos/features/signatures/sign-azure-key-vault/pdf-cs).

### Sign Document using Custom Time-Stamp Tokens

You can create custom time-stamp tokens and sign a document using them by implementing the [ITimeStampGenerator](/document-solutions/dot-net-pdf-api/api/online/DS.Documents.Pdf/GrapeCity.Documents.Pdf.ITimeStampGenerator.html) interface and assigning it to the **TimeStamp** property of [SignatureProperties](/document-solutions/dot-net-pdf-api/api/online/DS.Documents.Pdf/GrapeCity.Documents.Pdf.SignatureProperties.html) and [TimeStampProperties](/document-solutions/dot-net-pdf-api/api/online/DS.Documents.Pdf/GrapeCity.Documents.Pdf.TimeStampProperties.html) classes. ITimeStampGenerator interface defines the methods for generating time-stamp tokens.
Refer to the following example code to add a custom time-stamp token and a signature with a custom time-stamp token to the PDF document:

```csharp
// Create a custom time-stamp generator.
public class TimeStampGenerator : ITimeStampGenerator
{
    public string ServerUrl;
    public string UserName;
    public string Password;
    public OID HashAlgorithm;

    public TimeStampGenerator()
    {
        HashAlgorithm = new OID("2.16.840.1.101.3.4.2.1", "SHA256");
    }
    public TimeStampGenerator(string serverUrl, string userName, string password, OID hashAlgorithm)
    {
        ServerUrl = serverUrl;
        UserName = userName;
        Password = password;
        HashAlgorithm = hashAlgorithm;
    }

    private static long CopyStream(Stream src, Stream dst, bool useSingleWriteOperation = false)
    {
        byte[] buffer = new byte[16 * 1024];
        int bytesRead;
        long result = 0;
        while ((bytesRead = src.Read(buffer, 0, buffer.Length)) != 0)
        {
            dst.Write(buffer, 0, bytesRead);
            result += bytesRead;
        }
        return result;
    }

    private static void Update(IDigest dgst, byte[] input)
    {
        Update(dgst, input, 0, input.Length);
    }

    private static void Update(IDigest dgst, byte[] input, int offset, int len)
    {
        dgst.BlockUpdate(input, offset, len);
    }

    private static byte[] Digest(IDigest dgst)
    {
        byte[] output = new byte[dgst.GetDigestSize()];
        dgst.DoFinal(output, 0);
        return output;
    }

    private static byte[] Digest(IDigest dgst, byte[] input)
    {
        Update(dgst, input);
        return Digest(dgst);
    }

    private static byte[] Digest(IDigest dgst, Stream data)
    {
        byte[] buf = new byte[8192];
        int n;
        while ((n = data.Read(buf, 0, buf.Length)) > 0)
        {
            Update(dgst, buf, 0, n);
        }
        return Digest(dgst);
    }

    private static IDigest GetMessageDigest(OID hashAlgorithm)
    {
        if (hashAlgorithm == OID.HashAlgorithms.MD2)
            return new MD2Digest();
        else if (hashAlgorithm == OID.HashAlgorithms.MD5)
            return new MD5Digest();
        else if (hashAlgorithm == OID.HashAlgorithms.SHA1)
            return new Sha1Digest();
        else if (hashAlgorithm == OID.HashAlgorithms.SHA224)
            return new Sha224Digest();
        else if (hashAlgorithm == OID.HashAlgorithms.SHA256)
            return new Sha256Digest();
        else if (hashAlgorithm == OID.HashAlgorithms.SHA384)
            return new Sha384Digest();
        else if (hashAlgorithm == OID.HashAlgorithms.SHA512)
            return new Sha512Digest();
        else if (hashAlgorithm == OID.HashAlgorithms.RIPEMD128)
            return new RipeMD128Digest();
        else if (hashAlgorithm == OID.HashAlgorithms.RIPEMD160)
            return new RipeMD160Digest();
        else if (hashAlgorithm == OID.HashAlgorithms.RIPEMD256)
            return new RipeMD256Digest();
        else if (hashAlgorithm == OID.HashAlgorithms.GOST3411)
            return new Gost3411Digest();
        throw new ArgumentException();
    }

    private byte[] GetTsaResponseForUserRequest(byte[] requestBytes)
    {
        HttpWebRequest con;
        try
        {
            con = (HttpWebRequest)WebRequest.Create(ServerUrl);
        }
        catch (Exception e)
        {
            throw new Exception(string.Format("Failed to get response from TSA server {0}.", ServerUrl), e);
        }

        con.ContentLength = requestBytes.Length;
        con.ContentType = "application/timestamp-query";
        con.Method = "POST";
        if (!string.IsNullOrEmpty(UserName))
        {
            string authInfo = UserName + ":" + Password;
            authInfo = Convert.ToBase64String(Encoding.UTF8.GetBytes(authInfo));
            con.Headers["Authorization"] = "Basic " + authInfo;
        }

        using (Stream outp = con.GetRequestStream())
            outp.Write(requestBytes, 0, requestBytes.Length);

        HttpWebResponse httpWebResponse = (HttpWebResponse)con.GetResponse();
        using (Stream stream = httpWebResponse.GetResponseStream())
        {
            if (stream == null)
                return null;

            using (MemoryStream ms = new MemoryStream())
            {
                CopyStream(stream, ms);
                string encoding = httpWebResponse.Headers[HttpResponseHeader.ContentEncoding];
                byte[] data = ms.ToArray();
                if (string.Compare(encoding, "base64", StringComparison.InvariantCultureIgnoreCase) == 0)
                    data = Convert.FromBase64String(Encoding.ASCII.GetString(data));
                return data;
            }
        }
    }

    // Get time stamp token for hash.
    private byte[] GetTimeStampTokenForHash(byte[] hash)
    {
        // Setup the time stamp request.
        TimeStampRequestGenerator tsqGenerator = new TimeStampRequestGenerator();
        tsqGenerator.SetCertReq(true);

        // Generate random number.
        BigInteger nonce = BigInteger.ValueOf(unchecked((int)DateTime.Now.Ticks) + Environment.TickCount);
        TimeStampRequest request = tsqGenerator.Generate(new DerObjectIdentifier(HashAlgorithm.ID), hash, nonce);
        
        // Call the communications layer.
        byte[] requestBytes = request.GetEncoded();
        byte[] respBytes = GetTsaResponseForUserRequest(requestBytes);

        // Handle the TSA response.
        TimeStampResponse response = new TimeStampResponse(respBytes);

        // Validate communication level attributes (RFC 3161 PKIStatus).
        response.Validate(request);
        PkiFailureInfo failure = response.GetFailInfo();
        int value = failure == null ? 0 : failure.IntValue;
        if (value != 0)
            throw new Exception(string.Format("Invalid TSA response from {0}: {1}.", ServerUrl, response.GetStatusString()));

        // Extract just the time stamp token (removes communication status info).
        TimeStampToken tsToken = response.TimeStampToken;
        if (tsToken == null)
            throw new Exception(string.Format("No timetoken in TSA response from {0}.", ServerUrl));

        return tsToken.GetEncoded();
    }

    // Get time stamp token.
    public byte[] GetTimeStampToken(byte[] data)
    {
        // Build hash of the data.
        byte[] hash = Digest(GetMessageDigest(HashAlgorithm), data);
        return GetTimeStampTokenForHash(hash);
    }

    public byte[] GetTimeStampToken(Stream stream)
    {
        // Build hash of the data.
        byte[] hash = Digest(GetMessageDigest(HashAlgorithm), stream);
        return GetTimeStampTokenForHash(hash);
    }
}

internal class Program
{
    static void Main(string[] args)
    {
        // Generate the signature with time-stamp token.
        X509Certificate2 crt = new X509Certificate2(@"..\..\..\User.pfx", "User12");
        using (FileStream fs = new FileStream(@"..\..\..\AdobePDFWithEmptySignatureField.pdf", FileMode.Open))
        {
            // Initialize GcPdfDocument.
            GcPdfDocument doc = new GcPdfDocument();
            
            // Load the PDF document from stream.
            doc.Load(fs);

            // Initialize SignatureProperties.
            SignatureProperties sp = new SignatureProperties();

            // Build a chain of certificates.
            sp.SignatureBuilder = new Pkcs7SignatureBuilder()
            {
                CertificateChain = new X509Certificate2[] { crt },
            };

            // Add custom time stamp.
            sp.TimeStamp = new TimeStampGenerator()
            {
                ServerUrl = @"http://ts.ssl.com",
            };

            // Add signature to signature field.
            sp.SignatureField = doc.AcroForm.Fields[0];

            // Sign PDF document.
            doc.Sign(sp, "signed.pdf");
        }

        // Generate a document with time-stamp.
        using (FileStream fs = new FileStream(@"..\..\..\AdobePDFWithEmptySignatureField.pdf", FileMode.Open))
        {
            // Initialize GcPdfDocument.
            GcPdfDocument doc = new GcPdfDocument();

            // Load the PDF document from stream.
            doc.Load(fs);

            // Initialize TimeStampProperties.
            TimeStampProperties tsp = new TimeStampProperties();

            // Add custom time stamp.
            tsp.TimeStamp = new TimeStampGenerator()
            {
                ServerUrl = @"http://ts.ssl.com",
            };

            // Add time stamp to signature field.
            tsp.SignatureField = doc.AcroForm.Fields[0];

            // Add time stamp and save the document.
            doc.TimeStamp(tsp, "timestamp.pdf");
        }
    }
}
```

![](https://cdn.mescius.io/document-site-files/images/884d2bfb-301b-49bc-8d90-656c5b910507/images/sign-with-timestamp.png)

![](https://cdn.mescius.io/document-site-files/images/884d2bfb-301b-49bc-8d90-656c5b910507/images/timestamp.png)

## PDF Advanced Electronic Signatures

DsPdf lets you digitally sign PDF documents using PDF Advanced Electronic Signatures (PAdES). PAdES is a set of standards referring to a group of extensions and restrictions used when PDF documents are signed electronically. The documents signed using PAdES format remain valid for longer periods.
In PAdES, the following levels of verification of digital signatures are supported by DsPdf:

* B-Level: Indicates that an electronic signature was executed with a signing certificate that was valid on a date.
* T-Level: Similar to B-Level, only adds an additional time-stamp to prove that the signature existed at a certain date and time.
* LT-Level: Building up on T-level, it further adds verification related information to the Documents Security Store(DSS). In DsPdf, DSS is represented by the **DocumentSecurityStore** class.
* LTA-Level: Requires to add time stamp token also to the DSS in addition to the verification related information, thus establishing evidence that the validation data existed at the indicated time.

In DsPdf, you can use **CreatePAdES\_B\_B** and **CreatePAdES\_B\_T** methods of **SignatureProperties** class to create B-B and B-T level of signatures in a PDF document. It further provides **GrapeCity.Documents.Pdf.Security.DocumentSecurityStore** class and **GcPdfDocument.TimeStamp()** method to facilitate creation of advanced electronic signatures such as B-LT and B-LTA levels.

### Create PAdES B-B Signature

To create a PAdES B-B signature, follow these steps:

1. Initialize a certificate using the **X509Certificate2** class and pass the certificate file name and password to access the certificate.
2. Pass the certificate instance to **CreatePAdES\_B\_B** method of **SignatureProperties** class to create a PAdES B-B signature.
3. Set the first AcroForm field to store the signature using **SignatureField** property.
4. Sign and save the PDF document using **Sign** method of GcPdfDocument class.

    ```csharp
    using (FileStream fs = new FileStream(@"AdobePDFWithEmptySignatureField.pdf", FileMode.Open))
    {
        GcPdfDocument doc = new GcPdfDocument();
        doc.Load(fs);
    
        X509Certificate2 cert = new X509Certificate2("User.pfx", "User12");
        SignatureProperties sp = SignatureProperties.CreatePAdES_B_B(cert);
        sp.SignatureAppearance.Caption = "PAdES B-B";
        sp.SignatureField = doc.AcroForm.Fields[0];
        doc.Sign(sp, "signed_PAdES_B_B.pdf");
    }
    ```

### Create PAdES B-T Signature

To create a PAdES B-T signature, follow these steps:

1. Initialize a certificate using the **X509Certificate2** class and pass the certificate file name and password to access the certificate.
2. Pass the timestamp and certificate instance to **CreatePAdES\_B\_T** method of **SignatureProperties** class to create a PAdES B-T signature.
3. Set the first AcroForm field to store the signature using **SignatureField** property.
4. Sign and save the PDF document using **Sign** method of GcPdfDocument class.

    ```csharp
    using (FileStream fs = new FileStream(@"AdobePDFWithEmptySignatureField.pdf", FileMode.Open))
    {
        GcPdfDocument doc = new GcPdfDocument();
        doc.Load(fs);
    
        X509Certificate2 cert = new X509Certificate2("User.pfx", "User12");
        SignatureProperties sp = SignatureProperties.CreatePAdES_B_T(new TimeStamp("https://freetsa.org/tsr"), cert);
        sp.SignatureAppearance.Caption = "PAdES B-T";
        sp.SignatureField = doc.AcroForm.Fields[0];
        doc.Sign(sp, "signed_PAdES_B_T.pdf");
    }
    ```

### Create PAdES B-LT Signature

B-LT signature is built on the B-T signature by adding all the properties required for long-term validation of the signature. To create a PAdES B-LT signature, follow these steps:

1. [Create a PAdES B-T signature](/document-solutions/dot-net-pdf-api/docs/online/Features/digital_signature#create-pades-b-t-signature) and save the PDF document.
2. Add LTV information to the signatures using **AddVerification** method of the DocumentSecurityStore class.
3. Sign and save the document in [incremental update](/document-solutions/dot-net-pdf-api/docs/online/Features/IncrementalUpdate) mode using the **Save** method.

    ```csharp
    public int CreatePDF(Stream stream)
    {
        var doc = new GcPdfDocument();
        using var s = File.OpenRead(Path.Combine("Resources", "PDFs", "SignPAdESBT.pdf"));
        doc.Load(s);
    
        //Add a B-T Level signature
        var pfxPath = Path.Combine("Resources", "Misc", "DsPdfTest.pfx");
        var cert = new X509Certificate2(pfxPath, "qq");
        var sp = SignatureProperties.CreatePAdES_B_T(new TimeStamp("https://freetsa.org/tsr"), cert);
        sp.SignatureAppearance.Caption = "PAdES B-LT";
        sp.SignatureField = doc.AcroForm.Fields[0];
        doc.Sign(sp, stream);
        doc.Load(stream);
    
        // Adds LTV information which makes the signature compliant with PAdES B-LT:
        SignatureField signField = (SignatureField)doc.AcroForm.Fields[0];
        var sig = signField.Value;
        var vp = new DocumentSecurityStore.VerificationParams();
        var pfxPath = Path.Combine("CACertCertificate.pfx");
        var cert = new X509Certificate2(pfxPath, "1234");
        vp.Certificates = new X509Certificate2[] { cert };
        if (!doc.SecurityStore.AddVerification(sig, vp))
            throw new Exception($"Could not add verification for {sig.Name}.");
        doc.Save("SignedLTV.pdf", SaveMode.IncrementalUpdate);
    
        //Done.
        return doc.Pages.Count;
    
    }
    ```

### Create PAdES B-LTA Signature

B-LTA signature is built on the B-LT signature by adding time stamp token on the validation material. To create a PAdES B-LTA signature, follow these steps:

1. [Create a PAdES B-LT signature](/document-solutions/dot-net-pdf-api/docs/online/Features/digital_signature#create-pades-b-lt-signature) and save the PDF document.
2. Add timestamp to the B-LT signed PDF by using **TimeStampProperties** class to make it compliant with PAdES B-LTA level.
3. Call the **TimeStamp()** method and save the document with time stamp properties.

    ```csharp
    public int CreatePDF(Stream stream)
    {
        var doc = new GcPdfDocument();
        using var s = File.OpenRead(Path.Combine("Resources", "PDFs", "SignPAdESBT.pdf"));
        doc.Load(s);
    
        //Add a B-T Level signature
        var pfxPath = Path.Combine("Resources", "Misc", "DsPdfTest.pfx");
        var cert = new X509Certificate2(pfxPath, "qq");
        var sp = SignatureProperties.CreatePAdES_B_T(new TimeStamp("https://freetsa.org/tsr"), cert);
        sp.SignatureAppearance.Caption = "PAdES B-LTA";
        sp.SignatureField = doc.AcroForm.Fields[0];
        doc.Sign(sp, stream);
        doc.Load(stream);
    
        // Adds LTV information 
        SignatureField signField = (SignatureField)doc.AcroForm.Fields[0];
        var sig = signField.Value;
        var vp = new DocumentSecurityStore.VerificationParams();
        var pfxPath = Path.Combine("CACertCertificate.pfx");
        var cert = new X509Certificate2(pfxPath, "1234");
        vp.Certificates = new X509Certificate2[] { cert };
        if (!doc.SecurityStore.AddVerification(sig, vp))
            throw new Exception($"Could not add verification for {sig.Name}.");
        doc.Save("SignedLTV.pdf", SaveMode.IncrementalUpdate);
    
        doc.Load(stream);
        //Adds time stamp to a signed PDF which makes the document compliant with B-LTA level
        TimeStampProperties ts = new TimeStampProperties()
        {
            TimeStamp = new TimeStamp(@"http://ts.ssl.com"),
        };
        // Save the PDF to a file adding a time stamp to it:
        doc.TimeStamp(ts, stream);
    
        //Done.
        return doc.Pages.Count;
    }
    ```