Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / security / encryption

Calling a service with oasis header in C#

4.83/5 (3 votes)
23 Oct 2013CPOL2 min read 41K   1.4K  
Adding the WS-Security Header to a request using the WCF bindings

Objective

Calling a Java service by using the C# with X509 Certificate at the client side includes calling the service by adding the WSDL provided by the Java service. SOAP request with WS-Security tags with SOAP 1.1v format.

What is WS-Security?

These standards cover many aspects of security, including digital signatures, authentication and encryption of SOAP messages. The generic name for the standards is WS-*, and includes WS-Security, WS-Trust and WS-SecureConversation.

What is asymmetric binding?

According to the WS Security Specification, "The AsymmetricBinding assertion is used in scenarios in which message protection is provided by means defined in WSS: SOAP Message Security using asymmetric key (Public Key) technology". If we put this in a simplified manner, Asymmetric Binding can be used when both parties possess key pairs. For example, if both the parties possess X.509 certificates, then it is possible to use asymmetric binding.

In asymmetric binding, message encryption and signing takes place using the Public Key Infrastructure(PKI), i.e. sender encrypts messages using the public key of the recipient and sign the messages using his private key. Then the recipient can decrypt the received messages using his private key and verify the signature of the message using the public key of the sender. This way, the confidentiality, integrity, and the non-repudiation properties of the message exchanges can be assured.

Image 1

Sample Request

XML
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" 
   xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> 
<s:Header> 
<VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/
  servicemodelsink">uIDPo9BrQHxKdRBHnk55BHEVIegAAAAA9xEF2l05pE6
  oORfcQbIUtu/UUlm2aa1MoqgTA1LhHoAACQAA</VsDebuggerCausalityData> 
<o:Security s:mustUnderstand="1" 
  xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> 
<u:Timestamp u:Id="uuid-6d16b382-19a0-4ab9-a6e0-b8a9e45934e7-1"> 
<u:Created>2013-10-18T10:44:48.021Z</u:Created> 
<u:Expires>2013-10-18T10:49:48.021Z</u:Expires> 
</u:Timestamp> 
<o:BinarySecurityToken u:Id="uuid-fc380a85-c6d5-4d2f-802f-9408673f083d-2" 
  ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" 
  EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
  MIICBjCCAXOgAwIBAgIQSsDqfgBbIJxOmxixpri/</o:BinarySecurityToken> 
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> 
<SignedInfo> 
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> 
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> 
<Reference URI="#_1"> 
<Transforms> 
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> 
</Transforms> 
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> 
<DigestValue>4AmVSd/mVml+VYVtYgAT8dhYnVE=</DigestValue> 
</Reference> 
<Reference URI="#uuid-6d16b382-19a0-4ab9-a6e0-b8a9e45934e7-1"> 
<Transforms> 
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> 
</Transforms> 
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> 
<DigestValue>Ij2dZ5HA5xAw6/5GwVqA+vqoCc8=</DigestValue> 
</Reference> 
</SignedInfo> 
<SignatureValue>US78jxH5RkyFfPOCM05TDXvuwmk7MM6uPRluMXl9SlBNiigEf2R8BouwyHB8ODnVK3D84s
  PPrxttaapeVYDc2wCThWqtKS+Rf9+tETaucYxouttBaiarc6DE9k3FifU4LeeUBQz6nwpJJY1zKm1NviwwYwEvYTZy8ZU6rurzgqQ=</SignatureValue> 
<KeyInfo> 
<o:SecurityTokenReference> 
<o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-
  wss-x509-token-profile-1.0#X509v3" URI="#uuid-fc380a85-c6d5-4d2f-802f-9408673f083d-2"/> 
</o:SecurityTokenReference> 
</KeyInfo> 
</Signature> 
</o:Security> 
</s:Header> 
<s:Body u:Id="_1"> 
<DoSomething xmlns="http://test.com/play"> 
<wow>Salutations</wow> 
</DoSomething> 
</s:Body> 
</s:Envelope> 

Sample Response

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> 
<s:Body> 
<DoSomethingResponse xmlns="http://test.com/play"> 
<DoSomethingResult>yo</DoSomethingResult> 
</DoSomethingResponse> 
</s:Body> 
</s:Envelope> 

Steps to be followed format the request and response:

Step1: Create server certificate

makecert.exe -r -pe -n "CN=localhost" -ss my -sr LocalMachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 LocalhostTestKey.cer

Step 2: Create client certificate

makecert.exe -r -pe -n "CN=BradTestClientKey" -ss my -sr CurrentUser -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 BradTestClientKey.cer

Step 3: Operation Contract

C#
[ServiceContract(Namespace = "http://test.com/play", ProtectionLevel=ProtectionLevel.Sign)] 
interface ISer 
{ 
[OperationContract] 
string DoSomething(string wow); 
} 

Step 4: Injection of the Symmetric Binding Element

C#
using System; 
using System.Collections.Generic; 
using System.Text; 
using System.ServiceModel; 
using System.ServiceModel.Channels; 
using System.ServiceModel.Dispatcher; 
using System.ServiceModel.Description; 
using System.ServiceModel.Security; 
using System.ServiceModel.Security.Tokens; 
using System.ServiceModel.Configuration; 
namespace MySecurityBE 
{ 
public class AsymetricSecurityBE : BindingElement 
{ 
private AsymmetricSecurityBindingElement m_asymSecBE; 
public AsymetricSecurityBE() 
{ 
MessageSecurityVersion securityVersion = 
  MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConve
    rsationFebruary2005WSSecurityPolicy11BasicSecurityProfile10; 
SecurityBindingElement securityBE = 
  SecurityBindingElement.CreateMutualCertificateBindingElement(securityVersion, true); 
securityBE.IncludeTimestamp = true; 
securityBE.SetKeyDerivation(false); 
securityBE.SecurityHeaderLayout = SecurityHeaderLayout.Lax; 
securityBE.EnableUnsecuredResponse = true; 
m_asymSecBE = securityBE as AsymmetricSecurityBindingElement; 
} 
public AsymetricSecurityBE(AsymetricSecurityBE other) 
{ 
m_asymSecBE = other.m_asymSecBE; 
6 Steps to add a security header to every request from a .net client 
} 
public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context) 
{ 
return m_asymSecBE.BuildChannelListener<TChannel>(context); 
} 
public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context) 
{ 
return m_asymSecBE.BuildChannelFactory<TChannel>(context); 
} 
public override BindingElement Clone() 
{ 
AsymetricSecurityBE ret = new AsymetricSecurityBE(this); 
return ret; 
} 
public override T GetProperty<T>(BindingContext context) 
{ 
return m_asymSecBE.GetProperty<T>(context); 
} 
} 
class AsymetricSecurityBEExtentionElement : BindingElementExtensionElement 
{ 
public override Type BindingElementType 
{ 
get { return typeof(AsymetricSecurityBE); } 
} 
protected override BindingElement CreateBindingElement() 
{ 
return new AsymetricSecurityBE(); 
} 
} 
} 

Step 5: Service Configuration including the diagnostics

XML
<configuration> 
<system.serviceModel> 
<extensions> 
<bindingElementExtensions> 
<add name="MySecurityBindingElement" 
  type="MySecurityBE.AsymetricSecurityBEExtentionElement, MySecurityBE, 
    Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
</bindingElementExtensions> 
</extensions> 
<bindings> 
<customBinding> 
<binding name="MyCoolBinding"> 
<MySecurityBindingElement/> 
<textMessageEncoding messageVersion="Soap11"/> 
<httpTransport/> 
</binding> 
</customBinding> 
</bindings> 
<services> 
<service behaviorConfiguration="ServBeh" name="Service.MyImpl"> 
<host> 
<baseAddresses> 
<add baseAddress="http://localhost:8000" /> 
</baseAddresses> 
</host> 
<endpoint address="MyCoolEndpoint" binding="customBinding" bindingConfiguration="MyCoolBinding" 
name="MyCoolEndpoint" contract="Service.ISer"> 
</endpoint> 
<endpoint name="MetadataHttp" address="mex" 
  binding="mexHttpBinding" contract="IMetadataExchange" /> 
</service> 
</services> 
<behaviors> 
<serviceBehaviors> 
<behavior name="ServBeh"> 
<serviceMetadata httpGetEnabled="true" /> 
<serviceDebug includeExceptionDetailInFaults="true" /> 
<serviceCredentials> 
<clientCertificate> 
<authentication certificateValidationMode="None" revocationMode="NoCheck" /> 
</clientCertificate> 
<serviceCertificate storeLocation="LocalMachine" 
storeName="My" 
x509FindType="FindBySubjectName" 
findValue="LocalhostTestKey"/> 
<issuedTokenAuthentication certificateValidationMode="PeerOrChainTrust" /> 
</serviceCredentials> 
</behavior> 
</serviceBehaviors> 
</behaviors> 
<diagnostics> 
<messageLogging maxMessagesToLog="30000" 
logEntireMessage="true" 
logMessagesAtServiceLevel="false" 
logMalformedMessages="true" 
logMessagesAtTransportLevel="true"> 
<filters> 
<clear/> 
</filters> 
</messageLogging> 
</diagnostics> 
</system.serviceModel> 
<system.diagnostics> 
<sources> 
<source name="System.ServiceModel" switchValue="Warning, ActivityTracing" > 
<listeners> 
<add name="xml" /> 
</listeners> 
</source> 
<source name="System.ServiceModel.MessageLogging" switchValue="Warning"> 
<listeners> 
<add name="xml" /> 
</listeners> 
</source> 
</sources> 
<sharedListeners> 
<add name="xml" 
  type="System.Diagnostics.XmlWriterTraceListener" 
  initializeData="..\Logs\Server.svclog" /> 
</sharedListeners> 
<trace autoflush="true" /> 
</system.diagnostics> 
</configuration> 

Step 6: Add Proxy to client and client configuration

XML
<configuration> 
<system.serviceModel> 
<extensions> 
<bindingElementExtensions> 
<add name="MySecurityBindingElement" 
  type="MySecurityBE.AsymetricSecurityBEExtentionElement, MySecurityBE, 
        Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
</bindingElementExtensions> 
</extensions> 
<bindings> 
<customBinding> 
<binding name="MyCoolBinding"> 
<MySecurityBindingElement/> 
<textMessageEncoding messageVersion="Soap11" /> 
<httpTransport/> 
</binding> 
</customBinding> 
</bindings> 
<behaviors> 
<endpointBehaviors> 
<behavior name="cliBeh"> 
<clientCredentials> 
<clientCertificate storeLocation="CurrentUser" storeName="My" 
  x509FindType="FindBySubjectName" findValue="BradTestClientKey"/> 
<serviceCertificate> 
<defaultCertificate storeLocation="CurrentUser" storeName="My" 
  x509FindType="FindBySubjectName" findValue="localhost"/> 
<authentication certificateValidationMode="None" 
trustedStoreLocation="CurrentUser" /> 
</serviceCertificate> 
</clientCredentials> 
</behavior> 
</endpointBehaviors> 
</behaviors> 
<client> 
<endpoint address="http://localhost:8000/MyCoolEndpoint" 
  binding="customBinding" bindingConfiguration="MyCoolBinding" 
  name="MyCoolEndpoint" contract="ISer" 
  behaviorConfiguration="cliBeh"> 
<identity> 
<dns value="LocalhostTestKey"/> 
</identity> 
</endpoint> 
</client> 
<diagnostics> 
<messageLogging logEntireMessage="true" 
logMalformedMessages="true" 
logMessagesAtServiceLevel="true" 
logMessagesAtTransportLevel="true" 
maxMessagesToLog="3000" 
maxSizeOfMessageToLog="2000"/> 
</diagnostics> 
</system.serviceModel> 
<system.diagnostics> 
<sources> 
<source name="System.ServiceModel.MessageLogging"> 
<listeners> 
<add name="messages" 
  type="System.Diagnostics.XmlWriterTraceListener" 
  initializeData="..\Logs\Client.svclog"/> 
</listeners> 
</source> 
</sources> 
</system.diagnostics> 
</configuration> 

Conclusion

We have achieved the sample for the configuration

  • Server: Service behavior with X.509 certificate implementation.
  • Client: Sending authenticated request with X.509 certificate as signature to each request.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)