3

i'm not a WCF expert, and i know just the basics of service security, so maybe most of the things that i'll point out will be wrong. That said, i need to invoke a 3d party service that requires a specific format for the SOAP header. They require that the soap header provides: 1) timestamp block 2) Binary Token 3) digest (checksum of a part of data to encrypt)

They've provided me this exemple of request (i've removed the sensible parts)

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
  <S:Header>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
      <wsse:BinarySecurityToken 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#X509PKIPathv1"
                                wsu:Id="...omissis...">
      </wsse:BinarySecurityToken>

      <ds:Signature Id="SIG-6" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
          <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
            <ec:InclusiveNamespaces PrefixList="S" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
          </ds:CanonicalizationMethod>
          <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
          <ds:Reference URI="#TS-5">
            <ds:Transforms>
              <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                <ec:InclusiveNamespaces PrefixList="wsse S" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
              </ds:Transform>
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            <ds:DigestValue>...omissis...</ds:DigestValue>
          </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>
          ....
          ...omissis...
          ....
        </ds:SignatureValue>
        <ds:KeyInfo Id="KI-...omissis...">
          <wsse:SecurityTokenReference wsse11:TokenType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509PKIPathv1" wsu:Id="STR-...omissis..." xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd">
            <wsse:Reference URI="#X509-...omissis..." ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509PKIPathv1"/>
          </wsse:SecurityTokenReference>
        </ds:KeyInfo>
      </ds:Signature>
      <wsu:Timestamp wsu:Id="TS-5">
        <wsu:Created>2013-03-27T15:10:18.523Z</wsu:Created>
        <wsu:Expires>2013-03-27T15:26:58.523Z</wsu:Expires>
      </wsu:Timestamp>
    </wsse:Security>
  </S:Header>
<S:Body>
    ...clear (not encrypted) body of the soap request
</S:Body>
</S:Envelope>

They gave me also a WSDL and an xsd. What i've done was to create a new web application, using the wsdl as service reference. Checking the web.config, i can see that this have created a basicHttpBinding like this

<system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="CPBinding">
          <security mode="Transport" />
        </binding>
        <binding name="CPBinding1" />
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="https://...omissis"
        binding="basicHttpBinding" bindingConfiguration="CPBinding"
        contract="BTClient.CPCUVPortType" name="CPCUVPort" />
    </client>
  </system.serviceModel>

But this binding doesn't use any kind of security policy, so i've created a behaviour that takes into account the certificates (for a mutual certificate) like that

 <behaviors>
      <endpointBehaviors>
        <behavior name="CustomBehaviorForCertificates">
          <clientCredentials>
            <clientCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" findValue="...omissis..." />
            <serviceCertificate>
              <scopedCertificates>
                <add targetUri="https://...omissis..." storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindByThumbprint" findValue="...omissis..." />
              </scopedCertificates>
              <authentication certificateValidationMode="PeerTrust" revocationMode="NoCheck" />
            </serviceCertificate>
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>

And referenced this on the binding. By inspecting the outgoing messages (using the method BeforeSendRequest of a custom Inspector) i can see that it totally ignores the certificates, sending the same request as the without-behaviour one. The 3d party service answer to my request like 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">
      <wsu:Timestamp wsu:Id="Timestamp-..." xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <wsu:Created>2013-09-06T14:31:28Z</wsu:Created>
        <wsu:Expires>2013-09-06T14:36:28Z</wsu:Expires>
      </wsu:Timestamp>
      <wsse:BinarySecurityToken wsu:Id="SecurityToken-...." 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" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        ...omissis...
      </wsse:BinarySecurityToken>
      <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
        <SignedInfo>
          <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
          <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
          <Reference URI="#Timestamp-...">
            <Transforms>
              <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
            <DigestValue>...omissis...</DigestValue>
          </Reference>
        </SignedInfo>
        <SignatureValue>...omissis...</SignatureValue>
            <KeyInfo>
                <wsse:SecurityTokenReference xmlns="">
                    <wsse:Reference URI="#SecurityToken-...omissis..." ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" />
                </wsse:SecurityTokenReference>
            </KeyInfo>
        </Signature>
    </wsse:Security>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body wsu:Id="..." xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <SOAP-ENV:Fault>
      <faultcode>wsse:FailedCheck</faultcode>
      <faultstring>The signature or decryption was invalid</faultstring>
      <detail>
        <e:myfaultdetails xmlns:e="Some-URI">
          <errorCode>500</errorCode>
          <message>INTERNAL_SERVER_ERROR</message>
        </e:myfaultdetails>
      </detail>
    </SOAP-ENV:Fault>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

After doing some research i've read that to provide a BinarySecurityToken as requested i need to implement a customBinding. I've tried different approaches and combinations but i always fail to make progress.

For example, by using this custom behaviour:

  <customBinding>
    <binding name="cb">
      <security authenticationMode="MutualCertificateDuplex" requireDerivedKeys="false" includeTimestamp="true"
        messageProtectionOrder="EncryptBeforeSign" messageSecurityVersion="WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10" />
      <textMessageEncoding messageVersion="Soap11" />
      <httpsTransport />
    </binding>
  </customBinding>

I receive an Internal server error like this:

ExceptionType: System.ServiceModel.Security.MessageSecurityException: An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail.InnerException: System.ServiceModel.FaultException:Internal Error

and, most important...my outgoing request is ALWAYS the same as the basicHttpBinding one! Obviously i have not well understood something. I can see that, using the basicHttpBindig i can correctly communicate with them, but i fail to provide the required security fragments. If i try to use any other king of binding (for example wsHttpBinding or a customBinding) i receive an error message. Can someone please help me understanding the correct way to do such job? any help would be very appreciated.

Thanks a lot.

EDIT:

I'm adding the outgoing request:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
  <s:Header>
    <ActivityId CorrelationId="dd479557-7e51-41de-822b-d2ac669ff827" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">bbd2f92b-33d5-4ec0-87b6-690f2142cdf5</ActivityId>
    <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <u:Timestamp u:Id="uuid-7b22e181-f551-4821-91e0-cf8c9b8d9eef-1">
        <u:Created>2013-09-09T12:24:03.563Z</u:Created>
        <u:Expires>2013-09-09T12:29:03.563Z</u:Expires>
      </u:Timestamp>
      <o:BinarySecurityToken>
        <!-- Removed-->
      </o:BinarySecurityToken>
      <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
        <SignedInfo>
          <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod>
          <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod>
          <Reference URI="#_1">
            <Transforms>
              <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform>
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
            <DigestValue>...omissis...</DigestValue>
          </Reference>
          <Reference URI="#uuid-7b22e181-f551-4821-91e0-cf8c9b8d9eef-1">
            <Transforms>
              <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform>
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
            <DigestValue>...omissis...=</DigestValue>
          </Reference>
        </SignedInfo>
        <SignatureValue>...omissis...</SignatureValue>
        <KeyInfo>
          <o:SecurityTokenReference>
            <o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-e31a3eed-6ac7-4dcb-bfb2-2384764acd93-2"></o:Reference>
          </o:SecurityTokenReference>
        </KeyInfo>
      </Signature>
    </o:Security>
  </s:Header>
  <s:Body u:Id="_1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <CPCUValidityRequest xmlns="http://......omissis...">
      <serviceType>3</serviceType>
      <arg1>arg1</arg1>
      <arg2>arg2</arg2>
      ...omissis...
    </CPCUValidityRequest>
  </s:Body>
</s:Envelope>

Solution: Actually i can't successfully invoke the remote service due to an error (as stated in the comments to the accepted solution. But i can say that this question is answered due to the fact that i've managed to create a request mostly similar to the required one. Many thanks to Yaron.

PS:( An hint for those who will have a similar issue, to check the outgoing/incoming request, try to use the Microsoft Trace Viewer, enabling tracing as suggested in this answer https://stackoverflow.com/a/11678740/2274007 (remember to follow also the advice in the comment))

Community
  • 1
  • 1
Gnegno
  • 366
  • 1
  • 5
  • 15

2 Answers2

3

Please publish your outgoing request. In your binding I would change to authenticationMode="mutualCertificate". Otherwise it looks good.

Also in order to send just signed message and not encrypted one add this attribute on top of your data contract (reference.cs):

[System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReference1.SimpleServiceSoap", ProtectionLevel=System.Net.Security.ProtectionLevel.Sign)]

More details on this approach in this wcf security tips article.

Yaron Naveh
  • 23,560
  • 32
  • 103
  • 158
  • thanks for your answer, i've updated the question. I'll try your fixes and let you know as soon as i can. – Gnegno Sep 06 '13 at 15:23
  • I'm reading your blog post...it's truly awesome. Now i will finally manage to understand something...thanks =) – Gnegno Sep 06 '13 at 15:26
  • 1
    your outgoing request has no security in it. one option is that you tool the request from the wrong place in the wcf logs, before it is eecured. use Fiddler or take from transport stage at log. Another option is that your binding configuration is not applied on the endpoint, probably a config typo – Yaron Naveh Sep 06 '13 at 16:10
  • I've deleted my previous comment because i've successfully managed to read the secured outgoing request. I'm trying to analyze the differences to try to understand how to resolve it by myself (you've helped me already a lot, many thanks). In the meantime, i'll update my question with the correct outgoing request to help other people in my same situation. – Gnegno Sep 09 '13 at 09:02
  • After different tries trials and trials i've managed to create an almost identical request, but now i'm having this problem: The 'Body', 'http://schemas.xmlsoap.org/soap/envelope/' required message part was not signed...what does it means? (probably i have to create another question) – Gnegno Sep 09 '13 at 11:31
  • the questions is if this is an error the server returns or the server returns correct messgae and wcf throws this exception – Yaron Naveh Sep 09 '13 at 12:21
  • I can't say for sure. From the trace viewer I can see that the (secured) message that i receive contains this body (a SOAP-ENV:Failure) 500 INTERNAL_SERVER_ERROR But after receiving this message, i get a "Throwing an exception" event with the error message (The 'Body'...) followed by a Warning event stating that The security protocol cannot verify the incoming message. So it seems like the remote server is having a failure, but it's return message is not correctly recognized by my client. – Gnegno Sep 09 '13 at 12:36
  • the message you send (according your latest update) is different from the desired one. It still encrypts the request, make sure you apply the attribute as I suggested in my answer. You can apply it multiple times on multiple classes to make sure you cover it – Yaron Naveh Sep 09 '13 at 12:40
  • Sorry, i didn't updated the question with the latest result. Now i have a clear (unsigned) body and a correctly lax structure (i had an error caused by having my request with timestamp first and response with timestamp last). In a minute i will update the question. – Gnegno Sep 09 '13 at 12:42
  • the last update still has timestamp first. besdies that the main difference is that you sign the body and the real request does not, and that the real request use PrefixList. This is very hard to tune these two in WCF so I hope this is not the problem. Try to ask the service vendor for server logs. Also you can try with SOAPUI to build a working request and than slowly morph it to the failing one to see what difference causes the error. – Yaron Naveh Sep 09 '13 at 12:55
  • As always, many many thanks for your help. I'll try to use SOAPUI, in the meantime i'll contact the service vendor...but as far as i know they take some working days to answer event to a simple question =) – Gnegno Sep 09 '13 at 13:02
  • ...the vendor said that i need to not sign the body of the request (only the timestamp). Do you have some kind of reference or information to achieve that result? I think that it will not be a straight and easy way => Thanks in advance. – Gnegno Sep 18 '13 at 14:22
  • 1
    might be hard. could try to somehow use this sample http://webservices20.blogspot.co.il/2009/02/signing-custom-headers-in-wcf.html and remove the Body part from OutgoingSignatureParts – Yaron Naveh Sep 18 '13 at 14:32
  • Thanks to your link i've managed to successfully remove the body signature! Now i receive a 403 error saying "The HTTP request was forbidden with client authentication scheme 'Anonymous'"...reading your blog i can see that "This simply means the client certificate failed validation on the server. So check you use the correct certificate and that it is valid on the server."...but from what i can see from svctrace viewer i send a message, them i get a "Received bad HTTP response" error. Does it means that there's a problem on my side (certificates in the store) or on their side? – Gnegno Sep 19 '13 at 13:57
  • Sorry for the rush...i found the solution. It seems that the problem is on their side...using SOAPUi i can see that they return this error message "Unsupported or unrecognized Signature signer format in the message". I'm loving every moment of this integration... =) – Gnegno Sep 19 '13 at 14:03
0

Try this customBinding:

 <customBinding>
    <binding name="cb">
      <security authenticationMode="MutualCertificateDuplex" 
                defaultAlgorithmSuite="Basic128Rsa15" 
                requireDerivedKeys="false"
                enableUnsecuredResponse="true"
                messageProtectionOrder="EncryptBeforeSign" 
                messageSecurityVersion="WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10">
      </security>
      <textMessageEncoding messageVersion="Soap11WSAddressing10"/>
    <httpsTransport />
    </binding>
  </customBinding>
johnander11
  • 99
  • 1
  • 6