WCF : The EncryptedKey clause was not wrapped with the required encryption token 'System.IdentityModel.Tokens.X509SecurityToken'

Deadly 提交于 2019-12-19 07:10:00

问题


I'm trying to use WCF client to connect to Java based web services

Certificates I have been provided (self-signed) work perfectly in SOAPUI.

Here is my setup:

However, I'm having problems using WCF client.

My app.config

    <bindings>
      <customBinding>
        <binding name="Example_TestBinding">             
          <security defaultAlgorithmSuite="TripleDesRsa15" 
                    authenticationMode="MutualCertificate" 
                    requireDerivedKeys="false" 
                    includeTimestamp="false" 
                    messageProtectionOrder="SignBeforeEncrypt" 
                    messageSecurityVersion="WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10" 
                    requireSignatureConfirmation="false">                
            <localClientSettings detectReplays="true"/>
            <localServiceSettings detectReplays="true"/>                
          </security>              
          <textMessageEncoding messageVersion="Soap11"/>             
          <httpsTransport authenticationScheme="Basic" manualAddressing="false" maxReceivedMessageSize="524288000" transferMode="Buffered"/>            
        </binding>
      </customBinding>
    </bindings>
  <client>
    <endpoint 
      address="https://blabla.hana.ondemand.com/Example_Test" 
      binding="customBinding" 
      bindingConfiguration="Example_TestBinding" 
      contract="WebServiceTest.Example_Test" 
      name="Example_Test"
     />
  </client>

Using Keystore Explorer I export both certificates from JKS as:

  • public_test_hci_cert.cer
  • test_soap_ui.p12

Web service call:

            var client = new Example_TestClient();
            client.ClientCredentials.UserName.UserName = "user";
            client.ClientCredentials.UserName.Password = "pass";

            X509Certificate2 certClient = new X509Certificate2(certClientPath, certClientPassword);
            client.ClientCredentials.ClientCertificate.Certificate = certClient;

            X509Certificate2 certService= new X509Certificate2(certServicePath);
            client.ClientCredentials.ServiceCertificate.DefaultCertificate = certService;

            var response = client.Example_Test(requestObj);  

The request arrives perfectly at the server but it seems that WCF doesn't understand the response since I get this exception:

"The EncryptedKey clause was not wrapped with the required 
encryption token 'System.IdentityModel.Tokens.X509SecurityToken'."
    at System.ServiceModel.Security.WSSecurityJan2004.WrappedKeyTokenEntry.CreateWrappedKeyToken(String id, String encryptionMethod, String carriedKeyName, SecurityKeyIdentifier unwrappingTokenIdentifier, Byte[] wrappedKey, SecurityTokenResolver tokenResolver)\r\n ...

Service Trace gives:

The security protocol cannot verify the incoming message

UPDATE1: simplified the task by using the same certificate for signing and encryption. Same message.

UPDATE2: I wrote CustomTextMessageEncoder where I manually decrypt the message body and it works. However returning it in ReadMessage still throws the error.

    public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
    {
        var msgContents = new byte[buffer.Count];
        Array.Copy(buffer.Array, buffer.Offset, msgContents, 0, msgContents.Length);
        bufferManager.ReturnBuffer(buffer.Array);
        var message = Encoding.UTF8.GetString(msgContents);

        //return ReadMessage(Decryptor.DecryptBody(message), int.MaxValue);
        var stream = new MemoryStream(Encoding.UTF8.GetBytes(message));
        return ReadMessage(stream, int.MaxValue);
    }

    public static MemoryStream DecryptBody(string xmlResponse)
    {
        X509Certificate2 cert = new X509Certificate2(clientCertPath, certPass);
        SymmetricAlgorithm algorithm = new TripleDESCryptoServiceProvider();

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.PreserveWhitespace = true;
        xmlDoc.LoadXml(xmlResponse);

        XmlElement encryptedKeyElement = xmlDoc.GetElementsByTagName("EncryptedKey", XmlEncryptionStrings.Namespace)[0] as XmlElement;
        XmlElement keyCipherValueElement = encryptedKeyElement.GetElementsByTagName("CipherValue", XmlEncryptionStrings.Namespace)[0] as XmlElement;
        XmlElement encryptedElement = xmlDoc.GetElementsByTagName("EncryptedData", XmlEncryptionStrings.Namespace)[0] as XmlElement;

        var key = Convert.FromBase64String(keyCipherValueElement.InnerText);

        EncryptedData edElement = new EncryptedData();
        edElement.LoadXml(encryptedElement);
        EncryptedXml exml = new EncryptedXml();

        algorithm.Key = (cert.PrivateKey as RSACryptoServiceProvider).Decrypt(key, false);

        byte[] rgbOutput = exml.DecryptData(edElement, algorithm);
        exml.ReplaceData(encryptedElement, rgbOutput);

        //var body = Encoding.UTF8.GetString(rgbOutput);

        MemoryStream ms = new MemoryStream();
        xmlDoc.Save(ms);
        return ms;
    } 

回答1:


I left this problem for the final sprint in my project and finally got back to it.
It is certificate problem. The self-signed certificates I was provided by Java based web service was generated with KeyStore Explorer. Both certificates were missing an important part:

Subject Key Identifier

Once regenerated WCF was able to decrypt it without using encoders.

Also I had to:

  1. Install service certificate in the Trusted Root CA (user)
  2. Set Web Services to reply with Timestamp

I removed all config from the code (except client username and password) and placed in the app.config. Here is the complete config:

  <system.serviceModel>
      <bindings>
          <customBinding>
            <binding name="Example_TestBinding">             
              <security                        
                        defaultAlgorithmSuite="TripleDesRsa15" 
                        authenticationMode="MutualCertificate" 
                        requireDerivedKeys="false" 
                        includeTimestamp="true" 
                        messageProtectionOrder="SignBeforeEncrypt" 
                        messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10" 
                        requireSignatureConfirmation="false"
                        allowSerializedSigningTokenOnReply="true" 
                        >
              </security>              
              <textMessageEncoding messageVersion="Soap11"/>
              <httpsTransport authenticationScheme="Basic" 
                              manualAddressing="false" 
                              maxReceivedMessageSize="524288000" 
                              transferMode="Buffered"/>                          
            </binding>
          </customBinding>

        </bindings>
      <client>
        <endpoint address="https://klaatuveratanecto.com/cxf/Example_TestBinding"
                  behaviorConfiguration="endpointCredentialBehavior"
                  binding="customBinding" 
                  bindingConfiguration="Example_TestBinding" 
                  contract="WebServiceTest.Example_Test" 
                  name="Example_Test">
          <identity>
            <dns value="test.service.klaatuveratanecto.com"/>
          </identity>
        </endpoint>
      </client>
    <behaviors>
      <endpointBehaviors>
        <behavior name="endpointCredentialBehavior">
          <clientCredentials>
            <serviceCertificate>
              <defaultCertificate findValue="test.service.klaatuveratanecto.com"
                               storeLocation="CurrentUser"
                               storeName="Root"
                               x509FindType="FindBySubjectName" />
            </serviceCertificate>
            <clientCertificate findValue="test.client.klaatuveratanecto.com"
                               storeLocation="CurrentUser"
                               storeName="My"
                               x509FindType="FindBySubjectName" />
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>

How did I get there. Well looking at the stack trace:

Server stack trace: 
   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& message, SecurityToken requiredSigningToken, TimeSpan timeout, SecurityProtocolCorrelationState[] correlationStates)
   at System.ServiceModel.Security.AsymmetricSecurityProtocol.VerifyIncomingMessageCore(Message& message, String actor, TimeSpan timeout, SecurityProtocolCorrelationState[] correlationStates)
   at System.ServiceModel.Security.MessageSecurityProtocol.VerifyIncomingMessage(Message& 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)

I debugged CreateWrappedKeyToken method with help of JetBrains dotPeek and saw that it tries to read raw SKI from the certificate and it's not finding it.



来源:https://stackoverflow.com/questions/46686785/wcf-the-encryptedkey-clause-was-not-wrapped-with-the-required-encryption-token

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!