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



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

在 SOAP 响应的标头中是一个安全元素。它包含一个加密密钥和签名元素。正文是单独加密的。

用于解密正文的密钥包含在上述 EncryptedKey 元素中,但其中的实际密钥也已加密。在同一元素中有一个 X509Data 元素,该元素提供证书详细信息(颁发者名称和序列号)以解密该密钥,该密钥可用于解密正文。

收到的包含的响应

<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 客户端配置为:读取 x509 序列号以获取证书以解密加密密钥.密码值(加密...密钥),然后使用它来解密正文????

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

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

调试时,要求。以下函数中的 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

这令人难以置信地令人沮丧。任何帮助将不胜感激。提前谢谢。

找到了解决方案 - 我非常接近:使用AsymmetricSecurityBindingElement 和 CreateMutualCertificateDuplexBindingElement 对象。

"如何设置客户端"下:

我正在使用这个导致异常...

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

替换为此行,所有操作都将起作用:

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

最新更新