This is a preview draft document. The WCF specific code and configuration snippets and samples are based on the WCF February 2006 CTP and might deviate for more recent versions. This document has not been reviewed for language correctness.
William Tay
NCS Pte. Ltd.
Download the Sample Code for this Article
Synopsis: The releases of Windows Communication Foundation (previously known by its code-name Indigo and now known by its abbreviation “WCF”) Community Technology Preview (CTP) have attracted much attention from software developers and IT professionals from the field alike. Destined to be the next version of every Microsoft distributed technology out there today as well as the foundation for creating service-oriented applications on the Windows platform, one of the immediate concerns would be its integration, migration and interoperability with some of the existing Microsoft Web Services technologies. This article will focus on some of the migration and interoperability scenarios with Web Services Enhancements (WSE) and WCF, specifically with WSE 2.0.
Introduction
Web Services Enhancements (WSE) 2.0 simplifies the development and deployment of secure Web services by enabling developers using Visual Studio .NET and the .NET Framework to more easily apply security policy, establish long-running secure conversations, retrieve and validate security tokens, and more. It has been in release mode since 2004 and was one of the first advanced Web Services toolkits to hit the market. As such, we can expect a fair number of deployed solutions that are now using certain features of WSE 2.0 in one way or another. Based on conventional wisdom, one of the key WSE features used in the development of real-world solutions today is that of Web Services Security. Incidentally, WSE 2.0 implements the OASIS WS-Security 1.0 specifications. This WS-Security specification, ratified as a standard by OASIS since 2004, describes how to secure Web services at the message level, rather than at the transport protocol or wire level. Existing transport-level solutions such as SSL/TLS provide solid point-to-point data encryption and authentication but have limitations if a message needs to be processed or examined by an intermediate service.
The global embrace of SOAP in Web Services, which are standard cross-application communication protocols, has changed the face of software design and development. Today, it is not uncommon to find traces of the use of SOAP in deployed distributed applications and in “undistributed” ones as well. We are also slowly moving towards an era where there is a need for more business collaboration among the participants in an industry value chain to create better business value and innovation to the business consumer and returns on investment to the business owner.
The key to embracing the use of SOAP on a broad industry level in the enterprise lies in solving the 3 domain aspects of Security, Reliable-Messaging and Transactions in Web Services Architecture.
Software development environments must keep pace with technological changes and industry needs. This must be reflected in the tools and in the integrated development environments that developers use to build highly distributed and broadly interoperable service-oriented applications.
Microsoft’s upcoming technology for the creation of service-oriented applications is Windows Communication Foundation (WCF). As a core component of WinFX, it is designed to address and solve these challenges. WCF is implemented in managed code as an extension to the Microsoft .NET Framework 2.0 and is touted to be the next version of every Microsoft distributed technology out there today. It is also Microsoft’s unified programming model for rapidly building service-oriented applications on the Windows platform.
As such, WCF is designed and built on the basis of 3 key principles of
1. Unification
2. Interoperability and Integration
3. Productive Service-Oriented Programming
WCF applications will be able to wire-interop with other applications that may or may not be based on WCF or even Windows. Interoperability between applications begins and ends on the wire. As long as the message sent on the wire fits the wire-data model of the receiving application and vice-versa, interoperability can be achieved.
For this to happen, both sides of the communicating parties rely heavily on Web Services and other advanced WS-* standard protocols. The industry bodies of W3C, OASIS and WS-Interoperability Organization (WS-I) have gone through great lengths to define these standard protocols so that it can be widely accepted and adopted by the industry to create interoperable service-oriented applications.
WS-I, in particular, has created a few widely accepted and adopted specifications called Profiles (Basic Profile, Basic Security Profile, Attachments Profile, etc). Profiles comprise a set of named and versioned Web services specifications together with a set of implementation and interoperability guidelines recommending how the specifications may be used to develop interoperable Web services.
In terms of the definition of Integration in this article context, it means that WCF application will be able to work with Microsoft’s current set of distributed technologies such as ASMX, COM+ Enterprise Services and MSMQ. In addition, it will come with its own set of connectors and adapters to integrate with BizTalk Server and the Service Broker of SQL 2005.
However, just like interoperability, there exist some integration caveats on certain code changes with each specific Microsoft distributed technology before integration nirvana can be achieved. It is beyond the scope of this article to go into that space.
Another important aspect to take note is that of migration. Migration, in this context, refers to making changes to existing pieces of code. The efforts to migrate them to WCF will also differ with each of the Microsoft Technologies. It is logical to conclude that migration efforts to WCF can be justified if there is existing code that needs to be modified significantly, be it in the form of changing business logic and technical code, or the addition of new functionality. In most cases, the migration efforts to WCF could be a justification in itself.
In this article, I will discuss specific wire-interoperability scenarios between WSE 2.0 and WCF as well as a couple of migration scenarios from WSE 2.0 to WCF.
WSE 3.0 has just been released since November 2005 and it is a widely anticipated product release not just for its interoperability with WCF but also for its implementations of the newer specifications.
Some of the new features of WSE 3.0 include [Resources: 2]:
· Support for the W3C MTOM Recommendation to enable large amounts of binary data to be sent efficiently and securely.
· An improved policy framework
· Improved session management when using WS-SecureConversation and Security Context Tokens (SCTs). SCTs can now contain the original client authentication token when sent from the client to the service, which enable sessions to be re-established if lost e.g. when a service's application domain is reset. This provides reliability for the session and enables sessions to be used in web farm scenarios.
· WS-SecureConversation sessions can now be cancelled explicitly.
· Support for updated Web services specifications including WS-Addressing, WS-Security, WS-Trust, and WS-SecureConversation.
· Integrated tool support with Visual Studio 2005. The WSE 3.0 configuration tool can be accessed via the context menu on the Visual Studio 2005 Solution Explorer.
· Support for 64 bit runtime.
The following guidelines should be noted for interoperability between current and future Microsoft products WSE 2.0, WSE 3.0 and WCF. Because of the specification changes in WS-Addressing, WS-Trust and WS-SecureConversation,
· WSE 3.0 applications do not interoperate with WSE 2.0 applications. However, WSE 3.0 and WSE 2.0 client applications can run side-by-side with the .NET Framework 2.0. You can host WSE 3.0 Web services and WSE 2.0 Web services on the same computer, but they must be in separate virtual directories for ASP.NET or separate applications for Windows.
· Microsoft does not support interoperability between WSE 2.0 and WSE 3.0.
· Microsoft does not support interoperability between WSE 2.0 and WCF.
· Microsoft intends to provide interoperability between WSE 3.0 and WCF.
· Microsoft will not provide an automated mechanism to upgrade WSE 3.0 or WSE 2.0 applications to run on WCF.
· Microsoft will publish code migration guidelines to aid in the transition of moving application functionality from WSE 3.0 to WCF.
There are a lot more resources to be found here at Microsoft’s Patterns and Practices site. It should be noted that since some of the newer and advanced specifications have not been really nailed down yet, it would be unrealistic to expect full and broad-based interoperability with these specifications.
Having said all these, why is there a need to even look at wire-interoperability and migration between WSE 2.0 and WCF?
WSE 2.0 has seen 3 service pack releases since its official launch in 2004. It implemented the OASIS Web Services Security 1.0 specification which was the widely accepted interoperability standard protocols between secured web services as well as the implementations of WS-Addressing, WS-SecureConversation and WS-Trust. It was integrated very nicely into Visual Studio 2003. Even BizTalk Server 2004 carries with it a WSE 2.0 adapter for securing of Web Services. Thus, it would be fair to assume that there is more than its fair share of implementations in the market today.
Depending on timing, budget, complexity and a whole host of other requirements, some of these applications will need to be moved and migrated to WSE3.0 and some to WCF. Aaron Skonnard has provided a great resource in his “Service Station” column on MSDN on a brief overview on the migration of WSE 2.0 applications to WSE 3.0 ones. However, as stated in his article, there are some major changes in the programming model and architecture in WSE 3.0 and migrating them from WSE 2.0 may not be trivial.
Another very important factor to take note is while WinFX, and therefore WCF, is available downstream from Windows Vista to Windows 2003 and Windows XP. That is as far down as it goes. There still exists a huge installed base of Windows 2000 Servers out there running on server and data farms and if you need to implement the advanced Web Services stacks on those servers, WSE is still a very important strategy you cannot ignore.
As noted in the above guidelines, even though Microsoft will not guarantee interoperability between WSE 2.0 and WCF, the good news is that there are a few WSE 2.0 common scenarios, which can allow wire-interoperability with WCF. I will illustrate them in the next section.
As I have mentioned in an earlier paragraph, besides SOAP Routing and Addressing scenarios, I believe that WSE 2.0 is used primarily for WS-Security scenarios today. The main reason for my assumption is that the OASIS WS-Security 1.0 Specification is relatively much more mature and widely accepted than its addressing counterpart. However, I am still very inclined to believe that a fair bit of the Web Services Security today happens in the transport layer with SSL / HTTPS. Security at the transport layer can provide a very solid point-to-point data encryption and authentication solution. Although, it is limited in an end-to-end situation where multiple SOAP processing nodes plus other client-authentication and performance constraints is involved, being able to withstand intense public security scrutiny over the years has certainly helped it to become a legitimate contender for any sort of point-to-point distributed security solution on the HTTP protocol.
Let us look at a few possible security scenarios whereby a WSE 2.0 client is able to wire-interoperate with a WCF service implementation and vice-versa. These involve the use of username tokens and X509 Digital Certificates. I will briefly describe each of these scenarios below. Project details of all the described interoperability scenarios can be found in the attached solutions.
The environment needed to run the interoperability scenarios between the two solutions below require:
· For the WCF Environment
1. WinFX February CTP
2. Visual Studio 2005
3. IIS 6.0 with Digital Certificate Stores and SSL properly configured and set-up
· For the WSE 2.0 Environment
1. WSE 2.0 SP3
2. Visual Studio 2003
3. IIS 6.0 with Digital Certificate Stores and SSL properly configured and set-up
· Attached is also a set of certificates that you can use for the X509 Certificate Mutual Authentication scenarios that I will described later. These certificates each come with their Subject Key Identifier (SKI) for best interoperability results. See Figure 1. The SKI is an X509 version 3 extension that should be used to achieve interoperability. Alternatively, you can try to create test digital X509 certificates from public CA sites out there. The certificates that come with neither the WCF SDK nor the ones generated by the makecert.exe utility come with the SubjectKeyIdentifier.

