Аутентификация клиента (сертификат + закрытый ключ) с использованием WinInet - PullRequest
2 голосов
/ 22 марта 2019
  • Это эволюция моего предыдущего вопроса , который касался WinHttp.
  • Я надеюсь, что это правильный способ сделать это ...

Я пытаюсь в https связаться с сервером, используя WinInet (из Win32 API).

Вот очень минималистский код:

HINTERNET ses = InternetOpen("test",INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0) ;
HINTERNET con = InternetOpenUrl( ses,"https://stackoverflow.com",NULL,0,0,0 ) ;
DWORD read ;
char  str [3000] ;
InternetReadFile( con,reinterpret_cast<void*>( str ),sizeof( str )-1,&read ) ;
str[read] = 0 ;
cout << &str[0] ;
InternetCloseHandle( con ) ;
InternetCloseHandle( ses ) ;

Пока я общаюсь с "классическим" https-сервером, таким как stackoverflow.com, все идет хорошо. Проблема заключается в том, что я пытаюсь связаться с сервером, который запрашивает аутентификацию клиента.

У меня есть 3 файла .pem: сертификат и закрытый ключ для моего клиента, а также корневой сертификат, который аутентифицирует мой клиентский сертификат (т. Е. Цепочка сертификатов длиной 2).

Для информации, я могу подключить свой сервер с помощью командной строки cULR:

curl https://my.server --cert Client_cert.pem --key Client_key.pem --cacert Root_cert.pem

Это доказательство того, что это возможно!

Читая документацию по WinInet, я обнаружил страницу с именем " Обработка аутентификации ", но все дело в имени пользователя: пароле, а в сертификате ничего нет.

Я обнаружил, что мне нужно использовать библиотеку Crypt32: мне нужно создать контекст сертификата с CertCreateCertificateContext, затем вставить его в хранилище сертификатов, а затем использовать это хранилище для моего соединения ... Ну, я должен признать, что я был бы рад найти хороший учебник или пример кода! Кстати, у меня нет ни малейшего понятия о том, как вставить свой закрытый ключ в эти вещи ...

Заранее спасибо!

1 Ответ

0 голосов
/ 22 марта 2019

Вы должны передать свой сертификат в WinInet, используя INTERNET_OPTION_CLIENT_CERT_CONTEXT с вызовом InternetSetOption () :

INTERNET_OPTION_CLIENT_CERT_CONTEXT

1009

Этот флаг не поддерживается InternetQueryOption.Параметр lpBuffer должен быть указателем на структуру CERT_CONTEXT, а не указателем на указатель CERT_CONTEXT.Если приложение получает ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED, оно должно вызвать InternetErrorDlg или использовать InternetSetOption для предоставления сертификата, прежде чем повторять запрос.Затем вызывается CertDuplicateCertificateContext, чтобы передаваемый контекст сертификата мог самостоятельно освобождаться приложением.

Так, например:

InternetSetOption(hI,INTERNET_OPTION_CLIENT_CERT_CONTEXT,(void*)cert,sizeof(CERT_CONTEXT));

Кстати, вызовы curl не являются хорошими примерами, потому чтоcurl использует libcurl , который использует OpenSSL.

...