【问题标题】:How to sign xml with X509 cert, add digest value and signature to xml template如何使用 X509 证书对 xml 进行签名,将摘要值和签名添加到 xml 模板
【发布时间】:2016-03-28 13:42:51
【问题描述】:

我对 C# 非常陌生,尤其是对使用 X509 进行签名的新手。我有一个 xml 模板,我必须在其中添加使用的证书(完成)并签署时间戳(TS-1)、二进制安全令牌和正文(id-1)。 此外,我需要用这 3 个元素的摘要值编写(例如替换占位符)并添加签名值。

但是,我并不真正理解这个概念,例如这个怎么做。我读了几个网站,例如signing a xml document with x509 certificate 但我无法根据我的问题调整代码。

这是我尝试过的:

public static string SignXml(string template)
{

    XmlDocument document = new XmlDocument();
    document.LoadXml(template);

        // define elements that will be signed
        XmlNode securityToken = null;
        XmlNode validityPeriod = null;
        XmlNode body = null;
        XmlNode signedInfo = null;
        XmlNode signatureValue = null;
        XmlNodeList digestTags = null;



        XmlNamespaceManager namespaces = new XmlNamespaceManager(document.NameTable);
        namespaces.AddNamespace("ns", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
        namespaces.AddNamespace("nu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
        namespaces.AddNamespace("bo", "http://schemas.xmlsoap.org/soap/envelope/");
        namespaces.AddNamespace("si", "http://www.w3.org/2000/09/xmldsig#");
        namespaces.AddNamespace("sinfo", "soapenv xd xe");

        document.LoadXml(template);
        //XmlNode idNode = document.SelectSingleNode("/My_RootNode/ns:id", namespaces);

        securityToken = document.SelectSingleNode("descendant::ns:BinarySecurityToken", namespaces);
        validityPeriod = document.SelectSingleNode("descendant::nu:Timestamp", namespaces);
        body = document.SelectSingleNode("descendant::bo:Body", namespaces);
        signedInfo = document.SelectSingleNode("descendant::si:SignedInfo", namespaces);
        signatureValue = document.SelectSingleNode("descendant::si::sinfo:SignatureValue", namespaces);
        digestTags = document.SelectNodes("descendant::si:DigestValue", namespaces);

        // add the digests (to know where to write the digests)
        String nodeName = null;
        for (int counter = 0; counter < digestTags.Count; counter++)
        {
            nodeName = digestTags[counter].FirstChild.InnerText;
            if (WebserviceConstants.PLACEHOLDER_AUTHNREQUEST_DIGEST.Equals(nodeName))
            {

                generateDigest(body, digestTags[counter]);
            }
            else if (WebserviceConstants.PLACEHOLDER_CERTIFICATE_DIGEST.Equals(nodeName))
            {

                generateDigest(securityToken, digestTags[counter]);
            }
            else if (WebserviceConstants.PLACEHOLDER_TIMESTAMP_TAG_DIGEST.Equals(nodeName))
            {

                generateDigest(validityPeriod, digestTags[counter]);
            }
        }



        SignedXml signedXml = new SignedXml(document);



    X509Certificate2 cert = new X509Certificate2();
    cert = getbase();

    signedXml.SigningKey = cert.PrivateKey;

    // Create a reference to be signed.
    Reference reference = new Reference();
    reference.Uri = "#TS-1";

    // Add an enveloped transformation to the reference.            
    XmlDsigEnvelopedSignatureTransform env =
       new XmlDsigEnvelopedSignatureTransform(true);
    reference.AddTransform(env);

    //canonicalize
    XmlDsigC14NTransform c14t = new XmlDsigC14NTransform();
    reference.AddTransform(c14t);

    KeyInfo keyInfo = new KeyInfo();
    KeyInfoX509Data keyInfoData = new KeyInfoX509Data(cert);
    KeyInfoName kin = new KeyInfoName();
    kin.Value = "Public key of certificate";
    RSACryptoServiceProvider rsaprovider = (RSACryptoServiceProvider)cert.PublicKey.Key;
    RSAKeyValue rkv = new RSAKeyValue(rsaprovider);
    keyInfo.AddClause(kin);
    keyInfo.AddClause(rkv);
    keyInfo.AddClause(keyInfoData);
    signedXml.KeyInfo = keyInfo;

    // Add the reference to the SignedXml object.
    signedXml.AddReference(reference);

    // Compute the signature.
    signedXml.ComputeSignature();

    // Get the XML representation of the signature and save 
    // it to an XmlElement object.
    XmlElement xmlDigitalSignature = signedXml.GetXml();

    document.DocumentElement.AppendChild(
    document.ImportNode(xmlDigitalSignature, true));
    document.DocumentElement.AppendChild(document.ImportNode(xmlDigitalSignature, true));

        return document.OuterXml;
    }
}

我在质疑自己:

  • 如何获取摘要值以及如何将其写入对应的xml节点
  • 如何计算签名值,因为它“包含”所有 3 个引用的签名信息???

如您所见,我缺少一些一般背景和理解。如果你能帮助我,那就太好了!

谢谢

【问题讨论】:

    标签: c# xml x509 sign digest


    【解决方案1】:

    您不必手动创建签名节点,在计算签名后调用 GetXml 方法(您已经在执行此操作:signedXml.GetXml()),这将返回如下内容:

    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
      <SignedInfo>
        <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
        <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
        <Reference URI="">
            <Transforms>
                <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
                <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
            <DigestValue>zRSPtja5EtX7hVbyJ11EjoYTRDk=</DigestValue>
        </Reference>
      </SignedInfo>
      <SignatureValue>Ua1/WP28WzfXaxUj....</SignatureValue>
      <KeyInfo>        
        <X509Data>
            <X509Certificate>MIIF3jCCBUegAwIBAgIEPQa1....</X509Certificate>
        </X509Data>
      </KeyInfo>
    </Signature>
    

    那么您只需替换 xml 模板上的整个签名节点。

    --请记住,SignedXml 将为您提供该结构,现在我将回答您的问题

    您的第一个问题是关于您的参考文献的摘要值吗?如果是这样,当您调用 ComputeSignature 方法时,它将计算它并将其添加到相应的 xml 节点。

    签名值是在计算签名时计算出来的,不必自己计算。

    当您调用 ComputeSignature 方法时,它所做的是获取 SignedInfo 节点并对其进行消化。您的引用在此节点内,因此您将获得包含所有引用信息的签名值

    这是 ComputeSignature 方法获取签名信息节点的摘要值的方式,使用该值计算签名值:

    XmlElement e = this.SignedInfo.GetXml(); //get the signedinfo nodes
    document.AppendChild(document.ImportNode(e, true));
    Transform canonicalizationMethodObject=this.SignedInfo.CanonicalizationMethodObject;
    canonicalizationMethodObject.LoadInput(document);
    canonicalizationMethodObject.GetDigestedOutput(hash); //digest the signedinfo node
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-06
      • 1970-01-01
      • 2022-07-16
      • 1970-01-01
      • 1970-01-01
      • 2010-10-04
      • 1970-01-01
      • 2015-03-03
      相关资源
      最近更新 更多