Convalida del certificato X.509

In questo esempio viene illustrato come implementare una convalida del certificato X.509 personalizzata. Questo processo è utile nei casi in cui nessuna delle convalide incorporate del certificato X.509 è appropriata ai requisiti dell'applicazione. In questo esempio viene mostrato un servizio che dispone di una convalida personalizzata che accetta certificati autocertificati. Il client utilizza tale certificato per l'autenticazione nel servizio.

Nota: poiché chiunque può costruire un certificato autocertificato, la convalida personalizzata utilizzata dal servizio è meno affidabile del comportamento predefinito fornito da ChainTrust X509CertificateValidationMode. Le implicazioni di protezione di questa scelta devono essere considerate attentamente prima di utilizzare questa logica di convalida nel codice di produzione.

In sintesi, nell'esempio viene illustrato in che modo eseguire le operazioni seguenti:

  • Il client può essere autenticato tramite un certificato X.509.
  • Il server convalida le credenziali client a fronte di una convalida X509CertificateValidator personalizzata.
  • Il server viene autenticato tramite il certificato X.509 del server.

Il servizio espone un solo endpoint per comunicare con il servizio che viene definito mediante il file di configurazione App.config. L'endpoint è costituito da un indirizzo, un'associazione e un contratto. L'associazione viene configurata con una classe standard wsHttpBinding, per la quale è impostata l'autenticazione WSSecurity e del certificato client come predefinita. Il comportamento del servizio specifica la modalità personalizzata per la convalida dei certificati X.509 client insieme al tipo di classe della convalida. Il comportamento specifica inoltre il certificato server mediante l'elemento serviceCertificate. Il certificato server deve contenere per la proprietà SubjectName lo stesso valore dell'attributo findValue in serviceCertificate element of serviceCredentials.

  <system.serviceModel>
    <services>
      <service name="Microsoft.ServiceModel.Samples.CalculatorService"
               behaviorConfiguration="CalculatorServiceBehavior">
        <!-- use host/baseAddresses to configure base address -->
        <!-- provided by host -->
        <host>
          <baseAddresses>
            <add baseAddress =
                "https://localhost:8001/servicemodelsamples/service" />
          </baseAddresses>
        </host>
        <!-- use base address specified above, provide one endpoint -->
        <endpoint address="certificate"
               binding="wsHttpBinding"
               bindingConfiguration="Binding" 
               contract="Microsoft.ServiceModel.Samples.ICalculator" />
      </service>
    </services>
    <bindings>
      <wsHttpBinding>
        <!-- X509 certificate binding -->
        <binding name="Binding">
          <security mode="Message">
            <message clientCredentialType="Certificate" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior">
          <serviceDebug includeExceptionDetailInFaults ="true"/>
          <serviceCredentials>
            <!--The serviceCredentials behavior allows one -->
            <!-- to specify authentication constraints on -->
            <!-- client certificates. -->
            <clientCertificate>
              <!-- Setting the certificateValidationMode to -->
              <!-- Custom means that if the custom -->
              <!-- X509CertificateValidator does NOT throw -->
              <!-- an exception, then the provided certificate -- >
              <!-- will be trusted without performing any -->
              <!-- validation beyond that performed by the custom-->
              <!-- validator. The security implications of this -->
              <!-- setting should be carefully considered before -->
              <!-- using Custom in production code. -->
              <authentication 
                 certificateValidationMode="Custom" 
                 customCertificateValidatorType =
"Microsoft.ServiceModel.Samples.CustomX509CertificateValidator, service" />
            </clientCertificate>
            <!-- The serviceCredentials behavior allows one to -- >
            <!--define a service certificate. -->
            <!--A service certificate is used by a client to  -->
            <!--authenticate the service and provide message  -->
            <!--protection. This configuration references the  -->
            <!--"localhost" certificate installed during the setup  -->
            <!--instructions. -->
            <serviceCertificate findValue="localhost" 
                 storeLocation="LocalMachine" 
                 storeName="My" x509FindType="FindBySubjectName" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
      </system.serviceModel>

