Bagikan melalui


SSL di WinHTTP

Microsoft Windows HTTP Services (WinHTTP) mendukung transaksi Secure Sockets Layer (SSL) termasuk sertifikat klien. Topik ini menjelaskan konsep yang terlibat dalam transaksi SSL dan bagaimana mereka ditangani menggunakan WinHTTP.

Secure Sockets Layer

SSL adalah standar yang ditetapkan untuk memastikan transaksi HTTP yang aman. SSL menyediakan mekanisme untuk melakukan enkripsi hingga 128-bit pada semua transaksi antara klien dan server. Ini memungkinkan klien untuk memverifikasi bahwa server milik entitas tepercaya melalui penggunaan sertifikat server. Ini juga memungkinkan server untuk mengonfirmasi identitas klien dengan sertifikat klien.

Masing-masing masalah ini adalah enkripsi, identitas server, dan identitas klien dinegosiasikan dalam jabat tangan SSL yang terjadi ketika klien pertama kali meminta sumber daya dari server Secure Hypertext Transfer Protocol (HTTPS). Pada dasarnya, klien dan server masing-masing menyajikan daftar pengaturan yang diperlukan dan disukai. Jika serangkaian persyaratan umum dapat disepakati dan dipenuhi, koneksi SSL dibuat.

WinHTTP menyediakan antarmuka tingkat tinggi untuk menggunakan SSL. Sementara detail jabat tangan dan transaksi SSL ditangani secara internal, WinHTTP memungkinkan Anda untuk mengambil tingkat enkripsi, menentukan protokol keamanan, dan berinteraksi dengan sertifikat server dan klien. Bagian berikut ini menyediakan detail tentang membuat aplikasi berbasis WinHTTP yang memilih versi protokol SSL, memeriksa sertifikat server, dan memilih sertifikat klien untuk dikirim ke server HTTPS.

Sertifikat Server

Sertifikat server dikirim dari server ke klien sehingga klien dapat memperoleh kunci publik untuk server dan memastikan bahwa server telah diverifikasi oleh otoritas sertifikasi. Sertifikat dapat berisi berbagai jenis data. Misalnya, sertifikat X.509 mencakup format sertifikat, nomor seri sertifikat, algoritma yang digunakan untuk menandatangani sertifikat, nama otoritas sertifikasi (CA) yang mengeluarkan sertifikat, nama dan kunci publik entitas yang meminta sertifikat, dan tanda tangan CA.

Saat menggunakan antarmuka pemrograman aplikasi WinHTTP (API), Anda bisa mengambil sertifikat server dengan memanggil WinHttpQueryOption dan menentukan bendera WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT . Sertifikat server dikembalikan dalam struktur WINHTTP_CERTIFICATE_INFO . Jika Anda lebih suka mengambil konteks sertifikat, tentukan bendera WINHTTP_OPTION_SERVER_CERT_CONTEXT sebagai gantinya.

Jika sertifikat server berisi kesalahan, detail tentang kesalahan dapat diperoleh dalam fungsi panggilan balik status. Pemberitahuan WINHTTP_CALLBACK_STATUS_SECURE_FAILURE menunjukkan kesalahan dengan sertifikat server. Parameter lpvStatusInformation berisi satu atau beberapa bendera kesalahan terperinci. Lihat WINHTTP_STATUS_CALLBACK untuk informasi selengkapnya.

Sertifikat Klien

Selama jabat tangan SSL, server mungkin memerlukan autentikasi. Klien diautentikasi dengan menyediakan sertifikat klien yang valid ke server. WinHTTP memungkinkan Anda memilih dan mengirim sertifikat dari penyimpanan sertifikat lokal. Bagian berikut ini menjelaskan proses yang menyediakan sertifikat klien saat menggunakan API WinHTTP atau objek WinHttpRequest .

WinHTTP API

WinHttpSendRequest dan WinHttpReceiveResponse bisa gagal menunjukkan bahwa permintaan tidak berhasil karena server HTTPS memerlukan autentikasi. Dalam kasus ini, panggil GetLastError untuk mengembalikan ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED. Setelah menerima kesalahan ini, gunakan fungsi CryptoAPI yang sesuai untuk menemukan sertifikat yang sesuai. Tunjukkan bahwa sertifikat ini harus dikirim dengan permintaan berikutnya dengan memanggil WinHttpSetOption dengan bendera WINHTTP_OPTION_CLIENT_CERT_CONTEXT .

Contoh kode berikut menunjukkan cara membuka penyimpanan sertifikat dan menemukan sertifikat berdasarkan nama subjek setelah kesalahan ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED dikembalikan.

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

Sebelum mengirim ulang permintaan yang berisi sertifikat klien, Anda dapat menentukan apakah tingkat enkripsi yang didukung dapat diterima untuk aplikasi Anda. Panggil WinHttpQueryOption dan tentukan bendera WINHTTP_OPTION_SECURITY_FLAGS untuk menentukan tingkat enkripsi yang digunakan.

Pengambilan Daftar Penerbit untuk Autentikasi Klien SSL

