none
SOAP communication with separate certificates for signing and encryption RRS feed

  • Question

  • Service uses two different certificates - one for signing message (binary token) and one for TLS encryption. Communication is synchronous and CAN'T BE asynchronous. I implemented my own classes for that thing using tutorial from MSDN (can't post links yet).

    Thanks to that I'm able to connect and send request, but that's not the end of the problems. Next error was "The incoming message was signed with a token which was different from what used to encrypt the body. This was not expected."

    According to my research I should just erase whole Security header and configure my client to allow unsecured response. Therefore I should implement my own MessageEncoder what I actually did using another MSDN tutorial about creating CustomTextMessageEncoder. I also added one function that should remove header and some code from CustomTextMessageEncoder sample because without implementing IWsdlExportExtension in my CustomMessageEncodingBindingElement I got this error:

    "The message version of the outgoing message (Soap11 (http://schemas.xmlsoap.org/soap/envelope/) AddressingNone (http://schemas.microsoft.com/ws/2005/05/addressing/none)) does not match that of the encoder (Soap12 (http://www.w3.org/2003/05/soap-envelope) Addressing10 (http://www.w3.org/2005/08/addressing)). Make sure the binding is configured with the same version as the message."

    After that I have System.Xml.XmlException that basically means something like "duplicate attribute found, „a:Id” and „u:Id” — are both from „http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd” namespace". Encoder probably wants to add this reference twice and I don't know how to prevent it.

    My current custom classes look like that:

    public class DualCertClientCredentials : ClientCredentials { public X509Certificate2 ServiceSigningCertificate { get; set; } public X509Certificate2 ServiceEncryptingCertificate { get; set; } public X509Certificate2 ClientSigningCertificate { get; set; } public X509Certificate2 ClientEncryptingCertificate { get; set; } public DualCertClientCredentials() { } protected DualCertClientCredentials(DualCertClientCredentials other) : base(other) { this.ClientEncryptingCertificate = other.ClientEncryptingCertificate; this.ClientSigningCertificate = other.ClientSigningCertificate; this.ServiceEncryptingCertificate = other.ServiceEncryptingCertificate; this.ServiceSigningCertificate = other.ServiceSigningCertificate; } public override SecurityTokenManager CreateSecurityTokenManager() { return new MyClientCredentialsSecurityTokenManager(this); } protected override ClientCredentials CloneCore() { return new DualCertClientCredentials(this); } } internal class MyClientCredentialsSecurityTokenManager : ClientCredentialsSecurityTokenManager { DualCertClientCredentials credentials; public MyClientCredentialsSecurityTokenManager( DualCertClientCredentials credentials) : base(credentials) { this.credentials = credentials; } public override SecurityTokenProvider CreateSecurityTokenProvider( SecurityTokenRequirement requirement) { SecurityTokenProvider result = null; if (requirement.TokenType == SecurityTokenTypes.X509Certificate) { MessageDirection direction = MessageDirection.Input; if (direction == MessageDirection.Output) { if (requirement.KeyUsage == SecurityKeyUsage.Signature) { result = new X509SecurityTokenProvider( this.credentials.ClientSigningCertificate); } else { result = new X509SecurityTokenProvider(this.credentials. ServiceEncryptingCertificate); } } else { if (requirement.KeyUsage == SecurityKeyUsage.Signature) { result = new X509SecurityTokenProvider(this. credentials.ServiceSigningCertificate); } else { result = new X509SecurityTokenProvider(credentials. ClientEncryptingCertificate); } } } else { result = base.CreateSecurityTokenProvider(requirement); } return result; } public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver) { return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver); } } public class DualCertServiceCredentials : ServiceCredentials { public X509Certificate2 ClientSigningCertificate { get; set; } public X509Certificate2 ClientEncryptingCertificate { get; set; } public X509Certificate2 ServiceSigningCertificate { get; set; } public X509Certificate2 ServiceEncryptingCertificate { get; set; } public DualCertServiceCredentials() { } protected DualCertServiceCredentials(DualCertServiceCredentials other) : base(other) { this.ClientSigningCertificate = other.ClientSigningCertificate; this.ClientEncryptingCertificate = other.ClientEncryptingCertificate; this.ServiceSigningCertificate = other.ServiceSigningCertificate; this.ServiceEncryptingCertificate = other.ServiceEncryptingCertificate; } public X509Certificate2 ClientSigningCertificate1 { get => this.ClientSigningCertificate; set => this.ClientSigningCertificate = value; } public override SecurityTokenManager CreateSecurityTokenManager() { return new MyServiceCredentialsSecurityTokenManager(this); } protected override ServiceCredentials CloneCore() { return new DualCertServiceCredentials(this); } } internal class MyServiceCredentialsSecurityTokenManager : ServiceCredentialsSecurityTokenManager { DualCertServiceCredentials credentials; public MyServiceCredentialsSecurityTokenManager(DualCertServiceCredentials credentials) : base(credentials) { this.credentials = credentials; } public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement requirement) { SecurityTokenProvider result = null; if (requirement.TokenType == SecurityTokenTypes.X509Certificate) { MessageDirection direction = requirement. GetProperty<MessageDirection>( ServiceModelSecurityTokenRequirement. MessageDirectionProperty); if (direction == MessageDirection.Input) { if (requirement.KeyUsage == SecurityKeyUsage.Exchange) { result = new X509SecurityTokenProvider( credentials.ServiceEncryptingCertificate); } else { result = new X509SecurityTokenProvider( credentials.ClientSigningCertificate); } } else { if (requirement.KeyUsage == SecurityKeyUsage.Signature) { result = new X509SecurityTokenProvider( credentials.ServiceSigningCertificate); } else { result = new X509SecurityTokenProvider( credentials.ClientEncryptingCertificate); } } } else { result = base.CreateSecurityTokenProvider(requirement); } return result; } } class MyIdentityVerifier : IdentityVerifier { IdentityVerifier defaultVerifier; public MyIdentityVerifier() { this.defaultVerifier = IdentityVerifier.CreateDefault(); } public override bool CheckAccess(EndpointIdentity identity, AuthorizationContext authContext) { return true; } public override bool TryGetIdentity(EndpointAddress reference, out EndpointIdentity identity) { return this.defaultVerifier.TryGetIdentity(reference, out identity); } } public class InspectorBehavior : IEndpointBehavior { public string LastRequestXML { get { return myMessageInspector.LastRequestXML; } } public string LastResponseXML { get { return myMessageInspector.LastResponseXML; } } private MyMessageInspector myMessageInspector = new MyMessageInspector(); public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) { } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { } public void Validate(ServiceEndpoint endpoint) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { clientRuntime.MessageInspectors.Add(myMessageInspector); } } public class MyMessageInspector : IClientMessageInspector { public string LastRequestXML { get; private set; } public string LastResponseXML { get; private set; } public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState) { LastResponseXML = reply.ToString(); } public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel) { LastRequestXML = request.ToString(); return request; } } public class CustomTextMessageEncoderFactory : MessageEncoderFactory { private MessageVersion messageVersion; public override MessageEncoder Encoder { get; } public override MessageVersion MessageVersion { get { return messageVersion; } } public string MediaType { get; set; } public string CharSet { get; set; } public CustomTextMessageEncoderFactory(string mediaType, string charSet, MessageVersion version) { messageVersion = version; MediaType = mediaType; CharSet = charSet; Encoder = new CustomTextMessageEncoder(this); } } public class CustomMessageEncodingBindingElement : MessageEncodingBindingElement, IWsdlExportExtension { public override MessageVersion MessageVersion { get; set; } public string Encoding { get; set; } public string ContentType { get; set; } public XmlDictionaryReaderQuotas ReaderQuotas { get; set; } CustomMessageEncodingBindingElement(CustomMessageEncodingBindingElement binding) : this(binding.Encoding, binding.ContentType, binding.MessageVersion) { this.ReaderQuotas = new XmlDictionaryReaderQuotas(); binding.ReaderQuotas.CopyTo(this.ReaderQuotas); } public CustomMessageEncodingBindingElement(string encoding, string mediaType, MessageVersion msgVersion) { if (encoding == null) throw new ArgumentNullException("encoding"); if (mediaType == null) throw new ArgumentNullException("mediaType"); if (msgVersion == null) throw new ArgumentNullException("msgVersion"); this.MessageVersion = msgVersion; this.ContentType = mediaType; this.Encoding = encoding; this.ReaderQuotas = new XmlDictionaryReaderQuotas(); } public CustomMessageEncodingBindingElement() { MessageVersion = MessageVersion.Soap11; Encoding = "utf-8"; ContentType = "text/xml"; ReaderQuotas = new XmlDictionaryReaderQuotas(); } public override BindingElement Clone() { return new CustomMessageEncodingBindingElement(this); } public override MessageEncoderFactory CreateMessageEncoderFactory() { return new CustomTextMessageEncoderFactory(ContentType, Encoding, MessageVersion); } void IWsdlExportExtension.ExportContract(WsdlExporter exporter, WsdlContractConversionContext context) { } void IWsdlExportExtension.ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context) { TextMessageEncodingBindingElement mebe = new TextMessageEncodingBindingElement(); mebe.MessageVersion = this.MessageVersion; ((IWsdlExportExtension)mebe).ExportEndpoint(exporter, context); } public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(System.ServiceModel.Channels.BindingContext context) { if (context == null) throw new ArgumentNullException("context"); context.BindingParameters.Add(this); return context.BuildInnerChannelFactory<TChannel>(); } public override bool CanBuildChannelFactory<TChannel>(System.ServiceModel.Channels.BindingContext context) { if (context == null) throw new ArgumentNullException("context"); return context.CanBuildInnerChannelFactory<TChannel>(); } public override IChannelListener<TChannel> BuildChannelListener<TChannel>(System.ServiceModel.Channels.BindingContext context) { if (context == null) throw new ArgumentNullException("context"); context.BindingParameters.Add(this); return context.BuildInnerChannelListener<TChannel>(); } public override bool CanBuildChannelListener<TChannel>(System.ServiceModel.Channels.BindingContext context) { if (context == null) throw new ArgumentNullException("context"); context.BindingParameters.Add(this); return context.CanBuildInnerChannelListener<TChannel>(); } public override T GetProperty<T>(System.ServiceModel.Channels.BindingContext context) { if (typeof(T) == typeof(XmlDictionaryReaderQuotas)) { return (T)(object)this.ReaderQuotas; } else { return base.GetProperty<T>(context); } } } public class CustomTextMessageEncoder : MessageEncoder { private CustomTextMessageEncoderFactory factory; private XmlWriterSettings writerSettings; private string contentType; public override MessageVersion MessageVersion { get { return factory.MessageVersion; } } public override string MediaType { get { return factory.MediaType; } } public override string ContentType { get { return contentType; } } public CustomTextMessageEncoder(CustomTextMessageEncoderFactory factory) { this.factory = factory; this.writerSettings = new XmlWriterSettings(); this.writerSettings.NamespaceHandling = NamespaceHandling.OmitDuplicates; this.writerSettings.NewLineHandling = NewLineHandling.Entitize; this.writerSettings.Encoding = Encoding.GetEncoding(factory.CharSet); this.contentType = string.Format("{0}; charset={1}", this.factory.MediaType, this.writerSettings.Encoding.HeaderName); } public override System.ServiceModel.Channels.Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType) { byte[] msgContents = new byte[buffer.Count]; Array.Copy(buffer.Array, buffer.Offset, msgContents, 0, msgContents.Length); bufferManager.ReturnBuffer(buffer.Array); MemoryStream stream = new MemoryStream(msgContents); return ReadMessage(RemoveEnvelope(stream), int.MaxValue); }

    // erasing security header public static Stream RemoveEnvelope(Stream input) { string xml = new StreamReader(input).ReadToEnd(); XmlReader xr = XmlReader.Create(new StringReader(xml)); int envelope = 0; if ((envelope = xml.IndexOf("Security")) > 0) { int start = xml.LastIndexOf("<", envelope); int end = xml.LastIndexOf("Security"); end = xml.IndexOf(">", end) + 1; xml = xml.Substring(0, start) + xml.Substring(end); MemoryStream ms = new MemoryStream(new UTF8Encoding().GetBytes(xml)); return ms; } return input; } public override System.ServiceModel.Channels.Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType) { XmlReader reader = XmlReader.Create(stream); return System.ServiceModel.Channels.Message.CreateMessage(reader, maxSizeOfHeaders, this.MessageVersion); } public override ArraySegment<byte> WriteMessage(System.ServiceModel.Channels.Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset) { MemoryStream stream = new MemoryStream(); XmlWriter writer = XmlWriter.Create(stream, this.writerSettings); message.WriteMessage(writer); writer.Close(); byte[] messageBytes = stream.GetBuffer(); int messageLength = (int)stream.Position; stream.Close(); int totalLength = messageLength + messageOffset; byte[] totalBytes = bufferManager.TakeBuffer(totalLength); Array.Copy(messageBytes, 0, totalBytes, messageOffset, messageLength); ArraySegment<byte> byteArray = new ArraySegment<byte>(totalBytes, messageOffset, messageLength); return byteArray; } public override void WriteMessage(System.ServiceModel.Channels.Message message, Stream stream) { XmlWriter writer = XmlWriter.Create(stream, this.writerSettings); message.WriteMessage(writer); writer.Close(); } }

    I give my client all parameters through two functions:

            public static CustomBinding CreateBinding()
            {
                ICollection<BindingElement> bindingElements = new List<BindingElement>();
    
                var encoding = new CustomMessageEncodingBindingElement();
                encoding.MessageVersion = MessageVersion.Soap11;
    
                var security = AsymmetricSecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10, true);
                security.EnableUnsecuredResponse = true;
                security.MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
                security.IncludeTimestamp = false;
                security.LocalClientSettings.IdentityVerifier = new MyIdentityVerifier();
    
                bindingElements.Add(encoding);
                bindingElements.Add(security);
                bindingElements.Add(new HttpsTransportBindingElement() { RequireClientCertificate = true });
    
                return new CustomBinding(bindingElements);
            }
    
            public static EndpointAddress CreateEndpointAdress()
            {
                var builder = new EndpointAddressBuilder();
                builder.Uri = new Uri("ServiceURI");
                builder.Identity = DnsEndpointIdentity.CreateDnsIdentity("ServiceIdentity");
    
                return builder.ToEndpointAddress();
            }

    After that I invoke it like that:

                X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
                store.Open(OpenFlags.IncludeArchived);
    
                DualCertClientCredentials credentials = new DualCertClientCredentials();
                credentials.ClientEncryptingCertificate = store.Certificates.Find(X509FindType.FindByThumbprint, "thumb1", false)[0];
                credentials.ClientSigningCertificate = store.Certificates.Find(X509FindType.FindByThumbprint, "thumb2", false)[0];
                credentials.ServiceEncryptingCertificate = store.Certificates.Find(X509FindType.FindByThumbprint, "thumb1", false)[0];
                credentials.ServiceSigningCertificate = store.Certificates.Find(X509FindType.FindByThumbprint, "thumb2", false)[0];
    
                ServiceClient client = new ServiceClient(CreateBinding(), CreateEndpointAdress());
    
                client.ChannelFactory.Endpoint.EndpointBehaviors.Add(credentials);
                
                var requestInterceptor = new InspectorBehavior();
                client.Endpoint.Behaviors.Add(requestInterceptor);
                client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
    
                client.Endpoint.Contract.ProtectionLevel = System.Net.Security.ProtectionLevel.Sign;
    
                var result = client.SomeMethod(someParameters);

    Client class is parsed automatically from WSDL file. Theoretically I only need to configure the connection, give adequate certificates and it should work.


    • Edited by Granathar Wednesday, June 6, 2018 9:01 AM
    Wednesday, June 6, 2018 8:49 AM

All replies

  • Hi Granathar,

    >>I implemented my own classes for that thing using tutorial from MSDN (can't post links yet).

    Which document did you follow? You could paste link with plain text.

    Do you follow link below:

    #How to: Use Separate X.509 Certificates for Signing and Encryption

    https://docs.microsoft.com/en-us/dotnet/framework/wcf/extending/how-to-use-separate-x-509-certificates-for-signing-and-encryption

    Could you share us a simple project which could reproduce your issue?

    Best Regards,

    Tao Zhou


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, June 7, 2018 5:18 AM
  • Yes, it's this one. I also used this sample to create custom encoder: https://docs.microsoft.com/pl-pl/dotnet/framework/wcf/samples/custom-message-encoder-custom-text-encoder .

    "Could you share us a simple project which could reproduce your issue?"

    I'm afraid I shared as much as I can, but I can show how this SOAP message should look - I can take raw XML from SOAPUI. Duplicate attribute error appears in here:

    public override ArraySegment<byte> WriteMessage(System.ServiceModel.Channels.Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
            {
                MemoryStream stream = new MemoryStream();
                XmlWriter writer = XmlWriter.Create(stream, this.writerSettings);
                message.WriteMessage(writer); // here
                writer.Close();
    
                byte[] messageBytes = stream.GetBuffer();
                int messageLength = (int)stream.Position;
                stream.Close();
    
                int totalLength = messageLength + messageOffset;
                byte[] totalBytes = bufferManager.TakeBuffer(totalLength);
                Array.Copy(messageBytes, 0, totalBytes, messageOffset, messageLength);
    
                ArraySegment<byte> byteArray = new ArraySegment<byte>(totalBytes, messageOffset, messageLength);
                return byteArray;
            }

    So most probably it's some problem with my message encoder. We must remember that I give two different certificates depending of their use. So maybe that's the source of the problem, but I lack knowledge to know how to prevent this behavior. Without CustomMessageEncoder but with ordinary TextMessageEncodingBindingElement my request is able to reach service, but I can't read the response because of "The incoming message was signed with a token which was different from what used to encrypt the body. This was not expected.". Unfortunately inner exception shows "Missing wsse:Security header in request", so probably request goes out, but without signature (exactly the same error can be replicated in SOAPUI if we are missing security header)

    internal class MyClientCredentialsSecurityTokenManager : ClientCredentialsSecurityTokenManager
        {
            DualCertClientCredentials credentials;
    
            public MyClientCredentialsSecurityTokenManager(
                DualCertClientCredentials credentials) : base(credentials)
            {
                this.credentials = credentials;
            }
    
            public override SecurityTokenProvider CreateSecurityTokenProvider(
                SecurityTokenRequirement requirement)
            {
                SecurityTokenProvider result = null;
                if (requirement.TokenType == SecurityTokenTypes.X509Certificate)
                {
                    if (requirement.KeyUsage == SecurityKeyUsage.Signature)
                    {
                        result = new X509SecurityTokenProvider(this.
                            credentials.ServiceSigningCertificate);
                    }
                    else
                    {
                        result = new X509SecurityTokenProvider(credentials.
                            ClientEncryptingCertificate);
                    }
                }
                else
                {
                    result = base.CreateSecurityTokenProvider(requirement);
                }
    
                return result;
            }
    
            public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
            {
                return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
            }
        }
    Thursday, June 7, 2018 7:27 AM
  • And this is how correct request XML should look according to SOAPUI:

    POST https://serviceAdress HTTP/1.1
    Accept-Encoding: gzip,deflate
    Content-Type: text/xml;charset=UTF-8
    SOAPAction: "urn:SomeAction"
    Content-Length: 6446
    Host: ServiceHost
    Connection: Keep-Alive
    User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
    
    <soapenv:Envelope 
    	<!-- these namespaces doesn't matter, it's probably formatted properly -->
    	xmlns:k20="http://SomeNamespace1"
    	xmlns:k201="http://SomeNamespace2"
    	xmlns:soapenv="http://SomeNamespace3"
    	xmlns:v20="http://SomeNamespace4"
    	xmlns:v201="http://SomeNamespace5"
    	xmlns:v202="http://SomeNamespace6"
    	xmlns:w="http://SomeNamespace7">
    	<soapenv:Header>
    		<wsse:Security
    		soapenv:mustUnderstand="1"
    		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">
    			<wsse:BinarySecurityToken 
    			EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"
    			ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"
    			wsu:Id="X509-D58F2B83637B4DC3DB15283565977317">SOMEHASH==
    			</wsse:BinarySecurityToken>
    			<ds:Signature
    			Id="SIG-D58F2B83637B4DC3DB152835659773512"
    			xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    				<ds:SignedInfo>
    					<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
    						<ec:InclusiveNamespaces PrefixList="k20 k201 soapenv v20 v201 v202 w" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    					</ds:CanonicalizationMethod>
    					<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
    					<ds:Reference URI="#id-D58F2B83637B4DC3DB152835659773110">
    						<ds:Transforms>
    							<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
    								<ec:InclusiveNamespaces PrefixList="k20 soapenv v20 v201 v202 w" xmlns:ec="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:DigestValue>w10fTPyzot7f/XnxG1r1LrhZDJA=</ds:DigestValue>
    					</ds:Reference>
    					<ds:Reference URI="#id-D58F2B83637B4DC3DB152835659773211">
    						<ds:Transforms>
    							<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
    								<ec:InclusiveNamespaces PrefixList="k20 k201 v20 v201 v202 w" xmlns:ec="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:DigestValue>ZteZG18VmfX7R9si6N2w2BDfgVM=</ds:DigestValue>
    					</ds:Reference>
    				</ds:SignedInfo>
    				<ds:SignatureValue>SOMESIGNATURE</ds:SignatureValue>
    				<ds:KeyInfo Id="KI-D58F2B83637B4DC3DB15283565977318">
    					<wsse:SecurityTokenReference wsu:Id="STR-D58F2B83637B4DC3DB15283565977319">
    						<wsse:Reference URI="#X509-D58F2B83637B4DC3DB15283565977317" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
    					</wsse:SecurityTokenReference>
    				</ds:KeyInfo>
    			</ds:Signature>
    		</wsse:Security>
    		<k201:callContext wsu:Id="id-D58F2B83637B4DC3DB152835659773110" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    			<!-- this section looks alright -->
    		</k201:callContext>
    	</soapenv:Header>
    	<soapenv:Body wsu:Id="id-D58F2B83637B4DC3DB152835659773211" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    		<!-- body is alright and doesn't matter -->
    	</soapenv:Body>
    </soapenv:Envelope>

    We can see that xmlns:wsu is used few times, but it's recognized correctly. Meanwhile WCF wants to give it two different aliases resulting with something like that (it's translation from my native language) in message.WriteMessage(writer) line:

    'Duplicate attribute found. Both elements — „a:Id” and „u:Id” — originate from the same namespace „http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd”.'

    Thursday, June 7, 2018 8:22 AM
  • Hi Granathar,

    I'm trying to involve some senior engineers into this issue and it will take some time. Your patience will be greatly appreciated.
     
    Sorry for any inconvenience and have a nice day!

    Best Regards,

    Tao Zhou


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, June 8, 2018 5:37 AM
  • Does anyone know what am I missing here?
    Tuesday, June 12, 2018 7:53 AM
  • Hi Granathar,

    This problem appears to be too complicated to troubleshoot in forum. Can you capture a WCF trace and then raise a email-based on phone-based case to Microsoft support team?

    Best regards,

    Zhiqing


    Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question. This can be beneficial to other community members reading the thread.

    Friday, July 13, 2018 2:56 PM