Freigeben über


SSL in WinHTTP

Microsoft Windows HTTP Services (WinHTTP) unterstützt SSL-Transaktionen (Secure Sockets Layer), einschließlich Clientzertifikaten. In diesem Thema werden Konzepte erläutert, die an einer SSL-Transaktion beteiligt sind und wie sie mit WinHTTP verarbeitet werden.

Secure Sockets Layer

SSL ist ein etablierter Standard für sichere HTTP-Transaktionen. SSL bietet einen Mechanismus zum Ausführen einer bis zu 128-Bit-Verschlüsselung für alle Transaktionen zwischen Client und Server. Er ermöglicht dem Client zu überprüfen, ob der Server über die Verwendung von Serverzertifikaten zu einer vertrauenswürdigen Entität gehört. Außerdem kann der Server die Identität des Clients mit Clientzertifikaten bestätigen.

Jede dieser Probleme mit Verschlüsselung, Serveridentität und Clientidentität wird im SSL-Handshake ausgehandelt, der auftritt, wenn ein Client zuerst eine Ressource von einem HTTPS-Server (Secure Hypertext Transfer Protocol) anfordert. Im Wesentlichen stellt der Client und der Server jeweils eine Liste der erforderlichen und bevorzugten Einstellungen dar. Wenn eine gemeinsame Gruppe von Anforderungen vereinbart und erfüllt werden kann, wird eine SSL-Verbindung hergestellt.

WinHTTP stellt eine allgemeine Schnittstelle für die Verwendung von SSL bereit. Während die Details des SSL-Handshakes und der Transaktion intern verarbeitet werden, ermöglicht WinHTTP es Ihnen, Verschlüsselungsstufen abzurufen, das Sicherheitsprotokoll anzugeben und mit Server- und Clientzertifikaten zu interagieren. Die folgenden Abschnitte enthalten Details zum Erstellen von WinHTTP-basierten Anwendungen, die eine SSL-Protokollversion wählen, Serverzertifikate untersuchen und Clientzertifikate auswählen, die an HTTPS-Server gesendet werden sollen.

Serverzertifikate

Serverzertifikate werden vom Server an den Client gesendet, damit der Client einen öffentlichen Schlüssel für den Server abrufen und sicherstellen kann, dass der Server von einer Zertifizierungsstelle überprüft wurde. Zertifikate können unterschiedliche Datentypen enthalten. Beispielsweise enthält ein X.509-Zertifikat das Format des Zertifikats, die Seriennummer des Zertifikats, den Algorithmus, der zum Signieren des Zertifikats verwendet wurde, den Namen der Zertifizierungsstelle (CA), die das Zertifikat ausgestellt hat, den Namen und den öffentlichen Schlüssel der Entität, die das Zertifikat anfordert, und die Signatur der Zertifizierungsstelle.

Wenn Sie die WinHTTP-Anwendungsprogrammierschnittstelle (API) verwenden, können Sie ein Serverzertifikat abrufen, indem Sie WinHttpQueryOption- aufrufen und das WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT Flag angeben. Das Serverzertifikat wird in einer WINHTTP_CERTIFICATE_INFO Struktur zurückgegeben. Wenn Sie den Zertifikatkontext lieber abrufen möchten, geben Sie stattdessen das WINHTTP_OPTION_SERVER_CERT_CONTEXT Flag an.

Wenn ein Serverzertifikat Fehler enthält, können Details zum Fehler in der Statusrückruffunktion abgerufen werden. Die WINHTTP_CALLBACK_STATUS_SECURE_FAILURE-Benachrichtigung gibt einen Fehler mit einem Serverzertifikat an. Der lpvStatusInformation Parameter enthält ein oder mehrere detaillierte Fehlerkennzeichnungen. Weitere Informationen finden Sie unter WINHTTP_STATUS_CALLBACK.

Clientzertifikate

Während des SSL-Handshakes erfordert der Server möglicherweise eine Authentifizierung. Der Client wird authentifiziert, indem ein gültiges Clientzertifikat an den Server bereitgestellt wird. Mit WinHTTP können Sie ein Zertifikat aus einem lokalen Zertifikatspeicherauswählen und senden. In den folgenden Abschnitten wird der Prozess beschrieben, der Clientzertifikate bereitstellt, wenn sie entweder die WinHTTP-API oder das WinHttpRequest--Objekt verwenden.

WinHTTP-API

Sowohl WinHttpSendRequest als auch WinHttpReceiveResponse können nicht angeben, dass eine Anforderung nicht erfolgreich war, da der HTTPS-Server eine Authentifizierung erfordert. Rufen Sie in diesen Fällen GetLastError- auf, um ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED zurückgibt. Verwenden Sie nach Erhalt dieses Fehlers die entsprechenden CryptoAPI- Funktionen, um ein entsprechendes Zertifikat zu finden. Geben Sie an, dass dieses Zertifikat mit der nächsten Anforderung gesendet werden soll, indem Sie WinHttpSetOption- mit dem WINHTTP_OPTION_CLIENT_CERT_CONTEXT-Flag aufrufen.