La configurazione dell'endpoint client è costituita da un nome di configurazione, un indirizzo assoluto per l'endpoint del servizio, l'associazione e il contratto. L'associazione client viene configurata con la modalità e il clientCredentialType del messaggio appropriati.

<system.serviceModel>
    <client>
      <!-- X509 certificate based endpoint -->
      <endpoint name="Certificate"
        address=
        "https://localhost:8001/servicemodelsamples/service/certificate" 
                binding="wsHttpBinding" 
                bindingConfiguration="Binding" 
                behaviorConfiguration="ClientCertificateBehavior"
                contract="Microsoft.ServiceModel.Samples.ICalculator">
      </endpoint>
    </client>
    <bindings>
        <wsHttpBinding>
            <!-- X509 certificate binding -->
            <binding name="Binding">
                <security mode="Message">
                    <message clientCredentialType="Certificate" />
               </security>
            </binding>
       </wsHttpBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="ClientCertificateBehavior">
          <clientCredentials>
            <serviceCertificate>
              <!-- Setting the certificateValidationMode to -->
              <!-- PeerOrChainTrust means that if the certificate -->
              <!-- is in the user's Trusted People store, then it -->
              <!-- is trusted without performing a validation of -->
              <!-- the certificate's issuer chain. -->
              <!-- This setting is used here for convenience so -->
              <!-- that the sample can be run without having to -->
              <!-- have certificates issued by a certification -->
              <!-- authority (CA). This setting is less secure -->
              <!-- than the default, ChainTrust. The security -->
              <!-- implications of this setting should be -->
              <!-- carefully considered before using -->
              <!-- PeerOrChainTrust in production code.-->
              <authentication 
                  certificateValidationMode="PeerOrChainTrust" />
            </serviceCertificate>
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>

L'implementazione client imposta il certificato client da utilizzare.

// Create a client with Certificate endpoint configuration
CalculatorClient client = new CalculatorClient("Certificate");
try
{
    client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, "test1");

    // Call the Add service operation.
    double value1 = 100.00D;
    double value2 = 15.99D;
    double result = client.Add(value1, value2);
    Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);

    // Call the Subtract service operation.
    value1 = 145.00D;
    value2 = 76.54D;
    result = client.Subtract(value1, value2);
    Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result);

    // Call the Multiply service operation.
    value1 = 9.00D;
    value2 = 81.25D;
    result = client.Multiply(value1, value2);
    Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);

    // Call the Divide service operation.
    value1 = 22.00D;
    value2 = 7.00D;
    result = client.Divide(value1, value2);
    Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);
    client.Close();
}
catch (TimeoutException e)
{
    Console.WriteLine("Call timed out : {0}", e.Message);
    client.Abort();
}
catch (CommunicationException e)
{
    Console.WriteLine("Call failed : {0}", e.Message);
    client.Abort();
}
catch (Exception e)
{
    Console.WriteLine("Call failed : {0}", e.Message);
    client.Abort();
}

In questo esempio viene utilizzato un X509CertificateValidator personalizzato per convalidare i certificati. In questo esempio viene implementato CustomX509CertificateValidator, derivato da X509CertificateValidator. Per ulteriori informazioni, vedere la documentazione relativa a X509CertificateValidator. In questo particolare esempio la convalida personalizzata implementa il metodo Validate per accettare qualsiasi certificato X.509 che è autocertificata, come mostrato nel codice seguente.

public class CustomX509CertificateValidator : X509CertificateValidator
{
  public override void Validate ( X509Certificate2 certificate )
  {
   // Only accept self-issued certificates
   if (certificate.Subject != certificate.Issuer)
     throw new Exception("Certificate is not self-issued");
   }
}

Quando la convalida è stata implementata nel codice del servizio, l'host del servizio deve essere informato dell'istanza di convalida da utilizzare. Questa operazione viene eseguita tramite il codice seguente.

serviceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.Custom;
serviceHost.Credentials.ClientCertificate.Authentication.CustomCertificateValidator = new CustomX509CertificateValidator();

In alternativa, è possibile eseguire la stessa operazione nella configurazione come segue.

