سؤال

لقد نظرت إلى منشورات أخرى هنا فيما يتعلق بهذه القضية ويبدو أن أيًا منهم يعالج وضعي.

لقد كنت أحاول التحقق من تأكيد SAML خلال الأسبوع الماضي ولدي عميلان أرسلوا لي Saml لكن لا يمكنني التحقق منه.

العملية الرئيسية هي أننا نحصل على تأكيد مشفر BASE64 ونفكها. قم بتحميله في XMLDocment مع PreserveWhiteSpace = true.

طريقة التحقق هي

  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 تم إنشاؤه باستخدام signedxml جديد (xmlelement)

يتم إرجاع كلا العميلين عن طريق checksiscishature ، ولكن عندما أقوم بإنشاء SAML الموقّع الخاص بي مع شهادتي ، ستعود بشكل صحيح.

ماذا أفتقد هنا؟

تحرير: نعم كلا العملاء على جافا ونشرت طريقة setSigningKeyFromKeyInfo

هل كانت مفيدة؟

المحلول

لقد تعاملت مع موقع XML كثيرًا في الماضي. كل ما يمكنني قوله هو أنه كان كابوسًا. في الأساس ، عندما تقوم بتوقيع XML ، فإنه يمر بعملية تسمى الكنسي (C14N). يحتاج إلى تحويل نص XML إلى دفق بايت يمكن توقيعه. من الصعب فهم معايير مساحة المساحة البيضاء والمساحة ، من بين أمور أخرى ، في معايير XML C14N ، حتى من الصعب تنفيذها بشكل صحيح. هناك حتى أنواع متعددة من C14N.

تنفيذ .NET انتقائي للغاية حول ما يقبله. من الممكن تمامًا أن يكون تطبيقك الآخر لا يعمل بنفس الطريقة التي يعمل بها .NET One. وهذا أمر محزن جدا في الواقع. إذا تمكنت من التخلص من مساحات المساحة البيضاء ومساحات الأسماء من المصدر XML قبل التوقيع ، على سبيل المثال ، قد يساعد ذلك. أيضًا إذا كان بإمكانك التأكد من أن كلا التنفيذيين يستخدمان نفس إعدادات C14N.

وإلا فإن الكثير من التصحيح ينتظرك. يمكنك التصحيح في الإطار ، أو استدعاء أساليبها الداخلية باليد مع التفكير ، لمعرفة كيف يحسب جزء XML والتوقيع. وفعل الشيء نفسه مع التنفيذ الآخر. تحتاج بشكل أساسي إلى رؤية تدفقات البايت الدقيقة التي يتم توقيعها في كلتا الحالتين. هذه هي الخطوة الأخيرة من التحويل قبل التوقيع. إذا كانت هذه البايت تتطابق مع تدفقات البايت ، فلن تواجه أي مشاكل مع جزء توقيع RSA في تجربتي. إذا لم يتطابق هؤلاء ، كما هو الحال في حالتك ، فسترى على الأقل مكان المشكلة.

نصائح أخرى

لقد واجهت مشكلة مماثلة وفقدت الكثير من الوقت ، ربما يمكن أن يساعد هذا شخصًا ما.

بيئتي هي 100 ٪ .NET 4.5 ، ويستخدم الكود الخاص بي فقط فئة SignedXML. ولكن تم قبول تأكيد SAML في مكان واحد ورفض في آخر.

تبين أن مكانًا واحدًا كان يقوم بتحميل التأكيد من خلال مثيل XMLDOCUMIT PreserveWhitespace = true, ، في حين أن الآخر لم يكن.

وكان التأكيد مطبوعًا تمامًا ، لذلك كان له عائدات النقل والكثير من مساحات المسافة البادئة. إزالة جميع عوائد النقل ومساحات المسافة البادئة إصلاح مشكلتي.

كان لديه مشكلة مماثلة مع SAML كما Timores. يجب فك تشفير SAML من BASE64 ولكن أولاً استخدمت:

var saml = System.Text.Encoding.Default.GetString(Convert.FromBase64String(samlToken))

ولكن هذا يستخدم فك تشفير ASCII وكان لديه مشكلة مع الشخصيات الخاصة. مما يعني أن XML كان مختلفًا قليلاً عن الوقت الذي تم فيه توقيعه وهذا هو السبب في فشله. غيرته إلى:

var saml = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(samlToken))

وعملت لجميع الحالات.

لذا تأكد من أنك تستخدم الترميز الصحيح!

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top