SSPI/Kerberos-Interoperabilität mit GSSAPI
Bei der Verwendung des Kerberos Security Support Providers (SSP) ist Vorsicht geboten, wenn die Interoperabilität mit GSSAPI eine Voraussetzung ist. Die folgenden Codekonventionen ermöglichen die Interoperabilität mit GSSAPI-basierten Anwendungen:
Sie finden Beispielcode im Platform Software Development Kit (SDK) unter Samples\Security\SSPI\GSS. Darüber hinaus wird das entsprechende UNIX-Beispiel in den MIT- und Heimdal-Kerberos-Verteilungen, dem GSS-Client und dem Server verteilt.
Windows-kompatible Namen
GSSAPI-Funktionen verwenden ein Namensformat, das als gss_nt_service_name bezeichnet wird, wie in RFC angegeben. Beispielsweise ist sample@host.dom.com ein Name, der in einer GSSAPI-basierten Anwendung verwendet werden kann. Das Windows-Betriebssystem erkennt das Format gss_nt_service_name nicht und es muss der vollständige Dienstprinzipalname, zum Beispiel sample/host.dom.com@REALM, verwendet werden.
Authentifizierung
Die Authentifizierung wird in der Regel behandelt, wenn eine Verbindung zuerst zwischen einem Client und einem Server eingerichtet wird. In diesem Beispiel verwendet der Client die Security Support Provider-Schnittstelle (SSPI) und der Server verwendet GSSAPI.
So richten Sie die Authentifizierung im SSPI-Client ein
- Abrufen ausgehender Anmeldeinformationen mithilfe von AcquireCredentialsHandle.
- Erstellen Sie einen Dienstnamen mit gss_import_name() und rufen Sie eingehende Anmeldeinformationen mithilfe von gss_acquire_cred ab.
- Rufen Sie ein Authentifizierungstoken ab, um es mithilfe von InitializeSecurityContext (Kerberos) an den Server zu senden.
- Senden Sie das Token an den Server.
So richten Sie die Authentifizierung auf dem GSSAPI-Server ein
Analysieren Sie die Nachricht vom Client, um das Sicherheitstoken zu extrahieren. Verwenden Sie die gss_accept_sec_context-Funktion, wobei das Token als Argument übergeben wird.
Analysieren Sie die Nachricht vom Server, um das Sicherheitstoken zu extrahieren. Übergeben Sie dieses Sicherheitstoken an InitializeSecurityContext (Kerberos).
Senden Sie ein Antworttoken an den Client.
Die gss_accept_sec_context-Funktion kann ein Token zurückgeben, das Sie zurück an den Client senden können.
Wenn der Vorgang fortgesetzt werden muss, senden Sie ein Antworttoken an den Server; andernfalls ist die Einrichtung der Authentifizierung abgeschlossen.
Wenn der Vorgang fortgesetzt werden muss, warten Sie auf das nächste Token vom Client; andernfalls ist die Einrichtung der Authentifizierung abgeschlossen.
Integrität und Datenschutz von Nachrichten
Die meisten GSSAPI-basierten Anwendungen verwenden die GSS_Wrap-Funktion, um eine Nachricht zu signieren, bevor sie gesendet wird. Umgekehrt verifiziert die GSS_Unwrap-Funktion die Signatur. GSS_Wrap ist in Version 2.0 der API verfügbar und wird jetzt oft verwendet und in Internetstandards angegeben, die die Verwendung der GSSAPI zum Hinzufügen von Sicherheitsfunktionen zu Protokollen beschreiben. Zuvor wurden die Funktionen GSS SignMessage und SealMessage für die Nachrichtenintegrität und den Datenschutz verwendet. GSS_Wrap und GSS_Unwrap werden sowohl für die Integrität als auch für den Datenschutz verwendet, wobei die Verwendung von Privatsphärenfunktionen durch den Wert des Arguments „conf_flag“ gesteuert wird.
Wenn ein GSSAPI-basiertes Protokoll angewiesen wird, die Funktionen gss_get_mic und gss_verify_mic zu verwenden, wären die richtigen SSPI-Funktionen MakeSignature und VerifySignature. Beachten Sie, dass MakeSignature und VerifySignature nicht mit GSS_Wrap interoperieren, wenn conf_flag auf Null oder als GSS_Unwrap festgelegt ist. Das gleiche gilt für das Vermischen von EncryptMessage (Kerberos) nur für die Signatur und gss_verify_mic.
Hinweis
Verwenden Sie die Funktionen MakeSignature oder VerifySignature nicht, wenn GSS_Wrap und GSS_Unwrap aufgerufen werden.
Die SSPI-Entsprechung von GSS_Wrap ist EncryptMessage (Kerberos) für Integrität und Datenschutz.
Das folgende Beispiel zeigt die Verwendung von EncryptMessage (Kerberos), um Daten zu signieren, die von GSS_Unwrap verfiziert werden.
Im SSPI-Client:
// Need three descriptors, two for the SSP and
// one to hold the application data.
in_buf_desc.cBuffers = 3;
in_buf_desc.pBuffers = wrap_bufs;
in_buf_desc.ulVersion = SECBUFFER_VERSION;
wrap_bufs[0].cbBuffer = sizes.cbSecurityTrailer;
wrap_bufs[0].BufferType = SECBUFFER_TOKEN;
wrap_bufs[0].pvBuffer = malloc(sizes.cbSecurityTrailer);
// This buffer holds the application data.
wrap_bufs[1].BufferType = SECBUFFER_DATA;
wrap_bufs[1].cbBuffer = in_buf.cbBuffer;
wrap_bufs[1].pvBuffer = malloc(wrap_bufs[1].cbBuffer);
memcpy(wrap_bufs[1].pvBuffer, in_buf.pvBuffer, in_buf.cbBuffer);
wrap_bufs[2].BufferType = SECBUFFER_PADDING;
wrap_bufs[2].cbBuffer = sizes.cbBlockSize;
wrap_bufs[2].pvBuffer = malloc(wrap_bufs[2].cbBuffer);
maj_stat = EncryptMessage(&context,
SignOnly ? KERB_WRAP_NO_ENCRYPT : 0,
&in_buf_desc, 0);
// Send a message to the server.
Im GSSAPI-Server:
// Received message is in recv_buf.
maj_stat = gss_unwrap(&min_stat, context, &recv_buf, &msg_buf,
&conf_state, (gss_qop_t *) NULL);
(void) gss_release_buffer(&min_stat, &recv_buf);
// Original message is in msg_buf.
Die SSPI-Entsprechung von GSS_Unwrap ist DecryptMessage (Kerberos). Hier ist ein Beispiel, das zeigt, wie Sie DecryptMessage (Kerberos) zum Entschlüsseln von Daten verwenden, die von GSS_Wrap verschlüsselt wurden.
Im GSSAPI-Server:
// Seal the message.
send_buf.value = msg;
send_buf.length = msglen;
// If encrypt_flag = 1, privacy; encrypt_flag = 0, integrity.
maj_stat = gss_wrap(&min_stat, context, encrypt_flag,
GSS_C_QOP_DEFAULT, &send_buf, &state, &msg_buf);
// The message to send is in msg_buf.
Im SSPI-Client:
wrap_buf_desc.cBuffers = 2;
wrap_buf_desc.pBuffers = wrap_bufs;
wrap_buf_desc.ulVersion = SECBUFFER_VERSION;
// This buffer is for SSPI.
wrap_bufs[0].BufferType = SECBUFFER_STREAM;
wrap_bufs[0].pvBuffer = xmit_buf.pvBuffer;
wrap_bufs[0].cbBuffer = xmit_buf.cbBuffer;
// This buffer holds the application data.
wrap_bufs[1].BufferType = SECBUFFER_DATA;
wrap_bufs[1].cbBuffer = 0;
wrap_bufs[1].pvBuffer = NULL;
maj_stat = DecryptMessage(
&context,
&wrap_buf_desc,
0, // no sequence number
&qop
);
// This is where the data is.
msg_buf = wrap_bufs[1];
// Check QOP of received message.
// If QOP is KERB_WRAP_NO_ENCRYPT, the message is signed only;
// otherwise, it is encrypted.