.NET 署名付き XML プレフィックス
-
23-08-2019 - |
質問
署名付き XML ドキュメント (.Net の SignedXml クラス) の署名にプレフィックスを設定する方法はありますか?
したがって、代わりに:
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#>
...
</Signature>
次のようにすることができます。
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#>
...
</ds:Signature>
解決
まず第一に、実際にこれを行うには何らかの正当な理由がありません。 2つの形式は機能的に同等です。どれ行儀XMLプロセッサは絶対に同じようにそれらを処理します。あなたが適切にXML名前空間を実装していないアプリケーションに話をしようとしている場合を除きだから、それは言葉だけでデフォルトのフォームを残すために(IMO)方が良いでしょう。 (そして、その場合でも、それがすべてで可能な場合は、代わりに固定障害のあるアプリケーションを取得するために、より良いでしょう。)
あなたは手動でこのようにXPathを使用してSignedXml.GetXml(によって返されるのXmlElementのプレフィックス)とその子要素を設定することができ、言った:
XmlElement signature = signedXml.GetXml();
foreach (XmlNode node in signature.SelectNodes(
"descendant-or-self::*[namespace-uri()='http://www.w3.org/2000/09/xmldsig#']"))
{
node.Prefix = "ds";
}
他のヒント
これは、実行することはできません。あなたがXMLを変更した場合、それはを署名した後、の上記の例ではケースだった、検証することができない場合があります。 IMOこれは、あなたが一緒に暮らす必要がありますMSFTのデジタル署名の実装に欠陥がある。
多くの人がこれを行う理由はないと言うだろう、と彼らは技術的に正しいです。あなたは巨大なベンダー(すなわち、州政府や銀行)を扱っているときには、幸運は、彼らの最後にそれを変更してもらいます。ほとんどのリファレンス実装は、それが含まれます。
UPDATE:署名サインSignedInfoエレメント内のすべてを、あなたは事実の後、その要素を更新して行くので、もし、その後、署名が有効でなくなりました。あなたはメッセージで「改ざん」きます。
これは可能ですが、SignedInfo ノードのダイジェスト値を取得する前に、SignedXml クラスを変更してプレフィックスを追加する必要があります。
ComputeSignature メソッドは、prefix パラメーターを追加するように変更されます。
public void ComputeSignature(string prefix){...}
このメソッドが呼び出されると、SignedInfo ノードの値をダイジェストして署名値を計算します。「ds」プレフィックスなしでこの値を取得してプレフィックスを追加すると、無効な署名が取得されるため、プレフィックスを追加する必要があります。 signedinfo ノードのダイジェスト値を取得する前。
このダイジェスト値は GetC14NDigest メソッドで生成されるため、このメソッドはプレフィックス パラメーターを追加し、ダイジェスト値を取得する前にプレフィックスを追加するように変更されます。
private byte[] GetC14NDigest(HashAlgorithm hash, string prefix)
{
XmlDocument document = new XmlDocument();
document.PreserveWhitespace = false;
XmlElement e = this.SignedInfo.GetXml(); //get the signedinfo nodes
document.AppendChild(document.ImportNode(e, true));
Transform canonicalizationMethodObject = this.SignedInfo.CanonicalizationMethodObject;
SetPrefix(prefix, document.DocumentElement); /*Set the prefix before getting the HASH*/
canonicalizationMethodObject.LoadInput(document);
return canonicalizationMethodObject.GetDigestedOutput(hash);
}
OK、これで、「ds」プレフィックスが付いた SignedInfo ノードの署名値が得られました。ただし、プレフィックス付きの XML はまだないので、GetXml メソッドを呼び出すだけで、プレフィックスなしで XML を取得できます。もちろん、署名値は ds プレフィックスを考慮して計算されているため、無効な署名になります。これを回避してプレフィックス付きの XML 構造を取得するには、GetXml メソッドを変更し、プレフィックス パラメーターを追加して、署名 XML 内のすべてのノードに "ds" プレフィックスを追加する SetPrefix メソッドを呼び出す必要があります。
public XmlElement GetXml(string prefix)
{
XmlElement e = this.GetXml();
SetPrefix(prefix, e); //return the xml structure with the prefix
return e;
}
これらの変更を加えたクラスをここに残しておきます
カスタムクラス
internal sealed class CustomSignedXml : SignedXml
{
XmlElement obj = null;
public CustomSignedXml (XmlDocument xml)
: base(xml)
{
}
public CustomSignedXml (XmlElement xmlElement)
: base(xmlElement)
{
}
public XmlElement GetXml(string prefix)
{
XmlElement e = this.GetXml();
SetPrefix(prefix, e);
return e;
}
public void ComputeSignature(string prefix)
{
this.BuildDigestedReferences();
AsymmetricAlgorithm signingKey = this.SigningKey;
if (signingKey == null)
{
throw new CryptographicException("Cryptography_Xml_LoadKeyFailed");
}
if (this.SignedInfo.SignatureMethod == null)
{
if (!(signingKey is DSA))
{
if (!(signingKey is RSA))
{
throw new CryptographicException("Cryptography_Xml_CreatedKeyFailed");
}
if (this.SignedInfo.SignatureMethod == null)
{
this.SignedInfo.SignatureMethod = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
}
}
else
{
this.SignedInfo.SignatureMethod = "http://www.w3.org/2000/09/xmldsig#dsa-sha1";
}
}
SignatureDescription description = CryptoConfig.CreateFromName(this.SignedInfo.SignatureMethod) as SignatureDescription;
if (description == null)
{
throw new CryptographicException("Cryptography_Xml_SignatureDescriptionNotCreated");
}
HashAlgorithm hash = description.CreateDigest();
if (hash == null)
{
throw new CryptographicException("Cryptography_Xml_CreateHashAlgorithmFailed");
}
this.GetC14NDigest(hash, prefix);
this.m_signature.SignatureValue = description.CreateFormatter(signingKey).CreateSignature(hash);
}
private byte[] GetC14NDigest(HashAlgorithm hash, string prefix)
{
XmlDocument document = new XmlDocument();
document.PreserveWhitespace = false;
XmlElement e = this.SignedInfo.GetXml();
document.AppendChild(document.ImportNode(e, true));
Transform canonicalizationMethodObject = this.SignedInfo.CanonicalizationMethodObject;
SetPrefix(prefix, document.DocumentElement); //Set the prefix before getting the HASH
canonicalizationMethodObject.LoadInput(document);
return canonicalizationMethodObject.GetDigestedOutput(hash);
}
private void BuildDigestedReferences()
{
Type t = typeof(SignedXml);
MethodInfo m = t.GetMethod("BuildDigestedReferences", BindingFlags.NonPublic | BindingFlags.Instance);
m.Invoke(this, new object[] { });
}
private void SetPrefix(string prefix, XmlNode node)
{
foreach (XmlNode n in node.ChildNodes)
SetPrefix(prefix, n);
node.Prefix = prefix;
}
}
そして、その使い方は、
CustomSignedXml signedXml = new CustomSignedXml();
.
.//your code
.
//compute the signature with the "ds" prefix
signedXml.ComputeSignature("ds");
//get the xml of the signature with the "ds" prefix
XmlElement xmlDigitalSignature = signedXml.GetXml("ds");