2012-11-03 120 views
5

我是iTextSharp(和StackOverFlow)的新手。我正在尝试使用外部USB令牌在C#上签名PDF。我尝试使用我从互联网上挖掘的下面的代码。使用iTextSharp 5.3.3和USB令牌签署PDF

Org.BouncyCastle.X509.X509CertificateParser cp = new Org.BouncyCastle.X509.X509CertificateParser(); 

//Get Sertifiacte 
X509Certificate2 certClient = null; 
X509Store st = new X509Store(StoreName.My, StoreLocation.CurrentUser); 
st.Open(OpenFlags.MaxAllowed); 
X509Certificate2Collection collection = X509Certificate2UI.SelectFromCollection(st.Certificates, "Please choose certificate:", "", X509SelectionFlag.SingleSelection); 
if (collection.Count > 0){ 
    certClient = collection[0]; 
} 
st.Close(); 
//Get Cert Chain 
IList<Org.BouncyCastle.X509.X509Certificate> chain = new List<Org.BouncyCastle.X509.X509Certificate>(); 
X509Chain x509chain = new X509Chain(); 
x509chain.Build(certClient); 
foreach (X509ChainElement x509ChainElement in x509chain.ChainElements){ 
    chain.Add(DotNetUtilities.FromX509Certificate(x509ChainElement.Certificate)); 
} 

PdfReader reader = new PdfReader(sourceDocument); 
FileStream resStream = new FileStream(resultDocument, FileMode.Create, FileAccess.ReadWrite); 

PdfStamper stamper = PdfStamper.CreateSignature(reader, resStream , '\0', null, true); 

PdfSignatureAppearance appearance = stamper.SignatureAppearance; 
appearance.Reason = reason; 
appearance.Location = location; 
appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(20, 10, 170, 60), 1, "Signed"); 

X509Certificate2Signature es = new X509Certificate2Signature(certClient, "SHA-1"); 
MakeSignature.SignDetached(appearance, es, chain, null, null, null, 0, CryptoStandard.CMS); 

的问题是,我收到一个异常:

System.Security.Cryptography.CryptographicException was unhandled 
    Message=Invalid type specified. 

    Source=mscorlib 
    StackTrace: 
     at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr) 
     at System.Security.Cryptography.Utils._GetKeyParameter(SafeKeyHandle hKey, UInt32 paramID) 
     at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle) 
     at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair() 
     at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize) 
     at System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey() 
     at iTextSharp.text.pdf.security.X509Certificate2Signature..ctor(X509Certificate2 certificate, String hashAlgorithm) 
     at WindowsFormsApplication1.PDFSignerHelper.signPdfFile(String sourceDocument, String resultDocument, X509Certificate2 certClient, String reason, String location) 
    InnerException: 
+0

所以,现在我将回到iTextSharp的5.2.1并使用http://itextpdf.sourceforge.net/howtosign.html#signextdic中的示例。他们为我工作。如果有人找到iTextSHarp 5.3.3的解决方案,我会很高兴看到它。 –

回答

7

这种方法工作得很好对我们(iTextSharp的5.3.3)。我们使用智能卡和USB令牌(供应商 - www.author.kiev.ua):

  X509Store store = new X509Store(StoreLocation.CurrentUser); 
      store.Open(OpenFlags.ReadOnly); 
      X509Certificate2Collection sel = X509Certificate2UI.SelectFromCollection(store.Certificates, null, null, X509SelectionFlag.SingleSelection); 

      X509Certificate2 cert = sel[0]; 

      Org.BouncyCastle.X509.X509CertificateParser cp = new Org.BouncyCastle.X509.X509CertificateParser(); 
      Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] { 
      cp.ReadCertificate(cert.RawData)}; 

      IExternalSignature externalSignature = new X509Certificate2Signature(cert, "SHA-1"); 

      PdfReader pdfReader = new PdfReader(pathToBasePdf); 

      signedPdf = new FileStream(pathToBasePdf, FileMode.Create); 

      pdfStamper = PdfStamper.CreateSignature(pdfReader, signedPdf, '\0'); 
      PdfSignatureAppearance signatureAppearance = pdfStamper.SignatureAppearance; 

      signatureAppearance.SignatureGraphic = Image.GetInstance(pathToSignatureImage); 
      signatureAppearance.SetVisibleSignature(new Rectangle(100, 100, 250, 150), pdfReader.NumberOfPages, "Signature"); 
      signatureAppearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.GRAPHIC_AND_DESCRIPTION; 

      MakeSignature.SignDetached(signatureAppearance, externalSignature, chain, null, null, null, 0, CryptoStandard.CMS); 
