Monday, July 20, 2009

WCF : A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider



While working on WCF using secured connection i came across the following error

"A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider"

Here is my application scnerio
1. WCF services libraries hosted in IIS
2. Client is ASP.Net Client

Got it resolved by following the below steps

Step 1
Creating an SSL Certificate
To create a self-signed certificate to install in IIS as the SSL certificate, you can issue the following makecert.exe command from the Visual Studio 2005 command line:

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

The subject name “localhost” makes it possible to browse without errors to http://localhost or any path relative to it. The subject name of the SSL certificate must match the domain or machine name used in the path to access the site. If you used your machine name to browse to Web sites on your machine, for example
http://xyz/, you’d create the certificate with the subject name “CN=xyz”.

Step 2
Creating a Secure Messaging Certificate
To create a certificate for use in Web service message exchanges, you can give the certificate any relevant name. I tend to use the following names for various samples I create:
SubjectKey (for client applications)
RPKey (for target service applications)
IPKey (for identity provider services such as a security token service [STS])

You can use subject names that are meaningful to your applications. The syntax would be essentially the same for makecert.exe, with the exception of the subject name and certificate output filename:

makecert.exe -r -pe -n "CN=RPKey" -ss my -sr LocalMachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 c:\rpkey.cer


Step 3
Exporting the Certificate
The goal is to export a .pfx file (the key pair) and a .cer file (the public certificate) for later use. The .cer file is generated in the directory you specified in the makecert.exe command. The .pfx file can be exported from the Certificates snap-in tool as follows:
Because the certificate is generated to enable exporting the private key, you can export it using the Certificates console. Open the Certificates snap-in, expand the CurrentUser Personal store (assuming it was created in currentuser), and select All Tasks Export
Follow the steps in the wizard and be sure to select “Yes, export the private key”, and “Delete the private key if the export is successful”. Provide a password to protect the key upon export to the .pfx file.
Now you have a .pfx and .cer file ready to use for SSL or secure messaging.

Step 4
During development you may need to test applications that require SSL. If you create a certificate using makecert.exe, you can use the resulting key pair as the SSL certificate. Here are the steps to accomplish this:
1) Import the localhost.pfx certificate to the Local Machine Personal store. You can do this from the Certificates snap-in by right-clicking on the Personal store and selecting Import. You’ll be asked to provide the key pair password you used when exporting earlier.
2) Next, open the console for Internet Information Services (IIS) from Control Panel Administrative Tools.
3) Open the Properties dialog for the default Web site and select Server Certificate from the Directory Security tab.
4) Choose Assign an existing certificate. You’ll be presented with keys from the Local Machine Personal store; the localhost certificate should be listed. Select it.

(Please doble click on the IIS certificate to see whether the certificate is valid or not. if not valid you will find the error message there itself.

Before you start opening ASP.NET Web sites with SSL enabled, it’s a good idea to test the SSL certificate to verify the trust chain. You can use the IIS Diagnostic Toolkit to do this. Download and install the toolkit from http://www.microsoft.com/downloads/details.aspx?familyid=9BFA49BC-376B-4A54-95AA-73C9156706E7&displaylang=en. Then, from the Start menu find the program group for SSL Diagnostics and launch the SSL Diagnostics tool. You should be able to see the result in the grid itself

A test certificate will fail this test with the error: “A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.” That’s because the certificate was not issued by a provider installed in the Trusted Root Certification Authorities store. This problem will be solved if you import the localhost.cer file into Local Machine Trusted Root Certification Authorities.


Step 5
App.config file changes










Since the services are hosted in IIS replicate the above changes to web.config file also.


Step 6
Create a class inherating from "UserNamePasswordValidator ". Please note to add the below libraries

using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.ServiceModel;


public class ServiceValidator:UserNamePasswordValidator
{
public override void Validate(string strUserName, string strPassword)
{
if (string.IsNullOrEmpty(strUserName))
throw new ArgumentNullException("Invalid UserName");
if (string.IsNullOrEmpty(strPassword))
throw new ArgumentNullException("Invalid Password");
if (!ValidateUser(strUserName, strPassword))
throw new SecurityTokenException("Invalid userName or Password");
}
private bool ValidateUser(string strUserName, string strPassword)
{
if (strUserName == "Test1" && strPassword == "1Test")
return true;
else
return false;
}
}

After the changes in the web.config file and the code changes, every service request will validate the user against the credentials passed from the slient.

Step 7
Now pass the UserName and Password from the client along with the client proxy, while making a call to the service

//Here localhost.ProjectServicesClient is the proxy Name
localhost.ProjectServicesClient objProj = new
localhost.ProjectServicesClient();
objProj.ClientCredentials.UserName.UserName = "Test1";
objProj.ClientCredentials.UserName.Password = "1Test
";

Now with Every call to the service these credentials will be validated.

No comments: