微软C ++ HTTP服务器API(httpapi.lib)HttpReceiveClientCer

2019-11-01 13:38发布

微软C ++ HTTP服务器API(httpapi.lib)用于HTTPS

我想创建微软HTTP服务器API中的C ++ HTTPS服务器http://msdn.microsoft.com/en-us/library/windows/desktop/aa364510(v=vs.85).aspx

我以下被下面提到这些步骤

http://www.codeproject.com/Articles/24027/SSL-with-Self-hosted-WCF-Service?msg=3930582#xx3930582xx

  1. makecert -sv SignRoot.pvk -cy权威-r signroot.cer -a -n SHA1 “CN =开发证书颁发机构” -SS我-SR LOCALMACHINE

成功

  1. makecert -IV SignRoot.pvk -IC signroot.cer -cy结束-pe -n CN = “localhost” 的-eku 1.3.6.1.5.5.7.3.1 -ss我-sr LOCALMACHINE -sky交换-SP“微软RSA SChannel加密提供” -sy 12

成功

  1. 配置HTTPS根据http://msdn.microsoft.com/en-us/library/ms733791.aspx

netsh的HTTP添加的sslcert ipport = 127.0.0.1:4443 CERTHASH = 9eb4919ea794d783a348a0469474c4cf45d65fb3的appid = {F8C3E640-D91E-11D2-9944-8F3C3FD5C32F} sslctlstorename = MY clientcertnegotiation =使能

SSL证书添加成功

结果:

 IP:port : 127.0.0.1:4443 Certificate Hash : 9eb4919ea794d783a348a0469474c4cf45d65fb3 Application ID : {f8c3e640-d91e-11d2-9944-8f3c3fd5c32f} Certificate Store Name : (null) Verify Client Certificate Revocation : Enabled Verify Revocation Using Cached Client Certificate Only : Disabled Usage Check : Enabled Revocation Freshness Time : 0 URL Retrieval Timeout : 0 Ctl Identifier : (null) Ctl Store Name : MY DS Mapper Usage : Disabled Negotiate Client Certificate : Enabled 

这是完整的示例代码

#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <cstdlib>
#include <conio.h>
#include <iostream> 
#include <tchar.h>

using namespace std;

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#endif

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <http.h>
#pragma comment(lib, "httpapi.lib")

//
// Macros.
//
#define INITIALIZE_HTTP_RESPONSE( resp, status, reason )    \
do                                                      \
{                                                       \
    RtlZeroMemory( (resp), sizeof(*(resp)) );           \
    (resp)->StatusCode = (status);                      \
    (resp)->pReason = (reason);                         \
    (resp)->ReasonLength = (USHORT) strlen(reason);     \
} while (FALSE)

#define ADD_KNOWN_HEADER(Response, HeaderId, RawValue)               \
do                                                               \
{                                                                \
    (Response).Headers.KnownHeaders[(HeaderId)].pRawValue =      \
                                                      (RawValue);\
    (Response).Headers.KnownHeaders[(HeaderId)].RawValueLength = \
        (USHORT) strlen(RawValue);                               \
} while(FALSE)

#define ALLOC_MEM(cb) HeapAlloc(GetProcessHeap(), 0, (cb))

#define FREE_MEM(ptr) HeapFree(GetProcessHeap(), 0, (ptr))

//
// Prototypes.
//
DWORD DoReceiveRequests(HANDLE hReqQueue);

DWORD SendHttpResponse(HANDLE hReqQueue, PHTTP_REQUEST pRequest, USHORT StatusCode, PSTR pReason, PSTR pEntity);

DWORD SendHttpPostResponse(HANDLE hReqQueue, PHTTP_REQUEST pRequest);

/*******************************************************************/

int __cdecl wmain(int argc, wchar_t * argv[])
{   
    HTTPAPI_VERSION HttpApiVersion = HTTPAPI_VERSION_1;

    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 0;


    ULONG           retCode;
    HANDLE          hReqQueue      = NULL;  //request queue handle
    int             UrlAdded       = 0;

    retCode = HttpInitialize( 
                HttpApiVersion,
                HTTP_INITIALIZE_SERVER ,
                NULL                     
                );

    if (retCode == NO_ERROR)
    {  
        retCode = HttpCreateHttpHandle(&hReqQueue,// Req Queue
                    0                  // Reserved
                    );   
        if (retCode == NO_ERROR)
        {    
             retCode = HttpAddUrl(
                            hReqQueue,    // Req Queue
                            L"https://127.0.0.1:4443/",// Fully qualified URL
                            NULL          // Reserved
                            );
            if (retCode == NO_ERROR)
            {            
              DoReceiveRequests(hReqQueue);
            }      
        }
    }            
    return retCode;
}//main


