3

私は政府機関に XML メッセージを送信する作業を行っています (その政府機関の仕様を使用しているため、結果の XML がどのように見える必要があるかを制御することはできません)。開発には C# を使用しています (会社のポリシー)。

C# とインターネット テクノロジに関して私よりもはるかに優れている 2 人が、私より前に XML をレビューし、WCF は XML ドキュメントの署名を生成するために必要なメソッドをサポートしないことを知らせてくれました (これは少し安心しました。私は WCF プロジェクトを開発したことがなく、WCF が成熟した Web テクノロジであることを理解しているため、恐ろしいことです)。

そのため、LINQ to XML と System.Xml の組み合わせを使用してメッセージを生成し、署名を試みました。

以下は、XML の一部を抜粋したサンプルです。

<soapenv:Envelope 
  xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
  xmlns:soap-sec="http://schemas.xmlsoap.org/security/2000-12" 
  xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy" 
  xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
  xmlns:cns="http://customNamespace1.com" 
  xmlns:cnt="http://customNamespace2.com" 
  >
  <soapenv:Header>
    <ns2:Element1 xmlns:ns2="http://namespace2.element1.com" wsu:Id="id-1">
      ...
    </ns2:Element1>
    <ns2:Element2 xmlns:ns2="http://namespace2.element2.com/" wsu:Id="id-2">
      ...
    </ns2:Element2>
    <wsse:Security SOAP-ENV:mustUnderstand="1" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
      <wsu:Timestamp wsu:Id="id-3">
        ...
      </wsu:Timestamp>
      <wsse:UsernameToken wsu:Id="id-4">
        ...
      </wsse:UsernameToken>
      <wsse:BinarySecurityToken ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-5bf699c7-5336-4695-b395-88d2b984fe54" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
        ...
      </wsse:BinarySecurityToken>
      <ds:Signature Id="SIG-6" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
          <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
            <ec:InclusiveNamespaces PrefixList="SOAP-ENV cnt soap-sec soapenv sp cns wsdl wsp wsse wsu xs xsi" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" />
          </ds:CanonicalizationMethod>
          <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
          <ds:Reference URI="#id-1">
            <ds:Transforms>
              <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                <ec:InclusiveNamespaces PrefixList="SOAP-ENV cnt soap-sec soapenv sp cns wsdl wsp wsse wsu xs xsi" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" />
              </ds:Transform>
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
            <ds:DigestValue>...</ds:DigestValue>
          </ds:Reference>
          <ds:Reference URI="#id-2">
            <ds:Transforms>
              <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                <ec:InclusiveNamespaces PrefixList="SOAP-ENV cnt soap-sec soapenv sp cns wsdl wsp wsse wsu xs xsi" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" />
              </ds:Transform>
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
            <ds:DigestValue>...</ds:DigestValue>
          </ds:Reference>
          <ds:Reference URI="#id-3">
            <ds:Transforms>
              <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                <ec:InclusiveNamespaces PrefixList="SOAP-ENV cnt soap-sec soapenv sp cns wsdl wsp wsse xs xsi" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" />
              </ds:Transform>
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
            <ds:DigestValue>...</ds:DigestValue>
          </ds:Reference>
          <ds:Reference URI="#id-4">
            <ds:Transforms>
              <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                <ec:InclusiveNamespaces PrefixList="SOAP-ENV cnt soap-sec soapenv sp cns wsdl wsp wsu xs xsi" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" />
              </ds:Transform>
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
            <ds:DigestValue>...</ds:DigestValue>
          </ds:Reference>
          <ds:Reference URI="#id-5">
            <ds:Transforms>
              <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                <ec:InclusiveNamespaces PrefixList="SOAP-ENV cnt soap-sec sp cns wsdl wsp wsse wsu xs xsi" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" />
              </ds:Transform>
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
            <ds:DigestValue>...</ds:DigestValue>
          </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>
          ...
        </ds:SignatureValue>
        <ds:KeyInfo Id="KI-ABDCFEC7595B7819C213402151542862">
          <wsse:SecurityTokenReference wsu:Id="STR-ABDCFEC7595B7819C213402151542863">
            <wsse:Reference URI="#SecurityToken-5bf699c7-5336-4695-b395-88d2b984fe54" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" />
          </wsse:SecurityTokenReference>
        </ds:KeyInfo>
      </ds:Signature>
    </wsse:Security>
  </soapenv:Header>
  <soapenv:Body wsu:Id="id-5">
    <ns5:bodyelement xmlns:ns4="http://namespace4.com/" xmlns:ns3="http://namespace3.com/" xmlns:ns2="http://bodynamespace2.com/" xmlns:ns5="http://namespace5.com/">
      ...
    </ns5:bodyelement>
  </soapenv:Body>
</soapenv:Envelope>

私が試したコードの一部を次に示します (uri フラグメントを機能させるための 3 つの異なる方法)。適切な XML を生成するのに 200 行以上のコードが必要だったので、ここにコードの一部のみを投稿します。現在、署名を試みています。

