10

この問題に関する他の投稿を見てきましたが、私の状況に対処しているようには見えません。

先週、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(xmlElement) で作成された SignedXml オブジェクトです

どちらのクライアントも checksignature によって false が返されますが、証明書を使用して独自の署名付き saml を作成すると、true が返されます。

ここで何が欠けていますか?

編集: はい、両方のクライアントが Java 上にあり、SetSigningKeyFromKeyInfo メソッドを投稿しました

4

4 に答える 4

9

私はこれまで、署名付き XML を何度も扱ってきました。悪夢だったとしか言いようがない。基本的に、XML に署名すると、正規化 (C14N) と呼ばれるプロセスが行われます。XML テキストを署名可能なバイト ストリームに変換する必要があります。とりわけ、XML C14N 標準での空白と名前空間の処理は理解しにくく、正しく実装するのはさらに困難です。C14Nにも複数の種類があります。

.NET 実装は、受け入れるものについて非常に選択的です。他の実装が .NET の実装とまったく同じように機能しない可能性は十分にあります。これは実に悲しいことです。たとえば、署名する前にソース XML から空白と名前空間を削除できれば、それが役立つ可能性があります。また、両方の実装で同じ C14N 設定が使用されていることを確認できた場合。

そうしないと、多くのデバッグが待っています。フレームワークにデバッグするか、リフレクションを使用してその内部メソッドを手動で呼び出して、XML フラグメントと署名がどのように計算されるかを確認できます。他の実装でも同じことを行います。基本的に、両方のケースで署名されている正確なバイト ストリームを確認する必要があります。これは、署名前の変換の最終ステップです。これらのバイト ストリームが一致する場合、私の経験では RSA 署名部分に問題はありません。あなたの場合のように、それらが一致しない場合、少なくとも問題がどこにあるかがわかります。

于 2012-09-29T06:54:36.187 に答える