WCF:EncryptedKey子句未包含所需的加密令牌'System.IdentityModel.Tokens.X509SecurityToken'

问题描述 投票:7回答:1

我正在尝试使用WCF客户端连接到基于Java的Web服务

证书我已经提供(自签名)在SOAPUI中完美地工作。

这是我的设置:

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

但是,我在使用WCF客户端时遇到问题。

我的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>

使用Keystore Explorer我从JKS导出两个证书:

  • public_test_hci_cert.cer
  • test_soap_ui.p12

网络服务电话:

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

请求完全到达服务器,但似乎WCF不理解响应,因为我得到此异常:

"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 ...

服务跟踪给出:

The security protocol cannot verify the incoming message

UPDATE1:通过使用相同的证书进行签名和加密来简化任务。同样的消息。

UPDATE2:我编写了CustomTextMessageEncoder,我在其中手动解密消息体并且它可以正常工作。但是,在ReadMessage中返回它仍会引发错误。

    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;
    } 
c# web-services wcf soap
1个回答
7
投票

我把这个问题留给了我项目的最后冲刺,最后回到了它。 这是证书问题。我使用KeyStore Explorer生成了基于Java的Web服务提供的自签名证书。两个证书都缺少一个重要部分:

Subject Key Identifier

enter image description here

一旦重新生成,WCF就能够在不使用编码器的情况下对其进行解密。

我也不得不:

  1. 在受信任的根CA(用户)中安装服务证书
  2. 将Web服务设置为使用时间戳进行回复

我从代码中删除了所有配置(客户端用户名和密码除外)并放在app.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>

我是怎么到那儿的仔细看堆栈跟踪:

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)

我在JetBrains dotPeek的帮助下调试了CreateWrappedKeyToken方法,并看到它试图从证书中读取原始SKI并且它没有找到它。

© www.soinside.com 2019 - 2024. All rights reserved.