Implementation of WCF message security using self-signed certificates
We need to create 3 certificates.
1)
Dummy root certificate authority (CA)
2)
Server certificate using above CA.
3)
Client certificate using above CA.
Location of
certificates
1)
The Root CA will be in the trusted root folder
of server machine ONLY.
2)
The client needs the client certificate pfx (pvt
+ public key) along with the server certificate’s public key ONLY.
3)
The server needs the server certificate pfx (pvt
+ public key) ONLY. Nothing from client’s side is required. (Remember the root
CA is common).
4)
Make sure the private key is accessible by the
required process. Example “NetworkServiceAppPool” accessing server certificate
private key.
Commands
1)
Creation of root CA
makecert -r -pe -n "CN=Subhasis Certificate
Authority" -a sha1 -sky signature -cy authority -sv
SubhasisCAPrivateKey.pvk SubhasisCA.cer
////////keep pvt key pwd as “root”
2)
Creation of server cert using above CA
makecert -n "CN=WebService1.com" -ic
"SubhasisCA.cer" -iv "SubhasisCAPrivateKey.pvk" -a sha1
-sky exchange -pe -sv "WebService1PrivateKey.pvk"
"WebService1.com.cer"
//////////keep the private key password of the above “webservice1pvtkeypwd”
pvk2pfx -pvk "WebService1PrivateKey.pvk" -spc
"WebService1.com.cer" -pfx "WebService1.pfx" -pi webservice1pvtkeypwd
3)
Creation of client cert using same CA
makecert -n "CN=Client2.com" -ic
"SubhasisCA.cer" -iv "SubhasisCAPrivateKey.pvk" -a sha1
-sky exchange -pe -sv "Client2PrivateKey.pvk"
"Client2.com.cer"
//////////keep the private key password of the above
“client2pvtkeypwd”
pvk2pfx -pvk "Client2PrivateKey.pvk" -spc
"Client2.com.cer" -pfx "Client2.pfx" -pi client2pvtkeypwd
With the above settings, we can test the WCF client and
service using the below configuration (key parts with yellow highlight) (Remember only chaintrust will work in
this case) –
For peertrust, check
the end of the post.
Server
<system.serviceModel>
<client />
<services>
<service name="CertSecurityDemoService.Service1" behaviorConfiguration="customBehavior">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="customWsHttpBinding" contract="CertSecurityDemoService.IService1" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="customBehavior">
<!--
To avoid disclosing metadata information, set the values below to false before
deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!--
To receive exception details in faults for debugging purposes, set the value
below to true. Set to false before
deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceCredentials>
<serviceCertificate findValue="WebService1.com" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My"/>
<clientCertificate>
<authentication certificateValidationMode="ChainTrust" revocationMode="NoCheck"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<bindings>
<wsHttpBinding>
<binding name="customWsHttpBinding" sendTimeout="00:10:00" receiveTimeout="00:10:00" openTimeout="00:10:00" closeTimeout="00:10:00">
<security mode="Message">
<message clientCredentialType="Certificate" negotiateServiceCredential="false" establishSecurityContext="false"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Client
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="customBehavior">
<clientCredentials>
<clientCertificate findValue="Client2.com" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
<serviceCertificate>
<defaultCertificate findValue="WebService1.com"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService1" sendTimeout="00:10:00" receiveTimeout="00:10:00" openTimeout="00:10:00" closeTimeout="00:10:00">
<security mode="Message">
<message clientCredentialType="Certificate" negotiateServiceCredential="false" establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://abc.domain.co.in/WebService1/Service1.svc"
binding="wsHttpBinding" contract="ServiceReference1.IService1" name="WSHttpBinding_IService1" behaviorConfiguration="customBehavior" bindingConfiguration="WSHttpBinding_IService1">
<identity>
<dns value ="WebService1.com"/>
</identity>
</endpoint>
</client>
</system.serviceModel>
With the above approach, we get both following –
1)
Mutual authentication (as both certs are from
same CA).
2)
Confidentiality
- Encryption done using server cert’s private and public key. (by
default Symmetric binding – derived key scenario is used. For more details, see this post
3)
Integrity – Messages signed using certs trusted
by the Root CA.
Difference between chaintrust and peertrust –
PeerTrust
forces a public key of the client certificate to be present in the 'Trusted
People' certificate store on the service side and ChainTrust requests that the client cert can be validated
against the root certificates on the server side. ChainOrPeerTrust just executes the OR operator on the last
two.
Remark: PeerTrust and ChainOrPeerTrust are also subjected to another attribute called trustedStoreLocation. If peer trust is demanded, one can specify where the public keys are present, meaning either in LocalMachine or CurrentUser store.
The above implementation can be converted to “peertrust”
using the following steps –
1)
Delete the root CA from the server machine
trusted root folder (as it wont be needed)
2)
Copy the client machine certificate public key
ONLY to server machine trusted people folder
(not trusted roots).
3)
Change service config from “chaintrust” to “peertrust”.
As you might have noticed, with peertrust there is no
involvement of CAs in any machine’s trusted root.
No comments:
Post a Comment