2014-04-30 19 views
9

Jedes Mal, wenn ich versuche, eine signierte XML zu senden, weist der Webdienst-Prüfer sie zurück.Signieren eines xml-Dokuments mit x509-Zertifikat

das Dokument unterzeichnen ich diesen Beispielcode nur angepasst von Microsoft:

http://msdn.microsoft.com/es-es/library/ms229745(v=vs.110).aspx

Meine Implementierung:

public static XmlDocument FirmarXML(XmlDocument xmlDoc) 
    { 
     try 
     { 
      X509Certificate2 myCert = null; 
      var store = new X509Store(StoreLocation.CurrentUser); //StoreLocation.LocalMachine fails too 
      store.Open(OpenFlags.ReadOnly); 
      var certificates = store.Certificates; 
      foreach (var certificate in certificates) 
      { 
       if (certificate.Subject.Contains("xxx")) 
       { 
        myCert = certificate; 
        break; 
       } 
      } 

      if (myCert != null) 
      { 
       RSA rsaKey = ((RSA)myCert.PrivateKey); 

       // Sign the XML document. 
       SignXml(xmlDoc, rsaKey);      
      } 

     } 
     catch (Exception e) 
     { 
      MessageBox.Show(e.Message); 
     } 
     return xmlDoc; 
    } 


    // Sign an XML file. 
    // This document cannot be verified unless the verifying 
    // code has the key with which it was signed. 
    public static void SignXml(XmlDocument xmlDoc, RSA Key) 
    { 
     // Check arguments. 
     if (xmlDoc == null) 
      throw new ArgumentException("xmlDoc"); 
     if (Key == null) 
      throw new ArgumentException("Key"); 

     // Create a SignedXml object. 
     SignedXml signedXml = new SignedXml(xmlDoc); 

     // Add the key to the SignedXml document. 
     signedXml.SigningKey = Key; 

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

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

     // 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(); 

     // Append the element to the XML document. 
     xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true)); 

    } 

Ich denke, dass ich die gleichen Schritte bin nach meinem eigenen Zertifikat, aber es funktioniert nicht wie erwartet.

Jeder Vorschlag ist willkommen.

Antwort

8

Woher weiß der Server, mit welchem ​​Zertifikat das Dokument signiert ist? Sie scheinen nicht das CERT in das signierte Dokument zu enthalten:

KeyInfo keyInfo = new KeyInfo(); 
    KeyInfoX509Data keyInfoData = new KeyInfoX509Data(Key); 
    keyInfo.AddClause(keyInfoData); 
    signedXml.KeyInfo = keyInfo; 

Wenn Sie weitere Informationen benötigen, wenden Sie meinen Blog-Eintrag

http://www.wiktorzychla.com/2012/12/interoperable-xml-digital-signatures-c_20.html

+0

Hallo Wiktor, dein Blog war sehr interessant und ich habe die Beispiele, die du zeigst, getestet. Leider habe ich immer noch das gleiche Problem, die Unterschrift wird abgelehnt. Ich werde mehr Informationen unten posten. –

3

ich bereits einige Änderungen vorgenommen die Proben des Wiktor folgen. Allerdings wird die Signatur vom Web-Service immer noch abgelehnt.

Die Methode, die ich jetzt signieren, ist dies:

public static string SignXml(XmlDocument Document, X509Certificate2 cert) 
{ 
    SignedXml signedXml = new SignedXml(Document); 
    signedXml.SigningKey = cert.PrivateKey; 

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

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

    return Document.OuterXml; 
} 

Und die Signatur erscheint wie dies in dem Dokument:

<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> 
     <KeyName>Public key of certificate</KeyName> 
     <KeyValue> 
      <RSAKeyValue> 
       <Modulus>0mmCc5Rlibh44o/C/k5....</Modulus> 
       <Exponent>AQAB</Exponent> 
      </RSAKeyValue> 
     </KeyValue> 
     <X509Data> 
      <X509Certificate>MIIF3jCCBUegAwIBAgIEPQa1....</X509Certificate> 
     </X509Data> 
    </KeyInfo> 
</Signature> 

Wenn ein richtiges Dokument an den Server gesendet wird, fungieren diese Renditen Diese Signatur, die ich verwendet habe, um die notwendigen Felder zu identifizieren:

<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 
    <ds:SignedInfo> 
     <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /> 
     <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /> 
     <ds:Reference URI=""> 
      <ds:Transforms> 
       <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> 
       <ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /> 
      </ds:Transforms> 
      <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> 
      <ds:DigestValue>nQOtmW194/aI+hedq+Dqp+n3IuU=</ds:DigestValue> 
     </ds:Reference> 
    </ds:SignedInfo> 
    <ds:SignatureValue>kyp+a6arETylW8ZuucKJyd....</ds:SignatureValue> 
    <ds:KeyInfo> 
     <ds:KeyName>Public key of certificate</ds:KeyName> 
     <ds:KeyValue> 
      <ds:RSAKeyValue> 
       <ds:Modulus>t0Yial28LxcIoPj16PlLIzaV...</ds:Modulus> 
       <ds:Exponent>AQAB</ds:Exponent> 
      </ds:RSAKeyValue> 
     </ds:KeyValue> 
     <ds:X509Data> 
      <ds:X509Certificate>MIIHOTCCBiGgAwIBAgICVJIwDQYJKo....</ds:X509Certificate> 
     </ds:X509Data> 
    </ds:KeyInfo> 
</ds:Signature> 

Es scheint mir Recht. Aber immer noch nicht funktionieren. Hat jemand eine Ahnung?

+0

Es gibt zwei mögliche Täter. Erstens wäre das eigentliche Zertifikat, aus irgendeinem Grund könnte es abgelehnt werden. Zweitens wäre die Art, wie Sie die XML senden, möglicherweise auf dem Weg zum Server geändert werden (Formatierung, Abstand, was auch immer). Wenn ich Sie wäre, würde ich einfach den Serveranbieter kontaktieren und sie fragen, was falsch ist. –

+0

Ich erkannte, dass es meine Schuld ist. Ich habe vor Ihrer Methode die Signatur nicht verifiziert. Jetzt habe ich es gemacht und ich werde immer "falsch". Dann ist der Fehler auf meiner Seite. Ich bin ziemlich verwirrt, da ich die Schritte in Ihrem Blog befolgt habe und auch ein paar mehr hinzugefügt habe, um das gleiche Format zu verwenden, das der Server bei der Annahme des Dokuments zurückgibt. Dies ist meine signierte Datei: http://tinyurl.com/lb5o6m9 Wie kann ich tun, um den falschen Wert zu finden? Vielen Dank im Voraus. –

+0

können Sie mir eine E-Mail mit Einzelheiten Ihrer Implementierung senden? Ich sehe den Web-Service als Täter, aber ich brauche sowohl den Server als auch den Client-Code, um Ihnen zu helfen. Ich sende auch unterschriebene Dokumente über http und ich habe keine Probleme. –