简体   繁体   中英

.NET XAdES Signing throws CryptographicException

I'm trying to sign XML with XAdES with certificate stored on Smart Card.

First of all, it is worth to mention, that when I'm signing the same XML document with software added to this smart card, operation goes without any problem.

Here is code:

public class XadesWrapper
{
    private X509Certificate2 _certificate;
    private X509Chain _chain;
    private XmlDocument _envelopedSignatureXmlDocument;
    private XadesSignedXml _xadesSignedXml;
    private int _docDataObjectCounter;
    public byte[] _signedDoc;

    public XadesWrapper(XmlDocument xmlDoc, X509Certificate2 xCert)
    {
        try
        {
            _envelopedSignatureXmlDocument = xmlDoc;
            _certificate = xCert;   //certificate installed from smart card
            AddReference();
            CheckCertificate();
            AddKeyInfo();
            AddObjectInfo();
            AddSignatureToDocument();
        }
        catch (Exception e)
        {
            throw e;
        }
    }

    private void AddReference()
    {
        Reference reference = new Reference();
        _docDataObjectCounter = 1;

        _xadesSignedXml = new XadesSignedXml(_envelopedSignatureXmlDocument);
        _xadesSignedXml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/2001/10/xml-exc-c14n#";

        reference.Id = "r-id-" + _docDataObjectCounter;
        reference.Uri = "";
        reference.Type = "";
        reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());

        _xadesSignedXml.AddReference(reference);
    }

    private void CheckCertificate()
    {
        if (_certificate == null)
            return;

        _chain = new X509Chain();
        _chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
        _chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
        _chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 0, 30);
        _chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
        if (_chain.Build(_certificate) == true)
            AddKeyInfo();
        else
        {
            _certificate = null;
            _chain = null;
            throw new ArgumentException("Chain is not valid.");
        }
    }

    private void AddKeyInfo()
    {
        RSACryptoServiceProvider rsaKey = (RSACryptoServiceProvider)_certificate.PrivateKey;
        _xadesSignedXml.SigningKey = rsaKey;

        KeyInfo keyInfo = new KeyInfo();
        keyInfo.AddClause(new KeyInfoX509Data(_certificate));
        keyInfo.AddClause(new RSAKeyValue(rsaKey));

        this._xadesSignedXml.KeyInfo = keyInfo;
    }

    private void AddObjectInfo()
    {
        _xadesSignedXml.Signature.Id = "id-" + _certificate.Thumbprint.ToLower();

        XadesObject xadesObject = new XadesObject();
        xadesObject.QualifyingProperties.Target = "#" + _xadesSignedXml.Signature.Id;
        xadesObject.QualifyingProperties.SignedProperties.Id = "xades-" + _xadesSignedXml.Signature.Id;

        Cert cert = new Cert();
        cert.IssuerSerial.X509IssuerName = this._certificate.IssuerName.Name;
        cert.IssuerSerial.X509SerialNumber = BigInteger.Parse(this._certificate.SerialNumber, NumberStyles.HexNumber).ToString();
        cert.CertDigest.DigestMethod.Algorithm = "http://www.w3.org/2001/04/xmlenc#sha256";
        cert.CertDigest.DigestValue = new SHA256CryptoServiceProvider().ComputeHash(_certificate.RawData);

        xadesObject.QualifyingProperties.SignedProperties.SignedSignatureProperties.SigningCertificate.CertCollection.Add(cert);
        xadesObject.QualifyingProperties.SignedProperties.SignedSignatureProperties.SigningTime = DateTime.Now;

        DataObjectFormat newDataObjectFormat = new DataObjectFormat();
        newDataObjectFormat.Description = "";
        newDataObjectFormat.MimeType = "text/xml";
        newDataObjectFormat.ObjectReferenceAttribute = "#r-id-" + _docDataObjectCounter;
        xadesObject.QualifyingProperties.SignedProperties.SignedDataObjectProperties.DataObjectFormatCollection.Add(newDataObjectFormat);

        _xadesSignedXml.AddXadesObject(xadesObject);
    }

    private void AddSignatureToDocument()
    {
        _xadesSignedXml.ComputeSignature();
        _xadesSignedXml.SignatureValueId = "value-" + _xadesSignedXml.Signature.Id;

        _envelopedSignatureXmlDocument.DocumentElement.AppendChild(_envelopedSignatureXmlDocument.ImportNode(_xadesSignedXml.GetXml(), true));

        _signedDoc = Encoding.UTF8.GetBytes(_envelopedSignatureXmlDocument.OuterXml);
    }
}

Everything goes well till execution reaches line _xadesSignedXml.ComputeSignature() in AddSignatureToDocument() method.

System is asking for smart card PIN QSCD, and then ComputeSignature() throws a CryptographicException() with HRESULT -2146435068 (0x80100004) and message "One or more of the supplied parameters could not be properly interpreted."

Here is call stack:

at 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.RSAPKCS1SignatureFormatter.CreateSignature(Byte[] rgbHash)
   at System.Security.Cryptography.AsymmetricSignatureFormatter.CreateSignature(HashAlgorithm hash)
   at Microsoft.Xades.XadesSignedXml.ComputeSignature()

So I've found the solution: xadesSignedXml element had xadesSignedXml.SignedInfo.SignatureMethod property null, while the xadesSignedXml.SigningKey.SignatureAlgorithm property was automatically set to "http://www.w3.org/2000/09/xmldsig#rsa-sha1".

While xadesSignedXml.ComputeSignature() is being executed, and xadesSignedXml.SignedInfo.SignatureMethod is null, then value of xadesSignedXml.SigningKey.SignatureAlgorithm is assigned to it.

The problem occurred because the signing was performed with SHA-1, which is no longer supported by Microsoft.

Problem was solved by adding xadesSignedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"; in AddReference() method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM