none
secure WCF service with certificate

    Question

  •  

    I want to secure WCF service with message level. I create two certificates for client and server side. I know certificate which is generated by Makecert.exe is only used for test not for production, so I install Certificate Service in Windows 2003 server. I create two certificates by Certificate Service. My service is host in console application, when I run the host application, it throw a exception: The certificate 'CN=TServer' must have a private key that is capable of key exchange. The process must have access rights for the private key.

     

    So how to fix the problem?

    My code is as below:
     ServiceHost host = new ServiceHost(typeof(HelloWorld));

                host.Credentials.ClientCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.PeerTrust;
                host.Credentials.ServiceCertificate.SetCertificate(
                       StoreLocation.LocalMachine,
                       StoreName.My,
                       X509FindType.FindBySubjectName,
                       "TServer");

                host.Open();

    Friday, September 21, 2007 12:10 PM

Answers

  • This depends on the authenticationMode on the binding. If the authenticationMode is MutualCertificate, then you need to have Server's certificate (out-of-band) on the client's machine . If it is MutualSslNegotiated, then the server's certificate is negotiated during runtime, so you need not have it on the client's machine.

     

    The certificates created by makecert do not have a value in the "CRL Distribution Points" field. This means that we cannot do revocation check on these certificates. Hence they cannot be used in scenarios where revocation check needs to be done.

     

    They cannot be used when the X509CertificateValidationMode is ChainTrust, where revocation check is done by default. They can however be used when X509CertificateValidationMode is PeerTrust, where revocation check is not done by default. RevocationCheck can be controlled by the RevocationMode property and be disabled.

    Monday, September 24, 2007 5:08 PM
  • The client always sends its certificate to the server, so the server need not have client's certificate out-of-band.

     

    Tuesday, September 25, 2007 5:21 PM

All replies

  • There are two issues here:

    1. The certificate must have a private key associated with it. I dont know how you use the Certificate Service to create certificates, but it might take an argument that says if you want to create a private key for the certificate.

    2. The ASP.NET process account (ASPNET on XP and NetworkService on Vista) should have read access to the private key file of the certificate.

     

    Use FindPrivateKey.exe to find the path of the private key file of the certificate and manually give asp.net process account read permissions onn this file.

     

    (or)

     

    You can use the WinHttp Ceriticate Configuration tool and the following command

    winhttpcertcfg -g -c Local_Machine\My -s mycertificate -a NetworkService

     

    Friday, September 21, 2007 4:48 PM
  •  

    Hi srilatha inavolu,

     

         Thanks for you replay, do you know how to use 2003 Certificate Service to create a certificate with a private key?

     

    Thanks,

    Zhiho

    Saturday, September 22, 2007 4:38 AM
  • Hi Zhiho,

     

    I am not familiar with the certificate service but I guess it issues certificates with private keys. Can you open the certificate through mmc and see if it says "You have a private key that corresponds to this certificate". If yes, then you just need to work on the permissions part.

     

    Saturday, September 22, 2007 11:35 PM
  • Thanks, but I don't know why the certificate is generated by makecert.exe is only used for test? why not used in production server?

    Monday, September 24, 2007 4:27 AM
  • If my client is in computer A and my service is in computer B and I also will generate two certificates for client side and server side, the server side certificate is installed in computer B and client side certificate is installed in computer A. Whether I also need to install server side certificate in computer A?

    Monday, September 24, 2007 10:25 AM
  • This depends on the authenticationMode on the binding. If the authenticationMode is MutualCertificate, then you need to have Server's certificate (out-of-band) on the client's machine . If it is MutualSslNegotiated, then the server's certificate is negotiated during runtime, so you need not have it on the client's machine.

     

    The certificates created by makecert do not have a value in the "CRL Distribution Points" field. This means that we cannot do revocation check on these certificates. Hence they cannot be used in scenarios where revocation check needs to be done.

     

    They cannot be used when the X509CertificateValidationMode is ChainTrust, where revocation check is done by default. They can however be used when X509CertificateValidationMode is PeerTrust, where revocation check is not done by default. RevocationCheck can be controlled by the RevocationMode property and be disabled.

    Monday, September 24, 2007 5:08 PM
  • Hi Srilatha Inavolu:

         Thank you very much, but I have a question that whether the server side need install client certificate?

    Thanks,
    Zhihao

    Tuesday, September 25, 2007 11:33 AM
  • The client always sends its certificate to the server, so the server need not have client's certificate out-of-band.

     

    Tuesday, September 25, 2007 5:21 PM
  • Hi Srilatha Inavolu ,

     

        I have install my server certificate in my client computer, as your description I don't install my client certificate in my server computer, when I run my application it will throw a exception: At least one security token in the message could not be validated.

      

        But if I install my client certificate in my server computer it is ok. I don't know why?

        My server side configuration:
        <bindings>
          <basicHttpBinding>
            <binding name="customBinding">
              <security mode="Message">
                <message clientCredentialType="Certificate" />
              </security>
            </binding>
          </basicHttpBinding>
        </bindings>
        <behaviors>
          <serviceBehaviors>
            <behavior name="customBehavior">
              <serviceMetadata httpGetEnabled="true" />
              <serviceCredentials>
                <clientCertificate>
                  <authentication certificateValidationMode="PeerTrust" />
                </clientCertificate>
                <serviceCertificate findValue="ServerSide"
                                    x509FindType="FindBySubjectName"
                                    storeLocation="LocalMachine"
                                    storeName="My" />
              </serviceCredentials>
            </behavior>
          </serviceBehaviors>
        </behaviors>

        My client side configuratoin:
        <client>
       <endpoint
         address="http://localhost:8999/HelloWorld/"
         binding="wsHttpBinding"
         bindingConfiguration="customBinding"
         contract="ServerSide.IHelloWorld"
         name="BasicHttpBinding_IHelloWorld">
        <identity>
         <dns value="ServerSide" />
        </identity>
       </endpoint>
      </client>
      <behaviors>
       <endpointBehaviors>
        <behavior name="customBehavior">
         <clientCredentials>
          <clientCertificate findValue="ClientSide"
                 x509FindType="FindBySubjectName"
                 storeLocation="LocalMachine"
                 storeName="My" />

          <serviceCertificatefindValue="ServerSide"
                 x509FindType="FindBySubjectName"
                 storeLocation="LocalMachine"
                 storeName="My" />
           <authentication certificateValidationMode="PeerTrust" />
          </serviceCertificate>
         </clientCredentials>
        </behavior>
       </endpointBehaviors>
      </behaviors>
      <bindings>
       <basicHttpBinding>
        <binding name="customBinding">
         <security mode="Message">
          <message clientCredentialType="Certificate"/>
         </security>
        </binding>
       </basicHttpBinding>
      </bindings>

    Thanks,
    Zhihao

     

    Wednesday, September 26, 2007 5:54 AM
  •  

    This depends on the certificateValidationMode setting. Since you have set it to "PeerTrust", for the certificate to be valid, it should be present in the trusted people store. If you set it to "ChainTrust", it would be enough if the certificate chain builds to an issuer, who is trusted by the service (in other words, the issuer should be present in the trusted root store).
    Wednesday, September 26, 2007 5:20 PM