# Certificates

> Load X.509 signing certificates in Windows Forms from PFX files or the Windows certificate store, let users pick one with X509Certificate2UI and check it.

- **Product:** TX Text Control .NET for Windows Forms
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET for Windows Forms > Digital Signatures > Certificates
- **3342 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/digital-signatures/certificates/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/digital-signatures/certificates/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/digital-signatures/certificates/llms-full.txt

---

A digital signature is only as trustworthy as the certificate behind it. An X.509 certificate binds a public key to a person or an organization, and the certificate authority that issued it vouches for that binding. TX Text Control takes the certificate as a .NET `X509Certificate2` object, so your Windows Forms application loads it with the APIs of .NET: from a *.pfx* file, or from the Windows certificate store, where certificates on smart cards and USB tokens appear as well. Loading a certificate both ways, letting the user choose one and checking it before signing are shown below.

A test certificate is created in [Create a Self-Signed Certificate for Testing](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/getting-started/pdf/sign/#create-a-self-signed-certificate-for-testing) in Getting Started.

### What a Signing Certificate Needs

- **A private key.** The signature is created with the private key, so the certificate must come with it. A *.pfx* file, also called PKCS#12, contains the certificate and the key.
- **A certificate authority that recipients trust.** Signatures that other people must trust need a certificate from a certificate authority (CA). A self-signed certificate is its own issuer, which makes it suitable for development, tests and internal documents only.
- **A valid period.** PDF readers check whether the certificate was valid when the document was signed, so sign only with a certificate that hasn't expired. A trusted timestamp keeps the signature verifiable after the certificate expires, as [Timestamp Configuration](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/digital-signatures/timestamps/llms-full.txt) explains.

Samples of Text Control, such as the blog article on self-signed certificates below, load signing certificates with `X509KeyStorageFlags.Exportable`, and the test certificate of Getting Started is created with an exportable key. The samples below do the same.

### How TX Text Control Takes the Certificate

A [DigitalSignature](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/digitalsignature/llms-full.txt) represents a certificate for signing a PDF or PDF/A document. It has two [constructors](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/digitalsignature/constructor/llms-full.txt) and no other members:

| Constructor | Used for |
|---|---|
| `DigitalSignature(X509Certificate2 x509, string timeServerURL)` | Signing the whole document with [SaveSettings.DigitalSignature](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/savesettings/digitalsignature-property/llms-full.txt) |
| `DigitalSignature(X509Certificate2 x509, string timeServerURL, string signatureFieldName)` | Signing one signature field with [SaveSettings.SignatureFields](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/savesettings/signaturefields-property/llms-full.txt) |

The constructors take no file names, passwords or store locations: loading the certificate is up to your code. The certificate is used when the document is saved, and if it's invalid or has no private key, `Save` throws a [FilterException](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/filterexception/llms-full.txt) with the [Reason](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/filterexception/reason-property/llms-full.txt) `InvalidCertificate`.

*Form1.cs* needs these `using` directives for the samples:

```csharp
using System.Security.Cryptography.X509Certificates;
using TXTextControl;
```

### Load the Certificate From a PFX File

In .NET 9 and higher, `X509CertificateLoader` loads a *.pfx* file:

```csharp
X509Certificate2 certificate = X509CertificateLoader.LoadPkcs12FromFile(
    "certificate.pfx", "123", X509KeyStorageFlags.Exportable);
```

In a .NET 8 project and in the .NET Framework, `X509CertificateLoader` doesn't exist. Use the constructor with the same arguments, which .NET 9 and higher mark as obsolete:

```csharp
X509Certificate2 certificate = new X509Certificate2(
    "certificate.pfx", "123", X509KeyStorageFlags.Exportable);
```

A *.pfx* file and its password give anyone who has them the power to sign in your name. Don't ship them with the application or write the password into the code; keep them where only the people and computers that sign can read them, as [Certificate and Private Key Handling](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/security/certificates/llms-full.txt) describes.

### Let the User Choose a Certificate

Users who sign with their own certificate have it installed in their personal certificate store. Windows offers a dialog box for choosing one, which .NET opens with `X509Certificate2UI.SelectFromCollection`. Text Control's blog article [Sign PDF Documents with an X.509 Certificate on a Hardware Device](https://www.textcontrol.com/blog/2023/06/05/sign-pdf-documents-with-an-x509-certificate-on-a-hardware-device/) uses this dialog box, which also lists certificates on smart cards and USB tokens.

```csharp
private X509Certificate2 SelectCertificate()
{
    using (X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
    {
        store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

        // Offer only certificates that are valid today
        X509Certificate2Collection validCertificates = store.Certificates.Find(
            X509FindType.FindByTimeValid, DateTime.Now, false);

        // The Windows dialog box for choosing a certificate, owned by this form
        X509Certificate2Collection selected = X509Certificate2UI.SelectFromCollection(
            validCertificates,
            "Sign Document",
            "Select the certificate to sign the PDF document with.",
            X509SelectionFlag.SingleSelection,
            Handle);

        foreach (X509Certificate2 certificate in selected)
        {
            if (certificate.HasPrivateKey)
            {
                return certificate;
            }
        }
    }

    return null;
}

private void signWithMyCertificateButton_Click(object sender, EventArgs e)
{
    X509Certificate2 certificate = SelectCertificate();

    if (certificate == null)
    {
        MessageBox.Show(this, "No certificate with a private key was selected.");
        return;
    }

    SaveSettings saveSettings = new SaveSettings()
    {
        DigitalSignature = new DigitalSignature(certificate, "")
    };

    // Let the user choose where to save the signed PDF
    textControl1.Save(StreamType.AdobePDF, saveSettings);
}
```

The code works as follows:

- `X509Store` opens the personal store of the current user, the store that **Personal** > **Certificates** shows in the Certificate Manager, *certmgr.msc*.
- `Find` with `X509FindType.FindByTimeValid` leaves out certificates that have expired or aren't valid yet.
- `SelectFromCollection` shows the dialog box. `Handle` makes the form its owner, so the dialog box stays in front of it. The result is empty when the user cancels.
- `HasPrivateKey` makes sure the chosen certificate can sign. [TextControl.Save](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/save-method/llms-full.txt) then opens the **Save As** dialog box and signs the file.

The dialog box shows the name, the issuer and the validity period of each certificate:

![The Windows Security dialog box Choose your certificate, showing a self-signed certificate with its issuer and validity period.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-winforms/certificate-selection.d8f92763.webp)

### Find a Certificate by Its Thumbprint

An application that signs with one known certificate, such as a company certificate installed on the signing computer, finds it by its thumbprint, for example one read from the configuration of the application:

```csharp
private X509Certificate2 FindCertificate(string thumbprint)
{
    using (X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
    {
        store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

        // false: also find certificates without a trusted chain, such as test certificates
        X509Certificate2Collection found = store.Certificates.Find(
            X509FindType.FindByThumbprint, thumbprint, false);

        foreach (X509Certificate2 certificate in found)
        {
            if (certificate.HasPrivateKey)
            {
                return certificate;
            }
        }
    }

    return null;
}
```

With `true` as the last parameter of `Find`, only valid certificates are returned. A certificate that was installed for all users of the computer is in `StoreLocation.LocalMachine` instead of `CurrentUser`, and the user of the application needs access to its private key.

### Check a Certificate Before Signing

A check before signing turns a wrong or expired certificate into a clear message instead of an exception at save time:

```csharp
private string CheckCertificate(X509Certificate2 certificate)
{
    if (!certificate.HasPrivateKey)
    {
        return "The certificate has no private key and can't sign.";
    }

    if (certificate.NotAfter < DateTime.Now)
    {
        return $"The certificate expired on {certificate.NotAfter:d}.";
    }

    if (certificate.NotBefore > DateTime.Now)
    {
        return $"The certificate is valid from {certificate.NotBefore:d}.";
    }

    return null;
}

private void checkCertificateButton_Click(object sender, EventArgs e)
{
    X509Certificate2 certificate = X509CertificateLoader.LoadPkcs12FromFile(
        "certificate.pfx", "123", X509KeyStorageFlags.Exportable);

    string problem = CheckCertificate(certificate);

    MessageBox.Show(this,
        $"Subject: {certificate.Subject}\nIssuer: {certificate.Issuer}\n" +
        $"Valid until: {certificate.NotAfter:d}\n\n{problem ?? "The certificate can sign."}");
}
```

`Subject` names the owner of the certificate and `Issuer` the certificate authority that issued it; for a self-signed certificate, both are the same. Adobe Acrobat Reader shows the same details for each signature in its **Signatures** panel.

### Certificates for Development

Besides the PowerShell commands of Getting Started, two blog articles describe other ways to create a test certificate:

- [How to Create Self-Signed Certificates on Windows to Sign PDFs in .NET C#](https://www.textcontrol.com/blog/2025/02/28/how-to-create-self-signed-certificates-on-windows-to-sign-pdfs-in-net-c-sharp/) creates one with PowerShell and explains the parameters.
- [Sign Documents with a Self-Signed Digital ID From Adobe Acrobat Reader in .NET C#](https://www.textcontrol.com/blog/2024/08/12/sign-documents-with-a-self-signed-digital-id-from-adobe-acrobat-reader-in-net-c-sharp/) creates a digital ID as a *.pfx* file in Acrobat Reader.

When the certificate from a CA arrives, only the file or the certificate the code loads changes.

### Next Steps

- [Signing PDF Documents](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/digital-signatures/signing/llms-full.txt): sign documents with the certificate.
- [Timestamp Configuration](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/digital-signatures/timestamps/llms-full.txt): keep signatures verifiable after the certificate expires.
- [Certificate and Private Key Handling](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/security/certificates/llms-full.txt): protect certificates and keys.

---

## Nearby

- **Previous:** [Signing PDF Documents](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/digital-signatures/signing/llms-full.txt)
- **Next:** [Signature Fields and Signature Appearance](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/digital-signatures/signature-fields/llms-full.txt)
