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

时间:2017-10-11 11:13:30

标签: c# web-services wcf soap

我尝试使用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;
    } 

1 个答案:

答案 0 :(得分:7)

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

Subject Key Identifier

enter image description here

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

我也必须:

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

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