Now there are plenty of posts out there that deal with WSE, though we are going to concentrate solely on Mutual Authentication.
Mutual authentication requires certificates to be in both locations, now it is possible for use of a single certificate. The problem is once the single certificate is compromised then the whole system is compromised, we will go deeper into this soon.
Let’s look at a simple setup:

Now we want to make it so that all communications between this client and server are secure and only this client can talk to this service.
In order to achieve this, we must create 2 certificates that both contain a public/private keys as well as Digital Signature, Key Encipherment Data and Encipherment. We will go though how to create this type of certificate later.
Hence here is how we have to break down the certificates.

Now in order for Mutual Authentication to work, the Service (server side) needs each client you plan to allow to connect (Authorization, Authorized Clients). The client only requires its own certificate and the public key certificate of the server.
Now first we need to have .NET 2.0 and WSE 3.0 installed as well as VS.NET 2005.
Let’s take a look at what the client’s web.config looks like (and what it must contain), when you run though the WSE 3.0 wizard in VS.NET you will get several things added to your configuration file. One of those items worth mentioning is:
<microsoft.web.services3>
<policy fileName="wse3policyCache.config" />
<security>
<x509 allowTestRoot="false" verifyTrust="true" />
</security>
</microsoft.web.services3>
This tells WSE3 what policy file to use; it also lets it know if we are doing this in test and if we should verify the trust of the certificate.
If Trust is set to true then the issuer of the certificate has to be a trusted source (as well as the issuer of the Server certificate). If you run into trust issues on the client of the server certificate, you can always add the certificate to the trusted people store of your certificate stores. One way to have an un-trusted certificate is if you use your own CA to issue certificates and the foreign computer that it is imported into is not in your domain. Since it’s not in your domain, it can’t walk the certificate ladder to verify if it trusts the issuer of the certificate.
There are times when you will need to debug what’s going on in your web service. You would simply add this line and place it as follows:
<microsoft.web.services3>
<diagnostics>
<trace enabled="false" input="InputTrace.webinfo" output="OutputTrace.webinfo" />
</diagnostics>
<policy fileName="wse3policyCache.config" />
<security>
<x509 allowTestRoot="false" />
</security>
</microsoft.web.services3>
Setting the “Trace Enabled” to true will now save all information that either hits or is sent to the service. Hence if you turn this on the web service side, then input = data coming in from client and output = data going to client. If you turn this on the client side then input = data coming in from service and output = is data going out to service. Most problems will generate a WSE910 error, hence without this trace information you will go insane trying to find out what the problem is.
Now let’s look at the policy file, it is also possible to have more then one policy, for instance you have a client application that calls several web services. Note if all those web services are on different computers and you are using mutual authentication then your client will need the public key certificate for each service.
<policies xmlns="http://schemas.microsoft.com/wse/2005/06/policy">
<extensions>
<extension name="usernameForCertificateSecurity" type="Microsoft.Web.Services3.Design.UsernameForCertificateAssertion, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<extension name="x509" type="Microsoft.Web.Services3.Design.X509TokenProvider, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<extension name="requireActionHeader" type="Microsoft.Web.Services3.Design.RequireActionHeaderAssertion, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</extensions>
<policy name="ClientPolicy">
<mutualCertificate11Security establishSecurityContext="true" renewExpiredSecurityContext="true" requireSignatureConfirmation="true" messageProtectionOrder="SignBeforeEncrypt" requireDerivedKeys="true" ttlInSeconds="300">
<clientToken>
<x509 storeLocation="LocalMachine" storeName="My" findValue="CN=Clntcert" findType="FindBySubjectDistinguishedName" />
</clientToken>
<serviceToken>
<x509 storeLocation="LocalMachine" storeName="My" findValue="CN=Srvcert" findType="FindBySubjectDistinguishedName" />
</serviceToken>
<protection>
<request signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="true" />
<response signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="true" />
<fault signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />
</protection>
</mutualCertificate11Security>
<requireActionHeader />
</policy>
</policies>
Ok, as you can see here we have a “ClientPolicy” setup here, now we are not going to go though everything, but what I wanted to point out that causes the most trouble is that everything here (including the “extensions” at the top) needs to be the same as the servers policy file. Hence if you do something as simple as setting the “establishSecurityContext=”false”” and the server has it set to “true” then boom your connection between the client and server will fail. Now the differences are what certificates to use. Here you see the client’s certificate is “CINTCERT” and is what is used for the client token, then for the service token we got “SRVCERT” which is the public key certificate on the client of the server.
As you can see, it’s very important that settings match up, any one setting will cause a 910 error that means NOTHING AT ALL, and it’s so general that there are hundreds of things that could cause the error, including the two machines being out of time sync.
Another common error is that it can’t read the private key because of access security issues. Hence if you run trace it might tell you that “Object contains only the public half of a key pair. A private key must also be provided” now this could be a messed up certificate, or it could be that it can’t read the certificate. Hence the only way to fix this (after you verified that the client certificate has a public/private combo) is to give “Everyone” full rights to the “C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto” folder. Yes I know this isn’t nice, but I have personally tried giving proper accounts (Network Services and such) the rights needed and there is something, somewhere that keeps things from not working. Setting “Everyone” to full control fixes the problems. Now you must also hit the “Advanced” button and replicate the permissions to ever sub folder and item as well. This is also what was found via several searches on Google, many other people had to resort to the same extremes to get things working.
Now if I sound like I just know how to make it work a not how it works, you are right. Many long days on the phone with MS and many long hours finding solutions to issues have taught me one thing. Change 1 value and nothing works, it’s that simple. Just 1 value change and you get a very vague error and spend hours to track it down. To the point that you just concentrate on making sure things are the same all the way across the boards.
Let’s take a look at a service’s Policy file.
<policies xmlns="http://schemas.microsoft.com/wse/2005/06/policy">
<extensions>
<extension name="usernameForCertificateSecurity" type="Microsoft.Web.Services3.Design.UsernameForCertificateAssertion, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<extension name="x509" type="Microsoft.Web.Services3.Design.X509TokenProvider, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<extension name="requireActionHeader" type="Microsoft.Web.Services3.Design.RequireActionHeaderAssertion, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</extensions>
<policy name="IEPUserGroupList">
<authorization>
<allow user="CN=IEPWSE" />
<deny user="*" />
</authorization>
<mutualCertificate11Security establishSecurityContext="true" renewExpiredSecurityContext="true" requireSignatureConfirmation="true" messageProtectionOrder="SignBeforeEncrypt" requireDerivedKeys="true" ttlInSeconds="300">
<serviceToken>
<x509 storeLocation="LocalMachine" storeName="My" findValue="CN=Srvcert" findType="FindBySubjectDistinguishedName" />
</serviceToken>
<protection>
<request signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="true" />
<response signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="true" />
<fault signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />
</protection>
</mutualCertificate11Security>
<requireActionHeader />
</policy>
</policies>
As you can see here, much of it looks the same (such as the Service Token). The big difference you will see is the “Authorization” section. Here we can set who’s allowed to use this web service.
The “<allow user="CN=IEPWSE" />” section sets the allowed certificates, to allow more, just keep adding more of these sections. Now the “<deny user="*" />” section pretty much says don’t allow anyone, of course unless they been allowed already in the allow section.
Lets talk a bit about creating Test Certificates. We can easily create test certificates via the certificate creation tool “Makecert.exe” (ref: http://msdn2.microsoft.com/en-us/library/bfsktky3(VS.80).aspx).
We simply create a couple test certificates:
makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=DevServer -sky exchange -pe DevServer.cer
makecert.exe -sr LocalMachine -ss My -a sha1 -n CN=DevClient -sky exchange –pe DevClient.cer
One thing you want to be sure about is you set this option in the web/app.config:
<x509 allowTestRoot="false" verifyTrust="true" />
To:
<x509 allowTestRoot="true" verifyTrust="false" />
On both sides (web service and client side), this way these certificates created above will work. Note this is strictly only for testing.
You still need to make sure your service or application's security account has sufficient to access the certificate's private key. The “WinHttpCertCfg.exe" (ref: http://support.microsoft.com/kb/901183) tool can help grant access permission for certificates; you can find it in the WSE 3.0 SDK's installation folder.
Now lets talk about creating real certificates, the following outlines how to create certificates from a certificate authority.
Problem
You are using WSE 3.0. Everything was working fine during development on another client machine
However, that dev setup is not valid on the network. So, you are setting up new certificates on both sides.
You are using WSE for authentication
When setting up the WSE configuration, you get this error on the client when selecting a certificate:
"Selected Certificate does not support data encryption"
Environment
WSE 3.0
Windows 2003
Troubleshooting /Resolution
1. From http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wse3.0/html/97451b4c-d25b-480d-b304-3bde7834eaf5.asp
Error message - Security token does not support Data Encryption.
Cause - The Key Usage property of the certificate does not include Data Encipherment.
Remedy - Use a certificate with a Key Usage property that includes Data Encipherment.
2. We reviewed the certificate and the key usage settings are - Digital Signature and Key Encipherment.
The certificate also needs to include a key usage of Data Encipherment per the MSDN documention on WSE 3.0
You were not certain how to get such a certificate, but had access to the CA Server.
3. We discussed the following article but it did not quite help.
273856 Third-party certification authority support for encrypting file system
http://support.microsoft.com/default.aspx?scid=kb;EN-US;273856
4. We discussed how we can request a new certificate from the browser by going to http://CAName/certsrv
We can select "Other" for "Type of Certificate needed" and then put in this identifier for OID "1.3.6.1.4.1.311.10.3.4" and get a certificate that has Data Encipherment as a Key Usage
However, your web interface for requesting a certificate looks very different.
You do not have the same options when requesting certificate from browser.
You have an option to "Select Template", options in the drop-down menu include "Basic EFS", "EFS Recovery Agent", "User", etc.
We tried each of these options, however none of them issue a certificate with Key Usage of "Data Encipherment"
5. So, it looks like the CA setting of the templates would need to be modified.
You have full access to the CA server.
6. We looked into possible ways of modifying the templates. We discussed that none of the built-in certificate templates issue a certificate with "Data Encipherment" as a Key Usage and that is precisely what WSE needs.
Here are the steps we took to create a new template with a Key Usage of “Data Encipherment”.
1. Open the certificate template on the CA Server machine - certtmpl.msc
2. Find a template that is close to the type of template we want to create, right click on it, and select "Duplicate Template". In our case, we selected the "Web Server" certificate to duplicate.
3. Give a new name to this new template and make the modifications necessary:
a. On the General tab, Select "Publish certificate in Active Directory"
b. On the request handling tab, from the "Purpose" drop down list, select "Signing and encryption"
c. On the Extensions tab, select "Key Usage" and hit Edit. Under Encryption, the second radio button should be selected "Allow key exchange only with key encryption". Under this select the checkbox for "Allow encryption for user data" (this is what gives the "Data Encipherment" key usage). "Digital Signature" should already be selected; if not, select it.
d. On the Extensions tab, select "Application Policies" and hit Edit. Then add "Client Authentication", if it is not already in the list of "Application Policies"
4. Open Active Directory Sites and Services. Go to view and select "Show Services node" if Services node is not visible.
a. Expand Services, Public Key Services, Certificate Templates and select the new template
b. Go to the properties of the new template and go to the Security tab. Select ENROLL for the appropriate user(s).
5. Go into Certification Authority MMC and Right Click on "Certificate Templates" and select New->Certificate Template to Issue. Select the new template
6. Now, you should be able to browse to the certificate server's web interface (http://localhost/certsrv) and request the new certificate type.
We walked through the steps above and this seemed to work!, Now, you were able to get a new certificate with correct key usage.
So, we got a certificate with following properties:
Key Usage - Data Encipherment, Key Encipherment, Digital Signing
Purpose – Client Authentication, Server Authentication.
Root Cause
The certificate being used did not have a Key Usage of “Data Encipherment”
From http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wse3.0/html/97451b4c-d25b-480d-b304-3bde7834eaf5.asp
Error message - Security token does not support Data Encryption.
Cause - The Key Usage property of the certificate does not include Data Encipherment.
Remedy - Use a certificate with a Key Usage property that includes Data Encipherment.
Related Knowledge Base Articles
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wse3.0/html/97451b4c-d25b-480d-b304-3bde7834eaf5.asp
Tips & Tricks
Here we are just going to list out the things that cause most of the problems after you get things setup.
- MAKE SURE YOUR URLS ARE CORRECT (to the service you are calling)!
- Make sure client has Public half of Server Certificate and server has public half of Client Certificate.
- Make sure your policy files are configured (as far as options) exactly the same on both the client and server.
- Be sure to either give full control to the crypto directory “C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto” to Everyone or use the “WinHttpCertCfg.exe" utility.
- WSE910 can be anything, turn on tracing on both the client and server
- Make sure the client and server clocks are in sync, they can not be out of sync since soap messages are time sensitive (expire times).
- Be sure that the certificates you create support “Data Encipherment, Key Encipherment, Digital Signing”.
- If you are using certificates that cross domains and have your web/app.config option “VerifiyTrust” set to true, you must have all the client certificates in the “TrustedPeople” store. If you don’t then they won’t be trusted and you will get a WSE910 failure.
- Unit test your web service before enabling certificates, if it fails for non-WSE reasons, it will cause a WSE910 error.
An important thing to keep in mind at all times is that this is a message level defense, hence people can still hit the service as well as see it’s methods, they just can’t execute any methods.