RSACryptoServiceProvider rsacsp = (RSACryptoServiceProvider)Key;
SignedXml xmlWSig = new SignedXml(myDoc);
xmlWSig.SigningKey = Key;
xmlWSig.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
XmlDsigExcC14NTransform canMethod = (XmlDsigExcC14NTransform)xmlWSig.SignedInfo.CanonicalizationMethodObject;
canMethod.InclusiveNamespacesPrefixList = "SOAP-ENV cns soap-sec soapenv sp cnt wsdl wsp wsse wsu xs xsi";

Uri uri = new Uri("#id-1");
Reference ref1 = new Reference(uri.ToString());
XmlDsigExcC14NTransform transform1 = new XmlDsigExcC14NTransform("SOAP-ENV cns soap-sec soapenv sp cnt wsdl wsp wsse wsu xs xsi");
ref1.AddTransform(transform1);
ref1.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
xmlWSig.AddReference(ref1);

Reference ref2 = new Reference("#id-2"); 
XmlDsigExcC14NTransform transform2 = new XmlDsigExcC14NTransform("SOAP-ENV cns soap-sec soapenv sp cnt wsdl wsp wsse wsu xs xsi");
ref2.AddTransform(transform2);
ref2.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
xmlWSig.AddReference(ref2);

Reference ref3 = new Reference("");  
ref3.Uri = "#id-3";
XmlDsigExcC14NTransform transform3 = new XmlDsigExcC14NTransform("SOAP-ENV cns soap-sec soapenv sp cnt wsdl wsp wsse xs xsi");
ref3.AddTransform(transform3);
ref3.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
xmlWSig.AddReference(ref3);

//repeat things for id-4, and id-5

KeyInfo myKeyInfo = new KeyInfo();
myKeyInfo.AddClause(new RSAKeyValue((RSA)Key));
xmlWSig.KeyInfo = myKeyInfo;

xmlWSig.ComputeSignature();
XmlElement signedXmlElement = xmlWSig.GetXml();

Key は、X509 証明書から取得した秘密鍵です (ドキュメントに署名するための鍵として使用する必要があります)。myDoc は、署名を挿入するために生成した System.Xml XmlDocument です。

方法 #1 System.UriFormatException: 無効な URI: URI の形式を特定できませんでした。

方法 #2 System.Security.Cryptography.CryptograpicException: Malformed reference element が返されます (Uri から # を削除すると、System.UriFormatException: Invalid URI: The URI is empty が返されます)。

方法 3 では、方法 2 と同じエラーが発生します。

署名に Uris を使用することに関するすべてのドキュメントから、Uri Fragment のみを使用することが許可されています (参照されている要素が同じドキュメント内にあると仮定して) が、C# の Uri クラスは Fragments を受け入れ可能な Uri として受け入れないようです。

Reference クラスも、Fragment だけでなく、完全な Uri を必要としているようです。

仕様を使用して、この XML で署名を適切に生成する方法についての提案をお待ちしています。

更新: SignedXml + 参照 + 変換が最適なソリューションのように思えますが、.NET にはこれらのライブラリに大きなギャップがあると考え始めており、署名を生成するためにいくつかの下位レベルのライブラリにドロップダウンする可能性があります。必要。

残念ながら、私はまだどのライブラリが必要か、そして署名が必要なものを見つけるためのアルゴリズムを判断しようとして苦労しています。Exclusive Canonicalization についての私の理解では、InclusiveNamespaces PrefixList にリストされているプレフィックスによって指定された要素にのみ署名していたが、参照の URI は署名が必要なサブドキュメントを指定しているが、指定された要素内の要素は署名されていないということでした。含まれている名前空間のほとんどを使用しないでください。これらのリファレンスが機能する方法を理解していますか?

4

2 に答える 2

1

URI + 包括的名前空間を自分で実行するアルゴリズムを複製し (それがどのように機能するかを理解する必要があります)、それらの要素をバイト配列に変換する必要があるようです。次に、署名用に下位レベルのライブラリを使用します。

このようなもの:

RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey;
signedMessage = rsa.SignData(originalMessage, CryptoConfig.MapNameToOID("SHA1"));

次に、signedMessage を Base64 文字列に変換し、適切なダイジェスト値のそれぞれに挿入できます。

思っていたよりもはるかに多くの作業が必要でしたが、.NET が URI フラグメントをサポートしていない場合は、やらなければならないことをしなければならないと思います。

このソリューションは複雑であるため、誰かがよりスムーズなものを持っている場合、私は間違いなく代替案を受け入れます。

編集:正規化のドキュメントに数時間注ぎ込んだ後、排他的な正規化は、署名するためにXMLをリッピングするときにXMLに挿入する名前空間に関するものであるように見えます。名前空間が直接使用されておらず、包括的な名前空間プレフィックス リストに含まれていない場合は、署名する前に、署名する要素にその名前空間を追加しません。XML のより完全なコンテキスト内の要素にその名前空間を必ずしも必要としないため、これは私にはまだ奇妙に思えます。それに署名すると、変更できないことを意味しますが、それを含めていません。

更新: 何時間ものテストの後、ついにこれが機能するようになりました。しかし、それには非常に恐ろしいコードがたくさんありました。基本的に、サインアウトする各要素のコピーを取得し、その要素に含まれていた名前空間を手動で更新し、そこからハッシュを生成する必要がありました (この時点でより完全な変換を実行することを含みます)。しかし、それはうまくいきました。

于 2013-11-07T14:55:14.503 に答える