2013-02-21 8 views
6

Devo firmare un documento PDF utilizzando un certificato presente nell'archivio certificati di Windows. Sto scavando tutto il giorno cercando di capirlo, e io sono così vicino ancora così lontano.Come si firma un documento PDF utilizzando un certificato da Windows Cert Store?

Tutto ciò che manca è questo: Come si ottiene un oggetto IExternalSignature con cui firmare il file PDF?

Rahul Singla ha scritto un bellissimo esempio di come firmare un documento PDF utilizzando la nuova API iText 5.3.0 - finché è possibile accedere a un file pfx seduti intorno sul vostro PC da qualche parte.

C'è a previous question alla firma utilizzando un certificato da Windows Cert Store, tranne che utilizzava una versione dell'API in cui esiste ancora SetCrypto e la firma apparentemente era facoltativa. In iText 5.3.0, l'API è cambiata e SetCrypto non è più un problema.

Ecco quello che ho finora (i commenti aggiunti per i posteri, dal momento che questo potrebbe essere la versione più completa e recente di come fare questo 'sulla rete):

using iTextSharp.text.pdf; 
using iTextSharp.text.pdf.security; 
using BcX509 = Org.BouncyCastle.X509; 
using Org.BouncyCastle.Pkcs; 
using Org.BouncyCastle.Crypto; 
using DotNetUtils = Org.BouncyCastle.Security.DotNetUtilities; 

... 

// Set up the PDF IO 
PdfReader reader = new PdfReader(@"some\dir\SomeTemplate.pdf"); 
PdfStamper stamper = PdfStamper.CreateSignature(reader, 
    new FileStream(@"some\dir\SignedPdf.pdf", FileMode.Create), '\0'); 
PdfSignatureAppearance sap = stamper.SignatureAppearance; 

sap.Reason = "For no apparent raisin"; 
sap.Location = "..."; 

// Acquire certificate chain 
var certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine); 
certStore.Open(OpenFlags.ReadOnly); 

X509CertificateCollection certCollection = 
    certStore.Certificates.Find(X509FindType.FindBySubjectName, 
    "My.Cert.Subject", true); 
X509Certificate cert = certCollection[0]; 
// iTextSharp needs this cert as a BouncyCastle X509 object; this converts it. 
BcX509.X509Certificate bcCert = DotNetUtils.FromX509Certificate(cert); 
var chain = new List<BcX509.X509Certificate> { bcCert }; 
certStore.Close(); 

// Ok, that's the certificate chain done. Now how do I get the PKS? 
IExternalSignature signature = null; /* ??? */ 

// Sign the PDF file and finish up. 
MakeSignature.SignDetached(sap, signature, chain, // the important stuff 
    null, null, null, 0, CryptoStandard.CMS); 
stamper.Close(); 

Come si può vedere: Ho tutto tranne la firma, e sono perplesso su come dovrei ottenerlo!

+0

Molto utile. Grazie! –

risposta

3
X509Certificate cert = certCollection[0]; // Your code 
X509Certificate2 signatureCert = new X509Certificate2(cert); 

var pk = Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(signatureCert.PrivateKey).Private; 

Se avete la pk, che può avere come sopra, si crea un IExternalSignature come segue:

IExternalSignature es = new PrivateKeySignature(pk, "SHA-256"); 

È inoltre possibile trovare i seguenti articoli di uso:

+0

Funziona (ed è necessario convertire quella 'firma' in un oggetto' X509Certificate2' prima). Ci sono anche alcune questioni relative ai permessi per i certificati da tenere in considerazione - aggiungerò alcune informazioni in seguito. – doppelgreener

0

Si prega di scaricare il libro su PDF and digital signatures. Troverai un esempio Java su come firmare usando l'archivio certificati di Windows nel Capitolo 3. Come puoi vedere, hai bisogno del keystore Windows-MY.

Ora vai al repository dove abbiamo pubblicato il C# port of these examples. Cerca C3_11_SignWithToken.cs.

X509Store x509Store = new X509Store("My"); 
x509Store.Open(OpenFlags.ReadOnly); 
X509Certificate2Collection certificates = x509Store.Certificates; 
IList<X509Certificate> chain = new List<X509Certificate>(); 
X509Certificate2 pk = null; 
if (certificates.Count > 0) { 
    X509Certificate2Enumerator certificatesEn = certificates.GetEnumerator(); 
    certificatesEn.MoveNext(); 
    pk = certificatesEn.Current; 
    X509Chain x509chain = new X509Chain(); 
    x509chain.Build(pk); 
    foreach (X509ChainElement x509ChainElement in x509chain.ChainElements) { 
     chain.Add(DotNetUtilities.FromX509Certificate(x509ChainElement.Certificate)); 
    } 
} 
x509Store.Close(); 

Se ho capito bene chain e pk sono la variabile che stavi cercando;

+0

Questo mi ha insegnato come dovrei ottenere la catena di certificati, quindi grazie.Tuttavia, questo non è l'oggetto che sto cercando - "pk" in questo caso è solo un oggetto X509Certificate2. – doppelgreener

+1

Esempio di buon codice ma un po 'confuso. 'pk' può essere interpretato come chiave privata che non è ...' pk' è il certificato firmato. –

0
public byte[] SignPdf(byte[] pdf) 
{ 
    using (MemoryStream output = new MemoryStream()) 
    { 
     //get certificate from path 
     X509Certificate2 cert1 = new X509Certificate2(@"C:\temp\certtemp.pfx", "12345", X509KeyStorageFlags.Exportable); 
     //get private key to sign pdf 
     var pk = Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(cert1.PrivateKey).Private; 
     // convert the type to be used at .SetCrypt(); 
     Org.BouncyCastle.X509.X509Certificate bcCert = Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(cert1); 
     // get the pdf u want to sign 
     PdfReader pdfReader = new PdfReader(pdf); 

     PdfStamper stamper = PdfStamper.CreateSignature(pdfReader, output, '\0'); 
     PdfSignatureAppearance pdfSignatureAppearance = stamper.SignatureAppearance; 
     //.SetCrypt(); sign the pdf 
     pdfSignatureAppearance.SetCrypto(pk, new Org.BouncyCastle.X509.X509Certificate[] { bcCert }, null, PdfSignatureAppearance.WINCER_SIGNED); 

     pdfSignatureAppearance.Reason = "Este documento está assinado digitalmente pelo Estado Portugues"; 
     pdfSignatureAppearance.Location = " Lisboa, Portugal"; 
     pdfSignatureAppearance.SignDate = DateTime.Now; 

     stamper.Close(); 

     return output.ToArray(); 
    } 
} 

Io uso questo codice per ottenere byte[] PDF e tornare di nuovo un byte[] PDF già firmato.

È iTextSharp-LGPL.

Problemi correlati