Schannel

Das Sicherheitspaket Secure Channel (Schannel), dessen Authentifizierungsdienstbezeichner RPC_C_AUTHN_GSS_SCHANNEL ist, unterstützt die folgenden auf öffentlichen Schlüsseln basierenden Protokolle: SSL (Secure Sockets Layer) Version 2.0 und 3.0, TLS 1.0 (Transport Layer Security) und Private Communication Technology (PCT) 1.0. TLS 1.0 ist eine standardisierte, leicht modifizierte Version von SSL 3.0, die von der Internet Engineering Task Force (IETF) im Januar 1999 in Dokument RFC 2246 veröffentlicht wurde. Da TLS standardisiert wurde, werden Entwickler empfohlen, TLS anstelle von SSL zu verwenden. PCT ist nur aus Gründen der Abwärtskompatibilität enthalten und sollte nicht für neu entwickelt werden. Wenn das Schannel-Sicherheitspaket verwendet wird, handelt DCOM automatisch das beste Protokoll aus, abhängig von den Client- und Serverfunktionen.

In den folgenden Themen wird das TLS-Protokoll und dessen Funktionsweise mit DCOM kurz beschrieben.

Hinweis

Alle Informationen zum TLS-Protokoll in diesen Abschnitten gelten auch für die PROTOKOLLE SSL und PCT.

 

Verwendung von TLS

TLS ist die einzige verfügbare Sicherheitsoption, wenn Server ihre Identität anonymen Clients nachweisen müssen. Dies ist besonders wichtig für Websites, die am E-Commerce teilnehmen möchten, da es die Übertragung vertraulicher Informationen wie Kredit- Karte Nummern schützt. TLS stellt sicher, dass die E-Commerce-Kunden sicher sein können, mit wem sie Geschäfte machen, da ihnen der Nachweis der Identität des Servers erteilt wird. Außerdem erhält der E-Commerce-Server die Effizienz, sich nicht um die Authentifizierung der Identität jedes seiner Kunden kümmern zu müssen.

TLS erfordert, dass alle Server ihre Identität gegenüber Clients nachweisen. Darüber hinaus bietet TLS die Möglichkeit, dass Clients ihre Identität gegenüber Servern nachweisen können. Diese gegenseitige Authentifizierung kann hilfreich sein, um den Zugriff auf bestimmte Webseiten in einem großen Unternehmensintranet einzuschränken.

TLS unterstützt die stärksten Authentifizierungsebenen und bietet eine offene Architektur, die es ermöglicht, die Verschlüsselungsstärke im Laufe der Zeit zu erhöhen, um mit technologischen Innovationen Schritt zu halten. TLS ist die beste Wahl für Umgebungen, in denen die höchste Sicherheitsstufe für die übertragenen Daten gewünscht wird.

Kurze Übersicht über die Funktionsweise von TLS

TLS basiert auf einer Public Key-Infrastruktur (PKI), die öffentliche/private Schlüsselpaare zum Aktivieren der Datenverschlüsselung und zum Einrichten der Datenintegrität verwendet und X.509-Zertifikate für die Authentifizierung verwendet.

Viele Sicherheitsprotokolle, z. B. das Kerberos v5-Protokoll, hängen von einem einzelnen Schlüssel ab, um Daten zu verschlüsseln und zu entschlüsseln. Solche Protokolle sind daher vom sicheren Austausch von Verschlüsselungsschlüsseln abhängig; im Kerberos-Protokoll erfolgt dies über Tickets, die sie vom Key Distribution Center (KDC) erhalten haben. Dies erfordert, dass alle Benutzer, die das Kerberos-Protokoll verwenden, beim KDC registriert werden. Dies wäre eine unpraktische Einschränkung für einen E-Commerce-Webserver, der Millionen von Kunden aus der ganzen Welt anziehen soll. TLS basiert daher auf einer PKI, die zwei Schlüssel für die Datenverschlüsselung verwendet. Wenn ein Schlüssel des Paares die Daten verschlüsselt, kann nur der andere Schlüssel des Paares sie entschlüsseln. Der Hauptvorteil dieses Entwurfs besteht darin, dass die Verschlüsselung durchgeführt werden kann, ohne dass der sichere Austausch von Verschlüsselungsschlüsseln erforderlich ist.

Eine PKI verwendet ein Verfahren, bei dem einer der Schlüssel privat bleibt und nur für den Prinzipal verfügbar ist, bei dem er registriert ist, während der andere Schlüssel für jeden zugänglich gemacht wird. Wenn jemand eine private Nachricht an den Besitzer eines Schlüsselpaars senden möchte, kann die Nachricht mit dem öffentlichen Schlüssel verschlüsselt werden, und nur der private Schlüssel kann zum Entschlüsseln der Nachricht verwendet werden.

Schlüsselpaare werden auch verwendet, um die Integrität der gesendeten Daten zu überprüfen. Dazu kann der Besitzer des Schlüsselpaars vor dem Senden eine digitale Signatur an die Daten anfügen. Beim Erstellen einer digitalen Signatur wird ein Hash der Daten berechnet und der Hash mit dem privaten Schlüssel verschlüsselt. Jeder, der den öffentlichen Schlüssel zum Entschlüsseln der digitalen Signatur verwendet, ist sicher, dass die digitale Signatur nur von der Person stammen darf, die den privaten Schlüssel besitzt. Darüber hinaus kann der Empfänger einen Hash der Daten mit demselben Algorithmus wie der Absender berechnen, und wenn der berechnete Hash mit dem in der digitalen Signatur gesendeten übereinstimmt, kann der Empfänger sicher sein, dass die Daten nicht geändert wurden, nachdem sie digital signiert wurden.

Ein Nachteil der Verwendung einer PKI für die Verschlüsselung von Daten mit hohem Volumen ist die relativ langsame Leistung. Aufgrund der intensiven Mathematik kann die Verschlüsselung und Entschlüsselung von Daten mithilfe einer asymmetrischen Verschlüsselung, die von einem Schlüsselpaar abhängt, bis zu 1.000 Mal langsamer sein als die Verschlüsselung und Entschlüsselung mithilfe einer symmetrischen Verschlüsselung, die nur von einem einzelnen Schlüssel abhängt. TLS verwendet daher eine PKI nur zum Generieren digitaler Signaturen und zum Verhandeln des sitzungsspezifischen einzelen Schlüssels, der sowohl vom Client als auch vom Server für die Massenverschlüsselung und -entschlüsselung von Daten verwendet wird. TLS unterstützt eine Vielzahl von symmetrischen Verschlüsselungen mit nur einem Schlüssel, und in Zukunft können zusätzliche Verschlüsselungen hinzugefügt werden.

Weitere Informationen zum TLS-Handshakeprotokoll finden Sie unter TLS Handshake Protocol.

Weitere Informationen zur Kryptografie hinter dem TLS-Protokoll finden Sie unter Cryptography Essentials.

X.509-Zertifikate

Ein wichtiges Problem, das von einer PKI behandelt werden muss, ist die Fähigkeit, der Authentizität des verwendeten öffentlichen Schlüssels zu vertrauen. Wenn Sie einen öffentlichen Schlüssel verwenden, der für ein Unternehmen ausgestellt wurde, mit dem Sie Geschäfte machen möchten, möchten Sie sicher sein, dass der Schlüssel tatsächlich dem Unternehmen gehört und nicht einem Dieb, der Ihr Guthaben Karte Nummer ermitteln möchte.

Um die Identität eines Prinzipals mit einem Schlüsselpaar zu garantieren, wird dem Prinzipal von einer Zertifizierungsstelle (CA) ein X.509-Zertifikat ausgestellt. Dieses Zertifikat enthält Informationen zur Identifizierung des Prinzipals, enthält den öffentlichen Schlüssel des Prinzipals und wird von der Zertifizierungsstelle digital signiert. Diese digitale Signatur gibt an, dass die Zertifizierungsstelle der Meinung ist, dass der im Zertifikat enthaltene öffentliche Schlüssel wirklich zu dem Prinzipal gehört, der durch das Zertifikat identifiziert wird.

Und wie vertrauen Sie der Zertifizierungsstelle? Da die Zertifizierungsstelle selbst ein X.509-Zertifikat enthält, das von einer höheren Zertifizierungsstelle signiert wurde. Diese Kette von Zertifikatsignaturen wird fortgesetzt, bis sie eine Stammzertifizierungsstelle erreicht, bei der es sich um eine Zertifizierungsstelle handelt, die ihre eigenen Zertifikate signiert. Wenn Sie der Integrität der Stammzertifizierungsstelle eines Zertifikats vertrauen, sollten Sie der Echtheit des Zertifikats selbst vertrauen können. Daher ist die Auswahl von Stammzertifizierungsstellen, denen Sie vertrauen möchten, eine wichtige Aufgabe für einen Systemadministrator.

Clientzertifikate

Als Protokolle auf Sicherheitstransportebene zum ersten Mal herauskamen, bestand ihr Hauptzweck darin, zu gewährleisten, dass ein Client eine Verbindung mit einem authentischen Server herstellt und die Privatsphäre von Daten während der Übertragung schützt. SSL 3.0 und TLS 1.0 unterstützen jedoch auch die Übertragung des Zertifikats eines Clients während des Handshakes des Protokolls. Dieses optionale Feature ermöglicht die gegenseitige Authentifizierung von Client und Server.

Die Entscheidung, ob ein Clientzertifikat verwendet werden soll, sollte im Kontext der Anwendung getroffen werden. Clientzertifikate sind nicht erforderlich, wenn die Primäre Anforderung die Authentifizierung des Servers ist. Wenn die Clientauthentifizierung jedoch unerlässlich ist, kann das Zertifikat eines Clients verwendet werden, anstatt sich auf die benutzerdefinierte Authentifizierung innerhalb der Anwendung zu verlassen. Die Verwendung von Clientzertifikaten ist der benutzerdefinierten Authentifizierung vorzuziehen, da sie Benutzern ein Szenario für einmaliges Anmelden bietet.

Verwenden von TLS in COM

TLS unterstützt nur die Identitätswechselebene (RPC_C_IMP_LEVEL_IMPERSONATE). Wenn COM TLS als Authentifizierungsdienst für einen Proxy aushandelt, legt COM die Identitätswechselebene unabhängig von der Standardeinstellung des Prozesses fest. Damit der Identitätswechsel in TLS ordnungsgemäß funktioniert, muss der Client dem Server ein X.509-Zertifikat bereitstellen, und auf dem Server muss dieses Zertifikat einem bestimmten Benutzerkonto auf dem Server zugeordnet sein. Weitere Informationen finden Sie in der schrittweisen Anleitung zum Zuordnen von Zertifikaten zu Benutzerkonten.

TLS unterstützt das Cloaking nicht. Wenn ein Cloaking-Flag und TLS in einem CoInitializeSecurity- oder einem IClientSecurity::SetBlanket-Aufruf angegeben sind, werden E_INVALIDARG zurückgegeben.

TLS funktioniert nicht, wenn die Authentifizierungsebene auf Keine festgelegt ist. Der Handshake zwischen Client und Server überprüft die jeweils festgelegte Authentifizierungsebene und wählt die höhere Sicherheitseinstellung für die Verbindung aus.

Die Sicherheitsparameter für TLS können durch Aufrufen von CoInitializeSecurity und CoSetProxyBlanket festgelegt werden. In den folgenden Abschnitten werden die Nuancen beschrieben, die bei diesen Anrufen erforderlich sind.

Festlegen der Sicherheitsdecke durch einen Server

Wenn ein Server TLS verwenden möchte, muss er Schannel (RPC_C_AUTHN_GSS_SCHANNEL) als Authentifizierungsdienst im asAuthSvc-Parameter von CoInitializeSecurity angeben. Um zu verhindern, dass Clients mithilfe eines weniger sicheren Authentifizierungsdiensts eine Verbindung mit dem Server herstellen, sollte der Server beim Aufrufen von CoInitializeSecurity nur Schannel als Authentifizierungsdienst angeben. Der Server kann die Sicherheitsdecke nach dem Aufruf von CoInitializeSecurity nicht mehr ändern.

Um TLS zu verwenden, müssen die folgenden Parameter angegeben werden, wenn ein Server CoInitializeSecurity aufruft:

  • pVoid sollte entweder ein Zeiger auf ein IAccessControl-Objekt oder ein Zeiger auf eine SECURITY_DESCRIPTOR sein. Es sollte nicht NULL oder ein Zeiger auf eine AppID sein.
  • cAuthSvc darf nicht 0 oder -1 sein. COM-Server wählen nie Schannel aus, wenn cAuthSvc-1 ist.
  • asAuthSvc muss Schannel als möglichen Authentifizierungsdienst angeben. Hierzu werden die folgenden SOLE_AUTHENTICATION_SERVICE Parameter für den Schannel-Member des SOLE_AUTHENTICATION_LIST festgelegt:
    • dwAuthnSvc muss RPC_C_AUTHN_GSS_SCHANNEL sein.
    • dwAuthzSvc sollte RPC_C_AUTHZ_NONE sein. Derzeit wird er ignoriert.
    • pPrincipalName muss ein Zeiger auf eine CERT_CONTEXT sein, der als Zeiger auf OLECHAR umgewandelt wird, der das X.509-Zertifikat des Servers darstellt.
  • dwAuthnLevel gibt die Mindestauthentifizierungsebene an, die von Clients für eine erfolgreiche Verbindung akzeptiert wird. Sie kann nicht RPC_C_AUTHN_LEVEL_NONE werden.
  • für dwCapabilities sollte das flag EOAC_APPID nicht festgelegt sein. Das flag EOAC_ACCESS_CONTROL sollte festgelegt werden, wenn pVoid auf ein IAccessControl-Objekt zeigt. Sie sollte nicht festgelegt werden, wenn pVoid auf eine SECURITY_DESCRIPTOR zeigt. Informationen zu anderen Flags, die möglicherweise festgelegt werden, finden Sie unter CoInitializeSecurity.