+0

使用这种方式时是否存在插入USB令牌的任何案例证书?因为我的令牌的证书未使用此代码列出,而Acrobat *列出它。虽然Acrobat报告“密钥集未定义”。试图用它签名时出错... – user2173353

+0

没关系。看起来Acrobat在某些时候将证书导入了我的本地商店,并从那里查看它们。现在无法访问USB令牌..与我的中间件/驱动程序有关......这些公司如何销售这些东西?我花了几天的时间寻找正确的驱动程序版本...... :( – user2173353

+0

@ user2173353在我们的案例中,我们没有任何问题)示例,驱动程序,支持)感谢制造 – Sasha

3

相同的代码之上,但使用证书文件,而不是商店签署的最后一页上的PDF文档。

X509Certificate2 cert = new X509Certificate2("C:\\mycert.p12"); 

Org.BouncyCastle.X509.X509CertificateParser cp = new Org.BouncyCastle.X509.X509CertificateParser(); 
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] { 
cp.ReadCertificate(cert.RawData)}; 

IExternalSignature externalSignature = new X509Certificate2Signature(cert, "SHA-1"); 

PdfReader pdfReader = new PdfReader("C:\\multi-page-pdf.pdf"); 

var signedPdf = new FileStream("C:\\multi-page-pdf-signed.pdf", FileMode.Create); 

var pdfStamper = PdfStamper.CreateSignature(pdfReader, signedPdf, '\0'); 
PdfSignatureAppearance signatureAppearance = pdfStamper.SignatureAppearance; 

signatureAppearance.SignatureGraphic = Image.GetInstance("C:\\logo.png"); 
signatureAppearance.Reason = "Because I can"; 
signatureAppearance.Location = "My location"; 
signatureAppearance.SetVisibleSignature(new Rectangle(100, 100, 250, 150), pdfReader.NumberOfPages, "Signature"); 
signatureAppearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.GRAPHIC_AND_DESCRIPTION; 

MakeSignature.SignDetached(signatureAppearance, externalSignature, chain, null, null, null, 0, CryptoStandard.CMS); 

复制,粘贴,导入所需的库,并去其他工作。

5

我已经可以签署从Windows应用商店,智能卡或将PFX/P12文件为PDF C#项目 可能是它可以是有用的4你

using System; 
using System.Windows.Forms; 
using System.IO; 

using System.Security; 
using System.Security.Cryptography; 
using System.Security.Cryptography.X509Certificates; 

using iTextSharp.text.pdf; 
using iTextSharp.text.pdf.security; 



namespace SignPdf 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 
     private SecureString GetSecurePin(string PinCode) 
     { 
      SecureString pwd = new SecureString(); 
      foreach (var c in PinCode.ToCharArray()) pwd.AppendChar(c); 
      return pwd; 
     } 
     private void button1_Click(object sender, EventArgs e) 
     { 
      //Sign from SmartCard 
      //note : ProviderName and KeyContainerName can be found with the dos command : CertUtil -ScInfo 
      string ProviderName = textBox2.Text; 
      string KeyContainerName = textBox3.Text; 
      string PinCode = textBox4.Text; 
      if (PinCode != "") 
      { 
       //if pin code is set then no windows form will popup to ask it 
       SecureString pwd = GetSecurePin(PinCode); 
       CspParameters csp = new CspParameters(1, 
                 ProviderName, 
                 KeyContainerName, 
                 new System.Security.AccessControl.CryptoKeySecurity(), 
                 pwd); 
       try 
       { 
        RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider(csp); 
        // the pin code will be cached for next access to the smart card 
       } 
       catch (Exception ex) 
       { 
        MessageBox.Show("Crypto error: " + ex.Message); 
        return; 
       } 
      }   
      X509Store store = new X509Store(StoreLocation.CurrentUser); 
      store.Open(OpenFlags.ReadOnly); 
      X509Certificate2 cert = null; 
      if ((ProviderName == "") || (KeyContainerName == "")) 
      { 
       MessageBox.Show("You must set Provider Name and Key Container Name"); 
       return; 
      } 
      foreach (X509Certificate2 cert2 in store.Certificates) 
      { 
       if (cert2.HasPrivateKey) 
       { 
        RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert2.PrivateKey; 
        if (rsa == null) continue; // not smart card cert again 
        if (rsa.CspKeyContainerInfo.HardwareDevice) // sure - smartcard 
        { 
         if ((rsa.CspKeyContainerInfo.KeyContainerName == KeyContainerName) && (rsa.CspKeyContainerInfo.ProviderName == ProviderName)) 
         { 
          //we find it 
          cert = cert2; 
          break; 
         } 
        } 
       } 
      } 
      if (cert == null) 
      { 
       MessageBox.Show("Certificate not found"); 
       return; 
      } 
      SignWithThisCert(cert); 
     } 

     private void button2_Click(object sender, EventArgs e) 
     { 
      //Sign with certificate selection in the windows certificate store 
      X509Store store = new X509Store(StoreLocation.CurrentUser); 
      store.Open(OpenFlags.ReadOnly); 
      X509Certificate2 cert = null; 
      //manually chose the certificate in the store 
      X509Certificate2Collection sel = X509Certificate2UI.SelectFromCollection(store.Certificates, null, null, X509SelectionFlag.SingleSelection); 
      if (sel.Count > 0) 
       cert = sel[0]; 
      else 
      { 
       MessageBox.Show("Certificate not found"); 
       return; 
      } 
      SignWithThisCert(cert); 
     } 

     private void button3_Click(object sender, EventArgs e) 
     { 
      //Sign from certificate in a pfx or a p12 file 
      string PfxFileName = textBox5.Text; 
      string PfxPassword = textBox6.Text; 
      X509Certificate2 cert = new X509Certificate2(PfxFileName, PfxPassword); 
      SignWithThisCert(cert); 
     } 

     private void SignWithThisCert(X509Certificate2 cert) 
     { 
      string SourcePdfFileName = textBox1.Text; 
      string DestPdfFileName = textBox1.Text + "-Signed.pdf"; 
      Org.BouncyCastle.X509.X509CertificateParser cp = new Org.BouncyCastle.X509.X509CertificateParser(); 
      Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] { cp.ReadCertificate(cert.RawData) }; 
      IExternalSignature externalSignature = new X509Certificate2Signature(cert, "SHA-1"); 
      PdfReader pdfReader = new PdfReader(SourcePdfFileName); 
      FileStream signedPdf = new FileStream(DestPdfFileName, FileMode.Create); //the output pdf file 
      PdfStamper pdfStamper = PdfStamper.CreateSignature(pdfReader, signedPdf, '\0'); 
      PdfSignatureAppearance signatureAppearance = pdfStamper.SignatureAppearance; 
      //here set signatureAppearance at your will 
      signatureAppearance.Reason = "Because I can"; 
      signatureAppearance.Location = "My location"; 
      signatureAppearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.DESCRIPTION; 
      MakeSignature.SignDetached(signatureAppearance, externalSignature, chain, null, null, null, 0, CryptoStandard.CMS); 
      //MakeSignature.SignDetached(signatureAppearance, externalSignature, chain, null, null, null, 0, CryptoStandard.CADES); 
      MessageBox.Show("Done"); 
     } 

    } 


} 
+0

感谢jean-luc。我已经完成了我的项目,但我将在未来的开发中考虑您的代码。 –

+0

写得很好的方法和答案。 –