2016-03-28 24 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