Saat aplikasi klien WinHttp mengirim permintaan ke server HTTP aman yang memerlukan autentikasi klien SSL, WinHttp mengembalikan ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED jika aplikasi belum menyediakan sertifikat klien. Untuk komputer yang berjalan di Windows Server 2008 dan Windows Vista, WinHttp memungkinkan aplikasi untuk mengambil daftar penerbit sertifikat yang disediakan oleh server dalam tantangan autentikasi. Daftar Penerbit menentukan daftar Otoritas Sertifikat (CA) yang diotorisasi oleh server untuk menerbitkan sertifikat klien. Aplikasi memfilter daftar penerbit untuk mendapatkan sertifikat yang diperlukan.

Aplikasi klien WinHttp mengambil daftar pengeluar sertifikat saat WinHttpSendRequest, atau WinHttpReceiveResponse mengembalikan ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED. Ketika kesalahan ini dikembalikan, aplikasi memanggil WinHttpQueryOption dengan opsi WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST . Parameter lpBuffer harus cukup besar untuk berisi penunjuk ke struktur SecPkgContext_IssuerListInfoEx . Contoh kode berikut menunjukkan cara mengambil daftar pengeluar sertifikat.

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

Informasi dalam struktur SecPkgContext_IssuerListInfoEx , cIssuers , dan aIssuers, dapat digunakan untuk mencari sertifikat seperti yang ditunjukkan pada contoh kode di bawah ini. Untuk informasi selengkapnya, lihat 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;
}

Sertifikat SSL Klien Opsional

Mulai dari Windows Server 2008 dan Windows Vista, WinHttp API mendukung sertifikat klien opsional. Saat server meminta sertifikat klien, WinHttpSendRequest, atau WinHttpRecieveResponse mengembalikan kesalahan ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED . Jika server meminta sertifikat, tetapi tidak memerlukannya, aplikasi dapat menentukan opsi ini untuk menunjukkan bahwa server tidak memiliki sertifikat. Server dapat memilih skema autentikasi lain atau mengizinkan akses anonim ke server. Aplikasi menentukan makro WINHTTP_NO_CLIENT_CERT_CONTEXT dalam parameter lpBufferWinHttpSetOption seperti yang diperlihatkan dalam contoh kode berikut.

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

Jika WINHTTP_NO_CLIENT_CERT_CONTEXT diatur, dan server masih memerlukan sertifikat klien, server mungkin mengirim kode status HTTP 403. Untuk informasi selengkapnya, lihat opsi WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST .

Objek WinHttpRequest

Gunakan metode SetClientCertificate dari objek WinHttpRequest untuk memilih sertifikat klien untuk dikirim ke server dengan permintaan. Pilih sertifikat dengan menentukan string pilihan sertifikat dengan metode SetClientCertificate . String pemilihan sertifikat terdiri dari lokasi sertifikat, penyimpanan sertifikat, dan nama subjek yang dibatasi oleh garis miring terbelakang. Tabel berikut mencantumkan komponen untuk string pilihan ini.

Komponen Deskripsi Nilai yang memungkinkan
Lokasi Menentukan kunci registri tempat sertifikat disimpan. Nilai yang mungkin adalah "LOCAL_MACHINE" untuk menunjukkan bahwa penyimpanan sertifikat berada di bawah HKEY_LOCAL_MACHINE
dan "CURRENT_USER" untuk menunjukkan bahwa penyimpanan sertifikat berada di bawah HKEY_CURRENT_USER yang tidak ditiru.
Komponen ini peka huruf besar/kecil.
Penyimpanan sertifikat Menunjukkan nama penyimpanan sertifikat yang berisi sertifikat yang relevan. Penyimpanan sertifikat umum adalah "MY", "Root", dan "TrustedPeople". Komponen ini peka huruf besar/kecil.
Nama Subjek Mengidentifikasi sertifikat dalam penyimpanan sertifikat yang ditentukan. Sertifikat pertama yang berisi string yang ditentukan untuk komponen ini dipilih. Nama subjek dapat berupa string apa pun. String kosong menunjukkan bahwa sertifikat pertama di penyimpanan sertifikat harus digunakan. Komponen ini tidak peka huruf besar/kecil.

Nama dan lokasi penyimpanan sertifikat adalah komponen opsional. Namun, jika Anda menentukan penyimpanan sertifikat, Anda juga harus menentukan lokasi penyimpanan sertifikat tersebut. Lokasi default adalah CURRENT_USER dan penyimpanan sertifikat default adalah "MY".

Contoh kode berikut menunjukkan cara menentukan bahwa sertifikat dengan subjek "Sertifikat Middle-Tier Saya" harus dipilih dari penyimpanan sertifikat "Pribadi" di registri di bawah HKEY_LOCAL_MACHINE.

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

Catatan

Dalam beberapa bahasa, garis miring terbelakang adalah karakter escape. Ingatlah untuk mengubah string pemilihan sertifikat untuk mempertanyakan hal ini. Misalnya, di Microsoft JScript, gunakan dua garis miring terbalik yang bersebelahan, bukan satu.

Jika Anda tidak menentukan sertifikat dan server HTTPS memerlukan sertifikat klien, WinHTTP memilih sertifikat pertama di penyimpanan sertifikat default. Jika tidak ada sertifikat, kesalahan akan muncul. Jika sertifikat tidak diterima, server mengembalikan kode status 403 untuk menunjukkan bahwa permintaan tidak dapat dipenuhi. Anda kemudian dapat memilih sertifikat yang lebih sesuai dengan SetClientCertificate dan mengirim ulang permintaan.