signedxml checksignatureはfalseを返します
-
30-09-2019 - |
質問
私はこの問題に関してここで他の投稿を見ましたが、それらのどれも私の状況に対処していないようです。
私は先週、SAMLの主張を検証しようとしてきましたが、SAMLを送ってくれた2人のクライアントがいますが、検証することはできません。
主なプロセスは、base64エンコードされたアサーションを取得し、それをデコードすることです。 preservewhitespace = trueを使用してxmldocmentにロードします。
検証方法はです
public static bool Verify(X509Certificate2 cert, XmlElement xmlElement, SignedXml signedXml)
{
bool flag;
try
{
KeyInfo keyInfo = new KeyInfo();
var clause = new KeyInfoX509Data(cert);
keyInfo.AddClause(clause);
XmlElement signatureElement = GetSignatureElement(xmlElement);
if (signatureElement == null)
{
string message = "The XML does not contain a signature.";
throw new SAMLSignatureException(message);
}
signedXml.LoadXml(signatureElement);
if (keyInfo != null)
{
signedXml.KeyInfo = keyInfo;
}
SetSigningKeyFromKeyInfo(signedXml);
flag = signedXml.CheckSignature(cert.PublicKey.Key);
}
catch (Exception exception)
{
throw new SAMLSignatureException("Failed to verify the XML signature.", exception);
}
return flag;
}
private static void SetSigningKeyFromKeyInfo(SignedXml signedXml)
{
IEnumerator enumerator = signedXml.KeyInfo.GetEnumerator();
while (enumerator.MoveNext())
{
if (enumerator.Current is KeyInfoX509Data)
{
var current = (KeyInfoX509Data) enumerator.Current;
if (current.Certificates.Count != 0)
{
var certificate = (X509Certificate) current.Certificates[0];
var certificate2 = new X509Certificate2(certificate);
AsymmetricAlgorithm key = certificate2.PublicKey.Key;
signedXml.SigningKey = key;
return;
}
}
else
{
if (enumerator.Current is RSAKeyValue)
{
var value2 = (RSAKeyValue) enumerator.Current;
signedXml.SigningKey = value2.Key;
return;
}
if (enumerator.Current is DSAKeyValue)
{
var value3 = (DSAKeyValue) enumerator.Current;
signedXml.SigningKey = value3.Key;
return;
}
}
}
throw new SAMLSignatureException("No signing key could be found in the key info.");
}
web.config(base64エンコード文字列として保存されている)から読んだクライアントからの証明書を持っていますxmlelementは署名された要素であり、signedxmlはsignedxmlオブジェクトです。
どちらのクライアントもChecksignatureによって虚偽を返されますが、証明書で自分の署名されたSAMLを作成すると、Trueが返されます。
ここに何が欠けていますか?
編集:はい、両方のクライアントがJavaに参加しているので、SetSigingKeyFromKeyInfoメソッドを投稿しました
解決
私は過去に署名されたXMLの多くを扱いました。私が言えるのは、それが悪夢だったということだけです。基本的に、XMLに署名すると、Canonicalization(C14N)と呼ばれるプロセスを通過します。 XMLテキストを署名できるバイトストリームに変換する必要があります。 XML C14N標準のWhitespace&Namepaceの処理は、理解するのが難しく、正しく実装するのがさらに難しいです。 C14Nには複数のタイプがあります。
.NET実装は、それが受け入れるものについて非常に選択的です。他の実装が.NETのものとまったく同じ方法で機能しない可能性は非常に高いです。これは確かにとても悲しいです。たとえば、署名する前に、ソースXMLからホワイトスペースと名前空間を排除できる場合、それは役立ちます。また、両方の実装が同じC14N設定を使用していることを確認できる場合。
そうでなければ、多くのデバッグがあなたを待っています。フレームワークにデバッグするか、内部メソッドを反射して手作業で呼び出して、XMLフラグメントと署名をどのように計算するかを確認できます。また、他の実装でも同じことを行います。基本的に、両方の場合に署名されている正確なバイトストリームを確認する必要があります。これは、署名前の変換の最後のステップです。これらのバイトストリームが一致する場合、RSAの署名部品に私の経験に問題はありません。あなたの場合のように、それらが一致しない場合、少なくとも問題がどこにあるかがわかります。
他のヒント
私は同様の問題を抱えていて、多くの時間を失いました。おそらくこれは誰かを助けることができます。
私の環境は100%.NET 4.5で、コードはSignedXMLクラスのみを使用しています。しかし、SAMLの主張はある場所で受け入れられ、別の場所で拒否されました。
1つの場所が、で初期化されたXmldocumentインスタンスを介してアサーションをロードしていることが判明しました。 PreserveWhitespace = true
, 、もう1つはそうではありませんでした。
そして、このアサーションはかなり印刷されていたので、キャリッジリターンと多くのインデントスペースがありました。すべてのキャリッジリターンを削除すると、インデントスペースが私の問題を修正しました。
TimoresとしてSAMLと同様の問題がありました。 SAMLはbase64からデコードする必要がありましたが、最初に使用しました。
var saml = System.Text.Encoding.Default.GetString(Convert.FromBase64String(samlToken))
しかし、これはASCIIデコードを使用し、特殊文字に問題がありました。つまり、XMLは署名されたときとわずかに異なっていたため、失敗しました。それを変更しました:
var saml = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(samlToken))
そして、それはすべてのケースで機能しました。
正しいエンコードを使用していることを確認してください!