none
How do I configure a WCF .NET Client for a Response with Dual Encryption? RRS feed

  • Question

  • My actual question for you is below as THE PROBLEM

    Using .NET, I need to call a third party API which uses mutual authentication and dual encryption using mode Transport bindings. They have successfully received and decrypted my Request, processed it and sent a Response.

    In the Header of the SOAP Response is a Security element. This contains an EncryptedKey and Signature element. The Body is separately encrypted.

    The key to decrypt the body is contained in the above EncryptedKey element but this key is separately encrypted. In the same element is a X509Data element providing certificate details (IssuerName and SerialNumber) to decrypt that key, which can be used to decrypt the Body.


    Received Encrypted Response (only available from trace logs). 

    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
      <SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
        <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" soap:mustUnderstand="1">
          <wsu:Timestamp wsu:Id="TS-ba9edb63-214d-4d6b-8040-ed715a1326c7"></wsu:Timestamp>
          <xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="EK-fede8959-6d80-4166-9e79-4a4229efee4f">
            <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"></xenc:EncryptionMethod>
            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
              <wsse:SecurityTokenReference>
                <ds:X509Data>
                  <ds:X509IssuerSerial>
                    <ds:X509IssuerName>CN=Their Name,O=Their Organisation</ds:X509IssuerName>
                    <ds:X509SerialNumber>1234567*************************987654</ds:X509SerialNumber>
                  </ds:X509IssuerSerial>
                </ds:X509Data>
              </wsse:SecurityTokenReference>
            </ds:KeyInfo>
            <xenc:CipherData>
              <xenc:CipherValue>K+l28afn3i8e..Encrypted...Key....4gnOHW0kxK7aL6l7Q==</xenc:CipherValue>
            </xenc:CipherData>
            <xenc:ReferenceList></xenc:ReferenceList>
          </xenc:EncryptedKey>
          <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="SIG-77d3082f-2668-4347-9582-83d1ba9f0f8d">
            <ds:SignedInfo>
              <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"> </ds:CanonicalizationMethod>
              <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
              <ds:Reference URI="#TS-ba9edb63-214d-4d6b-8040-ed715a1326c7">
                <ds:Transforms> </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>yKJziO....SrJPNE=</ds:DigestValue>
              </ds:Reference>
              <ds:Reference URI="#_2d4d85db-41d7-446b-87f1-0a839b9b3e7f">
                <ds:Transforms>
                  <ds:Transform Algorithm="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:DigestMethod>
                <ds:DigestValue>9PNS98w.....KMWU0=</ds:DigestValue>
              </ds:Reference>
            </ds:SignedInfo>
            <ds:SignatureValue>EaqS4/iiXybpMe6r........RFM2NM6D3X/zpQ==</ds:SignatureValue>
            <ds:KeyInfo Id="KI-a6793d90-a124-4960-ae17-f07c43248f53">
              <wsse:SecurityTokenReference wsu:Id="STR-1d682670-9dde-40e1-ad14-e29c9c62c474">
                <ds:X509Data>
                  <ds:X509IssuerSerial>
                    <ds:X509IssuerName>CN=Their Name,O=Their Organisatio</ds:X509IssuerName>
                    <ds:X509SerialNumber>7654321*************************456789</ds:X509SerialNumber>
                  </ds:X509IssuerSerial>
                </ds:X509Data>
              </wsse:SecurityTokenReference>
            </ds:KeyInfo>
          </ds:Signature>
        </wsse:Security>
      </SOAP-ENV:Header>
      <soap:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="_2d4d85db-41d7-446b-87f1-0a839b9b3e7f">
        <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="ED-3900ed5b-952f-4d4a-976b-6a3e86967010" Type="http://www.w3.org/2001/04/xmlenc#Content">
          <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"></xenc:EncryptionMethod>
          <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
            <wsse:SecurityTokenReference xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey">
              <wsse:Reference URI="#EK-fede8959-6d80-4166-9e79-4a4229efee4f"></wsse:Reference>
            </wsse:SecurityTokenReference>
          </ds:KeyInfo>
          <xenc:CipherData>
            <xenc:CipherValue>7KCEA0yCcd.....Encrypted....Body....O0AIbjdJ3gKQy8=</xenc:CipherValue>
          </xenc:CipherData>
        </xenc:EncryptedData>
      </soap:Body>
    </soap:Envelope>


    THE PROBLEM/QUESTION :

    1. How do I configure the .NET client to: read the x509SerialNumber to get the cert on my PC/Server to decrypt EncryptedKey.CipherValue (encrypted...key) then use this to decrypt the body????
    2. Or how can I obtain this Response in code before .NET crashes so I can manually perform these .NET tasks?

    When I try and get the Response from code,

    Try
         Dim response As TheirService.TheirMethodResponse = client.DoMethodAction(request)
     Catch ex As Exception
         Dim test As String = ex.Message
     End Try

    ...I get the following Exception (taken from trace logs):

    <Exception>
      <ExceptionType>System.ServiceModel.Security.MessageSecurityException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
      <Message>
        Cannot resolve KeyInfo for unwrapping key: KeyInfo 'SecurityKeyIdentifier
        (
        IsReadOnly = False,
        Count = 1,
        Clause[0] = X509IssuerSerialKeyIdentifierClause(Issuer = 'CN=Their Name,O=Their Organisation', Serial = '1234567*************************987654')
        )
        ', available tokens 'SecurityTokenResolver
        (
        TokenCount = 1,
        TokenEntry[0] = (AllowedReferenceStyle=External, Token=System.ServiceModel.Security.Tokens.WrappedKeySecurityToken, Parameters=System.ServiceModel.Security.Tokens.WrappedKeySecurityTokenParameters:
        InclusionMode: Once
        ReferenceStyle: Internal
        RequireDerivedKeys: True)
        )
        '.
      </Message>
      <StackTrace>
        at System.ServiceModel.Security.WSSecurityJan2004.WrappedKeyTokenEntry.CreateWrappedKeyToken(String id, String encryptionMethod, String carriedKeyName, SecurityKeyIdentifier unwrappingTokenIdentifier, Byte[] wrappedKey, SecurityTokenResolver tokenResolver)
        at System.ServiceModel.Security.WSSecurityJan2004.WrappedKeyTokenEntry.ReadTokenCore(XmlDictionaryReader reader, SecurityTokenResolver tokenResolver)
        at System.ServiceModel.Security.WSSecurityTokenSerializer.ReadTokenCore(XmlReader reader, SecurityTokenResolver tokenResolver)
        at System.IdentityModel.Selectors.SecurityTokenSerializer.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver)
        at System.ServiceModel.Security.WSSecurityOneDotZeroReceiveSecurityHeader.DecryptWrappedKey(XmlDictionaryReader reader)
        at System.ServiceModel.Security.ReceiveSecurityHeader.ReadEncryptedKey(XmlDictionaryReader reader, Boolean processReferenceListIfPresent)
        at System.ServiceModel.Security.ReceiveSecurityHeader.ExecuteFullPass(XmlDictionaryReader reader)
        at System.ServiceModel.Security.StrictModeSecurityHeaderElementInferenceEngine.ExecuteProcessingPasses(ReceiveSecurityHeader securityHeader, XmlDictionaryReader reader)
        at System.ServiceModel.Security.ReceiveSecurityHeader.Process(TimeSpan timeout, ChannelBinding channelBinding, ExtendedProtectionPolicy extendedProtectionPolicy)
        at System.ServiceModel.Security.MessageSecurityProtocol.ProcessSecurityHeader(ReceiveSecurityHeader securityHeader, Message&amp; message, SecurityToken requiredSigningToken, TimeSpan timeout, SecurityProtocolCorrelationState[] correlationStates)
        at System.ServiceModel.Security.SymmetricSecurityProtocol.VerifyIncomingMessageCore(Message&amp; message, String actor, TimeSpan timeout, SecurityProtocolCorrelationState[] correlationStates)
        at System.ServiceModel.Security.MessageSecurityProtocol.VerifyIncomingMessage(Message&amp; message, TimeSpan timeout, SecurityProtocolCorrelationState[] correlationStates)
        at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.ProcessReply(Message reply, SecurityProtocolCorrelationState correlationState, TimeSpan timeout)
        at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.Request(Message message, TimeSpan timeout)
        at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
        at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
        at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
        at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
        at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&amp; msgData, Int32 type)
        at Test_Project.SiaSetupCard.SetupService.setup2(setup2Request request)
        at Test_Project.SiaSetupCard.SetupServiceClient.RemoteCompanySetup_SetupService_setup2(setup2Request request)
        at Test_Project.Module1.Main()
        at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
        at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
        at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
        at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
        at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
        at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
        at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
        at System.Threading.ThreadHelper.ThreadStart()
      </StackTrace>
      <ExceptionString>
        System.ServiceModel.Security.MessageSecurityException: Cannot resolve KeyInfo for unwrapping key: KeyInfo 'SecurityKeyIdentifier
        (
        IsReadOnly = False,
        Count = 1,
        Clause[0] = X509IssuerSerialKeyIdentifierClause(Issuer = 'CN=Their Name,O=Their Organisation', Serial = '1234567*************************987654')
        )
        ', available tokens 'SecurityTokenResolver
        (
        TokenCount = 1,
        TokenEntry[0] = (AllowedReferenceStyle=External, Token=System.ServiceModel.Security.Tokens.WrappedKeySecurityToken, Parameters=System.ServiceModel.Security.Tokens.WrappedKeySecurityTokenParameters:
        InclusionMode: Once
        ReferenceStyle: Internal
        RequireDerivedKeys: True)
        )
        '.
      </ExceptionString>
    </Exception>


    How I'm setting up the Client:

    Dim binding As New Channels.CustomBinding
     
            Dim securityBE As SymmetricSecurityBindingElement = SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10)
     
            securityBE.MessageProtectionOrder = Security.MessageProtectionOrder.SignBeforeEncrypt
            securityBE.RequireSignatureConfirmation = False  
            securityBE.EnableUnsecuredResponse = False 
            binding.Elements.Add(securityBE) 
     
            binding.Elements.Add(New TextMessageEncodingBindingElement(MessageVersion.Soap11, System.Text.Encoding.UTF8))
     
            Dim http As New HttpsTransportBindingElement()
            http.RequireClientCertificate = True  
    
            binding.Elements.Add(http)
    
             Dim endPoint As New EndpointAddress(New Uri("https://blar/blar/services/TheirMethodService"), EndpointIdentity.CreateDnsIdentity("Their Name"))
     
     
           Dim client As New SiaSetupCard.SetupCardServiceClient(binding, endPoint)
     
           Dim credentials As New ClientCredentials
           'Their cert where we have the public key only
           credentials.ServiceEncryptingCert = GetCert("c40ca927................c94640cdb7")
           'our their company's mutual auth cert where we have the private key
           credentials.ClientEncryptingCert = GetCert("e3debd49................e9a6cd39c5")
           'our their company's digital signing cert where we have the private key
           credentials.ClientSigningCert = GetCert("40091641................d622761b")
     
           client.ChannelFactory.Endpoint.EndpointBehaviors.Remove(GetType(Description.ClientCredentials))
           client.ChannelFactory.Endpoint.EndpointBehaviors.Add(credentials)
     
           'only sign the message do not encrypt it
           client.Endpoint.Contract.ProtectionLevel = ProtectionLevel.EncryptAndSign
     
           System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls Or System.Net.SecurityProtocolType.Tls12 
     
           Dim request As New TheirService.TheirMethodRequest
           request.ProductRequestItem = New TheirService.ProductRequestItem
           'Construct Request
    
    Try
        Dim response As TheirService.TheirMethodResponse = client.DoMethodAction(request)
    Catch ex As Exception
        Dim test As String = ex.Message
    End Try

    When running my simple proxy project and debugging, requirement.GetProperty in the following Function throws an Exception when querying the Response:

    Public Overrides Function CreateSecurityTokenProvider(requirement As SecurityTokenRequirement) As SecurityTokenProvider
        Dim result As SecurityTokenProvider
        If requirement.TokenType = System.IdentityModel.Tokens.SecurityTokenTypes.X509Certificate Then
     
            Dim direction As MessageDirection
            Dim noDirection  As Boolean = False
            Try
                direction = requirement.GetProperty(Of MessageDirection)(ServiceModelSecurityTokenRequirement.MessageDirectionProperty)
            Catch ex As Exception
                noDirection  = True
            End Try
     
            'this may be the client cert
            If noDirection Then
                result = New X509SecurityTokenProvider(Me.credentials.ClientEncryptingCert) 
            Else  
                If direction = MessageDirection.Output Then
                    If requirement.KeyUsage = IdentityModel.Tokens.SecurityKeyUsage.Signature Then
                        result = New X509SecurityTokenProvider(Me.credentials.ClientSigningCert)
                    Else
                        result = New X509SecurityTokenProvider(Me.credentials.ServiceEncryptingCert)
                    End If
                Else
                    If requirement.KeyUsage = IdentityModel.Tokens.SecurityKeyUsage.Signature Then
                        result = New X509SecurityTokenProvider(Me.credentials.ServiceEncryptingCert)
                    Else
                        result = New X509SecurityTokenProvider(Me.credentials.ClientSigningCert)
                    End If
                End If
            End If
        Else
            result = MyBase.CreateSecurityTokenProvider(requirement)
        End If 
        Return result
    End Function

    Monday, January 15, 2018 12:46 PM

Answers

  • Found the resolution - I was very close.


    Under How I'm setting up the Client:

    I was using this which caused the Exception...

    Dim securityBE As SymmetricSecurityBindingElement = SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10)

    Replace with this line and all will work:

    Dim securityBE As AsymmetricSecurityBindingElement = SecurityBindingElement.CreateMutualCertificateDuplexBindingElement(MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10)


    Wednesday, January 17, 2018 5:41 PM

All replies

  • Hi,

    Based on your description, it seems you are consuming the third-party Service.

    In general, we could consume WCF Service by generating the client code based on wsdl. But, it seems the general way is not enough to consume the service.

    In my option, the Service developer is more familiar with their Service. I would suggest you confirm with the Developer to check how to consume their Service.

    Best Regards,

    Tao Zhou


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, January 16, 2018 4:56 AM
  • You're right, we are consuming a third-party Service and generating client code based in the wsdl but not sure how to decrypt the key in the Response needed to decrypt the body.

    We have gone to the Service developer but unfortunately their side is all written in Java and can only give us common mistakes from a .NET perspective. 

    Is it possible to obtain the Response as soon as it arrives before .NET starts processing it?

    Tuesday, January 16, 2018 10:59 AM
  • Hi,

    >> Is it possible to obtain the Response as soon as it arrives before .NET starts processing it?

    For this, I suggest you check whether IClientMessageInspector meets your requirement.

    # WCF Extensibility – Message Inspectors

    https://blogs.msdn.microsoft.com/carlosfigueira/2011/04/18/wcf-extensibility-message-inspectors/

    Best Regards,

    Tao Zhou


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, January 17, 2018 2:30 AM
  • Thanks Tao

    >> For this, I suggest you check whether IClientMessageInspector meets your requirement.
    # WCF Extensibility – Message Inspectors

    Unfortunately it didn't, but good to know. Having got this working, the point at which the incoming Message is received on the wire and before it’s dispatched to the application (AfterReceive) is too far up the .NET stack to intercept before the Exception gets thrown i.e. The Exception still happens before the inspector calls the interface method.

    I've since found the fix for the original question (which I'll post separately): To give you an idea how high up the .NET stack Message Inspector works, the Message passed to the inspector interface method has the decrypted body. This is basically a high level full Response, not the low level of a ServiceModelTraceListener operates at.


    Wednesday, January 17, 2018 5:35 PM
  • Found the resolution - I was very close.


    Under How I'm setting up the Client:

    I was using this which caused the Exception...

    Dim securityBE As SymmetricSecurityBindingElement = SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10)

    Replace with this line and all will work:

    Dim securityBE As AsymmetricSecurityBindingElement = SecurityBindingElement.CreateMutualCertificateDuplexBindingElement(MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10)


    Wednesday, January 17, 2018 5:41 PM