首页 > 解决方案 > 用户在使用数字签名的应用程序中取消了操作

问题描述

的想法web app是使用digital signaturesmart card.

它已发布并设置为在local user机器上工作。我正在IIS为此设置bindings并启用接受client certificates

它与web app托管在cloud.

我也成功地certificate从 thesmart card和 theprivate key中得到了。

我用private key来签署文件。

 private InvoiceResult SignDocument(XmlDocument doc)
    {
        InvoiceResult resultValue;

        try
        {
            var (resultValue2, certificate) = GetDefaultCertificateStoredOnTheCard();
            resultValue = resultValue2;
            SignXmlDocumentWithCertificate(doc, certificate);

            resultValue = InvoiceResult.Success;
        }
        catch (Exception ex)
        {
            _log.TraceInformation($"Error when compute signature and it is : {ex.Message}");
            _log.TraceInformation($"Additional info => stack trace : {ex.StackTrace}");

            resultValue = InvoiceResult.CannotSignXmlFiles;
        }
        return resultValue;
    }


 public (InvoiceResult resultValue, X509Certificate2 cert) GetDefaultCertificateStoredOnTheCard()
    {

        var resultValue = InvoiceResult.Success;

        using X509Store x509Store = new X509Store(StoreName.My, StoreLocation.CurrentUser);

        X509Store store = x509Store;
        store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

        X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindByTimeValid, DateTime.Now, true);

        certs = certs.Find(X509FindType.FindByThumbprint, Settings.Default.Thumbprint, true);


        if (certs.Count == 0)
        {
            resultValue = InvoiceResult.CannotFindSignature;
        }
        X509Certificate2 cert = certs[0];
        if (cert.HasPrivateKey)
        {
            // software cert
            _ = cert.PrivateKey as RSACryptoServiceProvider;

        }
        else
        {
            // certificate from smartcard
            CspParameters csp = new CspParameters(1, "Microsoft Base Smart Card Crypto Provider")
            {
                Flags = CspProviderFlags.UseDefaultKeyContainer
            };
            _ = new RSACryptoServiceProvider(csp);
        }


        return (resultValue, cert);
    }

    private InvoiceResult SignXmlDocumentWithCertificate(XmlDocument xmlDoc, X509Certificate2 cert)
    {
        InvoiceResult resultValue = InvoiceResult.Success;

        SignedXml signedXml = new SignedXml(xmlDoc)
        {
            //we will sign it with private key
            SigningKey = cert.PrivateKey
        };

        if (cert.PrivateKey == null)
        {
            resultValue = InvoiceResult.CannotSignXmlFiles;

            //   throw new ArgumentException("Please make sure the application for electronic signatures is installed, so the private key can be obtained from the smart card!");
        }


        Reference reference = new Reference
        {
            //sign the entire doc
            Uri = ""
        };
        XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
        reference.AddTransform(env);
        signedXml.AddReference(reference);

        //PublicKey part
        RSACryptoServiceProvider rsaprovider = (RSACryptoServiceProvider)cert.PublicKey.Key;
        RSAKeyValue rkv = new RSAKeyValue(rsaprovider);

        KeyInfo keyInfo = new KeyInfo();
        keyInfo.AddClause(new KeyInfoX509Data(cert));
        //We add the public key here
        keyInfo.AddClause(rkv);

        signedXml.KeyInfo = keyInfo;
        _log.TraceInformation($"Cert has private key or not? {cert.HasPrivateKey}");

        signedXml.ComputeSignature();

        // Get the XML representation of the signature and save
        // it to an XmlElement object.
        _log.TraceInformation($"It computes the signature succesfully");

        XmlElement xmlDigitalSignature = signedXml.GetXml();

        // Append the element to the XML document.
        xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));

        _log.TraceInformation($"It appends the signature succesfully");


        return resultValue;
    }

它可以正常工作,Release/Debug但不能在Publish. 它得到 a popup,要求 aPIN并且一旦PIN输入了文档就会被签名。

它到达signedxml.ComputeSignature并返回一个错误:

该操作已被用户取消。

这是已引发的异常:

System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr) 在 System.Security.Cryptography.Utils.SignValue(SafeKeyHandle hKey, Int32 keyNumber, Int32 calgKey, Int32 calgHash, Byte[] hash, Int32 cbHash, ObjectHandleOnStack retSignature) 在系统。 Security.Cryptography.Utils.SignValue(SafeKeyHandle hKey, Int32 keyNumber, Int32 calgKey, Int32 calgHash, Byte[] hash) 在 System.Security.Cryptography.RSACryptoServiceProvider.SignHash(Byte[] rgbHash, Int32 calgHash) 在 System.Security.Cryptography .Xml.SignedXml.ComputeSignature()

出现此错误的唯一方法release/debug是取消要求PIN. 是否有另一种方法来计算signature并将其应用于XML?这是迄今为止我能找到的唯一一个。

它可能是一个IIS设置,但我尝试了各种方法都无济于事。如果我需要勾选,则可以找到证书并将其设置为SSL如图所示:Client SideAccept

在此处输入图像描述

我也尝试导出private key我在各种帖子上看到的,但是,因为它是smart card我无法导出的Private Key,我只能使用它,这就是我对我的代码所做的。

一旦我启动应用程序的这一部分,它最初会询问certificatePIN并返回​​相同的错误。在随后的尝试中,它从不要求PINcertificate

标签: c#certificateprivate-key

解决方案


将应用程序池标识更改为 Windows 帐户


推荐阅读