Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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)
{

}
like image 972
Gonzalo Lorieto Avatar asked Jul 25 '18 16:07

Gonzalo Lorieto


1 Answers

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.

like image 116
Sangman Avatar answered Oct 22 '22 01:10

Sangman