Weitere Informationen zur Verwendung von CoInitializeSecurity finden Sie unter Festlegen der prozessweiten Sicherheit mit CoInitializeSecurity.

Festlegen der Sicherheitsdecke durch einen Client

Wenn ein Client TLS verwenden möchte, muss er Schannel (RPC_C_AUTHN_GSS_SCHANNEL) in der Liste der Authentifizierungsdienste im pAuthList-Parameter von CoInitializeSecurity angeben. Wenn Schannel beim Aufruf von CoInitializeSecurity nicht als möglicher Authentifizierungsdienst angegeben wird, schlägt ein späterer Aufruf von CoSetProxyBlanket (oder IClientSecurity::SetBlanket) fehl, wenn versucht wird, Schannel als Authentifizierungsdienst anzugeben.

Die folgenden Parameter sollten angegeben werden, wenn ein Client CoInitializeSecurity aufruft:

  • dwAuthnLevel gibt die Standardauthentifizierungsebene an, die der Client verwenden möchte. Sie kann nicht RPC_C_AUTHN_LEVEL_NONE werden.
  • dwImpLevel muss RPC_C_IMP_LEVEL_IMPERSONATE sein.
  • pAuthList muss über die folgenden SOLE_AUTHENTICATION_INFO Parameter als Mitglied der Liste verfügen:
    • dwAuthnSvc muss RPC_C_AUTHN_GSS_SCHANNEL sein.
    • dwAuthzSvc muss RPC_C_AUTHZ_NONE sein.
    • pAuthInfo ist ein Zeiger auf einen CERT_CONTEXT, der als Zeiger auf void umgewandelt wird, der das X.509-Zertifikat des Clients darstellt. Wenn der Client kein Zertifikat besitzt oder sein Zertifikat nicht dem Server präsentieren möchte, muss pAuthInfoNULL sein, und es wird versucht, eine anonyme Verbindung mit dem Server herzustellen.
  • dwCapabilities ist eine Reihe von Flags, die auf zusätzliche Clientfunktionen hinweisen. Informationen dazu, welche Flags festgelegt werden sollten, finden Sie unter CoInitializeSecurity .

Weitere Informationen zur Verwendung von CoInitializeSecurity finden Sie unter Festlegen der prozessweiten Sicherheit mit CoInitializeSecurity.

Ändern der Sicherheitsdecke durch einen Client

Wenn ein Client TLS verwenden möchte, aber die Sicherheitsdecke nach dem Aufruf von CoInitializeSecurity ändern möchte, muss er entweder CoSetProxyBlanket oder IClientSecurity::SetBlanket mit Parametern aufrufen, die denen im Aufruf von CoInitializeSecurity ähneln, mit den folgenden Unterschieden:

  • pServerPrincName gibt den Prinzipalnamen des Servers im msstd- oder fullsic-Format an. Informationen zu diesen Formaten finden Sie unter Prinzipalnamen. Wenn der Client über das X.509-Zertifikat des Servers verfügt, kann er den Prinzipalnamen finden, indem er RpcCertGeneratePrincipalName aufruft.
  • pAuthInfo ist ein Zeiger auf eine CERT_CONTEXT, der als Zeiger auf RPC_AUTH_IDENTITY_HANDLE umgewandelt wird, der das X.509-Zertifikat des Clients darstellt. Wenn der Client kein Zertifikat besitzt oder sein Zertifikat nicht dem Server präsentieren möchte, muss pAuthInfoNULL sein, und es wird versucht, eine anonyme Verbindung mit dem Server herzustellen.
  • dwCapabilities besteht aus Flags, die zusätzliche Clientfunktionen angeben. Es können nur vier Flags verwendet werden, um Einstellungen für Sicherheitsdecken zu ändern: EOAC_DEFAULT, EOAC_MUTUAL_AUTH, EOAC_ANY_AUTHORITY (dieses Flag ist veraltet) und EOAC_MAKE_FULLSIC. Weitere Informationen finden Sie unter CoSetProxyBlanket.

Weitere Informationen zur Verwendung von CoSetProxyBlanket finden Sie unter Festlegen der Sicherheit auf der Schnittstellenproxyebene.

Beispiel: Client ändert die Sicherheitsdecke

Im folgenden Beispiel wird veranschaulicht, wie ein Client die Sicherheitsdecke ändern kann, um eine Anforderung des Servers für den Client zur Bereitstellung seines X.509-Zertifikats zu berücksichtigen. Fehlerbehandlungscode wird aus Platzgründen weggelassen.

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();
}

COM- und Sicherheitspakete