简体   繁体   中英

WCF Client consuming WS-Security webservice

I managed to consume a java based web service (third party) with WS-Security 1.1 protocol. The web service needs only to be signed over a x509 certificate, not encrypted. But I'm getting this error:

The signature confirmation elements cannot occur after the primary signature.

The captured server response package looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Header>
        <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="true">
            <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="Signature-501">
                <ds:SignedInfo>
                    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
                    <ds:Reference URI="#id-502">
                        <ds:Transforms>
                            <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                        </ds:Transforms>
                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                        <ds:DigestValue>...</ds:DigestValue>
                    </ds:Reference>
                    <ds:Reference URI="#SigConf-500">
                        <ds:Transforms>
                            <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                        </ds:Transforms>
                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                        <ds:DigestValue>...</ds:DigestValue>
                    </ds:Reference>
                </ds:SignedInfo>
                <ds:SignatureValue>
                ...
                </ds:SignatureValue>
                <ds:KeyInfo Id="KeyId-...">
                    <wsse:SecurityTokenReference xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="STRId-...">
                        <ds:X509Data>
                            <ds:X509IssuerSerial>
                                <ds:X509IssuerName>CN=COMODO RSA Organization Validation Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB</ds:X509IssuerName>

                                <ds:X509SerialNumber>...</ds:X509SerialNumber>
                            </ds:X509IssuerSerial>
                        </ds:X509Data>
                    </wsse:SecurityTokenReference>
                </ds:KeyInfo>
            </ds:Signature>
            <wsse11:SignatureConfirmation xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" Value="..." wsu:Id="SigConf-500"/>
        </wsse:Security>
    </soapenv:Header>
    <soapenv:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id-502">
        <altaClienteResponse xmlns="...">
            <altaClienteReturn>
                <codigoError>7</codigoError>
                <descripcionError>El código de banco no es válido.</descripcionError>
                <idTransaccion xsi:nil="true"/>
            </altaClienteReturn>
        </altaClienteResponse>
    </soapenv:Body>
</soapenv:Envelope>

The server is responding what it should but my app seems not to be interpreting it correctly. It seems that the <wsse11:SignatureConfirmation .../> tag must be before <ds:Signature></ds:Signature> tag.

I couldn't find any reference to a order standard of this.

EDIT: Adding my code.

try
{
    var certificate = new X509Certificate2(@"C:\Users\...\cert.pfx", PassKeyStore);

    var binding = new CustomBinding();

    var security = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateDuplexBindingElement(MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10);

    security.EndpointSupportingTokenParameters.Signed.Add(new X509SecurityTokenParameters
    {
        InclusionMode = SecurityTokenInclusionMode.Never,
        ReferenceStyle = SecurityTokenReferenceStyle.Internal,
    });

    security.RecipientTokenParameters.InclusionMode = SecurityTokenInclusionMode.Never;
    security.RecipientTokenParameters.ReferenceStyle = SecurityTokenReferenceStyle.Internal;

    security.MessageSecurityVersion =
        MessageSecurityVersion.
            WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;
    security.IncludeTimestamp = false;
    security.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.EncryptBeforeSign;    

    security.RequireSignatureConfirmation = true;
    security.AllowSerializedSigningTokenOnReply = true;   

    binding.Elements.Add(security);
    binding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8));
    binding.Elements.Add(new HttpsTransportBindingElement());    

    var client = new SistarbancService.WsMediosPagoClient(binding, new EndpointAddress(new Uri(UrlSistarbanc), new DnsEndpointIdentity("..."), new AddressHeaderCollection()));    

    client.ClientCredentials.ServiceCertificate.DefaultCertificate = new X509Certificate2("C:\\Users\\...\\servidor.cer");
    client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
        System.ServiceModel.Security.X509CertificateValidationMode.None;
    client.ClientCredentials.ClientCertificate.Certificate = certificate;

    client.Endpoint.Contract.ProtectionLevel = System.Net.Security.ProtectionLevel.Sign;

    var response = await client.altaClienteAsync("XXX", "0", "0", "0", "0", "0");
}
catch (Exception ex)
{

}

The exception is thrown by the ReceiveSecurityHeader class - see the source code of it here: https://referencesource.microsoft.com/#system.servicemodel/system/servicemodel/Security/ReceiveSecurityHeader.cs

Search for SignatureConfirmationsOccursAfterPrimarySignature and see this line:

    if (this.orderTracker.PrimarySignatureDone)
    {
        throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.SignatureConfirmationsOccursAfterPrimarySignature)), this.Message);
    }

I can't find any references to any kind of standard supporting this either...

You might be better off asking this question to Microsoft.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM