SSL с WinHTTP - PullRequest
       25

SSL с WinHTTP

3 голосов
/ 19 сентября 2011

Я создал простой веб-сервер с Winhttp, который имеет только один клиент, веб-сайт.Он работал отлично, пока я не включил SSL.Я не получаю никаких ошибок, и все, кажется, работает, но веб-сайт получает код ошибки 104, когда он пытается подключиться, и я не вижу никакой активности на сервере.Сайт был создан профессионалами, поэтому ошибка, скорее всего, будет в моем коде.Поскольку я ничего не знаю о веб-программировании, я создал тестовый клиент на c ++ для устранения проблемы.Без SSL он может подключиться к серверу.Но когда я пытаюсь установить сертификат клиента, он терпит неудачу.Так что теперь у меня есть две проблемы.

Вот соответствующая часть кода сервера:

ULONG ret = NO_ERROR;
HRESULT hr = S_OK;
HTTPAPI_VERSION ver = HTTPAPI_VERSION_1;

ret = HttpInitialize(ver,HTTP_INITIALIZE_SERVER|HTTP_INITIALIZE_CONFIG,NULL);
if(ret!=NO_ERROR)
    return;

SOCKADDR_IN sa;
HTTP_SERVICE_CONFIG_SSL_SET scssl;
memset(&sa,0,sizeof(sa));
sa.sin_addr.S_un.S_addr = 0;
sa.sin_family = AF_INET;
sa.sin_port = 443;
scssl.KeyDesc.pIpPort = (SOCKADDR*)&sa;
scssl.ParamDesc.AppId = AppID;
scssl.ParamDesc.DefaultCertCheckMode = 0;
scssl.ParamDesc.DefaultFlags = HTTP_SERVICE_CONFIG_SSL_FLAG_NEGOTIATE_CLIENT_CERT;
scssl.ParamDesc.DefaultRevocationFreshnessTime = 0;
scssl.ParamDesc.DefaultRevocationUrlRetrievalTimeout = 10000;
scssl.ParamDesc.pSslCertStoreName = L"MY";
scssl.ParamDesc.pDefaultSslCtlIdentifier = NULL;
scssl.ParamDesc.pDefaultSslCtlStoreName = NULL;
scssl.ParamDesc.pSslHash = (void*)ServerCertHash;
scssl.ParamDesc.SslHashLength = ARRAYSIZE(ServerCertHash);
ret = HttpSetServiceConfiguration(NULL,HttpServiceConfigSSLCertInfo,&scssl,sizeof(scssl),NULL);
if(ret!=NO_ERROR)
    return;

ret = HttpCreateHttpHandle(&m_RequestQueue,0);
if(ret!=NO_ERROR)
    return;

wcsncpy(m_Url,L"https://+:443/WebShop/",256);
ret = HttpAddUrl(m_RequestQueue,m_Url,NULL);
if(ret!=NO_ERROR)
    return;

В документации ничего не говорится о том, что происходит, когда pDefaultSslCtlIdentifier имеет значение NULL, но я предполагаю, что это означаетсервер принимает любой доверенный сертификат.Я попытался установить тот, который мне нужен, но затем произошел сбой вызова HttpSetServiceConfiguration.

На стороне клиента WinHttpSetOption завершился неудачно, и GetLastError () вернул 6. Иногда я вижу ошибки нарушения доступа в выходных данных отладки.Указанные адреса близки к значению запроса.Код клиента:

char* types[] = {"application/soap+xml",NULL};
hint = InternetOpen("WebTestClient",INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
if(hint!=NULL)
{
    InternetSetStatusCallback(hint,&HTTPStatusCallbackFunc);
    hsession = InternetConnect(hint,"127.0.0.1",443,NULL,NULL,3,0,NULL);
    if(hsession!=NULL)
    {
        hreqest = HttpOpenRequest(hsession,"GET","/WebShop/","HTTP/1.1",NULL,(LPCSTR*)types,INTERNET_FLAG_SECURE|INTERNET_FLAG_IGNORE_CERT_CN_INVALID,NULL);
        if(hreqest!=NULL)
        {
            if(SetupSSL(hreqest))
            {
                if(HttpSendRequest(hreqest,NULL,0,inbuf,inlen))
                {
                    ...
                }
            }
            InternetCloseHandle(hreqest);
        }
        InternetCloseHandle(hsession);
    }
    InternetCloseHandle(hint);
}

bool SetupSSL(HINTERNET request)
{
    HCERTSTORE store = CertOpenSystemStore(NULL,"MY");
    DWORD ret = 0;
    bool ok = false;

    if(store==NULL)
        return false;
    PCCERT_CONTEXT context = CertFindCertificateInStore(store,X509_ASN_ENCODING,0,CERT_FIND_SUBJECT_STR,L"WebClient",NULL);
    if(context!=NULL)
    {
        // this fails
        ok = WinHttpSetOption(request,WINHTTP_OPTION_CLIENT_CERT_CONTEXT,(LPVOID)context,sizeof(CERT_CONTEXT))==TRUE;
        if(!ok)
            ret = GetLastError();  // returns 6
        CertFreeCertificateContext(context);
    }
    CertCloseStore(store,0);
    return ok;
};

Я создал сертификаты с помощью этого сценария:

makecert -r -pe -n "CN=BeeLSoft" -ss CA -sr LocalMachine -a sha1 -sky signature -cy authority -sv Root.pvk Root.cer

makecert -pe -n "CN=beelsoft.dyndns.org" -a sha1 -sky exchange -eku 1.3.6.1.5.5.7.3.1 -ic Root.cer -iv Root.pvk -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 -sv Server.pvk Server.cer
pvk2pfx -pvk Server.pvk -spc Server.cer -pfx Server.pfx

makecert -pe -n "CN=WebClient" -a sha1 -sky exchange -eku 1.3.6.1.5.5.7.3.1 -ic Root.cer -iv Root.pvk -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 -sv Client.pvk Client.cer
pvk2pfx -pvk Client.pvk -spc Client.cer -pfx Client.pfx

Я не понимаю ничего из этого, но он должен создавать сертификаты, подходящие для SSL.

Если есть хороший урок на эту тему, это было бы неплохо.То, что я нашел до сих пор, было достаточно для написания кода выше.

...