Como ler o certificado do signatário a partir de assinaturas PDF verificadas em C# (X.509, eIDAS, Chain)
Um contrato chega ao seu fluxo de auditoria. Ele está assinado digitalmente, a assinatura é válida e sua equipe de conformidade precisa de respostas: quem o assinou, o certificado era válido naquela manhã e a Autoridade Certificadora emissora corresponde à sua lista de autoridades confiáveis? Você poderia extrair os bytes brutos da assinatura, analisar o DER (Relatório de Endereços de Certificados) e percorrer a cadeia de certificados manualmente. Ou você poderia perguntar ao objeto VerifiedSignature por seu SignerCertificate e ler as respostas como propriedades.
É para isso que servem as propriedades SignerCertificate e CertificateChain em VerifiedSignature . Retornados de PdfDocument.GetVerifiedSignatures() , eles expõem a identidade X.509 completa do signatário, a CA emissora, as datas de validade, a impressão digital SHA-256, os bytes DER brutos e todos os certificados intermediários até a raiz. Essa é a superfície de API necessária para conformidade com o eIDAS, vinculação de certificados, trilhas de auditoria e verificação da cadeia de confiança.
Este guia aborda três tipos de inspeção de certificados:
- Detalhes padrão X.509: propriedades de identidade, nomes distintos completos, janelas de validade e bytes DER brutos para interoperabilidade
X509Certificate2. - Campos eIDAS e setor regulamentado: extrair o ID nacional do signatário de
SubjectSerialNumbere ler OIDs numéricos como2.5.4.97para o organizationIdentifier do eIDAS. - Validação da cadeia de confiança: fixação da impressão digital SHA-256 e verificação completa da cadeia, do signatário à CA raiz.
Inicie um teste gratuito de 30 dias para experimentar a inspeção de certificados em seu processo de verificação.
Início rápido: Leia o certificado do signatário em um PDF assinado
Chame GetVerifiedSignatures em um PDF carregado e leia as propriedades do certificado do signatário diretamente do resultado.
-
Instale IronPDF com o Gerenciador de Pacotes NuGet
PM > Install-Package IronPdf -
Copie e execute este trecho de código.
var sig = PdfDocument.FromFile("signed.pdf").GetVerifiedSignatures().First(); var cert = sig.SignerCertificate; Console.WriteLine($"{cert?.CommonName} ({cert?.Organization}) valid until {cert?.NotAfter}"); -
Implante para testar em seu ambiente de produção.
Comece a usar IronPDF em seu projeto hoje com uma avaliação gratuita
Fluxo de trabalho mínimo (3 etapas)
- Baixe o IronPDF do NuGet.
- Carregue um PDF assinado e chame
GetVerifiedSignatures()para obter uma lista de objetos de assinatura verificados. - Leia
sig.SignerCertificatepara identidade e validade, ou percorrasig.CertificateChainpara a cadeia de confiança completa.
Como extrair o documento de identidade nacional ou pessoal do signatário?
A propriedade SubjectSerialNumber retorna o valor do OID SERIALNUMBER do Subject DN do certificado. Em setores regulamentados (certificados qualificados pelo eIDAS, serviços bancários, identidades digitais emitidas pelo governo), este campo contém o número de identificação nacional, o número de identificação fiscal ou o número de identificação pessoal do signatário. Não se trata do número de série do próprio certificado; isso é CertificateSerialNumber.
:path=/static-assets/pdf/content-code-examples/how-to/verify-pdf-signatures-serial-number.cs
using IronPdf;
using IronPdf.Signing.Inspection;
var pdf = PdfDocument.FromFile("eidas-signed-invoice.pdf");
foreach (var sig in pdf.GetVerifiedSignatures())
{
var cert = sig.SignerCertificate;
if (cert is null) continue;
// Subject DN SERIALNUMBER OID (national ID, tax ID, etc.)
Console.WriteLine($"Signer Identity (SERIALNUMBER): {cert.SubjectSerialNumber ?? "not present"}");
// Certificate's own serial from the issuing CA
Console.WriteLine($"Certificate Serial (CA-issued): {cert.CertificateSerialNumber}");
}
Imports IronPdf
Imports IronPdf.Signing.Inspection
Dim pdf = PdfDocument.FromFile("eidas-signed-invoice.pdf")
For Each sig In pdf.GetVerifiedSignatures()
Dim cert = sig.SignerCertificate
If cert Is Nothing Then Continue For
' Subject DN SERIALNUMBER OID (national ID, tax ID, etc.)
Console.WriteLine($"Signer Identity (SERIALNUMBER): {If(cert.SubjectSerialNumber, "not present")}")
' Certificate's own serial from the issuing CA
Console.WriteLine($"Certificate Serial (CA-issued): {cert.CertificateSerialNumber}")
Next
SubjectSerialNumber indica quem assinou o documento (um ID de pessoa ou organização, como um ID nacional ou número de contribuinte incorporado no DN do Assunto). CertificateSerialNumber indica qual certificado foi usado; É o número de série exclusivo que a Autoridade Certificadora emissora atribui às listas de revogação e aos registros de auditoria.
Como acessar as propriedades de identidade de conveniência?
SignerCertificateInfo expõe os campos Subject DN mais comumente necessários como propriedades diretas, para que você não precise analisar a string DN completa manualmente.
Leitura do nome e da afiliação do signatário
As propriedades CommonName, Organization, Country e Email abrangem o que a maioria dos fluxos de trabalho de identidade utiliza em primeiro lugar.
:path=/static-assets/pdf/content-code-examples/how-to/verify-pdf-signatures-identity-common.cs
using IronPdf;
using IronPdf.Signing.Inspection;
var pdf = PdfDocument.FromFile("signed-agreement.pdf");
foreach (var sig in pdf.GetVerifiedSignatures())
{
var cert = sig.SignerCertificate;
if (cert is null) continue;
// Common Subject DN fields exposed directly as properties
Console.WriteLine($"CommonName (CN): {cert.CommonName}");
Console.WriteLine($"Organization (O): {cert.Organization}");
Console.WriteLine($"Country (C): {cert.Country}");
Console.WriteLine($"Email: {cert.Email}");
}
Imports IronPdf
Imports IronPdf.Signing.Inspection
Dim pdf = PdfDocument.FromFile("signed-agreement.pdf")
For Each sig In pdf.GetVerifiedSignatures()
Dim cert = sig.SignerCertificate
If cert Is Nothing Then Continue For
' Common Subject DN fields exposed directly as properties
Console.WriteLine($"CommonName (CN): {cert.CommonName}")
Console.WriteLine($"Organization (O): {cert.Organization}")
Console.WriteLine($"Country (C): {cert.Country}")
Console.WriteLine($"Email: {cert.Email}")
Next
A propriedade Email primeiro verifica o DN do assunto para o OID emailAddress. Caso não esteja presente, utiliza-se a extensão do Nome Alternativo do Assunto (SAN) rfc822Name. A propriedade Country retorna o código ISO 3166-1 alfa-2 de duas letras (por exemplo, "DE", "US", "FR"). Todas as propriedades de conveniência retornam null se o campo correspondente não estiver presente no certificado.
Lendo o DN completo quando você precisa de tudo
Para fins de registro de auditoria, análise subsequente ou relatórios de conformidade, SubjectDN e IssuerDN retornam as strings completas do Nome Distinto.
:path=/static-assets/pdf/content-code-examples/how-to/verify-pdf-signatures-identity-full-dn.cs
using IronPdf;
using IronPdf.Signing.Inspection;
var pdf = PdfDocument.FromFile("signed-agreement.pdf");
foreach (var sig in pdf.GetVerifiedSignatures())
{
var cert = sig.SignerCertificate;
if (cert is null) continue;
// Full DN strings for audit logging or downstream parsing
Console.WriteLine($"Full Subject DN: {cert.SubjectDN}");
Console.WriteLine($"Full Issuer DN: {cert.IssuerDN}");
}
Imports IronPdf
Imports IronPdf.Signing.Inspection
Dim pdf = PdfDocument.FromFile("signed-agreement.pdf")
For Each sig In pdf.GetVerifiedSignatures()
Dim cert = sig.SignerCertificate
If cert Is Nothing Then Continue For
' Full DN strings for audit logging or downstream parsing
Console.WriteLine($"Full Subject DN: {cert.SubjectDN}")
Console.WriteLine($"Full Issuer DN: {cert.IssuerDN}")
Next
Como extrair campos arbitrários de sujeito e emissor?
Os métodos GetSubjectField(string) e GetIssuerField(string) aceitam nomes curtos ou OIDs numéricos. Eles não diferenciam maiúsculas de minúsculas e retornam null se o campo não estiver presente.
Nomes abreviados suportados: CN, O, OU, C, L, ST, E, SERIALNUMBER, SURNAME, T, GIVENNAME, UID, ORGANIZATIONIDENTIFIER.
Leitura de qualquer campo temático (incluindo OIDs eIDAS)
Passe um nome curto como "OU" ou um OID numérico como "2.5.4.97" (o identificador da organização eIDAS) para extrair qualquer campo do DN do Assunto.
:path=/static-assets/pdf/content-code-examples/how-to/verify-pdf-signatures-field-subject.cs
using IronPdf;
using IronPdf.Signing.Inspection;
var pdf = PdfDocument.FromFile("eidas-contract.pdf");
foreach (var sig in pdf.GetVerifiedSignatures())
{
var cert = sig.SignerCertificate;
if (cert is null) continue;
// Short-name lookups (case-insensitive)
string? orgUnit = cert.GetSubjectField("OU");
string? surname = cert.GetSubjectField("SURNAME");
string? givenName = cert.GetSubjectField("GIVENNAME");
string? title = cert.GetSubjectField("T");
// Numeric OID lookup (eIDAS organizationIdentifier)
string? orgId = cert.GetSubjectField("2.5.4.97");
Console.WriteLine($"Name: {givenName} {surname} ({title}), OU: {orgUnit}");
Console.WriteLine($"eIDAS Org ID (2.5.4.97): {orgId ?? "not present"}");
}
Imports IronPdf
Imports IronPdf.Signing.Inspection
Dim pdf = PdfDocument.FromFile("eidas-contract.pdf")
For Each sig In pdf.GetVerifiedSignatures()
Dim cert = sig.SignerCertificate
If cert Is Nothing Then Continue For
' Short-name lookups (case-insensitive)
Dim orgUnit As String = cert.GetSubjectField("OU")
Dim surname As String = cert.GetSubjectField("SURNAME")
Dim givenName As String = cert.GetSubjectField("GIVENNAME")
Dim title As String = cert.GetSubjectField("T")
' Numeric OID lookup (eIDAS organizationIdentifier)
Dim orgId As String = cert.GetSubjectField("2.5.4.97")
Console.WriteLine($"Name: {givenName} {surname} ({title}), OU: {orgUnit}")
Console.WriteLine($"eIDAS Org ID (2.5.4.97): {If(orgId, "not present")}")
Next
A consulta numérica por OID é essencial para o eIDAS e para certificados de setores regulamentados que incorporam identificadores de organização, qualificações Professional ou campos específicos da jurisdição não abrangidos por nomes curtos padrão.
Leitura dos campos do emissor
GetIssuerField funciona da mesma forma contra o Nome Distinto da CA emissora. Isso é útil para validação de confiança, relatórios de autoridades certificadoras e agrupamento de assinaturas por autoridade emissora.
:path=/static-assets/pdf/content-code-examples/how-to/verify-pdf-signatures-field-issuer.cs
using IronPdf;
using IronPdf.Signing.Inspection;
var pdf = PdfDocument.FromFile("eidas-contract.pdf");
foreach (var sig in pdf.GetVerifiedSignatures())
{
var cert = sig.SignerCertificate;
if (cert is null) continue;
// GetIssuerField works the same way as GetSubjectField
string? issuerCN = cert.GetIssuerField("CN");
string? issuerO = cert.GetIssuerField("O");
string? issuerCountry = cert.GetIssuerField("C");
Console.WriteLine($"Issued by: {issuerCN} ({issuerO}, {issuerCountry})");
}
Imports IronPdf
Imports IronPdf.Signing.Inspection
Dim pdf = PdfDocument.FromFile("eidas-contract.pdf")
For Each sig In pdf.GetVerifiedSignatures()
Dim cert = sig.SignerCertificate
If cert Is Nothing Then Continue For
' GetIssuerField works the same way as GetSubjectField
Dim issuerCN As String = cert.GetIssuerField("CN")
Dim issuerO As String = cert.GetIssuerField("O")
Dim issuerCountry As String = cert.GetIssuerField("C")
Console.WriteLine($"Issued by: {issuerCN} ({issuerO}, {issuerCountry})")
Next
Como verificar a validade de um certificado?
SignerCertificateInfo fornece dois auxiliares de validação:
IsExpiredretornatrueseDateTime.UtcNow > NotAfter.IsValidAt(DateTime)retornatruese o carimbo de data/hora fornecido estiver dentro da janelaNotAfter. O uso típico é para confirmar se o certificado era válido no momento da assinatura.
:path=/static-assets/pdf/content-code-examples/how-to/verify-pdf-signatures-validity.cs
using IronPdf;
using IronPdf.Signing.Inspection;
var pdf = PdfDocument.FromFile("archived-contract.pdf");
foreach (var sig in pdf.GetVerifiedSignatures())
{
var cert = sig.SignerCertificate;
if (cert is null) continue;
Console.WriteLine($"Valid from: {cert.NotBefore}");
Console.WriteLine($"Valid until: {cert.NotAfter}");
Console.WriteLine($"Expired now: {cert.IsExpired}");
// Confirm certificate was valid when the document was signed
if (sig.SigningDate.HasValue)
{
bool validAtSigning = cert.IsValidAt(sig.SigningDate.Value);
Console.WriteLine($"Valid at signing time ({sig.SigningDate.Value}): {validAtSigning}");
}
}
Imports IronPdf
Imports IronPdf.Signing.Inspection
Dim pdf = PdfDocument.FromFile("archived-contract.pdf")
For Each sig In pdf.GetVerifiedSignatures()
Dim cert = sig.SignerCertificate
If cert Is Nothing Then Continue For
Console.WriteLine($"Valid from: {cert.NotBefore}")
Console.WriteLine($"Valid until: {cert.NotAfter}")
Console.WriteLine($"Expired now: {cert.IsExpired}")
' Confirm certificate was valid when the document was signed
If sig.SigningDate.HasValue Then
Dim validAtSigning As Boolean = cert.IsValidAt(sig.SigningDate.Value)
Console.WriteLine($"Valid at signing time ({sig.SigningDate.Value}): {validAtSigning}")
End If
Next
IsExpired retorna false (não true) quando as datas de validade não podem ser extraídas do certificado. A função auxiliar é intencionalmente conservadora; ela não assume a expiração apenas porque faltam metadados. Para fluxos de trabalho de confiança zero, trate as datas de validade ausentes como um caso de falha explicitamente.
Para fins de auditoria , registre tanto a verificação IsExpired (validade atual) quanto a verificação IsValidAt(signingDate) (validade no momento da assinatura). Um certificado que já expirou pode ainda ter sido válido quando o documento foi assinado; Ambos os pontos de dados são importantes para a conformidade.
Como usar a impressão digital SHA-256 para o pining de certificados?
A propriedade Sha256Thumbprint retorna uma string hexadecimal de 64 caracteres em maiúsculas, o hash SHA-256 do certificado codificado em DER. Este é o valor que você atribui a uma lista confiável de certificados de assinatura aceitos.
:path=/static-assets/pdf/content-code-examples/how-to/verify-pdf-signatures-thumbprint-pinning.cs
using IronPdf;
using IronPdf.Signing.Inspection;
using System.Collections.Generic;
// Known-good signer thumbprints from a compliance database
var pinnedThumbprints = new HashSet<string>
{
"A1B2C3D4E5F6A1B2C3D4E5F6A1B2C3D4E5F6A1B2C3D4E5F6A1B2C3D4E5F6A1B2",
"F6E5D4C3B2A1F6E5D4C3B2A1F6E5D4C3B2A1F6E5D4C3B2A1F6E5D4C3B2A1F6E5"
};
var pdf = PdfDocument.FromFile("submitted-form.pdf");
foreach (var sig in pdf.GetVerifiedSignatures())
{
var cert = sig.SignerCertificate;
if (cert is null) continue;
// Pin against trusted thumbprint list
bool trusted = pinnedThumbprints.Contains(cert.Sha256Thumbprint);
Console.WriteLine($"Signer: {cert.CommonName}, Thumbprint: {cert.Sha256Thumbprint}");
Console.WriteLine($"Pinned: {trusted}");
}
Imports IronPdf
Imports IronPdf.Signing.Inspection
Imports System.Collections.Generic
' Known-good signer thumbprints from a compliance database
Dim pinnedThumbprints As New HashSet(Of String) From {
"A1B2C3D4E5F6A1B2C3D4E5F6A1B2C3D4E5F6A1B2C3D4E5F6A1B2C3D4E5F6A1B2",
"F6E5D4C3B2A1F6E5D4C3B2A1F6E5D4C3B2A1F6E5D4C3B2A1F6E5D4C3B2A1F6E5"
}
Dim pdf = PdfDocument.FromFile("submitted-form.pdf")
For Each sig In pdf.GetVerifiedSignatures()
Dim cert = sig.SignerCertificate
If cert Is Nothing Then Continue For
' Pin against trusted thumbprint list
Dim trusted As Boolean = pinnedThumbprints.Contains(cert.Sha256Thumbprint)
Console.WriteLine($"Signer: {cert.CommonName}, Thumbprint: {cert.Sha256Thumbprint}")
Console.WriteLine($"Pinned: {trusted}")
Next
Como construir um certificado X509 a partir de dados brutos de um certificado?
A propriedade RawData retorna o certificado codificado em DER como um byte[]. Cada chamada retorna uma cópia defensiva, de modo que os dados internos nunca são expostos por referência. Você pode usar isso para construir um System.Security.Cryptography.X509Certificates.X509Certificate2 para interoperabilidade com as APIs criptográficas nativas do .NET (construção de cadeia, validação de política, verificação de CRL).
:path=/static-assets/pdf/content-code-examples/how-to/verify-pdf-signatures-x509-interop.cs
using IronPdf;
using IronPdf.Signing.Inspection;
using System.Security.Cryptography.X509Certificates;
var pdf = PdfDocument.FromFile("signed-report.pdf");
foreach (var sig in pdf.GetVerifiedSignatures())
{
var cert = sig.SignerCertificate;
if (cert is null) continue;
// Construct X509Certificate2 from defensive DER copy
byte[] derBytes = cert.RawData;
var x509 = new X509Certificate2(derBytes);
Console.WriteLine($"X509 Subject: {x509.Subject}");
Console.WriteLine($"X509 Issuer: {x509.Issuer}");
Console.WriteLine($"X509 Serial: {x509.SerialNumber}");
Console.WriteLine($"X509 Algorithm: {x509.SignatureAlgorithm.FriendlyName}");
Console.WriteLine($"X509 Key Size: {x509.PublicKey.Key.KeySize} bits");
}
Imports IronPdf
Imports IronPdf.Signing.Inspection
Imports System.Security.Cryptography.X509Certificates
Dim pdf = PdfDocument.FromFile("signed-report.pdf")
For Each sig In pdf.GetVerifiedSignatures()
Dim cert = sig.SignerCertificate
If cert Is Nothing Then Continue For
' Construct X509Certificate2 from defensive DER copy
Dim derBytes As Byte() = cert.RawData
Dim x509 = New X509Certificate2(derBytes)
Console.WriteLine($"X509 Subject: {x509.Subject}")
Console.WriteLine($"X509 Issuer: {x509.Issuer}")
Console.WriteLine($"X509 Serial: {x509.SerialNumber}")
Console.WriteLine($"X509 Algorithm: {x509.SignatureAlgorithm.FriendlyName}")
Console.WriteLine($"X509 Key Size: {x509.PublicKey.Key.KeySize} bits")
Next
RawData retorna uma nova cópia defensiva. O array de bytes interno nunca é exposto por referência, portanto, modificar os bytes retornados não afetará chamadas posteriores.
Este caminho de interoperabilidade permite que você integre a verificação de assinatura do IronPDF em pipelines de validação de certificados .NET existentes, como X509Chain.Build() , verificação de revogação via CRL/OCSP ou implementações personalizadas X509CertificateValidator.
Como percorrer a cadeia de certificação?
A propriedade CertificateChain em VerifiedSignature retorna um IReadOnlyList<SignerCertificateInfo> ordenado de signatário → CA(s) intermediário(s) → CA raiz. O índice 0 é sempre o certificado do signatário (o mesmo objeto que SignerCertificate). A lista nunca é nula; Se a cadeia não puder ser extraída, ela conterá apenas o certificado do signatário.
:path=/static-assets/pdf/content-code-examples/how-to/verify-pdf-signatures-chain-walking.cs
using IronPdf;
using IronPdf.Signing.Inspection;
var pdf = PdfDocument.FromFile("enterprise-signed.pdf");
foreach (var sig in pdf.GetVerifiedSignatures())
{
Console.WriteLine($"--- Signature: {sig.SignatureName} ---");
Console.WriteLine($"Chain length: {sig.CertificateChain.Count}");
// Walk from signer (index 0) through intermediates to root CA
for (int i = 0; i < sig.CertificateChain.Count; i++)
{
var cert = sig.CertificateChain[i];
string role = i == 0 ? "Signer"
: i == sig.CertificateChain.Count - 1 ? "Root CA"
: $"Intermediate CA ({i})";
Console.WriteLine($" [{role}]");
Console.WriteLine($" Subject: {cert.SubjectDN}");
Console.WriteLine($" Issuer: {cert.IssuerDN}");
Console.WriteLine($" Serial: {cert.CertificateSerialNumber}");
Console.WriteLine($" Valid: {cert.NotBefore} to {cert.NotAfter}");
Console.WriteLine($" Expired: {cert.IsExpired}");
Console.WriteLine($" Thumbprint: {cert.Sha256Thumbprint}");
}
}
Imports IronPdf
Imports IronPdf.Signing.Inspection
Dim pdf = PdfDocument.FromFile("enterprise-signed.pdf")
For Each sig In pdf.GetVerifiedSignatures()
Console.WriteLine($"--- Signature: {sig.SignatureName} ---")
Console.WriteLine($"Chain length: {sig.CertificateChain.Count}")
' Walk from signer (index 0) through intermediates to root CA
For i As Integer = 0 To sig.CertificateChain.Count - 1
Dim cert = sig.CertificateChain(i)
Dim role As String = If(i = 0, "Signer", If(i = sig.CertificateChain.Count - 1, "Root CA", $"Intermediate CA ({i})"))
Console.WriteLine($" [{role}]")
Console.WriteLine($" Subject: {cert.SubjectDN}")
Console.WriteLine($" Issuer: {cert.IssuerDN}")
Console.WriteLine($" Serial: {cert.CertificateSerialNumber}")
Console.WriteLine($" Valid: {cert.NotBefore} to {cert.NotAfter}")
Console.WriteLine($" Expired: {cert.IsExpired}")
Console.WriteLine($" Thumbprint: {cert.Sha256Thumbprint}")
Next
Next
SignerCertificateInfo na cadeia expõe as mesmas propriedades que SignerCertificate: campos de identidade, validade, impressão digital, RawData, GetSubjectField() e GetIssuerField(). Você pode validar a expiração de cada CA intermediária, verificar a impressão digital da raiz em relação ao seu repositório de raízes confiáveis e registrar toda a cadeia para auditorias de conformidade.
Próximos passos
SignerCertificate e CertificateChain fornecem inspeção completa de X.509 sem sair da superfície da API do IronPDF . A partir daqui, os próximos passos naturais são explorar mais a fundo as partes do IronPDF nas quais essas propriedades se integram.
Para a parte de assinatura do fluxo de trabalho, o guia prático de assinaturas digitais aborda a criação de certificados, metadados e assinatura incremental. Para assinatura baseada em HSM em ambientes de alta segurança, o guia de assinatura HSM aborda a integração do PKCS#11. Precisa de trechos de código prontos para usar? O exemplo de código de assinaturas digitais as fornece.
Pronto para testar em seus próprios PDFs assinados? Inicie seu teste gratuito de 30 dias ou veja as opções de licenciamento .

