سؤال

هل هناك طريقة لتعيين البادئة على توقيع مستند XML الموقع (فئة SignedXML في .NET)؟

لذلك بدلا من:

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#>
...
</Signature>

يمكن أن يكون ما يلي:

<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#>
...
</ds:Signature>
هل كانت مفيدة؟

المحلول

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

ومع ذلك، يمكنك ضبط البادئة يدويا على XMLELELEMENT التي يتم إرجاعها بواسطة SignedXml.getXML () وعناصر الأطفال باستخدام XPath مثل هذا:

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 الذي سيتعين عليك التعايش معه.

سيقول الكثير من الناس أنه لا يوجد سبب للقيام بذلك، وهم صحيحون تقنيا. ولكن عندما تتعامل مع بائع ضخمة (أي حكومة حكومية أو بنك دولة)، حظا سعيدا في حملها لتغييره في نهايتها. معظم التطبيقات المرجعية تشمل ذلك.

تحديث: علامات التوقيع كل شيء في عنصر SignedInfo، لذلك إذا ذهبت في تحديث هذا العنصر بعد الحقيقة، فلن يكون التوقيع صالحا. لديك "العبث" بالرسالة.

يمكن القيام به، ولكن من الضروري تعديل فئة SignedXML لإضافة البادئة قبل الحصول على قيمة هضم عقدة SignedInfo.

سيتم تعديل طريقة ComputeSignature لإضافة معلمة البادئة

public void ComputeSignature(string prefix){...}

عندما تسمى هذه الطريقة التي تسمى هذه الطريقة بحساب قيمة التوقيع عن طريق هضم قيمة عقدة SignedInfo، إذا تلقيت هذه القيمة دون بادئة "DS"، ثم قم بإضافة البادئة، ستحصل على توقيع غير صالح، لذلك سيتعين عليك إضافة البادئة قبل الحصول على قيمة هضم العقدة SignedInfo.

يتم إنشاء قيمة Digest هذه في الطريقة 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);
}

حسنا، حتى الآن لديك قيمة توقيع لعقد SignedInfo مع بادئة "DS"، التي تقول أنك لا تزال لا تملك XML مع البادئة حتى الآن، لذلك إذا قمت فقط باستدعاء طريقة GetXML، فستحصل على XML بدون البادئة وبالطبع لأن قيمة التوقيع تم حسابها بالنظر إلى بادئة DS سيكون لديك توقيع غير صالح. لتجنب ذلك واحصل على بنية XML مع البادئة، يجب عليك تعديل أسلوب GetXML، وأضف معلمة البادئة، واستدعاء طريقة SETPREFIX WITH ستضيف بادئة "DS" لجميع العقد في XML التوقيع

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");
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top