Das folgende Codebeispiel zeigt, wie Sie einen Zertifikatspeicher öffnen und ein Zertifikat basierend auf dem Antragstellernamen suchen, nachdem der fehler ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED zurückgegeben wurde.

  if( !WinHttpReceiveResponse( hRequest, NULL ) )
  {
    if( GetLastError( ) == ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED )
    {
      //MY is the store the certificate is in.
      hMyStore = CertOpenSystemStore( 0, TEXT("MY") );
      if( hMyStore )
      {
        pCertContext = CertFindCertificateInStore( hMyStore,
             X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
             0,
             CERT_FIND_SUBJECT_STR,
             (LPVOID) szCertName, //Subject string in the certificate.
             NULL );
        if( pCertContext )
        {
          WinHttpSetOption( hRequest, 
                            WINHTTP_OPTION_CLIENT_CERT_CONTEXT,
                            (LPVOID) pCertContext, 
                            sizeof(CERT_CONTEXT) );
          CertFreeCertificateContext( pCertContext );
        }
        CertCloseStore( hMyStore, 0 );

        // NOTE: Application should now resend the request.
      }
    }
  }

Bevor Sie eine Anforderung erneut senden, die ein Clientzertifikat enthält, können Sie ermitteln, ob die unterstützte Verschlüsselungsstufe für Ihre Anwendung akzeptabel ist. Rufen Sie WinHttpQueryOption- auf, und geben Sie das WINHTTP_OPTION_SECURITY_FLAGS Flag an, um die verwendete Verschlüsselungsebene zu bestimmen.

Abruf der Ausstellerliste für die SSL-Clientauthentifizierung

Wenn die WinHttp-Clientanwendung eine Anforderung an einen sicheren HTTP-Server sendet, der SSL-Clientauthentifizierung erfordert, gibt WinHttp eine ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED zurück, wenn die Anwendung kein Clientzertifikat angegeben hat. Für Computer, die unter Windows Server 2008 und Windows Vista ausgeführt werden, ermöglicht WinHttp es der Anwendung, die vom Server bereitgestellte Zertifikatherausgeberliste in der Authentifizierungsabfrage abzurufen. Die Ausstellerliste gibt eine Liste der Zertifizierungsstellen (Certificate Authorities, CAs) an, die vom Server zum Ausgeben von Clientzertifikaten autorisiert sind. Die Anwendung filtert die Ausstellerliste, um das erforderliche Zertifikat abzurufen.

Die WinHttp-Clientanwendung ruft die Ausstellerliste ab, wenn WinHttpSendRequestoder WinHttpReceiveResponseERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDEDzurückgibt. Wenn dieser Fehler zurückgegeben wird, ruft die Anwendung WinHttpQueryOption mit der Option WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST auf. Der parameter lpBuffer muss groß genug sein, um einen Zeiger auf die SecPkgContext_IssuerListInfoEx Struktur zu enthalten. Das folgende Codebeispiel zeigt, wie die Ausstellerliste abgerufen wird.

#include <windows.h>
#include <winhttp.h>
#include <schannel.h>

//...

void GetIssuerList(HINTERNET hRequest)
{
  SecPkgContext_IssuerListInfoEx* pIssuerList = NULL;
  DWORD dwBufferSize = sizeof(SecPkgContext_IssuerListInfoEx*);

  if (WinHttpQueryOption(hRequest,
           WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST,
           &pIssuerList,
           &dwBufferSize) == TRUE)
  {
    // Use the pIssuerList for cert store filtering.
    GlobalFree(pIssuerList); // Free the issuer list when done.
  }
}

Die Informationen in der SecPkgContext_IssuerListInfoEx Struktur, cIssuers und aIssuers, können verwendet werden, um nach dem Zertifikat zu suchen, wie im folgenden Codebeispiel gezeigt. Weitere Informationen finden Sie unter CertFindChainInStore.

PCERT_CONTEXT pClientCert = NULL;
PCCERT_CHAIN_CONTEXT pClientCertChain = NULL;

CERT_CHAIN_FIND_BY_ISSUER_PARA SrchCriteria;
::ZeroMemory(&SrchCriteria, sizeof(CERT_CHAIN_FIND_BY_ISSUER_PARA));
SrchCriteria.cbSize = sizeof(CERT_CHAIN_FIND_BY_ISSUER_PARA);

SrchCriteria.cIssuer = pIssuerList->cIssuers;
SrchCriteria.rgIssuer = pIssuerList->aIssuers;

pClientCertChain = CertFindChainInStore(
            hClientCertStore,
            X509_ASN_ENCODING,
            CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_URL_FLAG |
            // Do not perform wire download when building chains.
            CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_FLAG,
            // Do not search pCacheEntry->_ClientCertStore 
            // for issuer certs.
            CERT_CHAIN_FIND_BY_ISSUER,
            &SrchCriteria,
            NULL);

if (pClientCertChain)
{
    pClientCert = (PCERT_CONTEXT) pClientCertChain->rgpChain[0]->rgpElement[0]->pCertContext;

    CertDuplicateCertificateContext(pClientCert);

    CertFreeCertificateChain(pClientCertChain);

    pClientCertChain = NULL;
}

