.NET XAdES签名引发加密异常

qojgxg4l  于 2023-01-22  发布在  .NET
关注(0)|答案(1)|浏览(175)

我正在尝试使用XAdES对XML进行签名,证书存储在智能卡上。
首先,值得一提的是,当我用添加到智能卡的软件签署同一个XML文档时,操作没有任何问题。
代码如下:

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

在执行到达AddSignatureToDocument()方法中的line _xadesSignedXml.ComputeSignature()之前,一切正常。
系统要求提供智能卡PIN QSCD,然后ComputeSignature()抛出CryptographicException(),并显示HRESULT -2146435068(0x 80100004)和消息“无法正确解释一个或多个提供的参数”。
下面是调用堆栈:

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()
f8rj6qna

f8rj6qna1#

所以我找到了解决办法:xadesSignedXml元素的xadesSignedXml.SignedInfo.SignatureMethod属性为空,而xadesSignedXml.SigningKey.SignatureAlgorithm属性被自动设置为“http://www.w3.org/2000/09/xmldsig#rsa-sha1“。
xadesSignedXml.ComputeSignature()正在执行时,并且xadesSignedXml.SignedInfo.SignatureMethod为空,则将xadesSignedXml.SigningKey.SignatureAlgorithm的值分配给它。
出现此问题是因为签名是使用SHA-1执行的,而Microsoft不再支持SHA-1。
通过在AddReference()方法中添加xadesSignedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";解决了问题。

相关问题