2025-11-28 00:35:46 +09:00

548 lines
15 KiB
C

/*++
Copyright (c) 2002 - 2002 Microsoft Corporation. All Rights Reserved.
THIS CODE AND INFORMATION IS PROVIDED "AS-IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
THIS CODE IS NOT SUPPORTED BY MICROSOFT.
--*/
#include "precomp.h"
//#pragma prefast(disable:24002)
#pragma hdrstop
//
// Macros
//
#define MAX_HASH 20
#define CONVERT_WCHAR(ch, n) \
if(iswdigit((ch))) \
{ \
(n) = (UCHAR)((ch) - L'0'); \
} \
else if(iswxdigit((ch))) \
{ \
(n) = (UCHAR) ((ch) + 10 - (iswlower((ch))?L'a':L'A')); \
} \
else \
{ \
wprintf(L"INVALID HASH \n"); \
return ERROR_INVALID_PARAMETER; \
}
//
// Private functions.
//
/***************************************************************************++
Routine Description:
Prints a record in the SSL store.
Arguments:
pOutput - A pointer to HTTP_SERVICE_CONFIG_SSL_SET
Return Value:
None.
--***************************************************************************/
void
PrintSslRecord(
__in PHTTP_SERVICE_CONFIG_SSL_SET pSsl
)
{
DWORD i;
WCHAR IpAddr[INET6_ADDRSTRLEN];
DWORD dwIpAddrLen = INET6_ADDRSTRLEN;
DWORD dwSockAddrLength;
PUCHAR pStr;
PSOCKADDR_IN pSockAddrIn;
DWORD Status;
// Convert address to string.
//
pSockAddrIn = (PSOCKADDR_IN) pSsl->KeyDesc.pIpPort;
if(pSockAddrIn->sin_family == AF_INET)
{
dwSockAddrLength = sizeof(SOCKADDR_IN);
}
else if(pSockAddrIn->sin_family == AF_INET6)
{
dwSockAddrLength = sizeof(SOCKADDR_IN6);
}
else
{
// Status = ERROR_REGISTRY_CORRUPT;
return;
}
Status = WSAAddressToString(pSsl->KeyDesc.pIpPort,
dwSockAddrLength,
NULL,
IpAddr,
&dwIpAddrLen
);
if(NO_ERROR != Status)
{
return;
}
// Print the Key.
wprintf(L"IP Address is %s \n", IpAddr);
wprintf(L"SSL Hash is: \n");
pStr = (PUCHAR) pSsl->ParamDesc.pSslHash;
for(i=0; i<pSsl->ParamDesc.SslHashLength; i++)
{
wprintf(L"%S",pStr[i]);
}
wprintf(L"\n");
wprintf(L"SSL CertStore Name is %s\n", pSsl->ParamDesc.pSslCertStoreName);
wprintf(L"SSL CertCheck Mode is %d\n", pSsl->ParamDesc.DefaultCertCheckMode);
wprintf(L"SSL Revocation Freshness Time is %d\n", pSsl->ParamDesc.DefaultRevocationFreshnessTime);
wprintf(L"SSL Revocation Retrieval Timeout is %d\n", pSsl->ParamDesc.DefaultRevocationUrlRetrievalTimeout);
wprintf(L"SSLCTL Identifier is %s\n", pSsl->ParamDesc.pDefaultSslCtlIdentifier);
wprintf(L"SSLCTL storename is %s\n", pSsl->ParamDesc.pDefaultSslCtlStoreName);
wprintf(L"SSL Flags is %d\n", pSsl->ParamDesc.DefaultFlags);
}
/***************************************************************************++
Routine Description:
Sets a SSL entry.
Arguments:
pIP - The IP address.
pGuid - The GUID
pHash - Hash of the certificate.
CertCheckMode - CertCheckMode (Bit Field).
Freshness - DefaultRevocationFreshnessTime (seconds)
Timeout - DefaultRevocationUrlRetrievalTimeout
Flags - DefaultFlags.
pCtlIdentifier - List of issuers that we want to trust.
pCtlStoreName - Store name under LOCAL_MACHINE where pCtlIdentifier
can be found.
pCertStoreName - Store name under LOCAL_MACHINE where certificate
can be found.
Return Value:
Success/Failure.
--***************************************************************************/
int
DoSslSet(
__in_opt PWSTR pIp,
__in_opt GUID AppGuid,
__in_opt PWSTR pHash,
__in_opt DWORD CertCheckMode,
__in_opt DWORD Freshness,
__in_opt DWORD Timeout,
__in_opt DWORD Flags,
__in_opt PWSTR pCtlIdentifier,
__in_opt PWSTR pCtlStoreName,
__in_opt PWSTR pCertStoreName
)
{
HTTP_SERVICE_CONFIG_SSL_SET SetParam;
DWORD Status;
SOCKADDR_STORAGE TempSockAddr;
USHORT HashLength;
UCHAR BinaryHash[MAX_HASH];
DWORD i, j;
UCHAR n1, n2;
ZeroMemory(&SetParam, sizeof(SetParam));
SetParam.KeyDesc.pIpPort = (LPSOCKADDR)&TempSockAddr;
//
// Convert the string based IP into a SOCKADDR
//
if((Status = GetAddress(pIp,
SetParam.KeyDesc.pIpPort,
sizeof(TempSockAddr)
)) != NO_ERROR)
{
wprintf(L"%s is not a valid Ip Address\n", pIp);
return Status;
}
//
// Set the GUID.
// Note that this GUID is hardcoded to 0XAAAABEEF
// Please use your own GUID for real application
//
SetParam.ParamDesc.AppId = AppGuid;
if(pHash)
{
HashLength = (USHORT) wcslen(pHash);
for(i=0, j=0; i<MAX_HASH && HashLength >= 2; )
{
CONVERT_WCHAR(pHash[j], n1);
CONVERT_WCHAR(pHash[j+1], n2);
BinaryHash[i] = ((n1<<4) & 0xF0) | (n2 & 0x0F);
// We've consumed 2 WCHARs
HashLength -= 2;
j += 2;
// and used up one byte in BinaryHash
i ++;
}
if(HashLength != 0 || i != MAX_HASH)
{
wprintf(L"Invalid Hash %s\n", pHash);
return ERROR_INVALID_PARAMETER;
}
SetParam.ParamDesc.SslHashLength = i;
SetParam.ParamDesc.pSslHash = BinaryHash;
}
SetParam.ParamDesc.pSslCertStoreName = pCertStoreName;
SetParam.ParamDesc.pDefaultSslCtlIdentifier = pCtlIdentifier;
SetParam.ParamDesc.pDefaultSslCtlStoreName = pCtlStoreName;
SetParam.ParamDesc.DefaultCertCheckMode = CertCheckMode;
SetParam.ParamDesc.DefaultRevocationFreshnessTime = Freshness;
SetParam.ParamDesc.DefaultRevocationUrlRetrievalTimeout = Timeout;
SetParam.ParamDesc.DefaultFlags = Flags;
Status = HttpSetServiceConfiguration(
NULL,
HttpServiceConfigSSLCertInfo,
&SetParam,
sizeof(SetParam),
NULL
);
wprintf(L"SetServiceConfiguration completed with Status %d\n", Status);
return Status;
}
/***************************************************************************++
Routine Description:
Queries for a SSL entry.
Arguments:
pIp - The IP address (if NULL, then enumerate the store).
Return Value:
Success/Failure.
--***************************************************************************/
int DoSslQuery(
__in_opt PWSTR pIp
)
{
DWORD Status;
PUCHAR pOutput = NULL;
DWORD OutputLength = 0;
DWORD ReturnLength = 0;
HTTP_SERVICE_CONFIG_SSL_QUERY QueryParam;
SOCKADDR_STORAGE TempSockAddr;
ZeroMemory(&QueryParam, sizeof(QueryParam));
if(pIp)
{
// if an IP address is specified, we'll covert it to a SOCKADDR
// and do an exact query.
QueryParam.QueryDesc = HttpServiceConfigQueryExact;
QueryParam.KeyDesc.pIpPort = (LPSOCKADDR)&TempSockAddr;
if((Status = GetAddress(pIp,
QueryParam.KeyDesc.pIpPort,
sizeof(TempSockAddr)
)) != NO_ERROR)
{
wprintf(L"%s is not a valid Ip Address\n", pIp);
return Status;
}
}
else
{
// We are enumerating all the records in the SSL store.
QueryParam.QueryDesc = HttpServiceConfigQueryNext;
}
for(;;)
{
//
// First, compute the bytes required to enumerate an entry.
//
Status = HttpQueryServiceConfiguration(
NULL,
HttpServiceConfigSSLCertInfo,
&QueryParam,
sizeof(QueryParam),
pOutput,
OutputLength,
&ReturnLength,
NULL
);
if(Status == ERROR_INSUFFICIENT_BUFFER)
{
// If the API completes with ERROR_INSUFFICIENT_BUFFER, we'll
// allocate memory for it & continue with the loop where we'll
// call it again.
if(pOutput)
{
// If there was an existing buffer, free it.
LocalFree(pOutput);
}
// Allocate a new buffer
pOutput = LocalAlloc(LMEM_FIXED, ReturnLength);
if(!pOutput)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
OutputLength = ReturnLength;
}
else if(Status == NO_ERROR)
{
// The query succeeded! We'll print the record that we just
// queried.
//
PrintSslRecord((PHTTP_SERVICE_CONFIG_SSL_SET)pOutput);
if(pIp != NULL)
{
//
// If we are not enumerating, we are done.
//
break;
}
else
{
//
// Since we are enumerating, we'll move on to the next
// record. This is done by incrementing the cursor, till
// we get ERROR_NO_MORE_ITEMS.
//
QueryParam.dwToken ++;
}
}
else if(ERROR_NO_MORE_ITEMS == Status && !pIp)
{
// We are enumerating and we have reached the end. This is
// indicated by a ERROR_NO_MORE_ITEMS error code.
// This is not a real error, since it is used to indicate that
// we've finished enumeration.
Status = NO_ERROR;
break;
}
else
{
//
// Some other error, so we are done
//
wprintf(L"HttpQueryServiceConfiguration completed with %d\n", Status);
break;
}
}
if(pOutput)
{
LocalFree(pOutput);
}
return Status;
}
/***************************************************************************++
Routine Description:
Deletes a SSL entry.
Arguments:
pIP - The IP address of entry to be deleted.
Return Value:
Success/Failure.
--***************************************************************************/
int DoSslDelete(
__in_opt PWSTR pIp
)
{
HTTP_SERVICE_CONFIG_SSL_SET SetParam;
DWORD Status;
SOCKADDR_STORAGE TempSockAddr;
SetParam.KeyDesc.pIpPort = (LPSOCKADDR)&TempSockAddr;
// Convert string IP address to a SOCKADDR structure
Status = GetAddress(pIp,
SetParam.KeyDesc.pIpPort,
sizeof(TempSockAddr)
);
if(Status != NO_ERROR)
{
wprintf(L"%s is not a valid Ip Address\n", pIp);
return Status;
}
// Call the API.
Status = HttpDeleteServiceConfiguration(
NULL,
HttpServiceConfigSSLCertInfo,
&SetParam,
sizeof(SetParam),
NULL
);
wprintf(L"HttpDeleteServiceConfiguration completed with %d\n", Status);
return Status;
}
//
// Public functions.
//
/***************************************************************************++
Routine Description:
The function that parses parameters specific to SSL
calls Set, Query or Delete.
Arguments:
argc - Count of arguments.
argv - Pointer to command line arguments.
Type - Type of operation to be performed.
Return Value:
Success/Failure.
--***************************************************************************/
int DoSsl(
int argc,
__in_ecount(argc) WCHAR **argv,
HTTPCFG_TYPE type
)
{
GUID AppGuid;
PWSTR pHash = NULL;
PWSTR pCertStoreName = NULL;
PWSTR pCtlIdentifier = NULL;
PWSTR pCtlStoreName = NULL;
DWORD CertCheckMode = 0;
DWORD Freshness = 0;
DWORD Timeout = 0;
DWORD Flags = 0;
PWSTR pIp = NULL;
WCHAR **argvSaved = argv;
while(argc >= 2 && (argv[0][0] == L'-' || argv[0][0] == L'/'))
{
switch(toupper(argv[0][1]))
{
case 'I':
pIp = argv[1];
break;
case 'C':
pCertStoreName = argv[1];
break;
case 'N':
pCtlStoreName = argv[1];
break;
case 'T':
pCtlIdentifier = argv[1];
break;
case 'M':
CertCheckMode = _wtoi(argv[1]);
break;
case 'R':
Freshness = _wtoi(argv[1]);
break;
case 'X':
Timeout = _wtoi(argv[1]);
break;
case 'F':
Flags = _wtoi(argv[1]);
break;
case 'H':
pHash = argv[1];
break;
default:
wprintf(L"%s is an invalid command", argv[0]);
return ERROR_INVALID_PARAMETER;
}
argc -=2;
argv +=2;
}
ZeroMemory(&AppGuid, sizeof(AppGuid));
AppGuid.Data1 = 0XAAAABEEF;
switch(type)
{
case HttpCfgTypeSet:
return DoSslSet(
pIp,
AppGuid,
pHash,
CertCheckMode,
Freshness,
Timeout,
Flags,
pCtlIdentifier,
pCtlStoreName,
pCertStoreName
);
case HttpCfgTypeQuery:
return DoSslQuery(pIp);
case HttpCfgTypeDelete:
return DoSslDelete(pIp);
default:
wprintf(L"%s is not a valid command \n", argvSaved[0]);
return ERROR_INVALID_PARAMETER;
break;
}
}