Figure 1
Let us take a closer look at each of these security credentials.
A Username token is just like using basic HTTP authentication, except that the token is within the SOAP message headers. It is one of the simplest and easiest security token-based solutions to implement with WSE 2.0. When user authentication is involved, you'll often use the Username token to authenticate with a server. The password can be dispatched to the receiving application either through one of the following self-explanatory PasswordOption transmission modes of SendPlainText, SendHashed or SendNone.
One of the key drawbacks of using username token to secure or sign the messages is that the password is based on a symmetric shared secret. Consider that if a username token is often used to sign messages and encrypt messages, you are allowing an attacker to see these signatures or ciphertext which renders your shared secret and therefore your message to the dreaded offline brute force and dictionary attacks. This also includes the digest produced by PasswordOption.SendHashed in WSE 2.0 [Resources: 3]
The PasswordOption.SendHashed also encourages the server-side plumbing to store cleartext passwords on the server. This is in consideration of how the server must react when sent a hash of a nonce, timestamp, and cleartext password. The executing program code must look up the user's clear text password, and combine it with the nonce and timestamp sent in the message in order to calculate the hash value. Needless to say, storing cleartext passwords in server-side username account databases is a very dangerous practice
WSE 3.0 and WCF have moved away from using the hashed password as well as the <nonce> element in the username token that WSE 2.0 implements. The reason for not supporting the use of Hashed Passwords is due to the implications of the false perceived security hashed passwords brings. WCF’s standard bindings can only encrypt the username token (and therefore the user password as well) either with channel (transport) security or with the service X509 Digital Certificate. In other words, the username and its password credentials cannot be used for encrypting or signing the message in WCF. This encourages the development of a much more secure and simpler end-to-end solution.
Keith Brown has written an excellent article [Resources: 3] on how best to secure a username token with WSE 2.0.
Nonce and Created fields inside usernamepassword tokens were the mechanisms used for replay detection in WSE 2.0 as well as signatures and timestamps. The latter mechanisms offer a much more interoperable way in moving forward and are used specifically in WSE3 and WCF since other technology vendor platforms do not use the Nonce and Created elements as well.
One of the scenarios that offer wire-interoperability between WSE 2.0 and WCF involves the sending of username tokens over a secured transport layer (SSL / HTTPS)
The easiest straightforward way for a successful interoperability scenario is to leverage on transport-layer security. This also means that a properly configured WCF implementation can interoperate with a Basic Profile 1.0 compliant ASP.NET Web Service (ASMX) that is currently deployed via SSL / HTTPS as well as with a WSE 2.0 service or client and likewise.
WCF has a standard binding called “<basicHttpBinding>” which derives its name from the Basic Profile specifications. There is a security mode within this binding called “TransportWithMessageCredential”. You can choose either a transport or a message credentials in this security mode. Setting it to <message clientCredentialType="UserName"/> uses Transport-Level Security (SSL / HTTPS) with SOAP-Level Username token security credentials. This is in accordance with the WSS SOAP Message Security Username Token Profile 1.0 and it implements WSS SOAP Message Security 1.0 specification for username/password (for client authentication) over HTTPS (for privacy).
A WSE 2.0 client can easily interoperate with a WCF service with username tokens for authentication. See Table 1 for the configured <basicProfileBinding> section in a WCF service configuration. While defining bindings in a service configuration file is the most flexible and practical approach, you can just as easily define your own custom bindings in code as you could via a configuration file. I will illustrate how custom bindings can be done in code in a later section.
|
<bindings>
<basicHttpBinding>
<binding name="SomeArbitraryName">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None"/>
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings> |
Table 1
Table 2 shows how you can set the username and password in a WSE client to communicate with a HTTPS-enabled WCF service.
|
Dim unt As New UsernameToken("Softwaremaker", "drowssaPemoS", PasswordOption.SendPlainText)
Dim indigoSvcProxy As New WSE2IndigoInteropServiceWse
indigoSvcProxy.Url = "https://WCFServer/WCFInteropWithWSE2SP3/WCFTestService.svc"
indigoSvcProxy.RequestSoapContext.Security.Tokens.Add(unt)
Dim crdCard As New CreditCard
crdCard.AccountName = "William Tay"
crdCard.CreditCardType = "American Express"
crdCard.CreditCardNo = "1234567890"
crdCard.CreditCardExpiryDate = "08082008"
Console.WriteLine(indigoSvcProxy.SubmitCreditCard(crdCard)) |
Table 2
To switch sides, to set the username and password in a WCF client to communicate with a HTTPS-enabled WSE 2.0 service, we can either set the username / password via a WCF client proxy or use a Channel Factory to do so. You can also use your own configured bindings in code or referenced a set of customizable bindings in your configuration file to get the Channel Factory to create the appropriate channel for you. See Table 3.
|
Dim cFactory As New ChannelFactory(Of IWSE2IndigoInterop)("SomeArbitaryConfigName")
‘OR
Dim cFactory As New ChannelFactory(Of IWSE2IndigoInterop)(SomeCodeBinding, _
'New EndpointAddress(New Uri("https://WSE2Server/WCFInteropWithWSE2SP3/WSE2TestService.asmx ")))
cFactory.Credentials.UserName.UserName = “Softwaremaker”
cFactory.Credentials.UserName.Password = “drowssaPemoS”
Dim indigoSvcProxy As IWSE2IndigoInterop = cFactory.CreateChannel
Console.WriteLine(indigoSvcProxy.SubmitCreditCard(crdCard)) |
Table 3
Note the sending to a HTTPS endpoint above. If the endpoint is not configured properly to implement HTTPS or if I send a message to a HTTP endpoint, the channel will throw an exception complaining that the HTTP scheme is incorrect and it is expecting a HTTPS scheme.
While WSE 2.0 supports all the three forms of sending passwords in usernametokens (PlainText, None, Hashed). For best security and interoperability scenarios, I would recommend to use this PlainText approach and protect the password via a transport-level or message-level security measures.
As I have mentioned above, one other thing to take note of is that in order for WSE 2.0 to consume usernametokens from other advanced Web Services toolkits as well as WCF, one needs to disable the WSE <replayDetection> feature, i.e. <replayDetection enabled=”false” />. This is the way forward and WSE 3.0 is removing its dependency on those elements as well.
What we have seen above are examples of using the Username Tokens to do Windows Authentication. If you should desire to use a custom authentication scheme for your working scenario, you can do so easily with the new built-in support for membership (user name/password credential storage) and role management services that is provided by the .NET Framework 2.0 and Visual Studio 2005 (You can read more about how to implement a Membership Provider in .NET 2.0 here).
Below in Table 4 is a short snippet of the membership provider as implemented in the attached solution.
|
Public Class SWMMembershipProvider : Inherits MembershipProvider
' ...
Public Overrides Function ValidateUser(ByVal username As String, ByVal password As String) As Boolean
‘Probably read from a custom username / password credentials store. I will use the below logic for simplicity.
If username = "Softwaremaker" And password = "drowssaPemoS" Then Return True
End Function
' ...
End Class |
Table 4
In the WCF service configuration file, there are a couple of settings to take note of as shown in Table 5.
|
<configuration>
...
<system.serviceModel>
<services>
<service name="WSE2IndigoInteropService" behaviorConfiguration="returnFaults">
<endpoint contract="IWSE2IndigoInterop" binding="basicHttpBinding" bindingConfiguration="WSE2WCFSvcBehavior"/>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="UsernameTokenOverTransportSecurity">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None"/>
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<behavior name="WSE2WCFSvcBehavior" returnUnknownExceptionsAsFaults="true">
<serviceCredentials>
<userNameAuthentication membershipProviderName="SWMMembershipProvider" userNamePasswordValidationMode="MembershipProvider" />
</serviceCredentials>
</behavior>
</behaviors>
...
</system.serviceModel>
<system.web>
...
<membership>
<providers>
<add name="SWMMembershipProvider" type="SWMMembershipProvider" />
</providers>
</membership>
</system.web>
</configuration> |
Table 5
Table 6 below shows the resultant snippet of the interoperable message exchanges between a WSE 2.0 client and a WCF service. This entire message is encrypted via the HTTPS transport protocol while in transmit and will only be the clear once it reaches its intended endpoint. The WS-Addressing headers implemented by WSE 2.0 are different from those implemented by WCF. However, WCF ignores the addressing headers sent by WSE 2.0 because they are not stamped with a mustUnderstand=“1”.
|
<soap:Header>
<!-- WSE 2.0's implementation of WS-Addressing Headers -->
<wsse:Security soap:mustUnderstand="1">
<wsu:Timestamp wsu:Id="Timestamp-b2859cb8-bdf3-40d8-8c57-517212b01bac">
<wsu:Created>2005-08-15T04:28:13Z</wsu:Created>
<wsu:Expires>2005-08-15T04:33:13Z</wsu:Expires>
</wsu:Timestamp>
<wsse:UsernameToken xmlns:wsu="..." wsu:Id="SecurityToken-...">
<wsse:Username>Softwaremaker</wsse:Username>
<wsse:Password Type="...">SomePassword</wsse:Password>
<wsse:Nonce>wtsRMoMaaUvCXmlpSy2Xfg==</wsse:Nonce>
<wsu:Created>2005-08-15T04:28:13Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soap:Header>
<soap:Body>
<!-- ... -->
</soap:Body>
</soap:Envelope> |
Table 6
[Author note]: For HTTPS communication between the two endpoints, the appropriate SSL Certificate is to be properly installed in the Digital Certificate store and the Directory Security \ Secure Communications in IIS is properly set up as well.
Besides the username token security credentials, the other security credential that can offer interoperability between WSE 2.0 and WCF involves the use of X509 Digital Certificates on both ends of the communicating channel.
An asymmetric key encryption solution is a lot more secure than a symmetric one that is employed by using a username token. However, processing performance takes a back seat in comparison to a symmetric one. It is generally not advisable to encrypt or sign a message using a user password, due to its weak nature. Instead, we should employ a strong session key with good key length and then encrypt that symmetric key with an asymmetric one. WS-Security uses a combination of these techniques with Public-Private keys and X509 certificates.
While encrypting a message via a transport protocol is very useful and is widely accepted, it does have its restrictions. Besides being restricted to an end-to-end scenario instead of a point-to-point one, it is restricted to the transport itself. This makes it very difficult to re-use the same security channel over another transport such as TCP, SMTP or MSMQ. In many complex messaging scenarios, a message must be secured and routed over different transports just to get to its ultimate destination. Another drawback is the factor of non-repudiation whereby many transaction and audit trail requirements stipulate that integrity needs to be persisted all the way to a database, for example, instead of ending at the transport layer. HTTPS has no signature that can be used for non-repudiation.
WSE 2.0 supports the use of mutual X509 Certificates to secure messages using only WS-Security 1.0 while WSE3 and WCF supports both Mutual Certificate Authentication 1.0 (WS-Security 1.0) as well as Mutual Certificate Authentication 1.1 (WS-Security 1.1). One of the significant advantages WS-Security 1.1 has over 1.0 is the use of a symmetric encrypted key to sign messages and then securing that key with an asymmetric key algorithm. This reduces the payload of the signature as well.
Having explained the benefits of message security over a transport channel security above, let me show you how easy it is to configure your WCF security bindings so that it is able to understand and respond to an incoming signed and secured message from a WSE2.0 client.
There is a MessageProtectionOrder property and other security bindings we need to set in the AsymmetricSecurityBindingElement to facilitate interoperable secured messages between both WSE2 and WCF.
One of the message protection ordering properties that WCF supports is the signing and encryption of confidential or sensitive information messages and this offers a good scenario for a secured exchange between WSE 2.0 and WCF.
WCF supports three MessageProtectionOrder of a message – SignBeforeEncrypt, EncryptBeforeSign and SignBeforeEncryptAndEncryptSignature. As far as using WS-Security 1.0 and asymmetric security is concerned, an EncryptBeforeSign message protection order is generally not as secure as a SignBeforeEncrypt one because it can enable a man-in-the-middle attack where the attacker replaces the sender's signature without the recipient being able to detect that it has been replaced. We will focus on the SignBeforeEncrypt method, which is the default value, in this interoperability scenario.
To show the extensibility of WCF a bit more, I employ the use of custom bindings via code in this example instead of the configuration-based one I did in the earlier example. Do take note that both can be used to extend and configure the security, transport, encoding bindings.
Table 7 below shows how I consume my custom-defined binding in a ServiceHost implementation. Take note that I have set the SoapMessageProtectionOrder property = MessageProtectionOrder.SignBeforeEncrypt. This is to specify the order of encryption and signing of messages. In this case, we are signing first then encrypting it later. As stated in the OASIS WS-Security specifications, security headers can be re-ordered by intermediaries. However, there are no rules governing the order in which headers are processed. Security headers will generally have ordering dependencies. Let me try to illustrate. It is important to note that SOAP headers can be re-ordered by intermediaries. Therefore, a SOAP message that was sent out as follows:
<soap:Header>
<header1>...</header1>
<header2>...</header2>
</soap:Header>
can be re-ordered by processing intermediaries and thus can be received looking like this:
<soap:Header>
<header2>...</header2>
<header1>...</header1>
</soap:Header>
SOAP endpoints should still be able to process the message, as there are no rules governing the order in which headers are processed. However, security headers generally do have some form of ordering dependencies. If the message body is to be signed first before encryption or vice-versa, the message receiver needs to know the order of the process so it can carry out the decryption first before signature verification or vice-versa. There is a more detailed explanation of this in an earlier article I have here.
Another thing to take note of is the SecurityAlgorithmSuite. The recommended combination would be AES256 for symmetric encryption and RSA-OAEP for key-wrapping. This would be the default algorithm suite used in WCF and WSE 3.0 as well. However, this key transport algorithm that is not implemented by all vendors that have an advanced Web Services stack as their offerings. Key transport algorithms are used to optimize encryption by encrypting symmetric encryption keys, such as data encryption keys, with asymmetric encryption keys. RSA-OAEP is also not supported on Windows operating systems earlier than Windows XP. WS-I Basic Security Profile refers to the key transport algorithm with the following excerpt:
R5621 When used for Key Transport, any xenc:EncryptionMethod/@Algorithm attribute in an ENCRYPTED_KEY MUST has a value of http://www.w3.org/2001/04/xmlenc#rsa-1_5” or “http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p”
The RSA (PKCS#1.5) algorithm (“http://www.w3.org/2001/04/xmlenc#rsa-1_5”) is widely implemented and deployed in existing practice. The RSA-OAEP algorithm (“http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p”) is relatively new and becoming widely implemented and deployed.
WSE 2.0 uses the AES128 and RSA1.5 as its security algorithm. Therefore, to interoperate with WSE 2.0, we need to set that to the value of “Rsa15Aes128” in WCF as shown in Table 7.
If you should decide to strengthen the security key algorithm in WSE 2.0, there are ways to make WSE 2.0 emit out the appropriate crypto algorithms via the <binarySecurityTokenManager> section in the WSE 2.0 configuration file (Table 8) or via WSE 2.0 code (Table 9). Of course, the same set of the security algorithm suite need to be set in WCF as well for interoperability to happen.
|
Public Class WSE2FriendlySvcHost : Implements IServiceHostFactory
Public Function CreateServiceHost(ByVal constructorString As String, ByVal baseAddresses() As System.Uri) As System.ServiceModel.ServiceHostBase Implements System.ServiceModel.IServiceHostFactory.CreateServiceHost
Dim serviceHost As ServiceHost
serviceHost = New ServiceHost(GetType(WSE2IndigoInteropService), baseAddresses)
serviceHost.Description.Endpoints.Clear()
Dim wse2HttpBinding As New WSE2WCFHttpBinding
wse2HttpBinding.SecurityAssertion = WSE2WCFSecurityAssertion.MutualCertificate10
wse2HttpBinding.SoapMessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt
wse2HttpBinding.SoapMessageSecurityAlgorithmSuite = SecurityAlgorithmSuite.Rsa15Aes128
Dim svcCreds As ServiceCredentials = New ServiceCredentials()
svcCreds.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, _
StoreName.My, X509FindType.FindBySubjectName, "Server")
svcCreds.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, _
StoreName.TrustedPeople, X509FindType.FindBySubjectName, "Client")
svcCreds.ClientCertificate.Authentication.CertificateValidationMode = ServiceModel.Security.X509CertificateValidationMode.PeerOrChainTrust
serviceHost.Description.Behaviors.Add(svcCreds)
' Add a single endpoint that supports this custom Binding
serviceHost.AddServiceEndpoint(GetType(IWSE2IndigoInterop), wse2HttpBinding, "")
Return serviceHost
End Function
End Class |
Table 7
|
<microsoft.web.services2>
…
<security>
<binarySecurityTokenManager
valueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">
<sessionKeyAlgorithm name="AES256"/>
<keyAlgorithm name="RSA15"/>
</binarySecurityTokenManager>
</security>
...
<microsoft.web.services2> |
Table 8
|
Dim secTokMgt as ISecurityTokenManager = _ SecurityTokenManager.GetSecurityTokenManagerByTokenType(WSTrust.TokenTypes.X509v3)
secTokMgt.DefaultSessionKeyAlgorithm = "AES256"
secTokMgt.DefaultKeyAlgorithm = "RSA15" |
Table 9
The WSE 2.0 code client side to invoke a WCF service is relatively straightforward and it explicitly signs the message first before it encrypts the data (Table 10).
|
Try
Dim X5Store As X509.X509CertificateStore
X5Store = X509.X509CertificateStore.CurrentUserStore( _
X509.X509CertificateStore.OtherPeople)
Dim open As Boolean = X5Store.OpenRead()
Dim eXDCert As X509.X509Certificate = X5Store.FindCertificateByKeyIdentifier _
(Convert.FromBase64String(AppSettings("ServerCertBase64String")))(0)
X5Store = X509.X509CertificateStore.CurrentUserStore(X509.X509CertificateStore.MyStore)
open = X5Store.OpenRead()
Dim sXDCert As X509.X509Certificate = X5Store.FindCertificateByKeyIdentifier _
(Convert.FromBase64String(AppSettings("ClientCertBase64String")))(0)
Dim sXToken As New X509SecurityToken(sXDCert)
Dim eXToken As New X509SecurityToken(eXDCert)
Dim indigoSvcProxy As New WSE2IndigoInteropServiceWse
indigoSvcProxy.RequestSoapContext.Security.Elements.Add(New MessageSignature(sXToken))
indigoSvcProxy.RequestSoapContext.Security.Tokens.Add(sXToken)
indigoSvcProxy.RequestSoapContext.Security.Elements.Add(New EncryptedData(eXToken))
' ...
Catch
'...
End Try |
Table 10
Binding the WSE 2.0 application to a WS-Policy file is relatively straightforward as well. The WS-Policy file to bind to in our attached example would be “SignEncInSignEncOut_TSnBODY.config” and just like the above, we are just signing and encrypting the soap:Body and the timestamp. Figure 2 (at the end of this article) shows what our WSE 2.0 WS-Policy file looks like which asserts a Signed and then Encrypted message exchange.
You can use the same binding settings above if you would want a WCF client to talk to a WSE2 service. In the attached sample, I have the same policy file (as defined in Figure 2) bound to my WSE2 service.
On my WCF client, once I have defined my security bindings, I used the ChannelFactory to create an outgoing channel with the appropriate endpoint address and the defined bindings before sending the message across. Table 11 shows my WCF client code.
|
Dim wse2HttpBinding As New WSE2WCFHttpBinding
wse2HttpBinding.SecurityAssertion = WSE2WCFSecurityAssertion.MutualCertificate10
wse2HttpBinding.SoapMessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt
wse2HttpBinding.SoapMessageSecurityAlgorithmSuite = SecurityAlgorithmSuite.Rsa15Aes128
‘---
Dim cFactory As New ChannelFactory(Of IWSE2IndigoInterop)(wse2HttpBinding, _
New EndpointAddress(New Uri("http://WSE2Server/WCFInteropWithWSE2SP3/WSE2TestService.asmx "), Identity.CreateDnsIdentity("Server")))
'---
cFactory.Credentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.CurrentUser, _
StoreName.TrustedPeople, X509FindType.FindBySubjectName, "Server")
cFactory.Credentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, _
StoreName.My, X509FindType.FindBySubjectName, "Client")
cFactory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust
‘---
Dim svcProxy As IWSE2IndigoInterop = cFactory.CreateChannel
Console.WriteLine(svcProxy.SubmitCreditCard(cc)) |
Table 11
Setting the certificateValidationMode to PeerOrChainTrust means that if the certificate is in the user's Trusted People store, the message will be trusted without WCF performing a validation of the certificate's chain.
Another thing you may want to take note is that when you create the CreateMutualCertificateBindingElement from AsymmetricSecurityBindingElement, you need to set the value of allowSerializedSigningTokenOnReply to “True”.
The primary reason for this is how both WCF and WSE generates and expects references to the signing token in the security headers. WCF spits out and expects external reference for the signature token on the response. It is done to simplify cryptographic correlation - verification that response is signed with the private key corresponding to the public key used (in the request message) during encryption of the response. WSE, on the other hand, churns out an internal reference to the signing token on the response but it can accept either an internal or an external reference.
To add a brief explanation note: An internal reference to a signing token means that the SecurityTokenReference points to a BinarySecurityToken encoded in the message while an external reference implies that the SecurityTokenReference is pointing to an “external” KeyIdentifier that corresponds to an installed X509 Certificate token with a stated base64 encoding of its Subject Key Identifier.
To ensure that the WCF client is able to deserialize a reply message from a WSE2.0 service, which will contain an internal reference to the BinarySecurityToken encoded in the message, the allowSerializedSigningTokenOnReply property must be set to “True” in the security bindings of WCF.
There may be scenarios where you would want signed-only messages just for the purpose of non-repudiation and prevention of data tampering. This is done very easily in WCF by setting the ProtectionLevel to “Sign” when you decorate your functions or routines with the OperationContracts attributes.
<OperationContract(ProtectionLevel:=Net.Security.ProtectionLevel.Sign)>
Do remember that signed messages do not offer any data-encryption on the wire and is therefore susceptible to eavesdropping and confidentiality issues.
Since some of the newer and advanced specifications have not been fully established yet, it would be unrealistic to expect full and broad-based interoperability with these specifications.