1

I have the following requirements from a 3rd party service that I'm using

Transactions dealing with personal information and other sensitive data use transport layer security protection. The web service message will be transported over https (HTTP over SSL) and must adhere to Web Service (WS)-Security v1.1 standard. The WS-Security section of the service message must:

  • Be signed with x.509 certificate using a 2048 bit key size
  • Use SHA2 with RSA algorithm for encryption
  • Use C14 canonicalization.

I managed to get my message signed with the following code

someServiceRef.widjetClient client = null;

try
{
    X509Certificate2 signingCert = GetSigningCert();
    var bindings = new BasicHttpsBinding();
    bindings.Security.Mode = BasicHttpsSecurityMode.TransportWithMessageCredential;
    bindings.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;

    client = new someServiceRef.widjetClient(
        bindings,
        new EndpointAddress(@"<URL OF SERVICE>"));

    client.ClientCredentials.ClientCertificate.Certificate = signingCert;
    client.ClientCredentials.ServiceCertificate.DefaultCertificate = signingCert;

    client.Open();

    var request = BuildRequest();

    var response = client.SayHello(request);

    Console.WriteLine(response);
}
finally
{
    if (client != null)
    {
        if (client.State == System.ServiceModel.CommunicationState.Faulted)
            client.Abort();
        else
            client.Close();
    }
}

The problem is that my message is being signed with sha1 instead of sha2. I'm trying to sign my message properly but the examples I found online have you generate the soap message then manually modify it with XML parsing and adding new nodes. I don't understand these examples and I'm trying to figure out a way to tell the service to do it for me. I have a sample of what the request signature should look like from the 3rd party below. I don't see anything in the client or binding class that would allow me to change things like the signature algorithm. How would I go about doing this?

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header>
        <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" SOAP-ENV:mustUnderstand="1">
            <wsse:BinarySecurityToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="XWSSGID-12324774331131695995061">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</wsse:BinarySecurityToken>
            <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <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-sha2" />
                    <ds:Reference URI="#XWSSGID-1232477437326-1352495766">
                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha2" />
                        <ds:DigestValue>XXXXXXXXXXXXXXXXXXXXXX</ds:DigestValue>
                    </ds:Reference>
                    <ds:Reference URI="#XWSSGID-1232477437326-823787906">
                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha2" />
                        <ds:DigestValue>XXXXXXXXXXXXXXXXXXXXX</ds:DigestValue>
                    </ds:Reference>
                </ds:SignedInfo>
                <ds:SignatureValue>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</ds:SignatureValue>
                <ds:KeyInfo>
                    <wsse:SecurityTokenReference xmlns:wsse="http://www.w3.org/2000/09/xmldsig#" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsse:Id="XWSSGID-1232477437311698965010">
                        <wsse:Reference URI="#XWSSGID-12324774331131695995061" />
                        <ds:X509Data>
                            <ds:X509IssuerName>XXXXXXXXXXXXXXXXXXXXXXXXX</ds:X509IssuerName>
                            <ds:X509SerialNumber>XXXXXXXXXXXXXXXXXXX</ds:X509SerialNumber>
                        </ds:X509Data>
                    </wsse:SecurityTokenReference>
                </ds:KeyInfo>
            </ds:Signature>
            <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="XWSSGID-1232477437326-823787906">
                <wsu:Created>2009-01-20T18:50:37.233Z</wsu:Created>
                <wsu:Expires>2009-01-20T18:50:42.233Z</wsu:Expires>
            </wsu:Timestamp>
        </wsse:Security>
    </SOAP-ENV:Header>
    <SOAP-ENV:Body xmlns:SOAP-ENV="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="XWSSGID-1232477437326-1352495766">
        BODY OF MESSAGE GOES HERE
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
scottDeveloper
  • 159
  • 2
  • 17
  • Sha2 is 256 SHA. So use following : https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.sha256?redirectedfrom=MSDN&view=net-5.0 – jdweng Dec 11 '20 at 16:28
  • This doesn't answer my question. Where in the creation of the service or binding would I do something like this? The example you posted is just computing the hash of a file – scottDeveloper Dec 11 '20 at 16:35
  • The default version of sha (sh1 or sha 256) depends on version of Net. See following : https://learn.microsoft.com/en-us/dotnet/framework/migration-guide/retargeting/4.5.1-4.7.2 – jdweng Dec 11 '20 at 16:35
  • This may help you:https://social.msdn.microsoft.com/Forums/vstudio/en-US/8b149878-f9a2-44e3-afd4-68884b02e129/algorithm-suite-wcf-ws-security?forum=wcf – Theobald Du Dec 14 '20 at 09:35
  • @TheobaldDu yes that was part of it. I figured it out like 2 days ago. I'll post a solution – scottDeveloper Dec 15 '20 at 15:46

1 Answers1

0

Got it working here is the final solution

someServiceRef.widjetClient client = null;

try
{
    X509Certificate2 signingCert = GetSigningCert();
    var bindings = new BasicHttpsBinding();
    bindings.Security.Mode = BasicHttpsSecurityMode.TransportWithMessageCredential;
    bindings.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;
    bindings.Security.Message.AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256

    var elements = bindings.CreateBindingElements();
    elements.Find<SecurityBindingElement>().EnableUnsecuredResponse = true;
    var customBindings = new CustomBinding(elements);

    client = new someServiceRef.widjetClient(
        customBindings,
        new EndpointAddress(@"<URL OF SERVICE>"));

    client.ClientCredentials.ClientCertificate.Certificate = signingCert;
    client.ClientCredentials.ServiceCertificate.DefaultCertificate = signingCert;

    client.Open();

    var request = BuildRequest();

    var response = client.SayHello(request);

    Console.WriteLine(response);
}
finally
{
    if (client != null)
    {
        if (client.State == System.ServiceModel.CommunicationState.Faulted)
            client.Abort();
        else
            client.Close();
    }
}
scottDeveloper
  • 159
  • 2
  • 17