<behaviors>
    <serviceBehaviors>
     <behavior name="CalculatorServiceBehavior">
       ...
   <serviceCredentials>
    <!--The serviceCredentials behavior allows one to specify --> 
    <!--authentication constraints on client certificates.-->
    <clientCertificate>
    <!-- Setting the certificateValidationMode to Custom means --> 
    <!--that if the custom X509CertificateValidator does NOT --> 
    <!--throw an exception, then the provided certificate will-- > 
    <!-- be trusted without performing any validation beyond that-- >
    <!-- performed by the custom validator. The security -- > 
    <!--implications of this setting should be carefully -- >
    <!--considered before using Custom in production code. -->
    <authentication certificateValidationMode="Custom"
       customCertificateValidatorType =
"Microsoft.ServiceModel.Samples. CustomX509CertificateValidator, service" />
   </clientCertificate>
   ...
  </behavior>
 </serviceBehaviors>
</behaviors>

Quando si esegue l'esempio, le richieste e le risposte dell'operazione vengono visualizzate nella finestra della console client. Il client deve chiamare correttamente tutti i metodi. Premere INVIO nella finestra del client per arrestare il client.

File batch di installazione

Il file batch Setup.bat incluso con questo esempio consente di configurare il server con i certificati attinenti per eseguire un'applicazione indipendente che richiede la protezione server basata su certificato. Questo file batch deve essere modificato per funzionare su computer diversi o per operare in applicazioni indipendenti.

Di seguito viene fornita una breve panoramica delle varie sezioni dei file batch così che possono essere modificati per l'esecuzione nella configurazione appropriata.

  • Creazione del certificato del server:
    Le righe seguenti del file batch Setup.bat creano il certificato server da utilizzare. La variabile %SERVER_NAME% specifica il nome del server. Modificare questa variabile per specificare il nome del server. Il valore predefinito è localhost.

    echo ************
    echo Server cert setup starting
    echo %SERVER_NAME%
    echo ************
    echo making server cert
    echo ************
    makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=%SERVER_NAME% -sky exchange -pe
    
  • Installazione del certificato server nell'archivio certificati attendibili del client:
    Le righe seguenti nel file batch Setup.bat copiano il certificato server nell'archivio delle persone attendibili del client. Questo passaggio è necessario poiché i certificati generati da Makecert.exe non sono considerati implicitamente attendibili dal sistema client. Se è già disponibile un certificato impostato come radice in un certificato radice client attendibile, ad esempio un certificato rilasciato da Microsoft, il passaggio della popolazione dell'archivio certificati client con il certificato server non è necessario.

    certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople
    
  • Creazione del certificato del client:
    Le righe seguenti del file batch Setup.bat creano il certificato client da utilizzare. La variabile %USER_NAME% specifica il nome del client. Questo valore è impostato su "test1" perché questo è il nome cercato dal codice client. Se si modifica il valore di % USER_NAME% è necessario modificare il valore corrispondente nel file di origine Client.cs e rigenerare il client.
    Il certificato viene memorizzato nell'archivio personale nel percorso di archivio CurrentUser.

    echo ************
    echo Client cert setup starting
    echo %USER_NAME%
    echo ************
    echo making client cert
    echo ************
    makecert.exe -sr CurrentUser -ss MY -a sha1 -n CN=%USER_NAME% -sky exchange -pe
    
  • Installazione del certificato client nell'archivio certificati attendibili del server:
    Le righe seguenti nel file batch Setup.bat copiano il certificato client nell'archivio delle persone attendibile. Questo passaggio è necessario poiché i certificati generati da Makecert.exe non sono considerati implicitamente attendibili dal sistema server. Se è già disponibile un certificato che è impostato come radice in un certificato radice attendibile, ad esempio un certificato rilasciato da Microsoft, il passaggio della popolazione dell'archivio certificati server con il certificato client non è necessario.

    certmgr.exe -add -r CurrentUser -s My -c -n %USER_NAME% -r LocalMachine -s TrustedPeople
    

Per impostare e compilare l'esempio

  1. Per compilare la soluzione, seguire le istruzioni in Generazione degli esempi Windows Communication Foundation.

  2. Per eseguire l'esempio su una configurazione con un solo computer o tra computer diversi, seguire le istruzioni seguenti.

Per eseguire l'esempio sullo stesso computer

  1. Verificare che il percorso includa la cartella in cui è situato Makecert.exe.

  2. Eseguire Setup.bat dalla cartella di installazione dell'esempio. In questo modo vengono installati tutti i certificati necessari per l'esecuzione dell'esempio.

  3. Avviare Service.exe da service\bin.

  4. Avviare Client.exe da \client\bin. L'attività del client viene visualizzata nella finestra dell'applicazione console.

  5. Se il client e il servizio non sono in grado di comunicare, vedere Suggerimenti per la risoluzione dei problemi.

Per eseguire l'esempio tra più computer

  1. Creare una directory sul computer del servizio.

  2. Copiare i file del programma del servizio da \service\bin alla directory virtuale nel computer del servizio. Copiare anche i file Setup.bat, Cleanup.bat,GetComputerName.vbs e ImportClientCert.bat nel computer del servizio.

  3. Creare una directory sul client del servizio per i file binari del client.

  4. Copiare i file di programma del client nella directory del client sul computer del client. Copiare anche i file Setup.bat, Cleanup.bat e ImportServiceCert.bat nel computer del client.

  5. Eseguire setup.bat service sul server. Eseguendo setup.bat con l'argomento service si crea un certificato del servizio con il nome di dominio completo del computer e si esporta il certificato del servizio in un file denominato Service.cer.

  6. Modificare Service.exe.config per riflettere il nuovo nome del certificato (nell'attributo findValue in serviceCertificate element of serviceCredentials) che corrisponde al nome di dominio completo del computer. Modificare inoltre il nome del computer nell'elemento <service>/<baseAddresses> da localhost al nome completo del computer del servizio.

  7. Copiare il file Service.cer dalla directory del servizio alla directory del client sul computer client.

  8. Eseguire setup.bat client sul client. Eseguendo setup.bat con l'argomento client si crea un certificato client denominato Client.com e si esporta il certificato client in un file denominato Client.cer.

  9. Nel file Client.exe.config nel computer client, modificare il valore dell'indirizzo della definizione dell'endpoint in base al nuovo indirizzo del servizio. Tale operazione viene eseguita sostituendo localhost con il nome di dominio completo del server.

  10. Copiare il file Client.cer dalla directory del client alla directory del servizio sul server.

  11. Nel client, eseguire ImportServiceCert.bat. In questo modo viene importato il certificato del servizio dal file Service.cer nell'archivio CurrentUser - TrustedPeople.

  12. Eseguire sul server ImportClientCert.bat. In questo modo il certificato client viene importato dal file Client.cer nell'archivio LocalMachine - TrustedPeople.

  13. Sul computer server, avviare Service.exe dalla finestra del prompt dei comandi.

  14. Sul computer client, avviare Client.exe da una finestra del prompt dei comandi. Se il client e il servizio non sono in grado di comunicare, vedere Suggerimenti per la risoluzione dei problemi.

Per eseguire la pulitura dopo l'esempio

  1. Eseguire Cleanup.bat nella cartella degli esempi una volta completato l'esempio. In questo modo i certificati server e client vengono rimossi dall'archivio certificati.

Nota

Questo script non rimuove i certificati del servizio su un client quando si esegue questo esempio tra più computer. Se sono stati eseguiti esempi di Windows Communication Foundation (WCF) che utilizzano certificati tra più computer, assicurarsi di cancellare i certificati del servizio installati nell'archivio CurrentUser - TrustedPeople. Per eseguire questa operazione, utilizzare il seguente comando: certmgr -del -r CurrentUser -s TrustedPeople -c -n <Fully Qualified Server Machine Name> Ad esempio: certmgr -del -r CurrentUser -s TrustedPeople -c -n server1.contoso.com.

Send comments about this topic to Microsoft.
© 2007 Microsoft Corporation. All rights reserved.