Sdílet prostřednictvím


SSL ve Službě WinHTTP

Microsoft Windows HTTP Services (WinHTTP) podporuje transakce SSL (Secure Sockets Layer) včetně klientských certifikátů. Toto téma vysvětluje koncepty spojené s transakcí SSL a způsob jejich zpracování pomocí WinHTTP.

Vrstva zabezpečených soketů

SSL je zavedený standard pro zajištění zabezpečených transakcí HTTP. PROTOKOL SSL poskytuje mechanismus pro provedení až 128bitového šifrování všech transakcí mezi klientem a serverem. Umožňuje klientovi ověřit, že server patří k důvěryhodné entitě prostřednictvím použití certifikátů serveru. Umožňuje také serveru potvrdit identitu klienta pomocí klientských certifikátů.

Každý z těchto problémů se šifrováním, identitou serveru a identitou klienta se vyjednává v protokolu SSL handshake, ke kterému dochází, když klient poprvé požádá o prostředek ze serveru HTTPS (Secure Hypertext Transfer Protocol). Klient a server v podstatě představují seznam požadovaných a upřednostňovaných nastavení. Pokud je možné odsouhlasit a splnit společnou sadu požadavků, vytvoří se připojení SSL.

WinHTTP poskytuje rozhraní vysoké úrovně pro použití SSL. Zatímco podrobnosti o metodách handshake a transakce SSL se zpracovávají interně, WinHTTP umožňuje načíst úrovně šifrování, zadat protokol zabezpečení a pracovat se serverovými a klientskými certifikáty. Následující části obsahují podrobnosti o vytváření aplikací založených na winHTTP, které vyberou verzi protokolu SSL, prověřují certifikáty serveru a vyberou klientské certifikáty, které se mají odesílat na servery HTTPS.

Certifikáty serveru

Certifikáty serveru se odesílají ze serveru klientovi, aby klient mohl získat veřejný klíč pro server a zajistit, aby byl server ověřen certifikační autoritou. Certifikáty můžou obsahovat různé typy dat. Například certifikát X.509 obsahuje formát certifikátu, sériové číslo certifikátu, algoritmus použitý k podepsání certifikátu, název certifikační autority (CA), který certifikát vydal, název a veřejný klíč entity, která certifikát požaduje, a podpis certifikační autority.

Při použití aplikačního programovacího rozhraní WinHTTP (API) můžete načíst certifikát serveru voláním WinHttpQueryOption a zadáním příznaku WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT. Certifikát serveru se vrátí ve struktuře WINHTTP_CERTIFICATE_INFO. Pokud chcete načíst kontext certifikátu, zadejte místo toho příznak WINHTTP_OPTION_SERVER_CERT_CONTEXT.

Pokud certifikát serveru obsahuje chyby, lze podrobnosti o chybě získat ve funkci zpětného volání stavu. Oznámení WINHTTP_CALLBACK_STATUS_SECURE_FAILURE indikuje chybu s certifikátem serveru. Parametr lpvStatusInformation obsahuje jeden nebo podrobnější příznak chyby. Další informace najdete v tématu WINHTTP_STATUS_CALLBACK.

Klientské certifikáty

Během metody handshake PROTOKOLU SSL může server vyžadovat ověření. Klient se ověřuje zadáním platného klientského certifikátu na server. WinHTTP umožňuje vybrat a odeslat certifikát z místního úložiště certifikátů . Následující části popisují proces, který poskytuje klientské certifikáty při použití rozhraní WINHTTP API nebo WinHttpRequest objektu.

WinHTTP API

winHttpSendRequest i WinHttpReceiveResponse může být neúspěšné, protože server HTTPS vyžaduje ověření. V těchto případech voláním GetLastError vrátí ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED. Po zobrazení této chyby vyhledejte odpovídající certifikát pomocí příslušných funkcí CryptoAPI. Označte, že tento certifikát by se měl odeslat s dalším požadavkem voláním WinHttpSetOption příznakem WINHTTP_OPTION_CLIENT_CERT_CONTEXT.

Následující příklad kódu ukazuje, jak otevřít úložiště certifikátů a vyhledat certifikát na základě názvu subjektu po vrácení ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED chyby.

  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.
      }
    }
  }

Před opětovným odesláním požadavku, který obsahuje klientský certifikát, můžete určit, jestli je podporovaná úroveň šifrování pro vaši aplikaci přijatelná. Zavolejte WinHttpQueryOption a zadejte příznak WINHTTP_OPTION_SECURITY_FLAGS k určení úrovně použitého šifrování.

Načtení seznamu vystavitelů pro ověřování klienta SSL

Když klientská aplikace WinHttp odešle požadavek na zabezpečený server HTTP, který vyžaduje ověření klienta SSL, winHttp vrátí ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED, pokud aplikace nezadá klientský certifikát. Pro počítače se systémem Windows Server 2008 a Windows Vista umožňuje winHttp aplikaci načíst seznam vystavitelů certifikátů zadaný serverem v ověřovací výzvě. Seznam vystavitelů určuje seznam certifikačních autorit (CA), které jsou serverem autorizované k vydávání klientských certifikátů. Aplikace filtruje seznam vystavitelů, aby získala požadovaný certifikát.

Klientská aplikace WinHttp načte seznam vystavitelů, když WinHttpSendRequestnebo WinHttpReceiveResponse vrátí ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED. Když se tato chyba vrátí, aplikace volá WinHttpQueryOption s možností WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST. Parametr lpBuffer musí být dostatečně velký, aby obsahoval ukazatel na SecPkgContext_IssuerListInfoEx strukturu. Následující příklad kódu ukazuje, jak načíst seznam vystavitelů.

#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.
  }
}

Informace ve struktuře SecPkgContext_IssuerListInfoEx, cIssuers a aIssuers, lze použít k vyhledání certifikátu, jak je znázorněno v příkladu kódu níže. Další informace naleznete v tématu 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;
}

Volitelné klientské certifikáty SSL

Od systému Windows Server 2008 a Windows Vista rozhraní API WinHttp podporuje volitelné klientské certifikáty. Když server požaduje klientský certifikát, WinHttpSendRequestnebo WinHttpRecieveResponse vrátí chybu ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED. Pokud server požádá o certifikát, ale nevyžaduje ho, může tuto možnost zadat, aby určila, že certifikát nemá. Server může zvolit jiné schéma ověřování nebo povolit anonymní přístup k serveru. Aplikace určuje WINHTTP_NO_CLIENT_CERT_CONTEXT makro v parametru lpBufferWinHttpSetOp tion, jak je znázorněno v následujícím příkladu kódu.

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

Pokud je nastavená WINHTTP_NO_CLIENT_CERT_CONTEXT a server stále vyžaduje klientský certifikát, může odeslat stavový kód HTTP 403. Další informace najdete v WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST možnosti.

WinHttpRequest – objekt

Pomocí metody SetClientCertificate objektu WinHttpRequest vyberte klientské certifikáty, které se mají odeslat na server s požadavkem. Vyberte certifikát zadáním řetězce výběru certifikátu pomocí metody SetClientCertificate. Řetězec výběru certifikátu se skládá z umístění certifikátu, úložiště certifikátůa názvu subjektu odděleného zpětnými lomítky. Následující tabulka uvádí komponenty pro tento řetězec výběru.

Komponenta Popis Možné hodnoty
Umístění Určuje klíč registru, pod kterým jsou certifikáty uloženy. Možné hodnoty jsou "LOCAL_MACHINE" označující, žeúložiště certifikátůje pod HKEY_LOCAL_MACHINE
a "CURRENT_USER" označující, že úložiště certifikátů je pod zosobněnýmHKEY_CURRENT_USER.
U této komponenty se rozlišují malá a velká písmena.
úložiště certifikátů Označuje název úložiště certifikátů, který obsahuje příslušný certifikát. Typické úložiště certifikátů jsou MY, Root a TrustedPeople. U této komponenty se rozlišují malá a velká písmena.
Název subjektu Identifikuje certifikát v zadaném úložišti certifikátů . Je vybrán první certifikát, který obsahuje řetězec zadaný pro tuto komponentu. Název subjektu může být libovolný řetězec. Prázdný řetězec označuje, že se má použít první certifikát v úložišti certifikátů . Tato komponenta nerozlišuje malá a velká písmena.

Název a umístění úložiště certifikátů jsou volitelné součásti. Pokud však zadáte úložiště certifikátů, musíte také zadat umístění tohoto úložiště certifikátů. Výchozí umístění je CURRENT_USER a výchozí úložiště certifikátů je MY.

Následující příklad kódu ukazuje, jak určit, že certifikát s předmětem "My Middle-Tier Certificate" by měl být vybrán z "Osobní" úložiště certifikátů v registru v HKEY_LOCAL_MACHINE.

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

Poznámka

V některých jazycích je zpětné lomítko řídicí znak. Nezapomeňte upravit řetězec výběru certifikátu tak, aby byl pro tento účet. Například v Microsoft JScriptu použijte dvě sousední zpětná lomítka místo jednoho.

Pokud nezadáte certifikát a server HTTPS vyžaduje klientský certifikát, winHTTP vybere první certifikát ve výchozím úložišti certifikátů. Pokud neexistují žádné certifikáty, dojde k chybě. Pokud certifikát není přijat, server vrátí stavový kód 403, který indikuje, že požadavek nelze splnit. Pak můžete zvolit vhodnější certifikát s SetClientCertificate a žádost znovu odeslat.