Ошибка проверки основной подписи - PullRequest
1 голос
/ 23 августа 2011

Я разработал клиент WCF.net, который отправляет SOAP-запрос поставщику.Чтобы соответствовать требованиям безопасности WS поставщика, я должен создать настраиваемый заголовок SOAP и отправить запрос с настраиваемым заголовком в веб-службу на стороне поставщика.Поэтому я создал собственный заголовок, реализовав новый класс, извлеченный из MessageHeader (см. Ниже)

public class SignOnlyMessageHeader : MessageHeader
{
    private const string PREFIX_CP = "wsse";

    public string m_Username { get; set; }
    public string m_Envelope { get; set; }

    public SignOnlyMessageHeader(string Username, string Envelope)
    {
        m_Username = Username;
        m_Envelope = Envelope;
    }

    public override string Name
    {
        get { return "wsse:Security"; }
    }

    public override string Namespace
    {
        get { return null; }
    }

    public override bool MustUnderstand
    {
        get
        {
            return false;
        }
    }

    protected override void OnWriteStartHeader(XmlDictionaryWriter writer, MessageVersion messageVersion)
    {
        base.OnWriteStartHeader(writer, messageVersion);
        writer.WriteXmlnsAttribute(PREFIX_CP, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
    }

    protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
    {
        writer.WriteStartElement(PREFIX_CP, "UsernameToken", null);
        writer.WriteAttributeString("wsu:Id", "UsernameToken-20");
        writer.WriteXmlnsAttribute("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
        writer.WriteElementString(PREFIX_CP, "Username", null, m_Username);
        writer.WriteEndElement();
        SignXmlFile(writer);
    }

    public void SignXmlFile(XmlDictionaryWriter writer)
    {
        string certificatePath = "C:\\Users\\22428-cert.p12";
        System.Security.Cryptography.X509Certificates.X509Certificate2 cert = new X509Certificate2(certificatePath, "changeit");

        // Create a new XML document.
        XmlDocument doc = new XmlDocument();

        // Format the document to ignore white spaces.
        doc.PreserveWhitespace = false;
        doc.LoadXml(m_Envelope);

        // Create a SignedXml object.
        SignedXml signedXml = new SignedXml(doc);

        // Add the key to the SignedXml document. 
        //signedXml.SigningKey = Key;
        signedXml.SigningKey = cert.PrivateKey;

        // Create a new KeyInfo object.
        KeyInfo keyInfo = new KeyInfo();
        keyInfo.Id = "";

        // Load the certificate into a KeyInfoX509Data object
        // and add it to the KeyInfo object.
        KeyInfoX509Data keyInfoData = new KeyInfoX509Data();
        keyInfoData.AddCertificate(cert);
        keyInfo.AddClause(keyInfoData);
        // Add the KeyInfo object to the SignedXml object.
        signedXml.KeyInfo = keyInfo;

        signedXml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/2001/10/xml-exc-c14n#";

        // Create a reference to be signed.
        Reference reference = new Reference();
        reference.Uri = "";

        // Add an enveloped transformation to the reference.
        XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
        reference.AddTransform(env);
        reference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";

        // Add the reference to the SignedXml object.
        signedXml.AddReference(reference);
        signedXml.Signature.Id = "";

        // Compute the signature.
        signedXml.ComputeSignature();

        // Get the XML representation of the signature and save
        // it to an XmlElement object.
        XmlElement xmlDigitalSignature = signedXml.GetXml();

        // Check the signature and return the result.
        if (!signedXml.CheckSignature(new X509Certificate2(certificatePath, "changeit"), true))
        {
            Console.WriteLine("invalid signature");
        }

        xmlDigitalSignature.WriteTo(writer);
    }

Так что после создания пользовательского класса заголовка я переопределил метод IClientMessageInspector.BeforeSendRequest, чтобы перехватить исходящий запрос и добавить свойПользовательский заголовок для запроса мыла.См. Код ниже:

    object IClientMessageInspector.BeforeSendRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel)
    {
        request.Headers.RemoveAt(0);
        SignOnlyMessageHeader header = new SignOnlyMessageHeader("x509user", env);
        request.Headers.Add(header);
        return null;
    }

В результате я перехватываю запрос SOAP и правильно заменяю текущий заголовок настраиваемым заголовком.Перед отправкой запроса я проверил обновленный запрос SOAP (установил точку останова), структура ТОЧНО совпадает с запросом поставщика.Но я получаю сообщение об ошибке после обработки запроса на стороне поставщика.Он только говорит «Подпись не прошла проверку ядра».Я думаю, что я правильно подписываю весь конверт в методе "SignXmlFile".Я даже проверил валидность в методе (если (! SignatureXml.CheckSignature (новый X509Certificate2 (certificatePath, "changeit"), true))), оператор возвращает false, что указывает на действительность подписи.

Что такоеЯ делаю не так?

1 Ответ

0 голосов
/ 04 сентября 2011

Ну, я пытался и пытался, что-то с тем, как я перехватываю заголовок и после того, как я вставляю заголовок с подписью ... проверка не проходит. В качестве обходного пути я удалил весь заголовок из моего .net-клиента. Я направляю свой запрос только с мылом baod на XML-шлюз, мы настроили шлюз для перехвата запроса и добавления необходимого заголовка init и перенаправления запроса внешнему поставщику. Это сработало.

...