2016-03-28 8 views
1

Я новичок в C# и особенно новичок в подписи с X509. У меня есть шаблон xml, в котором я должен добавить используемый сертификат (сделанный) и подписать метку времени (TS-1), двоичный маркер безопасности и тело (id-1). Кроме того, мне нужно написать (например, заменить заполнители) значением дайджеста этих трех элементов и добавить значение подписи.Как подписать xml с сертификатом X509, добавить значение дайджеста и подпись к шаблону 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