2016-03-28 99 views
1

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

enter image description here

不过,我真的不理解这个概念,例如这个怎么做。我读了几个网站,例如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个引用的签名信息?

正如你所看到的,我错过了一些一般的背景和理解。如果你能帮我解决问题,那真的很酷!

谢谢

回答

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模板整个签名节点。

--Keeping记住,SignedXml会给你的结构,现在我会回答你的问题

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

签名值是在计算签名时计算的,您不必亲自计算签名。

当您调用ComputeSignature方法时,它所做的就是使用SignedInfo节点并对其进行消化。你引用此节点里面,所以你会得到包含所有引用

这是ComputeSignature方法是如何得到的SignedInfo节点的摘要值,使用该值它计算签名值的信息签名值:

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