2017-10-11 71 views
7

我試圖使用WCF客戶端連接到 WCF:該EncryptedKey條款不包裹所需的加密令牌「System.IdentityModel.Tokens.X509SecurityToken」

證書我已經提供了基於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> 

使用密鑰庫資源管理器中,我從JKS同時導出證書爲:

  • public_test_hci_cert.cer
  • test_soap_ui.p12

Web服務c所有:

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

回答

7

我離開了這個問題,在我的項目中進行了最後的衝刺,最後回到了它。
這是證書問題。基於Java的Web服務提供的自簽名證書是使用KeyStore Explorer生成的。這兩個證書中缺少的重要組成部分:

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) 

我調試CreateWrappedKeyTokenJetBrains公司dotPeek的幫助下,看到它試圖從證書讀取原始SKI,它不是找到它。

+0

它確實:證書是錯誤的。你還想知道什麼? –