/*******************************************************************++

Routine Description:
The function to receive a request. This function calls the  
corresponding function to handle the response.

Arguments:
hReqQueue - Handle to the request queue

Return Value:
Success/Failure.

--*******************************************************************/
DWORD DoReceiveRequests(IN HANDLE hReqQueue)
{
ULONG              result;
HTTP_REQUEST_ID    requestId;
DWORD              bytesRead;
PHTTP_REQUEST      pRequest;
PCHAR              pRequestBuffer;
ULONG              RequestBufferLength;

//
// Allocate a 2 KB buffer. This size should work for most 
// requests. The buffer size can be increased if required. Space
// is also required for an HTTP_REQUEST structure.
//
RequestBufferLength = sizeof(HTTP_REQUEST) + 2048;
pRequestBuffer      = (PCHAR) ALLOC_MEM( RequestBufferLength );

if (pRequestBuffer == NULL)
{
    return ERROR_NOT_ENOUGH_MEMORY;
}

pRequest = (PHTTP_REQUEST)pRequestBuffer;

//
// Wait for a new request. This is indicated by a NULL 
// request ID.
//

HTTP_SET_NULL_ID( &requestId );

for(;;)
{
    RtlZeroMemory(pRequest, RequestBufferLength);

    result = HttpReceiveHttpRequest(
                hReqQueue,          // Req Queue
                requestId,          // Req ID
                0,                  // Flags
                pRequest,           // HTTP request buffer
                RequestBufferLength,// req buffer length
                &bytesRead,         // bytes received
                NULL                // LPOVERLAPPED
                );
          if(NO_ERROR == result)
    {

        DWORD answer = 0;
        HTTP_SSL_CLIENT_CERT_INFO sslClientCertInfo;
        ULONG bytesReceived;
        answer = HttpReceiveClientCertificate(hReqQueue, pRequest->ConnectionId, 0,
                &sslClientCertInfo, sizeof( HTTP_SSL_CLIENT_CERT_INFO ), &bytesReceived, NULL );


        if (answer != NO_ERROR)
        {
          result = SendHttpResponse(hReqQueue, pRequest, 401, "Unauthorized request", "Unauthorized request");
        }
        else
        {
          result = SendHttpResponse(hReqQueue, pRequest, 200, "OK", "OK");
        }

        if (result != NO_ERROR)
        {
          break; //if failed to send response, stop listening for further incoming requests
        }
        //
        // Reset the Request ID to handle the next request.
        //
        HTTP_SET_NULL_ID( &requestId );
    }
    else
    {
        break;
    }

}
if(pRequestBuffer)
{
    FREE_MEM( pRequestBuffer );
}

return result;
}



/*******************************************************************++

Routine Description:
The routine sends a HTTP response

Arguments:
hReqQueue     - Handle to the request queue
pRequest      - The parsed HTTP request
StatusCode    - Response Status Code
pReason       - Response reason phrase
pEntityString - Response entity body

Return Value:
Success/Failure.
--*******************************************************************/

DWORD SendHttpResponse(
IN HANDLE        hReqQueue,
IN PHTTP_REQUEST pRequest,
IN USHORT        StatusCode,
IN PSTR          pReason,
IN PSTR          pEntityString
)
{
HTTP_RESPONSE   response;
HTTP_DATA_CHUNK dataChunk;
DWORD           result;
DWORD           bytesSent;


INITIALIZE_HTTP_RESPONSE(&response, StatusCode, pReason);
ADD_KNOWN_HEADER(response, HttpHeaderContentType, "text/html");


if(pEntityString)
{
    // 
    // Add an entity chunk.
    //
    dataChunk.DataChunkType           = HttpDataChunkFromMemory;
    dataChunk.FromMemory.pBuffer      = pEntityString;
    dataChunk.FromMemory.BufferLength = 
                                   (ULONG) strlen(pEntityString);

    response.EntityChunkCount         = 1;
    response.pEntityChunks            = &dataChunk;
}

result = HttpSendHttpResponse(
                hReqQueue,           // ReqQueueHandle
                pRequest->RequestId, // Request ID
                0,                   // Flags
                &response,           // HTTP response
                NULL,                // pReserved1
                &bytesSent,          // bytes sent  (OPTIONAL)
                NULL,                // pReserved2  (must be NULL)
                0,                   // Reserved3   (must be 0)
                NULL,                // LPOVERLAPPED(OPTIONAL)
                NULL                 // pReserved4  (must be NULL)
                ); 

if(result != NO_ERROR)
{
    wprintf(L"HttpSendHttpResponse failed with %lu \n", result);
}

return result;
}

我的问题是HttpReceiveClientCertificate返回1168 ERROR_NOT_FOUND

该功能无法找到客户端证书。 谁也不能保证这个客户端证书将可即使HTTPCFG配置为f / 2 [协商客户端证书。

http://msdn.microsoft.com/en-us/library/windows/desktop/aa364494(v=vs.85).aspx

谢谢

Answer 1:

我不知道为什么你会得到错误1168.但如果你真正的问题是:如何获取客户端证书,那么答案是:有一个在您HTTP_REQUEST副本:

ULONG sz = pRequest->pSslInfo->pClientCertInfo->CertEncodedSize;
unsigned char *ptr = pRequest->pSslInfo->pClientCertInfo->pCertEncoded;
const CERT_CONTEXT * cp = CertCreateCertificateContext(
                PKCS_7_ASN_ENCODING|X509_ASN_ENCODING,ptr,sz);
const CERT_INFO *ci = cp->pCertInfo;
char ibuf[500], sbuf[500];
CertNameToStr(X509_ASN_ENCODING,(PCERT_NAME_BLOB)&ci->Issuer,CERT_SIMPLE_NAME_STR,ibuf,sizeof(ibuf));
CertNameToStr(X509_ASN_ENCODING,(PCERT_NAME_BLOB)&ci->Subject,CERT_SIMPLE_NAME_STR,sbuf,sizeof(sbuf));
//these are FileTime instances...
//ci->NotBefore
//ci->NotAfter
CertFreeCertificateContext(cp);


文章来源: Microsoft C++ HTTP Server API (httpapi.lib) HttpReceiveClientCertificate function Return ERROR_NOT_FOUND ( 1168 )
标签: c++ ssl https