Optionale Client-SSL-Zertifikate

Ab Windows Server 2008 und Windows Vista unterstützt die WinHttp-API optionale Clientzertifikate. Wenn der Server ein Clientzertifikat anfordert, gibt WinHttpSendRequestoder WinHttpRecieveResponse einen ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED Fehler zurück. Wenn der Server das Zertifikat anfordert, aber nicht benötigt, kann die Anwendung diese Option angeben, um anzugeben, dass es kein Zertifikat hat. Der Server kann ein anderes Authentifizierungsschema auswählen oder anonymen Zugriff auf den Server zulassen. Die Anwendung gibt das WINHTTP_NO_CLIENT_CERT_CONTEXT Makro im lpBuffer Parameter von WinHttpSetOption an, wie im folgenden Codebeispiel gezeigt.

BOOL fRet = WinHttpSetOption ( hRequest,
                               WINHTTP_OPTION_CLIENT_CERT_CONTEXT,
                               WINHTTP_NO_CLIENT_CERT_CONTEXT,
                               0);

Wenn die WINHTTP_NO_CLIENT_CERT_CONTEXT festgelegt ist und der Server weiterhin ein Clientzertifikat benötigt, sendet er möglicherweise einen 403 HTTP-Statuscode. Weitere Informationen finden Sie in der option WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST.

WinHttpRequest-Objekt

Verwenden Sie die SetClientCertificate Methode des WinHttpRequest- Objekts, um Clientzertifikate auszuwählen, die mit einer Anforderung an den Server gesendet werden sollen. Wählen Sie ein Zertifikat aus, indem Sie eine Zertifikatauswahlzeichenfolge mit der SetClientCertificate Methode angeben. Die Zertifikatauswahlzeichenfolge besteht aus dem Zertifikatspeicherort, Zertifikatspeicherund durch umgekehrte Schrägstriche getrennten Antragstellernamen. In der folgenden Tabelle sind Komponenten für diese Auswahlzeichenfolge aufgeführt.

Bestandteil Beschreibung Mögliche Werte
Ort Bestimmt den Registrierungsschlüssel, unter dem die Zertifikate gespeichert werden. Die möglichen Werte sind "LOCAL_MACHINE", um anzugeben, dass der Zertifikatspeicher unter HKEY_LOCAL_MACHINE
und "CURRENT_USER", um anzugeben, dass der Zertifikatspeicher unter dem nicht imitiertenHKEY_CURRENT_USER liegt.
Bei dieser Komponente wird die Groß-/Kleinschreibung beachtet.
Zertifikatspeicher Gibt den Namen des Zertifikatspeichers an, das das relevante Zertifikat enthält. Typische Zertifikatspeicher "MY", "Root" und "TrustedPeople". Bei dieser Komponente wird die Groß-/Kleinschreibung beachtet.
Antragstellername Identifiziert ein Zertifikat im angegebenen Zertifikatspeicher. Das erste Zertifikat, das die für diese Komponente angegebene Zeichenfolge enthält, ist ausgewählt. Der Antragstellername kann eine beliebige Zeichenfolge sein. Eine leere Zeichenfolge gibt an, dass das erste Zertifikat im Zertifikatspeicher verwendet werden soll. Bei dieser Komponente wird die Groß-/Kleinschreibung nicht beachtet.

Der Zertifikatspeicher Namen und Speicherort sind optionale Komponenten. Wenn Sie jedoch einen Zertifikatspeicherangeben, müssen Sie auch den Speicherort dieses Zertifikatspeichersangeben. Der Standardspeicherort ist CURRENT_USER und der standardmäßige Zertifikatspeicher "MY" lautet.

Im folgenden Codebeispiel wird gezeigt, wie Sie angeben, dass ein Zertifikat mit dem Betreff "Mein Middle-Tier Zertifikat" aus dem Zertifikatspeicher "Persönlich" in der Registrierung unter HKEY_LOCAL_MACHINEausgewählt werden soll.

HttpReq.SetClientCertificate("LOCAL_MACHINE\Personal\My Middle-Tier Certificate")

Anmerkung

In einigen Sprachen ist der umgekehrte Schrägstrich ein Escapezeichen. Denken Sie daran, die Zertifikatauswahlzeichenfolge so zu ändern, dass dies berücksichtigt wird. Verwenden Sie z. B. in Microsoft JScript zwei benachbarte umgekehrte Schrägstriche anstelle eines.

Wenn Sie kein Zertifikat angeben und ein HTTPS-Server ein Clientzertifikat erfordert, wählt WinHTTP das erste Zertifikat im Standardzertifikat Zertifikatspeicheraus. Wenn keine Zertifikate vorhanden sind, wird ein Fehler ausgelöst. Wenn das Zertifikat nicht akzeptiert wird, gibt der Server einen Statuscode 403 zurück, um anzugeben, dass die Anforderung nicht erfüllt werden kann. Anschließend können Sie ein passendes Zertifikat mit SetClientCertificate auswählen und die Anforderung erneut senden.