Condividi tramite


Schannel

Il pacchetto di sicurezza Secure Channel (Schannel), il cui identificatore del servizio di autenticazione è RPC_C_AUTHN_GSS_SCHANNEL, supporta i protocolli basati su chiave pubblica seguenti: SSL (Secure Sockets Layer) versioni 2.0 e 3.0, Transport Layer Security (TLS) 1.0 e Private Communication Technology (PCT) 1.0. TLS 1.0 è una versione standardizzata e leggermente modificata di SSL 3.0 rilasciata dalla Internet Engineering Task Force (IETF) nel gennaio 1999, nel documento RFC 2246. Poiché TLS è stato standardizzato, gli sviluppatori sono invitati a usare TLS anziché SSL. PCT è incluso solo per la compatibilità con le versioni precedenti e non deve essere usato per il nuovo sviluppo. Quando si usa il pacchetto di sicurezza Schannel, DCOM negozia automaticamente il protocollo migliore, a seconda delle funzionalità client e server.

Gli argomenti seguenti descrivono brevemente il protocollo TLS e il relativo funzionamento con DCOM.

Nota

Tutte le informazioni sul protocollo TLS in queste sezioni si applicano anche ai protocolli SSL e PCT.

 

Quando usare TLS

TLS è l'unica opzione di sicurezza disponibile quando i server devono dimostrare la propria identità ai client anonimi. Ciò è particolarmente importante per i siti Web che desiderano partecipare all'e-commerce perché contribuisce a proteggere la trasmissione di informazioni riservate come i numeri di carta di credito. TLS garantisce che i clienti di e-commerce possano essere certi di chi sta facendo affari con perché hanno la prova dell'identità del server. Fornisce inoltre al server di e-commerce l'efficienza di non doversi preoccupare di autenticare l'identità di ognuno dei suoi clienti.

TLS richiede che tutti i server dimostrino la propria identità ai client. INOLTRE, TLS offre la possibilità di avere i client dimostrare la propria identità ai server. Questa autenticazione reciproca può essere utile per limitare l'accesso di determinate pagine Web in una rete Intranet aziendale di grandi dimensioni.

TLS supporta i livelli di autenticazione più avanzati e offre un'architettura aperta che consente l'aumento della forza di crittografia nel tempo per mantenere il passo con l'innovazione tecnologica. TLS è la scelta migliore per gli ambienti in cui è necessario il massimo livello di sicurezza per i dati in transito.

Breve panoramica del funzionamento di TLS

TLS è basato su un'infrastruttura a chiave pubblica (PKI), che usa coppie di chiavi pubbliche/private per abilitare la crittografia dei dati e stabilire l'integrità dei dati e usa certificati X.509 per l'autenticazione.

Molti protocolli di sicurezza, ad esempio il protocollo Kerberos v5, dipendono da una singola chiave per crittografare e decrittografare i dati. Tali protocolli dipendono quindi dallo scambio sicuro delle chiavi di crittografia; nel protocollo Kerberos, questa operazione viene eseguita tramite ticket ottenuti dal Centro distribuzione chiavi (KDC). Ciò richiede che tutti gli utenti che usano il protocollo Kerberos siano registrati con il KDC, che sarebbe una limitazione poco pratica per un server Web di e-commerce destinato ad attirare milioni di clienti da tutto il mondo. TLS si basa quindi su un'infrastruttura a chiave pubblica che usa due chiavi per la crittografia dei dati quando una chiave della coppia crittografa i dati, solo l'altra chiave della coppia può decrittografarla. Il vantaggio principale di questa progettazione è che la crittografia può essere eseguita senza richiedere lo scambio sicuro di chiavi di crittografia.

Un'infrastruttura a chiave pubblica usa una tecnica in cui una delle chiavi viene mantenuta privata ed è disponibile solo per l'entità a cui è registrato, mentre l'altra chiave viene resa pubblica per chiunque possa accedere. Se un utente vuole inviare un messaggio privato al proprietario di una coppia di chiavi, il messaggio può essere crittografato con la chiave pubblica e solo la chiave privata può essere usata per decrittografare il messaggio.

Le coppie chiave vengono usate anche per verificare l'integrità dei dati inviati. A tale scopo, il proprietario della coppia di chiavi può allegare una firma digitale ai dati prima di inviarla. La creazione di una firma digitale comporta il calcolo di un hash dei dati e la crittografia dell'hash con la chiave privata. Chiunque usi la chiave pubblica per decrittografare la firma digitale è certo che la firma digitale deve provenire solo dalla persona che possiede la chiave privata. Inoltre, il destinatario può calcolare un hash dei dati usando lo stesso algoritmo del mittente e, se l'hash calcolato corrisponde a quello inviato nella firma digitale, il destinatario può essere certo che i dati non sono stati modificati dopo la firma digitale.

Uno svantaggio dell'uso di un'infrastruttura a chiave pubblica per la crittografia dei dati con volumi elevati è rappresentato da prestazioni relativamente lente. A causa della matematica intensiva coinvolta, la crittografia e la decrittografia dei dati usando una crittografia asimmetrica che dipende da una coppia di chiavi può essere fino a 1.000 volte più lenta della crittografia e decrittografia usando una crittografia simmetrica che dipende solo da una singola chiave. TLS usa quindi un'infrastruttura a chiave pubblica solo per generare firme digitali e per negoziare la chiave singola specifica della sessione che verrà usata sia dal client che dal server per la crittografia e la decrittografia dei dati in blocco. TLS supporta un'ampia gamma di crittografie simmetriche a chiave singola e potrebbero essere aggiunte altre crittografie in futuro.

Per altre informazioni sul protocollo handshake TLS, vedere Tls Handshake Protocol.For more information about the TLS handshake protocol, see TLS Handshake Protocol.

Per altri dettagli sulla crittografia dietro il protocollo TLS, vedere Cryptography Essentials.

Certificati X.509

Un problema critico che deve essere gestito da un'infrastruttura a chiave pubblica è la possibilità di considerare attendibile l'autenticità della chiave pubblica usata. Quando si usa una chiave pubblica rilasciata a una società con cui si vuole svolgere attività commerciali, si vuole essere certi che la chiave appartenga effettivamente all'azienda anziché a un ladro che vuole individuare il numero di carta di credito.

Per garantire l'identità di un'entità che contiene una coppia di chiavi, l'entità viene emesso un certificato X.509 da un'autorità di certificazione (CA). Questo certificato contiene informazioni che identificano l'entità, contengono la chiave pubblica dell'entità e sono firmate digitalmente dalla CA. Questa firma digitale indica che la CA ritiene che la chiave pubblica contenuta nel certificato appartenga effettivamente all'entità identificata dal certificato.

E come si considera attendibile la CA? Poiché la CA contiene un certificato X.509 firmato da una CA di livello superiore. Questa catena di firme di certificati continua fino a raggiungere una CA radice, ovvero un'autorità di certificazione che firma i propri certificati. Se si considera attendibile l'integrità della CA radice di un certificato, si dovrebbe essere in grado di considerare attendibile l'autenticità del certificato stesso. Di conseguenza, la selezione di ca radice che si è disposti a considerare attendibile è un compito importante per un amministratore di sistema.

Certificati client

Quando i protocolli del livello di trasporto di sicurezza sono emerso per la prima volta, il loro scopo principale era garantire che un client si connettesse a un server autentico e contribuisse a proteggere la privacy dei dati durante il transito. Tuttavia, SSL 3.0 e TLS 1.0 includono anche il supporto per la trasmissione del certificato di un client durante l'handshake del protocollo. Questa funzionalità facoltativa abilita l'autenticazione reciproca del client e del server.

La decisione di usare un certificato client deve essere presa nel contesto dell'applicazione. I certificati client non sono necessari se il requisito primario esegue l'autenticazione del server. Tuttavia, se l'autenticazione client è essenziale, è possibile usare il certificato di un client anziché basarsi sull'autenticazione personalizzata all'interno dell'applicazione. L'uso dei certificati client è preferibile rispetto all'autenticazione personalizzata perché offre agli utenti uno scenario single sign-on.

Uso di TLS in COM

TLS supporta solo il livello di rappresentazione (RPC_C_IMP_LEVEL_IMPERSONATE) di rappresentazione. Se COM negozia TLS come servizio di autenticazione in un proxy, COM imposta il livello di rappresentazione per rappresentare indipendentemente dal processo predefinito. Affinché la rappresentazione funzioni correttamente in TLS, il client deve fornire un certificato X.509 al server e il server deve disporre del certificato mappato a un account utente specifico nel server. Per altre informazioni, vedere la Guida dettagliata al mapping dei certificati agli account utente.

TLS non supporta il mantello. Se un flag di mantello e TLS vengono specificati in una chiamata CoInitializeSecurity o IClientSecurity::SetBlanket, verrà restituito E_INVALIDARG.

TLS non funziona con il livello di autenticazione impostato su Nessuno. L'handshake tra il client e il server esamina il livello di autenticazione impostato da ognuno e sceglie l'impostazione di sicurezza più elevata per la connessione.

I parametri di sicurezza per TLS possono essere impostati chiamando CoInitializeSecurity e CoSetProxyBlanket. Le sezioni seguenti descrivono le sfumature coinvolte nell'effettuare tali chiamate.

Modalità di impostazione della coperta di sicurezza da parte di un server

Se un server vuole usare TLS, deve specificare Schannel (RPC_C_AUTHN_GSS_SCHANNEL) come servizio di autenticazione nel parametro asAuthSvc di CoInitializeSecurity. Per impedire ai client di connettersi al server usando un servizio di autenticazione meno sicuro, il server deve specificare solo Schannel come servizio di autenticazione quando chiama CoInitializeSecurity. Il server non può modificare la coperta di sicurezza dopo aver chiamato CoInitializeSecurity.

Per usare TLS, è necessario specificare i parametri seguenti quando un server chiama CoInitializeSecurity:

  • pVoid deve essere un puntatore a un oggetto IAccessControl o un puntatore a un edizione StandardCURITY_DESCRIPTOR. Non deve essere NULL o un puntatore a un AppID.
  • cAuthSvc non può essere 0 o -1. I server COM non scelgono mai Schannel quando cAuthSvcè -1.
  • asAuthSvc deve specificare Schannel come possibile servizio di autenticazione. Questa operazione viene eseguita impostando i parametri SOLE_AUTHENTICATION_edizione Standard RVICE seguenti per il membro Schannel del SOLE_AUTHENTICATION_LIST:
    • dwAuthnSvc deve essere RPC_C_AUTHN_GSS_SCHANNEL.
    • dwAuthzSvc deve essere RPC_C_AUTHZ_NONE. Attualmente, viene ignorato.
    • pPrincipalName deve essere un puntatore a un CERT_CONTEXT, eseguire il cast come puntatore a OLECHAR, che rappresenta il certificato X.509 del server.
  • dwAuthnLevel indica il livello di autenticazione minimo che verrà accettato dai client per una connessione riuscita. Non può essere RPC_C_AUTHN_LEVEL_NONE.
  • dwCapabilities non deve avere il flag EOAC_APPID impostato. Il flag EOAC_ACCESS_CONTROL deve essere impostato se pVoid punta a un oggetto IAccessControl; non deve essere impostato se pVoid punta a un edizione StandardCURITY_DESCRIPTOR. Per altri flag che possono essere impostati, vedere CoInitializeSecurity.

Per altre informazioni sull'uso di CoInitializeSecurity, vedere Impostazione della sicurezza a livello di processo con CoInitializeSecurity.

Come un client imposta la coperta di sicurezza

Se un client vuole usare TLS, deve specificare Schannel (RPC_C_AUTHN_GSS_SCHANNEL) nell'elenco dei servizi di autenticazione nel parametro pAuthList di CoInitializeSecurity. Se Schannel non viene specificato come possibile servizio di autenticazione quando viene chiamato CoInitializeSecurity , una chiamata successiva a CoSetProxyBlanket (o IClientSecurity::SetBlanket) avrà esito negativo se tenta di specificare Schannel come servizio di autenticazione.

Quando un client chiama CoInitializeSecurity, è necessario specificare i parametri seguenti:

  • dwAuthnLevel specifica il livello di autenticazione predefinito che il client vuole usare. Non può essere RPC_C_AUTHN_LEVEL_NONE.
  • dwImpLevel deve essere RPC_C_IMP_LEVEL_IMPERSONATE.
  • pAuthList deve avere i parametri di SOLE_AUTHENTICATION_INFO seguenti come membri dell'elenco:
    • dwAuthnSvc deve essere RPC_C_AUTHN_GSS_SCHANNEL.
    • dwAuthzSvc deve essere RPC_C_AUTHZ_NONE.
    • pAuthInfo è un puntatore a un CERT_CONTEXT, di cui viene eseguito il cast come puntatore a void, che rappresenta il certificato X.509 del client. Se il client non dispone di un certificato o non vuole presentare il certificato al server, pAuthInfo deve essere NULL e verrà tentata una connessione anonima con il server.
  • dwCapabilities è un set di flag che indicano funzionalità client aggiuntive. Per informazioni sui flag da impostare, vedere CoInitializeSecurity.

Per altre informazioni sull'uso di CoInitializeSecurity, vedere Impostazione della sicurezza a livello di processo con CoInitializeSecurity.

Modalità di modifica della coperta di sicurezza da parte di un client

Se un client vuole usare TLS ma modificare la coperta di sicurezza dopo aver chiamato CoInitializeSecurity, deve chiamare CoSetProxyBlanket o IClientSecurity::SetBlanket con parametri simili a quelli usati nella chiamata a CoInitializeSecurity, con le differenze seguenti:

  • pServerPrincName indica il nome dell'entità del server, in formato msstd o fullsic. Per informazioni su questi formati, vedere Nomi entità. Se il client ha il certificato X.509 del server, può trovare il nome dell'entità chiamando RpcCertGeneratePrincipalName.
  • pAuthInfo è un puntatore a un CERT_CONTEXT, eseguito il cast come puntatore a RPC_AUTH_IDENTITY_HANDLE, che rappresenta il certificato X.509 del client. Se il client non dispone di un certificato o non vuole presentare il certificato al server, pAuthInfo deve essere NULL e verrà tentata una connessione anonima con il server.
  • dwCapabilities è costituito da flag che indicano funzionalità client aggiuntive. È possibile usare solo quattro flag per modificare le impostazioni della coperta di sicurezza: EOAC_DEFAULT, EOAC_MUTUAL_AUTH, EOAC_ANY_AUTHORITY (questo flag è deprecato) e EOAC_MAKE_FULLSIC. Per altre informazioni, vedere CoSetProxyBlanket.

Per altre informazioni sull'uso di CoSetProxyBlanket, vedere Impostazione della sicurezza a livello di proxy di interfaccia.

Esempio: Il client modifica la coperta di sicurezza

Nell'esempio seguente viene illustrato come un client può modificare la coperta di sicurezza in modo da soddisfare una richiesta dal server affinché il client fornisca il certificato X.509. Il codice di gestione degli errori viene omesso per brevità.

void ClientChangesSecurity ()
{
  HCRYPTPROV                   provider           = 0;
  HCERTSTORE                   cert_store         = NULL;
  PCCERT_CONTEXT               client_cert        = NULL;
  PCCERT_CONTEXT               server_cert        = NULL;
  WCHAR                        *server_princ_name = NULL;
  ISecret                      *pSecret           = NULL;
  MULTI_QI                     server_instance;
  COSERVERINFO                 server_machine;
  SOLE_AUTHENTICATION_LIST     auth_list;
  SOLE_AUTHENTICATION_INFO     auth_info[1];



  // Specify all the authentication info. 
  // The client is willing to connect using SChannel,
  //   with no client certificate.
  auth_list.cAuthInfo     = 1;
  auth_list.aAuthInfo     = auth_info;
  auth_info[0].dwAuthnSvc = RPC_C_AUTHN_GSS_SCHANNEL;
  auth_info[0].dwAuthzSvc = RPC_C_AUTHZ_NONE;
  auth_info[0].pAuthInfo  = NULL;  // No certificate

  // Initialize client security with no client certificate.
  CoInitializeSecurity( NULL, -1, NULL, NULL,
                        RPC_C_AUTHN_LEVEL_PKT,
                        RPC_C_IMP_LEVEL_IMPERSONATE, &auth_list,
                        EOAC_NONE, NULL );
  
  // Specify info for the proxy.
  server_instance = {&IID_ISecret, NULL, S_OK};
  server_machine  = {0, L"ServerMachineName", NULL, 0};
  
  // Create a proxy.
  CoCreateInstanceEx( CLSID_Secret, NULL, CLSCTX_REMOTE_SERVER, 
                      &server_machine, 1, &server_instance);
  pSecret = (ISecret *) server_instance.pItf;

  //** The client obtained the server's certificate during the handshake.
  //** The server requests a certificate from the client.

  // Get the default certificate provider.
  CryptAcquireContext( &provider, NULL, NULL, PROV_RSA_SCHANNEL, 0 );

  // Open the certificate store.
  cert_store = CertOpenSystemStore( provider, L"my" );

  // Find the client's certificate.
  client_cert = 
    CertFindCertificateInStore( cert_store,
                                X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                                0,
                                CERT_FIND_SUBJECT_STR,
                                L"ClientName",  // Use the principal name
                                NULL );

  // Find the fullsic principal name of the server.
  RpcCertGeneratePrincipalName( server_cert, RPC_C_FULL_CERT_CHAIN, 
                                &server_princ_name );

  // Change the client's security: 
  // Increase the authentication level and attach a certificate.
  CoSetProxyBlanket( pSecret, RPC_C_AUTHN_GSS_SCHANNEL,
                     RPC_C_AUTHZ_NONE,
                     server_princ_name, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
                     RPC_C_IMP_LEVEL_IMPERSONATE, 
                     (RPC_AUTH_IDENTITY_HANDLE *) client_cert,
                     EOAC_NONE );

  cleanup:
  if (server_princ_name != NULL)
    RpcStringFree( &server_princ_name );
  if (client_cert != NULL)
    CertFreeCertificateContext(client_cert);
  if (server_cert != NULL)
    CertFreeCertificateContext(server_cert);
  if (cert_store != NULL)
    CertCloseStore( cert_store, CERT_CLOSE_STORE_CHECK_FLAG );
  if (provider != 0 )
    CryptReleaseContext( provider, 0 );
  if (pSecret != NULL)
    pSecret->Release();
  CoUninitialize();
}

Pacchetti COM e di sicurezza