代码之家  ›  专栏  ›  技术社区  ›  Fitsch

iTextSharp 5.5.6:SwissSign USB令牌的签名无效

  •  0
  • Fitsch  · 技术社区  · 9 年前

    我读了布鲁诺·洛瓦吉的白皮书:PDF文档的数字签名。

    我遵循了这些示例,我能够使用MSCAPI使用SwissSign USB令牌签署PDF。这行代码实现了以下目的:

    MakeSignature。SignDetached(外观、pks、链、crlList、ocspClient、tsaClient、估计大小、子筛选器);

    我还将SwissSign TSA URL:TSA(点)SwissSign(点)net传递给TSA客户端

    当我在Acrobat Reader DC 2015中打开已签名的PDF时,我收到错误:

    签名无效。

    此签名中包含的格式或信息存在错误

    签名人的身份尚未验证

    签名时间来自签名者计算机上的时钟。

    使用SwissSign工具签署PDF时,一切看起来都很好:签名有效。

    我把PDF放在这里:

    invalid PDF - signed with iTextSharp 5.5.6

    valid PDF - signed with SwissSign tool

    我尝试过不同的哈希算法组合,但没有成功。我错过了什么?

    感谢任何帮助。

    顺致敬意,

    菲尔

    以下是完整代码:

        private void _sign_Click(object sender, RoutedEventArgs e)
        {
            X509Store x509Store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
            x509Store.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection certificates = x509Store.Certificates;
            IList<Org.BouncyCastle.X509.X509Certificate> chain = new List<Org.BouncyCastle.X509.X509Certificate>();
            X509Certificate2 pk = null;
            if (certificates.Count > 0)
            {
                for (int i = 0; i < certificates.Count; i++)
                {
                    if (certificates[i].FriendlyName == "Philipp Egger (Qualified Signature) .....")        // Phil Egger Signature Certificate
                    {
                        pk = certificates[i];
                        break;
                    }
                }
    
                X509Chain x509chain = new X509Chain();
                x509chain.Build(pk);
    
                foreach (X509ChainElement x509ChainElement in x509chain.ChainElements)
                {
                    chain.Add(Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(x509ChainElement.Certificate));
                }
            }
            x509Store.Close();
    
            if (pk != null)
            {
                #region connect usb token
                ///////////////////
                RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)pk.PrivateKey;
    
                CspParameters cspp = new CspParameters();
                cspp.KeyContainerName = rsa.CspKeyContainerInfo.KeyContainerName;
                cspp.ProviderName = rsa.CspKeyContainerInfo.ProviderName;
                cspp.ProviderType = rsa.CspKeyContainerInfo.ProviderType;
    
                cspp.Flags = CspProviderFlags.NoPrompt;
                System.Security.SecureString pwstr = new System.Security.SecureString();
                pwstr.AppendChar('x');
                pwstr.AppendChar('x');
                pwstr.AppendChar('x');
                cspp.KeyPassword = pwstr;
    
                RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider(cspp);
                rsa2.PersistKeyInCsp = true;
                // PIN is cached from now on and popup won't appear
                ///////////////////////
                #endregion
    
                IOcspClient ocspClient = new OcspClientBouncyCastle();
                ITSAClient tsaClient = null;
                for (int i = 0; i < chain.Count; i++)
                {
                    Org.BouncyCastle.X509.X509Certificate cert = chain[i];
                    String tsaUrl = CertificateUtil.GetTSAURL(cert);
                    if (tsaUrl != null)
                    {
                        tsaClient = new TSAClientBouncyCastle(tsaUrl);
                        break;
                    }
                }
    
                if (tsaClient == null)
                { 
                    tsaClient = new TSAClientBouncyCastle("http://tsa.swisssign.net");
                    //tsaClient = new MyTSAClientBouncyCastle("http://tsa.swisssign.net");      // set user-agent
                }
    
                IList<ICrlClient> crlList = new List<ICrlClient>();
                crlList.Add(new CrlClientOnline(chain));
    
                string pathSource = @"C:\Temp\test_to_sign.pdf";
                string pathTarget3 = @"C:\Temp\test_to_sign-signed3.pdf";
    
                // this.SignNew(pathSource, pathTarget1, chain, pk, DigestAlgorithms.SHA1, CryptoStandard.CMS, "Test", "Rheinau", crlList, ocspClient, tsaClient, 0);
                // this.SignNew(pathSource, pathTarget2, chain, pk, DigestAlgorithms.SHA1, CryptoStandard.CADES, "Test", "Rheinau", crlList, ocspClient, tsaClient, 0);
                this.SignNew(pathSource, pathTarget3, chain, pk, DigestAlgorithms.SHA256, CryptoStandard.CMS, "Test", "Rheinau", crlList, ocspClient, tsaClient, 0);
                // this.SignNew(pathSource, pathTarget4, chain, pk, DigestAlgorithms.SHA256, CryptoStandard.CADES, "Test", "Rheinau", crlList, ocspClient, tsaClient, 0);
                // this.SignNew(pathSource, pathTarget5, chain, pk, DigestAlgorithms.SHA384, CryptoStandard.CMS, "Test", "Rheinau", crlList, ocspClient, tsaClient, 0);
                // this.SignNew(pathSource, pathTarget6, chain, pk, DigestAlgorithms.SHA384, CryptoStandard.CADES, "Test", "Rheinau", crlList, ocspClient, tsaClient, 0);
                // this.SignNew(pathSource, pathTarget7, chain, pk, DigestAlgorithms.SHA512, CryptoStandard.CMS, "Test", "Rheinau", crlList, ocspClient, tsaClient, 0);
                // this.SignNew(pathSource, pathTarget8, chain, pk, DigestAlgorithms.SHA512, CryptoStandard.CADES, "Test", "Rheinau", crlList, ocspClient, tsaClient, 0);
    
                this._txt.Text = "Signed successfully.";
            }
            else
            {
                this._txt.Text = "Certificate not found.";
            }
        }
    
        public void SignNew(String src, String dest,
                 ICollection<Org.BouncyCastle.X509.X509Certificate> chain, X509Certificate2 pk,
                 String digestAlgorithm, CryptoStandard subfilter,
                 String reason, String location,
                 ICollection<ICrlClient> crlList,
                 IOcspClient ocspClient,
                 ITSAClient tsaClient,
                 int estimatedSize)
        {
            // Creating the reader and the stamper
            PdfReader reader = null;
            PdfStamper stamper = null;
            FileStream os = null;
            try
            {
                reader = new PdfReader(src);
                os = new FileStream(dest, FileMode.Create);
                stamper = PdfStamper.CreateSignature(reader, os, '\0');
                // Creating the appearance
                PdfSignatureAppearance appearance = stamper.SignatureAppearance;
                appearance.Reason = reason;
                appearance.Location = location;
                appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(36, 748, 144, 780), 1, "Signature1");
                // Creating the signature
                IExternalSignature pks = new X509Certificate2Signature(pk, digestAlgorithm);
                MakeSignature.SignDetached(appearance, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
            }
            catch (Exception e)
            {
                this._txt.Text = e.Message;
            }
            finally
            {
                if (reader != null)
                    reader.Close();
                if (stamper != null)
                    stamper.Close();
                if (os != null)
                    os.Close();
            }
        }
    
    1 回复  |  直到 9 年前
        1
  •  0
  •   Fitsch    9 年前

    问题是,显然是SwissSign CSP(加密服务提供商;一个在Windows系统存储和硬件设备之间提供桥梁的层)在使用MSCAPI时选择了错误的私钥。

    在MSCAPI中选择正确的私钥似乎没有解决方法。

    因此,我决定使用PKCS11和NCryptroki库。这里是代码:

    using Cryptware.NCryptoki;
    using iTextSharp.text;
    using iTextSharp.text.log;
    using iTextSharp.text.pdf;
    using iTextSharp.text.pdf.security;
    using Org.BouncyCastle.Security;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Security.Cryptography.X509Certificates;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace _07SignWithPKCS11DLL
    {
        class Program
        {
            static void Main(string[] args)
            {
                LoggerFactory.GetInstance().SetLogger(new SysoLogger());
    
                // Creates a Cryptoki object related to the specific PKCS#11 native library
                Cryptoki cryptoki = new Cryptoki("cvP11.dll");
                cryptoki.Initialize();
    
                // Reads the set of slots containing a token
                SlotList slots = cryptoki.Slots;
                if (slots.Count == 0)
                {
                    Console.WriteLine("No slot available");
                    Console.ReadLine();
                    return;
                }
                // Gets the first slot available
                Slot slot = slots[0];
                if (!slot.IsTokenPresent)
                {
                    Console.WriteLine("No token inserted in the slot: " + slots[0].Info.Description);
                    Console.ReadLine();
                    return;
                }
    
                // Gets the first token available
                Token token = slot.Token;
    
                // Opens a read serial session
                Session session = token.OpenSession(Session.CKF_SERIAL_SESSION, null, null);
    
                // Executes the login passing the user PIN
                int nRes = session.Login(Session.CKU_USER, "secret");
                if (nRes != 0)
                {
                    Console.WriteLine("Wrong PIN");
                    return;
                }
    
                CSignWithPKCS11SC.Smartcardsign(session, "PhilippEggerQualifiedSignature", "SwissSign_nonRep                ");
    
                /*
                CryptokiCollection template = new CryptokiCollection();
                template.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_CERTIFICATE));
                template.Add(new ObjectAttribute(ObjectAttribute.CKA_CERTIFICATE_TYPE, Certificate.CKC_X_509));
    
                CryptokiCollection objects = session.Objects.Find(template, 10);
    
                // If the private keys is found continue
                if (objects.Count > 0)
                {
                    foreach (Object obj in objects)
                    {
                        Cryptware.NCryptoki.X509Certificate cert = (Cryptware.NCryptoki.X509Certificate)obj;
                        Console.WriteLine(cert.Label + " - " + cert.ID);
                    }
                }
                */
    
                // Logouts and closes the session
                session.Logout();
                session.Close();
                cryptoki.Finalize(IntPtr.Zero);
    
                Console.ReadLine();
            }
        }
    
        class CryptokiPrivateKeySignature : IExternalSignature
        {
            private readonly Cryptware.NCryptoki.Session session;
            RSAPrivateKey privateKey;
    
            public CryptokiPrivateKeySignature(Session session, String alias)
            {
                this.session = session;
                CryptokiCollection template = new CryptokiCollection();
                template.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_PRIVATE_KEY));
                template.Add(new ObjectAttribute(ObjectAttribute.CKA_KEY_TYPE, Key.CKK_RSA));
                // "SwissSign_nonRep                "
                // "SwissSign_digSig                "
                template.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, alias));
    
                /*
                CryptokiCollection objects = session.Objects.Find(template, 10);
                if (objects.Count > 0)
                {
                    foreach (Object obj in objects)
                    {
                        RSAPrivateKey cert = (RSAPrivateKey)obj;
                        Console.WriteLine(cert.Label);
                    }
                }
                */
    
                privateKey = (RSAPrivateKey)session.Objects.Find(template);
            }
    
            public String GetHashAlgorithm()
            {
                return "SHA1";
            }
    
            public String GetEncryptionAlgorithm()
            {
                return "RSA";
            }
    
            public byte[] Sign(byte[] message)
            {
                session.SignInit(Mechanism.SHA1_RSA_PKCS, privateKey);
                return session.Sign(message);
            }
        }
    
        class CSignWithPKCS11SC
        {
            public const String SRC = @"C:\Temp\test_to_sign.pdf";
            public const String DEST = @"C:\Temp\test_to_sign-pkcs11.pdf";
            //public const String DLL = "c:/windows/system32/beidpkcs11.dll";
            public const String DLL = "c:/windows/system32/cvP11.dll";
    
            public void Sign(String src, String dest, ICollection<Org.BouncyCastle.X509.X509Certificate> chain, Session session, String alias,
                             String digestAlgorithm, CryptoStandard subfilter, String reason, String location,
                             ICollection<ICrlClient> crlList, IOcspClient ocspClient, ITSAClient tsaClient, int estimatedSize)
            {
                // Creating the reader and the stamper
                PdfReader reader = null;
                PdfStamper stamper = null;
                FileStream os = null;
                try
                {
                    reader = new PdfReader(src);
                    os = new FileStream(dest, FileMode.Create);
                    stamper = PdfStamper.CreateSignature(reader, os, '\0');
                    // Creating the appearance
                    PdfSignatureAppearance appearance = stamper.SignatureAppearance;
                    appearance.Reason = reason;
                    appearance.Location = location;
                    appearance.SetVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
                    // Creating the signature
                    IExternalSignature pks = new CryptokiPrivateKeySignature(session, alias);
                    MakeSignature.SignDetached(appearance, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
                }
                finally
                {
                    if (reader != null)
                        reader.Close();
                    if (stamper != null)
                        stamper.Close();
                    if (os != null)
                        os.Close();
                }
            }
    
    
            public static void Smartcardsign(Session session, String alias, String aliasPrivateKey)
            {
                // Searchs for an RSA certificate object
                // Sets the template with its attributes
                CryptokiCollection template = new CryptokiCollection();
                template.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_CERTIFICATE));
                template.Add(new ObjectAttribute(ObjectAttribute.CKA_CERTIFICATE_TYPE, Certificate.CKC_X_509));
                template.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, alias));
    
                Cryptware.NCryptoki.X509Certificate nCert = (Cryptware.NCryptoki.X509Certificate)session.Objects.Find(template);
    
                if (nCert != null)
                {
    
                    X509Certificate2 cert = Utils.ConvertCertificate(nCert);
                    ICollection<Org.BouncyCastle.X509.X509Certificate> chain = new List<Org.BouncyCastle.X509.X509Certificate>();
                    X509Chain x509chain = new X509Chain();
                    x509chain.Build(cert);
    
                    foreach (X509ChainElement x509ChainElement in x509chain.ChainElements)
                    {
                        chain.Add(DotNetUtilities.FromX509Certificate(x509ChainElement.Certificate));
                    }
    
                    IOcspClient ocspClient = new OcspClientBouncyCastle();
                    List<ICrlClient> crlList = new List<ICrlClient>();
                    crlList.Add(new CrlClientOnline(chain));
                    TSAClientBouncyCastle tsaClient = new TSAClientBouncyCastle("http://tsa.swisssign.net");
    
                    CSignWithPKCS11SC app = new CSignWithPKCS11SC();
    
                    Console.WriteLine("Logged in? " + session.IsLoggedIn);
    
                    app.Sign(SRC, DEST, chain, session, aliasPrivateKey, DigestAlgorithms.SHA256, CryptoStandard.CMS,
                            "Test", "Rheinau", crlList, ocspClient, tsaClient, 0);
                }
                else
                {
                    Console.WriteLine("Certificate not found: " + alias);
                }
            }
        }
    }