locked
The operation was canceled by the user in an application that uses digital signature under IIS RRS feed

  • Question

  • The idea of the web app is to sign documents with a digital signature that is loaded from a smart card.

    It is published and set to work on a local user machine. I am using IIS for that matter to set the bindings and enable to accept client certificates.

    It communicates with a web app that is hosted on the cloud.

    I am successfully getting the certificate from the smart card and the private key as well.

    I use the private key to sign the document.

     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;
        }

    It works fine on Release/Debug but not in Publish. It gets a popup, asks for a PIN and once the PIN has been entered the docs are signed.

    It gets to the signedxml.ComputeSignature and it returns an error :

    The operation was canceled by the user.

    Here is the exception that has been thrown :

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

    The only way I get the same error on release/debug is if I cancel the window which asks for a PIN.

    It  is an IIS setting and a permission issue, but I have tried various things to no avail. The certificate can be found if I require SSL on Client Side is ticked and set it to Accept as in the image :

    I have also tried exporting the private key which I saw on various posts, however, because it is a smart card I am unable to export the Private Key, I can only use it which is what I am doing with my code.

    I also tried to run the same app from the .exe which succesfully digitally signs the xml but the window won't even open and asks for the user pin.

    • Moved by CoolDadTx Monday, December 9, 2019 4:23 PM ASP.NET related
    Monday, December 9, 2019 12:01 PM

All replies

  • Please post questions related to IIS and web development in the ASP.NET forums.

    Michael Taylor http://www.michaeltaylorp3.net

    Monday, December 9, 2019 4:23 PM