title: MVC web app (https) calling a WCF Service (https) that also requires a SSL certificate for authentication
body: <p>I have a problem with getting a MVC web app with HTTPS to call a WCF Service that also uses HTTPS. The MVC web app must authenticate with a certificate to the WCF Service.</p>
  
  <p>I'm using Windows 7, IIS 7.5, VS 2010 with C# and .NET Framework 4.0.</p>
  
  <h2>Here is what I've done so far:</h2>
  
  <ol>
  <li><p>I created a Certificate Authority called 'Development Authority':</p>
  
  <pre><code>makecert -pe -n "CN=Development Authority" -ss my -sr LocalMachine -a sha1 -sky signature -r "c:\Development Authority.cer"
  </code></pre>
  
  <p>I imported the newly created certificate with the MMC tool in the 'Trusted Root Certification Authorities' folder and in the 'Third-Party Root Certification Authorities' folder (Local Computer). This certificate can also be found in the 'Personal' folder.</p>
  
  <p>I saw that if I import the CA only in the 'Trusted Root CA' it will still give a 'not trusted' warning. After importing the CA in the 'Third-Party Root CA' folder, the warning dissappeared.</p></li>
  <li><p>I created two other certificates (signed by the newly created CA), using the following command :</p>
  
  <pre><code>makecert -pe -n "CN=mvc.localhost" -ss my -sr LocalMachine -a sha1 -sky exchange -eku 1.3.6.1.5.5.7.3.1 -in "Development Authority" -is MY -ir LocalMachine -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 c:\mvc.localhost.cer
  </code></pre>
  
  <p>In this way I created 'mvc.localhost' and 'wcf.localhost' certificates. I imported them into the 'Personal' folder (for Local Computer), using the MMC tool.</p></li>
  <li><p>In my Windows hosts files I created two aliases for the two applications that are going to be hosted with IIS (MVC app and WCF Service app). I updated my hosts file with the following lines:</p>
  
  <pre><code>#development
  127.0.0.1 mvc.localhost
  127.0.0.1 wcf.localhost 
  </code></pre></li>
  <li><p>Under IIS, I mapped a new website 'mvc.localhost' to a very simple MVC web app.
  I also mapped a new website 'wcf.localhost' to a basic newly created WCF Service.</p>
  
  <h3>mcv.localhost:</h3>
  
  <ul>
  <li><p><strong>Application pool:</strong> .NET Framework 4.0 running using 'ApplicationPoolIdentity'.</p></li>
  <li><p><strong>Anonymous Authentication</strong>: enabled and set to 'Specific User' : 'IUSR'.</p></li>
  <li><p><strong>Bindings:</strong> </p>
  
  <p>HTTP (hostname 'mvc.localhost', port 80) -> can access with 'http://mvc.localhost/'</p>
  
  <p>HTTPS (hostname 'mvc.localhost', port 1234) -> can access with 'https://mvc.localhost:1234/'. Added with the 'mvc.localhost' certificate.</p></li>
  </ul>
  
  <h3>wcf.localhost:</h3>
  
  <ul>
  <li><p><strong>Application pool:</strong> .NET Framework 4.0 running using 'ApplicationPoolIdentity'.</p></li>
  <li><p><strong>Anonymous Authentication</strong>: enabled and set to 'Specific User' : 'IUSR'.</p></li>
  <li><p><strong>Bindings:</strong> </p>
  
  <p>HTTP (hostname 'wcf.localhost', port 80) -> can access with 'http://wcf.localhost/'</p>
  
  <p>HTTPS (hostname 'wcf.localhost', port 443) -> can access with 'https://wcf.localhost/'. Added with the 'wcf.localhost' certificate.</p></li>
  </ul>
  
  <p>To modify the hostnames for the HTTPS bindings I used the following command:</p>
  
  <pre><code>c:\Windows\System32\inetsrv&gt;appcmd set site /site.name:"wcf.localhost" /bindings.[protocol='https',bindingInformation='*:443:'].bindingInformation:*:443:wcf.localhost
  </code></pre></li>
  <li><p>I tested the two websites separately with HTTPS and they worked without problems (except Firefox that has a strict policy when I comes to local certificates created for testing purposes and gives you a 'sec_error_unknown_issuer' warning, but this is not my problem for now).</p></li>
  <li><p><strong>WCF Service configuration</strong> for certificate authentication:</p>
  
  <p>
      
        
      </p>
  
  <pre><code>&lt;bindings&gt; 
    &lt;wsHttpBinding&gt;
      &lt;binding name="wsHttpEndpointBinding"&gt;
        &lt;security mode="Transport"&gt;
          &lt;transport clientCredentialType="Certificate"/&gt;
        &lt;/security&gt;
      &lt;/binding&gt;
    &lt;/wsHttpBinding&gt; 
  &lt;/bindings&gt;
  
  &lt;services&gt;
    &lt;service name="wcf.localhost.WelcomeService"  behaviorConfiguration="wcf.localhost.WelcomeServiceBehavior"&gt;    
      &lt;endpoint address="https://wcf.localhost/WelcomeService.svc" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" contract="wcf.localhost.IWelcomeService"&gt; 
      &lt;/endpoint&gt;
      &lt;!--&lt;endpoint address="mex" binding="mexHttpsBinding" 
      name="mexEndpoint" contract="IMetadataExchange"/&gt;--&gt;
    &lt;/service&gt;
  &lt;/services&gt;
  
  &lt;behaviors&gt;
    &lt;serviceBehaviors&gt;
      &lt;behavior name="wcf.localhost.WelcomeServiceBehavior"&gt;
        &lt;serviceMetadata httpsGetEnabled="true" httpGetEnabled="false"/&gt;
        &lt;serviceDebug includeExceptionDetailInFaults="false"/&gt;
  
        &lt;serviceCredentials&gt;
          &lt;clientCertificate&gt;
            &lt;authentication revocationMode="NoCheck" certificateValidationMode="PeerOrChainTrust" /&gt;
          &lt;/clientCertificate&gt;
          &lt;serviceCertificate findValue="&lt;&lt;wcf.localhost Certificate Thumbprint inserted here&gt;&gt;" storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint"/&gt;
        &lt;/serviceCredentials&gt;
      &lt;/behavior&gt;
    &lt;/serviceBehaviors&gt;
  &lt;/behaviors&gt;
  </code></pre>
  
  <p>
  In IIS, for SSL Settings I set 'Require SSL' with the 'Require' option.</p>
  
  <p>The service WelcomeService exposes a method called 'SayHello(string)' that concatenates 'Hello' to the input parameter and returns the new string.</p>
  
  <p>I can reach 'https://wcf.localhost/welcomeservice.svc' without problems.</p></li>
  <li><p><strong>MVC web app</strong> configuration:</p>
  
  <p></p>
  
  <pre><code>&lt;bindings&gt;
    &lt;wsHttpBinding&gt;
      &lt;binding name="WSHttpBinding_IWelcomeService" closeTimeout="00:01:00"
        openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
        bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
        maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text"
        textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false"&gt;
        &lt;readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
          maxBytesPerRead="4096" maxNameTableCharCount="16384" /&gt;
        &lt;reliableSession ordered="true" inactivityTimeout="00:10:00"
          enabled="false" /&gt;
        &lt;security mode="Transport"&gt;
          &lt;transport clientCredentialType="Certificate"/&gt;
        &lt;/security&gt;
      &lt;/binding&gt;
    &lt;/wsHttpBinding&gt;
  &lt;/bindings&gt;
  
  &lt;client&gt;
    &lt;endpoint address="https://wcf.localhost/WelcomeService.svc"
      binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IWelcomeService"
      contract="WelcomeService.IWelcomeService" name="WSHttpBinding_IWelcomeService" behaviorConfiguration="CustomBehavior"&gt;        
    &lt;/endpoint&gt;
  &lt;/client&gt;
  
  &lt;behaviors&gt;
    &lt;endpointBehaviors&gt;
      &lt;behavior name="CustomBehavior" &gt;
        &lt;clientCredentials&gt;
          &lt;clientCertificate findValue="&lt;&lt;mvc.localhost Certificate Thumbprint inserted here&gt;&gt;"
          storeLocation="LocalMachine"
          storeName="My"
          x509FindType="FindByThumbprint"/&gt;
          &lt;serviceCertificate&gt;
            &lt;authentication certificateValidationMode="PeerOrChainTrust" revocationMode="NoCheck"&gt;&lt;/authentication&gt;
          &lt;/serviceCertificate&gt;
        &lt;/clientCredentials&gt;          
      &lt;/behavior&gt;
    &lt;/endpointBehaviors&gt;
  &lt;/behaviors&gt;
  </code></pre>
  
  <p></p></li>
  <li><p><strong>Now for the problem :</strong> 
  After using the MVC app to call the WCF service I get the following error :</p>
  
  <p>Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. </p>
  
  <pre><code>Exception Details: System.Net.WebException: The remote server returned an error: (403) Forbidden.
  
  Source Error: 
  
  
  Line 48:         
  Line 49:         public void SayHello(string name) {
  Line 50:             base.Channel.SayHello(name);
  Line 51:         }
  Line 52:     }
  
  Source File: C:\Projects\ssl.research\mvc.localhost\Service References\WelcomeService\Reference.cs    Line: 50 
  
  Stack Trace: 
  
  
  [WebException: The remote server returned an error: (403) Forbidden.]
     System.Net.HttpWebRequest.GetResponse() +7859156
     System.ServiceModel.Channels.HttpChannelRequest.WaitForReply(TimeSpan timeout) +99
  
  [MessageSecurityException: The HTTP request was forbidden with client authentication scheme 'Anonymous'.]
     System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) +4727747
     System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&amp; msgData, Int32 type) +1725
     mvc.localhost.WelcomeService.IWelcomeService.SayHello(String name) +0
     mvc.localhost.WelcomeService.WelcomeServiceClient.SayHello(String name) in C:\Projects\ssl.research\mvc.localhost\Service References\WelcomeService\Reference.cs:50
     mvc.localhost.Controllers.HomeController.CallService(HomeModel model) in C:\Projects\ssl.research\mvc.localhost\Controllers\HomeController.cs:33
     lambda_method(Closure , ControllerBase , Object[] ) +127
     System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +264
     System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +39
     System.Web.Mvc.&lt;&gt;c__DisplayClass15.&lt;InvokeActionMethodWithFilters&gt;b__12() +129
     System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +826410
     System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +314
     System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +825632
     System.Web.Mvc.Controller.ExecuteCore() +159
     System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +335
     System.Web.Mvc.&lt;&gt;c__DisplayClassb.&lt;BeginProcessRequest&gt;b__5() +62
     System.Web.Mvc.Async.&lt;&gt;c__DisplayClass1.&lt;MakeVoidDelegate&gt;b__0() +20
     System.Web.Mvc.&lt;&gt;c__DisplayClasse.&lt;EndProcessRequest&gt;b__d() +54
     System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +469
     System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean&amp; completedSynchronously) +375
  
  Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.237
  </code></pre></li>
  </ol>
  
  <p>On the client side I also tried:</p>
  
  <ul>
  <li><pre>ServicePointManager.ServerCertificateValidationCallback += customXertificateValidation
  ...
  private static bool customXertificateValidation(object sender, X509Certificate cert,
  X509Chain chain, SslPolicyErrors error)
      {
          return true;
      }</pre></li>
  <li>Using the service certificate thumbprint to authenticate with the service.</li>
  <li>Different certificateValidationMode values.</li>
  </ul>
  
  <p>Nothing worked.</p>
  
  <p>I used SSL Diagnostics 1.1 to verify the two web applications and their certificates.
  No errors were shown. The SSL Handshake Simulation went fine, without errors.</p>
  
  <p>I feel that I am quite close to finishing the test project (having resolved other issues along the way). </p>
  
  <p>Searching the web, I could find only HTTP WCF services or WCF services that didn't use a certificate for authentication or WCF service that use certificate authentication but are HTTP. </p>
  
  <p>I'm trying to have a HTTPS running MVC web app call a HTTPS running WCF Service that requires a certificate for authentication.</p>
  
  <p>Many of the great articles out there helped me with other problems with this project. </p>
  
  <p>Now I'm stuck and I cannot seem to find a solution. </p>
  
  <p>Any suggestion is appreciated. </p>
  
  <p>Thank you, Bogdan.</p>
  
  <h2>UPDATE</h2>
  
  <p>I noticed that both of my certificates have as their purpose(s):
  'Ensures the identity of a remote computer' (serverAuth) but I don't see anything about the clientAuth. </p>
  
  <p>Also, Chrome browser prompts me to select a certificate when I access the MVC web app. In the certificates list I cannot see the two certificates that I created. </p>
  
  <p>I can see only one certificate that has as one of its purposes (but is a different certificate from the ones that I plan on using!) :
  'Proves your identity to a remote computer'</p>
  
  <p>Maybe this is why I get the error? Maybe I cannot use either of my newly created certificates to authenticate the client to the server?</p>
  
  <p>Any thoughts? If I'm right, how can I add clientAuth purpose to any of my certificates? 
  Thanks</p>