如何为具有双重加密的响应配置WCF .NET客户端?

时间:2018-01-12 14:27:20

标签: .net wcf-security

使用.NET,我需要使用模式传输绑定调用第三方API,该API使用相互身份验证和双重加密。他们已成功收到并解密我的请求,处理并发送了回复。

SOAP响应的标头是一个安全元素。它包含EncryptedKey和Signature元素。正文是单独加密的。

解密正文的密钥包含在上面的EncryptedKey元素中,但其中的实际密钥也是加密的。在同一元素中是X509Data元素,提供证书详细信息(IssuerName和SerialNumber)来解密该密钥,该密钥可用于解密Body。

收到加密响应

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

问题: 如何配置.NET客户端:读取x509SerialNumber以获取证书以解密EncryptedKey.CipherValue(加密...密钥)然后使用它来解密正文????

当我尝试在代码中获取响应时:

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

我得到以下异常(取自跟踪日志):

<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 SIA_Test_Project.SiaSetupCard.SetupCardService.setupCard2(setupCard2Request request)
    at SIA_Test_Project.SiaSetupCard.SetupCardServiceClient.SiaSetupCard_SetupCardService_setupCard2(setupCard2Request request)
    at SIA_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>

我如何设置客户端

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 TheirService.TheirServiceServiceClient(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

调试时,以下函数中的requirement.GetProperty在查询响应时抛出异常:

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

令人难以置信的是令人沮丧。任何帮助都感激不尽。提前谢谢。

1 个答案:

答案 0 :(得分:0)

找到解决方案 - 我非常接近:使用非对称 SecurityBindingElement和CreateMutualCertificate Duplex BindingElement对象。

我如何设置客户端

我正在使用它导致异常......

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

替换为这一行,一切都会起作用:

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