简体   繁体   中英

How do I configure a WCF .NET Client for a Response with Dual Encryption?

Using .NET, I need to call a third party API which uses mutual authentication and dual encryption using mode Transport bindings. They have successfully received and decrypted my Request, processed it and sent a Response.

In the Header of the SOAP Response is a Security element. This contains an EncryptedKey and Signature element. The Body is separately encrypted.

The key to decrypt the body is contained in the above EncryptedKey element but the actual key within is also encrypted. In the same element is a X509Data element providing certificate details (IssuerName and SerialNumber) to decrypt that key, which can be used to decrypt the Body.

Received Encrpted Response

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

THE PROBLEM : How do I configure the .NET client to: read the x509SerialNumber to get the cert to decrypt EncryptedKey.CipherValue (encrypted...key) then use this to decrypt the body????

When I try and get the Response in code:

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

I get the following Exception (taken from trace logs):

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

How I'm setting up the Client :

 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 

When debugging, requirement.GetProperty in the following Function throws an Exception when querying the Response:

 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 

This is incredibly frustrating. Any help will be much appreciated. Thanks in advance.

Found the resolution - I was very close: Use the Asymmetric SecurityBindingElement and CreateMutualCertificate Duplex BindingElement objects.

Under How I'm setting up the Client :

I was using this which caused the Exception...

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

Replace with this line and all will work:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM