Microsoft C++ HTTP Server API (httpapi.lib) for HTTPS
I want create https server in c++ by Microsoft http server api http://msdn.microsoft.com/en-us/library/windows/desktop/aa364510(v=vs.85).aspx
i following these steps that are mentioned below
http://www.codeproject.com/Articles/24027/SSL-with-Self-hosted-WCF-Service?msg=3930582#xx3930582xx
- makecert -sv SignRoot.pvk -cy authority -r signroot.cer -a sha1 -n "CN=Dev Certification Authority" -ss my -sr localmachine
Succeeded
- makecert -iv SignRoot.pvk -ic signroot.cer -cy end -pe -n CN="localhost" -eku 1.3.6.1.5.5.7.3.1 -ss my -sr localmachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12
Succeeded
- config https according http://msdn.microsoft.com/en-us/library/ms733791.aspx
netsh http add sslcert ipport=127.0.0.1:4443 certhash=9eb4919ea794d783a348a0469474c4cf45d65fb3 appid={F8C3E640-D91E-11D2-9944-8F3C3FD5C32F} sslctlstorename=MY clientcertnegotiation=enable
SSL Certificate successfully added
Result :
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
This is complete sample code
#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;
}
My problem is HttpReceiveClientCertificate Return 1168 ERROR_NOT_FOUND
The function cannot find the client certificate. There is no guarantee that the client certificate will be available even if HTTPCFG is configured with /f 2 [Negotiate Client Cert].
http://msdn.microsoft.com/en-us/library/windows/desktop/aa364494(v=vs.85).aspx
thanks