999 lines
33 KiB
C++
999 lines
33 KiB
C++
// DrtSdkSample.cpp : Defines the entry point for the console application.
|
|
|
|
// 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.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved
|
|
|
|
|
|
#include "DrtSdkSample.h"
|
|
#include "CAPIWrappers.h"
|
|
#include "CustomBootstrapper.h"
|
|
#include "CustomSecurityProvider.h"
|
|
#include "FirewallConfig.h"
|
|
|
|
#pragma comment(lib,"drt")
|
|
#pragma comment(lib,"drtprov")
|
|
#pragma comment(lib,"drttransport")
|
|
|
|
//Global variable to enable the asynchronous display of DRT Events
|
|
BOOL g_DisplayEvents = false;
|
|
|
|
|
|
//********************************************************************************************
|
|
// Function: FlushCurrentLine
|
|
//
|
|
// Description: Clears any input lingering in the STDIN buffer
|
|
//
|
|
//********************************************************************************************
|
|
void FlushCurrentLine()
|
|
{
|
|
int i;
|
|
while((i = getc(stdin)) != EOF && i != '\n')
|
|
continue;
|
|
}
|
|
|
|
|
|
//********************************************************************************************
|
|
// Function: GetUserChoice
|
|
//
|
|
// Description: Presents an interactive menu to the user and returns the user's choice
|
|
//
|
|
// Input: PCWSTR *choices - An array of strings representing the choices to be presented to
|
|
// the users
|
|
//
|
|
//********************************************************************************************
|
|
int GetUserChoice(PCWSTR *choices, int numchoices)
|
|
{
|
|
int chr = -1;
|
|
wprintf(L"---------------------------------------------------------\n");
|
|
for(int i=0; i<numchoices; i++)
|
|
{
|
|
wprintf(L" %i. %s\n",i+1,choices[i]);
|
|
}
|
|
wprintf(L"---------------------------------------------------------\n");
|
|
wprintf(L"Enter a choice (1-%i): ",numchoices);
|
|
wscanf_s(L"%i",&chr);
|
|
FlushCurrentLine();
|
|
if(chr > 0 && chr <= numchoices)
|
|
{
|
|
return chr - 1;
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"Invalid Choice\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
//********************************************************************************************
|
|
// Function: DisplayError
|
|
//
|
|
// Description: Maps common HRESULTs to descriptive error strings
|
|
//
|
|
//********************************************************************************************
|
|
void DisplayError(__in const PWSTR fnname, __in const HRESULT hr)
|
|
{
|
|
struct error_description
|
|
{
|
|
HRESULT hr;
|
|
PWSTR description;
|
|
} valid_errors[] =
|
|
{
|
|
{S_OK, L"Succeeded: S_OK"},
|
|
{E_INVALIDARG, L"Error: E_INVALIDARG"},
|
|
{E_OUTOFMEMORY, L"Error: E_OUTOFMEMORY"},
|
|
{ERROR_INVALID_HANDLE, L"Error: ERROR_INVALID_HANDLE"},
|
|
{ERROR_INVALID_PARAMETER, L"Error: ERROR_INVALID_PARAMETER"},
|
|
{ERROR_ADAP_HDW_ERR, L"Error: ERROR_ADAP_HDW_ERR"},
|
|
{DRT_E_TIMEOUT, L"Error: DRT_E_TIMEOUT"},
|
|
{DRT_E_INVALID_KEY_SIZE, L"Error: DRT_E_INVALID_KEY_SIZE"},
|
|
{DRT_E_INVALID_CERT_CHAIN, L"Error: DRT_E_INVALID_CERT_CHAIN"},
|
|
{DRT_E_INVALID_MESSAGE, L"Error: DRT_E_INVALID_MESSAGE"},
|
|
{DRT_E_NO_MORE, L"Error: DRT_E_NO_MORE"},
|
|
{DRT_E_INVALID_MAX_ADDRESSES, L"Error: DRT_E_INVALID_MAX_ADDRESSES"},
|
|
{DRT_E_SEARCH_IN_PROGRESS, L"Error: DRT_E_SEARCH_IN_PROGRESS"},
|
|
{DRT_E_INVALID_KEY, L"Error: DRT_E_INVALID_KEY"},
|
|
{DRT_E_INVALID_PORT, L"Error: DRT_E_INVALID_PORT"},
|
|
{DRT_E_STILL_IN_USE, L"Error: DRT_E_STILL_IN_USE"},
|
|
{DRT_E_INVALID_ADDRESS, L"Error: DRT_E_INVALID_ADDRESS"},
|
|
{DRT_E_INVALID_SCOPE, L"Error: DRT_E_INVALID_SCOPE"},
|
|
{DRT_E_INVALID_SETTINGS, L"Error: DRT_E_INVALID_SETTINGS"},
|
|
{DRT_S_RETRY, L"Error: DRT_S_RETRY"},
|
|
{DRT_E_INVALID_MAX_ENDPOINTS, L"Error: DRT_E_INVALID_MAX_ENDPOINTS"},
|
|
{DRT_E_INVALID_SEARCH_RANGE, L"Error: DRT_E_INVALID_SEARCH_RANGE"},
|
|
{DRT_E_INVALID_TRANSPORT_PROVIDER, L"Error: DRT_E_INVALID_TRANSPORT_PROVIDER"},
|
|
{DRT_E_INVALID_SECURITY_PROVIDER, L"Error: DRT_E_INVALID_SECURITY_PROVIDER"},
|
|
{DRT_E_STILL_IN_USE, L"Error: DRT_E_STILL_IN_USE"},
|
|
{DRT_E_INVALID_BOOTSTRAP_PROVIDER, L"Error: DRT_E_INVALID_BOOTSTRAP_PROVIDER"},
|
|
{DRT_E_TRANSPORT_SHUTTING_DOWN, L"Error: DRT_E_TRANSPORT_SHUTTING_DOWN"},
|
|
{DRT_E_NO_ADDRESSES_AVAILABLE, L"Error: DRT_E_NO_ADDRESSES_AVAILABLE"},
|
|
{DRT_E_DUPLICATE_KEY, L"Error: DRT_E_DUPLICATE_KEY"},
|
|
{DRT_E_TRANSPORTPROVIDER_IN_USE, L"Error: DRT_E_TRANSPORTPROVIDER_IN_USE"},
|
|
{DRT_E_TRANSPORTPROVIDER_NOT_ATTACHED,L"Error: DRT_E_TRANSPORTPROVIDER_NOT_ATTACHED"},
|
|
{DRT_E_SECURITYPROVIDER_IN_USE, L"Error: DRT_E_SECURITYPROVIDER_IN_USE"},
|
|
{DRT_E_SECURITYPROVIDER_NOT_ATTACHED, L"Error: DRT_E_SECURITYPROVIDER_NOT_ATTACHED"},
|
|
{DRT_E_BOOTSTRAPPROVIDER_IN_USE, L"Error: DRT_E_BOOTSTRAPPROVIDER_IN_USE"},
|
|
{DRT_E_BOOTSTRAPPROVIDER_NOT_ATTACHED,L"Error: DRT_E_BOOTSTRAPPROVIDER_NOT_ATTACHED"},
|
|
{DRT_E_TRANSPORT_ALREADY_BOUND, L"Error: DRT_E_TRANSPORT_ALREADY_BOUND"},
|
|
{DRT_E_TRANSPORT_NOT_BOUND, L"Error: DRT_E_TRANSPORT_NOT_BOUND"},
|
|
{DRT_E_TRANSPORT_UNEXPECTED, L"Error: DRT_E_TRANSPORT_UNEXPECTED"},
|
|
{DRT_E_TRANSPORT_INVALID_ARGUMENT, L"Error: DRT_E_TRANSPORT_INVALID_ARGUMENT"},
|
|
{DRT_E_TRANSPORT_NO_DEST_ADDRESSES, L"Error: DRT_E_TRANSPORT_NO_DEST_ADDRESSES"},
|
|
{DRT_E_TRANSPORT_EXECUTING_CALLBACK, L"Error: DRT_E_TRANSPORT_EXECUTING_CALLBACK"},
|
|
{DRT_E_TRANSPORT_ALREADY_EXISTS_FOR_SCOPE,L"Error: DRT_E_TRANSPORT_ALREADY_EXISTS_FOR_SCOPE"},
|
|
{DRT_E_INVALID_SEARCH_INFO, L"Error: DRT_E_INVALID_SEARCH_INFO"},
|
|
{DRT_E_FAULTED, L"Error: DRT_E_FAULTED"},
|
|
{DRT_E_TRANSPORT_STILL_BOUND, L"Error: DRT_E_TRANSPORT_STILL_BOUND"},
|
|
{DRT_E_INSUFFICIENT_BUFFER, L"Error: DRT_E_INSUFFICIENT_BUFFER"},
|
|
{DRT_E_INVALID_INSTANCE_PREFIX, L"Error: DRT_E_INVALID_INSTANCE_PREFIX"},
|
|
{DRT_E_INVALID_SECURITY_MODE, L"Error: DRT_E_INVALID_SECURITY_MODE"},
|
|
{DRT_E_CAPABILITY_MISMATCH, L"Error: DRT_E_CAPABILITY_MISMATCH"},
|
|
{CRYPT_E_FILE_ERROR, L"Error: CRYPT_E_FILE_ERROR (Check permissions on the current directory)"},
|
|
|
|
};
|
|
if (hr==S_OK)
|
|
return;
|
|
wprintf(L"%s ", fnname);
|
|
for(int eindex=0;
|
|
eindex < sizeof(valid_errors) / sizeof(struct error_description);
|
|
eindex++ )
|
|
{
|
|
if(hr==valid_errors[eindex].hr)
|
|
{
|
|
wprintf(L"%s\n",valid_errors[eindex].description);
|
|
return;
|
|
}
|
|
}
|
|
wprintf(L"Undocumented Error Code: 0x%x\n",hr);
|
|
}
|
|
|
|
|
|
//********************************************************************************************
|
|
// Function: DrtEventCallback
|
|
//
|
|
// Description: Callback to handle general DRT Events.
|
|
// These include registration state changes, leafset changes, and status changes.
|
|
//
|
|
//********************************************************************************************
|
|
void CALLBACK DrtEventCallback(__in PVOID Param, __in BOOLEAN TimedOut)
|
|
{
|
|
HRESULT hr;
|
|
DRT_CONTEXT *Drt = (DRT_CONTEXT*)Param;
|
|
PDRT_EVENT_DATA pEventData = NULL;
|
|
ULONG ulDrtEventDataLen = 0;
|
|
UNREFERENCED_PARAMETER(TimedOut);
|
|
|
|
hr = DrtGetEventDataSize (Drt->hDrt, &ulDrtEventDataLen);
|
|
if(FAILED(hr))
|
|
{
|
|
if(hr != DRT_E_NO_MORE)
|
|
wprintf(L" DrtGetEventDataSize failed: 0x%x\n",hr);
|
|
goto Cleanup;
|
|
}
|
|
pEventData = (PDRT_EVENT_DATA) malloc(ulDrtEventDataLen);
|
|
if (pEventData == NULL)
|
|
{
|
|
printf (" Out of memory\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = DrtGetEventData(Drt->hDrt, ulDrtEventDataLen, pEventData);
|
|
if(FAILED(hr))
|
|
{
|
|
if(hr != DRT_E_NO_MORE)
|
|
wprintf(L" DrtGetEventData failed: 0x%x\n",hr);
|
|
goto Cleanup;
|
|
}
|
|
|
|
if(pEventData->type == DRT_EVENT_STATUS_CHANGED)
|
|
{
|
|
if(pEventData->statusChange.status == DRT_ACTIVE)
|
|
{
|
|
SetConsoleTitle(L"DrtSdkSample Current Drt Status: Active");
|
|
if(g_DisplayEvents)
|
|
wprintf(L" DRT Status Changed to Active\n");
|
|
}
|
|
else if(pEventData->statusChange.status == DRT_ALONE)
|
|
{
|
|
SetConsoleTitle(L"DrtSdkSample Current Drt Status: Alone");
|
|
if(g_DisplayEvents)
|
|
wprintf(L" DRT Status Changed to Alone\n");
|
|
}
|
|
else if(pEventData->statusChange.status == DRT_NO_NETWORK)
|
|
{
|
|
SetConsoleTitle(L"DrtSdkSample Current Drt Status: No Network");
|
|
if(g_DisplayEvents)
|
|
wprintf(L" DRT Status Changed to No Network\n");
|
|
}
|
|
else if(pEventData->statusChange.status == DRT_FAULTED)
|
|
{
|
|
SetConsoleTitle(L"DrtSdkSample Current Drt Status: Faulted");
|
|
if(g_DisplayEvents)
|
|
wprintf(L" DRT Status Changed to Faulted\n");
|
|
}
|
|
}
|
|
else if(pEventData->type == DRT_EVENT_LEAFSET_KEY_CHANGED)
|
|
{
|
|
if(g_DisplayEvents)
|
|
{
|
|
if(pEventData->leafsetKeyChange.change == DRT_LEAFSET_KEY_ADDED)
|
|
wprintf(L" Leafset Key Added Event: [hr: 0x%x]\n", pEventData->hr);
|
|
else if(pEventData->leafsetKeyChange.change == DRT_LEAFSET_KEY_DELETED)
|
|
wprintf(L" Leafset Key Deleted Event: [hr: 0x%x]\n", pEventData->hr);
|
|
}
|
|
}
|
|
else if(pEventData->type == DRT_EVENT_REGISTRATION_STATE_CHANGED)
|
|
{
|
|
if(g_DisplayEvents)
|
|
wprintf(L" Registration State Changed Event: [hr: 0x%x, registration state: %i]\n", pEventData->hr, pEventData->registrationStateChange.state);
|
|
}
|
|
free(pEventData);
|
|
pEventData = NULL;
|
|
|
|
Cleanup:
|
|
if(pEventData)
|
|
free(pEventData);
|
|
return;
|
|
}
|
|
|
|
|
|
//********************************************************************************************
|
|
// Function: InitializeDrt
|
|
//
|
|
// Description: Initializes and brings a DRT instance online
|
|
// 1) Brings up an ipv6 transport layer
|
|
// 2) Attaches a security provider (according to user's choice)
|
|
// 3) Attaches a bootstrap provider (according to user's choice)
|
|
// 4) Calls DrtOpen to bring the DRT instance online
|
|
//
|
|
//********************************************************************************************
|
|
bool InitializeDrt(DRT_CONTEXT *Drt)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwSize = 0;
|
|
PWSTR pwszCompName = NULL;
|
|
WCHAR pwszBootstrapHostname[1024] = {0};
|
|
USHORT usBootstrapPort = 0;
|
|
|
|
//
|
|
// Initialize DrtSettings
|
|
//
|
|
Drt->port = 0;
|
|
Drt->settings.pwzDrtInstancePrefix = L"Local_DRT";
|
|
Drt->settings.dwSize = sizeof(DRT_SETTINGS);
|
|
Drt->settings.cbKey = KEYSIZE;
|
|
Drt->settings.ulMaxRoutingAddresses = 4;
|
|
Drt->settings.bProtocolMajorVersion = 0x6;
|
|
Drt->settings.bProtocolMinorVersion = 0x65;
|
|
Drt->settings.eSecurityMode = DRT_SECURE_CONFIDENTIALPAYLOAD;
|
|
Drt->settings.hTransport = NULL;
|
|
Drt->settings.pSecurityProvider = NULL;
|
|
Drt->settings.pBootstrapProvider = NULL;
|
|
Drt->hDrt = NULL;
|
|
|
|
//
|
|
// *Transport*
|
|
//
|
|
|
|
hr = DrtCreateIpv6UdpTransport(
|
|
DRT_GLOBAL_SCOPE,
|
|
0,
|
|
300,
|
|
&Drt->port,
|
|
&Drt->settings.hTransport
|
|
);
|
|
|
|
VERIFY_OR_ABORT("DrtCreateTransport",hr);
|
|
|
|
//
|
|
// *Security Provider*
|
|
//
|
|
|
|
if(Drt->SecurityProviderType == 0) //Null Security Provider
|
|
{
|
|
hr = DrtCreateNullSecurityProvider(&Drt->settings.pSecurityProvider);
|
|
}
|
|
else if(Drt->SecurityProviderType == 1) //Derived Key Security Provider
|
|
{
|
|
hr = ReadCertFromFile(L"RootCertificate.cer", &Drt->pRoot, NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"No RootCertificate.cer file found in the current directory, Creating a new root certificate.\n");
|
|
hr = MakeCert(L"RootCertificate.cer", L"RootCert", NULL, NULL);
|
|
VERIFY_OR_ABORT(L"MakeCert",hr);
|
|
hr = ReadCertFromFile(L"RootCertificate.cer", &Drt->pRoot, NULL);
|
|
VERIFY_OR_ABORT(L"ReadCertFromFile", hr);
|
|
}
|
|
|
|
// We now have a root cert, read an existing local cert or create one based on root cert
|
|
hr = ReadCertFromFile(L"LocalCertificate.cer", &Drt->pLocal, NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"No LocalCertificate.cer file found in the current directory, Creating a new local certificate.\n");
|
|
hr = MakeCert(L"LocalCertificate.cer", L"LocalCert", L"RootCertificate.cer", L"RootCert");
|
|
VERIFY_OR_ABORT(L"MakeCert",hr);
|
|
hr = ReadCertFromFile(L"LocalCertificate.cer", &Drt->pLocal, NULL);
|
|
VERIFY_OR_ABORT(L"ReadCertFromFile", hr);
|
|
}
|
|
hr = DrtCreateDerivedKeySecurityProvider(
|
|
Drt->pRoot,
|
|
Drt->pLocal,
|
|
&Drt->settings.pSecurityProvider
|
|
);
|
|
}
|
|
else if(Drt->SecurityProviderType == 2) //Custom Security Provider
|
|
{
|
|
hr = DrtCreateCustomSecurityProvider(&Drt->settings.pSecurityProvider);
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"Invalid Security Provider passed to InitializeDrt");
|
|
hr = E_FAIL;
|
|
}
|
|
VERIFY_OR_ABORT("DrtCreateSecurityProvider",hr);
|
|
|
|
//
|
|
// *Bootstrap Provider*
|
|
//
|
|
|
|
if(Drt->BootstrapProviderType == 0) //DNS Bootstrap Provider
|
|
{
|
|
GetComputerNameEx(ComputerNameDnsFullyQualified, NULL, &dwSize );
|
|
pwszCompName = new WCHAR[dwSize+1];
|
|
if(pwszCompName == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
wprintf(L"Out of memory");
|
|
goto Cleanup;
|
|
}
|
|
::GetComputerNameEx(ComputerNameDnsFullyQualified, pwszCompName, &dwSize);
|
|
|
|
wprintf(L"Enter 'hostname port' for DNS Bootstrap Provider (currently %s %i):\n", pwszCompName, Drt->port);
|
|
if(wscanf_s(L"%s %hu",pwszBootstrapHostname, 1024, &usBootstrapPort) < 2)
|
|
{
|
|
FlushCurrentLine();
|
|
hr = E_INVALIDARG;
|
|
wprintf(L"Invalid hostname:port\n");
|
|
goto Cleanup;
|
|
}
|
|
wprintf(L"DNS Bootstrapping from: %s:%i\n",pwszBootstrapHostname, usBootstrapPort);
|
|
FlushCurrentLine();
|
|
|
|
hr = DrtCreateDnsBootstrapResolver(
|
|
usBootstrapPort,
|
|
pwszBootstrapHostname,
|
|
&Drt->settings.pBootstrapProvider
|
|
);
|
|
}
|
|
else if (Drt->BootstrapProviderType == 1) //PNRP Bootstrap Provider
|
|
{
|
|
wprintf(L"Enter a PNRP name for PNRP Bootstrap Provider (IE 0.DemoName)\n");
|
|
if(wscanf_s(L"%s",pwszBootstrapHostname, 1024) < 1)
|
|
{
|
|
FlushCurrentLine();
|
|
wprintf(L"Invalid PNRP name\n");
|
|
goto Cleanup;
|
|
}
|
|
wprintf(L"PNRP Bootstrapping from: %s\n",pwszBootstrapHostname);
|
|
FlushCurrentLine();
|
|
hr = DrtCreatePnrpBootstrapResolver(
|
|
TRUE,
|
|
pwszBootstrapHostname,
|
|
L"Global_",
|
|
NULL,
|
|
&Drt->settings.pBootstrapProvider
|
|
);
|
|
}
|
|
else if (Drt->BootstrapProviderType == 2) //Custom Bootstrap Provider
|
|
{
|
|
GetComputerNameEx(ComputerNameDnsFullyQualified, NULL, &dwSize );
|
|
pwszCompName = new WCHAR[dwSize+1];
|
|
::GetComputerNameEx(ComputerNameDnsFullyQualified, pwszCompName, &dwSize);
|
|
|
|
if(pwszCompName == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
wprintf(L"Out of memory");
|
|
goto Cleanup;
|
|
}
|
|
|
|
wprintf(L"Enter 'hostname port' for Custom Bootstrap Provider (currently %s %i\n", pwszCompName, Drt->port);
|
|
if(wscanf_s(L"%s %hu",pwszBootstrapHostname, 1024, &usBootstrapPort) < 2)
|
|
{
|
|
FlushCurrentLine();
|
|
hr = E_INVALIDARG;
|
|
wprintf(L"Invalid hostname:port\n");
|
|
goto Cleanup;
|
|
}
|
|
wprintf(L"Custom Bootstrapping from: %s:%i\n",pwszBootstrapHostname, usBootstrapPort);
|
|
FlushCurrentLine();
|
|
|
|
hr = DrtCreateCustomBootstrapResolver(
|
|
usBootstrapPort,
|
|
pwszBootstrapHostname,
|
|
&Drt->settings.pBootstrapProvider
|
|
);
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"Invalid Bootstrap Provider passed to InitializeDrt");
|
|
hr = E_FAIL;
|
|
}
|
|
VERIFY_OR_ABORT("DrtCreateBootstrapResolver",hr);
|
|
|
|
//
|
|
// *Make sure the Windows Firewall is open*
|
|
// Also open port 3540 (used by PNRP, if the PNRP bootstrap provider is chosen)
|
|
//
|
|
|
|
if(Drt->BootstrapProviderType==1)
|
|
hr = OpenFirewallForDrtSdkSample(TRUE);
|
|
else
|
|
hr = OpenFirewallForDrtSdkSample(FALSE);
|
|
|
|
VERIFY_OR_ABORT("OpenFirewallForDrtSdkSample",hr);
|
|
|
|
//
|
|
// Open the DRT
|
|
//
|
|
|
|
Drt->eventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if(NULL == Drt->eventHandle)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = DrtOpen(&Drt->settings, Drt->eventHandle, NULL, &Drt->hDrt);
|
|
|
|
VERIFY_OR_ABORT("DrtOpen", hr);
|
|
|
|
//
|
|
// Register a callback to handle DRT Events
|
|
//
|
|
RegisterWaitForSingleObject(&Drt->DrtWaitEvent, Drt->eventHandle, (WAITORTIMERCALLBACK)DrtEventCallback, Drt, INFINITE, WT_EXECUTEDEFAULT);
|
|
|
|
Cleanup:
|
|
if(pwszCompName)
|
|
delete pwszCompName;
|
|
return SUCCEEDED(hr);
|
|
}
|
|
|
|
|
|
//********************************************************************************************
|
|
// Function: GetKeyFromUser
|
|
//
|
|
// Description: Gets a registration key from the user (used for registration and search)
|
|
//
|
|
//********************************************************************************************
|
|
bool GetKeyFromUser(PCWSTR pcwszKeyName, BYTE* KeyData)
|
|
{
|
|
int i;
|
|
int hexdigit=0;
|
|
wprintf(L"Enter %s as a string of hex digits, Example: 01 ff 0a b8 80 z\n", pcwszKeyName);
|
|
wprintf(L"The current keysize is %i bytes. Enter z as the last digit and the remainder of the key will be zero-filled (Most significant byte is first)\n",KEYSIZE);
|
|
for(i=KEYSIZE-1;i>=0;i--)
|
|
{
|
|
if(wscanf_s(L"%2X",&hexdigit) < 1)
|
|
break;
|
|
KeyData[i] = (BYTE)hexdigit;
|
|
}
|
|
for(;i>=0;i--)
|
|
KeyData[i] = 0;
|
|
wprintf(L"Resulting %s:\n", pcwszKeyName);
|
|
for(i=KEYSIZE-1;i>=0;i--)
|
|
wprintf(L"%02x ",KeyData[i]);
|
|
wprintf(L"\n");
|
|
FlushCurrentLine();
|
|
|
|
return true;
|
|
}
|
|
|
|
//********************************************************************************************
|
|
// Function: PerformDrtSearch
|
|
//
|
|
// Description: Initializes and performs a search through the DRT
|
|
//
|
|
//********************************************************************************************
|
|
|
|
bool PerformDrtSearch(DRT_CONTEXT* Drt, INT SearchType)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwSize = 1024;
|
|
bool fKeyFound = FALSE;
|
|
DRT_SEARCH_INFO SearchInfo = {0};
|
|
DRT_SEARCH_INFO* pSearchInfo = NULL;
|
|
HDRT_SEARCH_CONTEXT SearchContext = {0};
|
|
DRT_SEARCH_RESULT *pSearchResult = NULL;
|
|
BYTE searchKeyData[KEYSIZE] = {0};
|
|
BYTE minKeyData[KEYSIZE] = {0};
|
|
BYTE maxKeyData[KEYSIZE] = {0};
|
|
DRT_DATA searchKey = {0};
|
|
DRT_DATA minKey = {0};
|
|
DRT_DATA maxKey = {0};
|
|
|
|
//Create a manual reset event
|
|
//The DRT will reset the event when the search result buffer has been consumed
|
|
HANDLE hDrtSearchEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
if(NULL == hDrtSearchEvent)
|
|
{
|
|
wprintf(L"Out of memory\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//Set Some Defaults for SearchInfo
|
|
SearchInfo.dwSize = sizeof(DRT_SEARCH_INFO);
|
|
SearchInfo.fIterative = FALSE;
|
|
SearchInfo.fAllowCurrentInstanceMatch = TRUE;
|
|
SearchInfo.fAnyMatchInRange = FALSE;
|
|
SearchInfo.cMaxEndpoints = 1;
|
|
SearchInfo.pMinimumKey = &minKey;
|
|
SearchInfo.pMaximumKey = &maxKey;
|
|
|
|
searchKey.cb = KEYSIZE;
|
|
searchKey.pb = searchKeyData;
|
|
minKey.cb = KEYSIZE;
|
|
minKey.pb = minKeyData;
|
|
maxKey.cb = KEYSIZE;
|
|
maxKey.pb = maxKeyData;
|
|
|
|
if(!GetKeyFromUser(L"Search Key",searchKeyData))
|
|
goto Cleanup;
|
|
|
|
if(SearchType==2) //Simple DRT Search
|
|
{
|
|
pSearchInfo = NULL;
|
|
}
|
|
else if(SearchType==3) //Nearest Match Search
|
|
{
|
|
SearchInfo.fAnyMatchInRange = FALSE;
|
|
pSearchInfo = &SearchInfo;
|
|
memset(minKeyData,0,KEYSIZE);
|
|
memset(maxKeyData,0xFF,KEYSIZE);
|
|
}
|
|
else if(SearchType==4) //Iterative Search
|
|
{
|
|
SearchInfo.fIterative = TRUE;
|
|
pSearchInfo = &SearchInfo;
|
|
minKey.pb = searchKey.pb;
|
|
maxKey.pb = searchKey.pb;
|
|
}
|
|
else if(SearchType==5) //Range Search
|
|
{
|
|
SearchInfo.fAnyMatchInRange = TRUE;
|
|
if(!GetKeyFromUser(L"Min Search Key (01 z)",minKeyData))
|
|
goto Cleanup;
|
|
if(!GetKeyFromUser(L"Max Search Key (ff z)",maxKeyData))
|
|
goto Cleanup;
|
|
pSearchInfo = &SearchInfo;
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"Invalid Search Type passed to DrtPerformSearch");
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = DrtStartSearch(
|
|
Drt->hDrt,
|
|
&searchKey,
|
|
pSearchInfo,
|
|
5000,
|
|
hDrtSearchEvent,
|
|
NULL,
|
|
&SearchContext);
|
|
|
|
VERIFY_OR_ABORT("DrtStartSearch",hr);
|
|
|
|
do
|
|
{
|
|
DWORD dwRes = WaitForSingleObject(hDrtSearchEvent, 30*1000);
|
|
|
|
if(dwRes == WAIT_OBJECT_0)
|
|
{
|
|
hr = DrtGetSearchResultSize(SearchContext,&dwSize);
|
|
if(hr != S_OK)
|
|
{
|
|
continue;
|
|
}
|
|
pSearchResult = (DRT_SEARCH_RESULT*)malloc(dwSize);
|
|
if(pSearchResult == NULL)
|
|
{
|
|
wprintf(L"Error: Out of memory\n");
|
|
break;
|
|
}
|
|
hr = DrtGetSearchResult(SearchContext, dwSize, pSearchResult);
|
|
if(hr != S_OK)
|
|
{
|
|
continue;
|
|
}
|
|
if(pSearchResult->type == DRT_MATCH_EXACT)
|
|
{
|
|
fKeyFound = TRUE;
|
|
wprintf(L"*Found Key*: ");
|
|
for(int i=pSearchResult->registration.key.cb-1;i>=0;i--)
|
|
wprintf(L"%02x ",pSearchResult->registration.key.pb[i]);
|
|
wprintf(L"\n");
|
|
PrintSearchPath(SearchContext);
|
|
}
|
|
else if(pSearchResult->type == DRT_MATCH_NEAR)
|
|
{
|
|
wprintf(L"*Found Near Match*: ");
|
|
for(int i=pSearchResult->registration.key.cb-1;i>=0;i--)
|
|
wprintf(L"%02x ",pSearchResult->registration.key.pb[i]);
|
|
wprintf(L"\n");
|
|
if(SearchType==3)
|
|
fKeyFound = TRUE;
|
|
PrintSearchPath(SearchContext);
|
|
}
|
|
else if(pSearchResult->type == DRT_MATCH_INTERMEDIATE)
|
|
{
|
|
wprintf(L"Intermediate Match: ");
|
|
for(int i=pSearchResult->registration.key.cb-1;i>=0;i--)
|
|
wprintf(L"%02x ",pSearchResult->registration.key.pb[i]);
|
|
wprintf(L"\n");
|
|
DrtContinueSearch(SearchContext);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"Drt Search Timed out\n");
|
|
break;
|
|
}
|
|
if(pSearchResult)
|
|
{
|
|
free(pSearchResult);
|
|
pSearchResult = NULL;
|
|
}
|
|
} while( (hr == DRT_E_SEARCH_IN_PROGRESS) || (hr == S_OK) );
|
|
DrtEndSearch(SearchContext);
|
|
|
|
//
|
|
// When the search is finished, the HRESULT should be DRT_E_NO_MORE
|
|
//
|
|
if(hr != DRT_E_NO_MORE)
|
|
{
|
|
wprintf(L"Unexpected HRESULT from DrtGetSearchResult: 0x%x\n",hr);
|
|
}
|
|
|
|
if(!fKeyFound)
|
|
wprintf(L"Could not find key\n");
|
|
|
|
Cleanup:
|
|
if(pSearchResult)
|
|
free(pSearchResult);
|
|
if (hDrtSearchEvent)
|
|
CloseHandle(hDrtSearchEvent);
|
|
|
|
return true;
|
|
}
|
|
|
|
void PrintSearchPath(HDRT_SEARCH_CONTEXT SearchContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG ulSearchPathLen = 0;
|
|
DRT_ADDRESS_LIST* pSearchPath = NULL;
|
|
|
|
hr = DrtGetSearchPathSize(SearchContext, &ulSearchPathLen);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
pSearchPath = (PDRT_ADDRESS_LIST) malloc(ulSearchPathLen);
|
|
if(pSearchPath == NULL)
|
|
{
|
|
printf ("Out of memory\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = DrtGetSearchPath(SearchContext, ulSearchPathLen, pSearchPath);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
wprintf(L"Search Path:\n");
|
|
for(UINT i=0;i<pSearchPath->AddressCount;i++)
|
|
{
|
|
SOCKADDR_IN6 addr = *(SOCKADDR_IN6*)(&pSearchPath->AddressList[i].socketAddress);
|
|
wprintf(L"Port: %i Flags: 0x%x, Nearness: %i Latency: %i\n",
|
|
addr.sin6_port,
|
|
pSearchPath->AddressList[i].flags,
|
|
pSearchPath->AddressList[i].nearness,
|
|
pSearchPath->AddressList[i].latency);
|
|
}
|
|
|
|
Cleanup:
|
|
if(pSearchPath)
|
|
{
|
|
free(pSearchPath);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//********************************************************************************************
|
|
// Function: RegisterKey
|
|
//
|
|
// Description: Registers a key in the current DRT Instance
|
|
//
|
|
//********************************************************************************************
|
|
bool RegisterKey(DRT_CONTEXT* Drt)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BYTE* newKeyData = NULL;
|
|
BYTE* newPayloadData = NULL;
|
|
REG_CONTEXT reg = {0};
|
|
CERT_CONTEXT *pRegCertContext = NULL;
|
|
|
|
newKeyData = (BYTE*)malloc(KEYSIZE);
|
|
newPayloadData = (BYTE*)malloc(KEYSIZE);
|
|
reg.regInfo.key.cb = KEYSIZE;
|
|
reg.regInfo.key.pb = newKeyData;
|
|
reg.regInfo.appData.cb = KEYSIZE;
|
|
reg.regInfo.appData.pb = newPayloadData;
|
|
reg.hDrtReg = NULL;
|
|
|
|
if(!newKeyData || !newPayloadData)
|
|
{
|
|
wprintf(L"Not enough memory");
|
|
goto Cleanup;
|
|
}
|
|
|
|
if(Drt->SecurityProviderType == 1) // Derived Key Security Provider
|
|
{
|
|
wprintf(L"Generating a new certificate for the new registration...\n");
|
|
hr = MakeCert(L"LastRegisteredCert.cer", L"LocalCert", L"RootCertificate.cer", L"RootCert");
|
|
VERIFY_OR_ABORT(L"MakeCert",hr);
|
|
wprintf(L"Creating a new key based on the generated certificate...\n");
|
|
hr = ReadCertFromFile(L"LastRegisteredCert.cer", &pRegCertContext, NULL);
|
|
VERIFY_OR_ABORT("ReadCertFromFile",hr);
|
|
hr = DrtCreateDerivedKey(pRegCertContext,®.regInfo.key);
|
|
VERIFY_OR_ABORT("DrtCreateDerivedKey",hr);
|
|
}
|
|
else
|
|
{
|
|
if(!GetKeyFromUser(L"Registration Key",newKeyData))
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = DrtRegisterKey(Drt->hDrt, ®.regInfo, pRegCertContext, ®.hDrtReg);
|
|
VERIFY_OR_ABORT("DrtRegisterKey",hr);
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
Drt->registrations.push_back(reg);
|
|
|
|
// newKeyData and newPayloadData will be freed on unregister
|
|
newKeyData = NULL;
|
|
newPayloadData = NULL;
|
|
|
|
wprintf(L"Successfully Registered: ");
|
|
for(int i=reg.regInfo.key.cb-1;i>=0;i--)
|
|
wprintf(L"%02x ",reg.regInfo.key.pb[i]);
|
|
wprintf(L"\n");
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if(newKeyData)
|
|
free(newKeyData);
|
|
if(newPayloadData)
|
|
free(newPayloadData);
|
|
if(pRegCertContext)
|
|
CertFreeCertificateContext(pRegCertContext);
|
|
return true;
|
|
}
|
|
|
|
|
|
//********************************************************************************************
|
|
// Function: UnRegisterKey
|
|
//
|
|
// Description: Unregisters a previously registered key
|
|
//
|
|
//********************************************************************************************
|
|
bool UnRegisterKey(DRT_CONTEXT* Drt)
|
|
{
|
|
int choice = 0;
|
|
wprintf(L"Current Registrations:\n");
|
|
for(UINT i=0; i<Drt->registrations.size(); i++)
|
|
{
|
|
wprintf(L"%i: ",i);
|
|
for(int k=Drt->registrations[i].regInfo.key.cb-1; k>=0; k--)
|
|
wprintf(L" %02x",Drt->registrations[i].regInfo.key.pb[k]);
|
|
wprintf(L"\n");
|
|
}
|
|
wprintf(L"Enter a registration to unregister (or c to cancel):");
|
|
if( (wscanf_s(L"%i",&choice) < 1) ||
|
|
(choice >= (int)Drt->registrations.size()) ||
|
|
(choice < 0) )
|
|
{
|
|
FlushCurrentLine();
|
|
goto Cleanup;
|
|
}
|
|
FlushCurrentLine();
|
|
|
|
wprintf(L"Unregistering key: ");
|
|
for(int k=Drt->registrations[choice].regInfo.key.cb; k<=0; k++)
|
|
wprintf(L" %02x",Drt->registrations[choice].regInfo.key.pb[k]);
|
|
wprintf(L"\n");
|
|
|
|
DrtUnregisterKey(Drt->registrations[choice].hDrtReg);
|
|
|
|
if(Drt->registrations[choice].regInfo.key.pb)
|
|
free(Drt->registrations[choice].regInfo.key.pb);
|
|
if(Drt->registrations[choice].regInfo.appData.pb)
|
|
free(Drt->registrations[choice].regInfo.appData.pb);
|
|
Drt->registrations.erase(Drt->registrations.begin()+choice);
|
|
|
|
Cleanup:
|
|
return true;
|
|
}
|
|
|
|
|
|
//********************************************************************************************
|
|
// Function: CleanupDrt
|
|
//
|
|
// Description: Deletes and Frees the various objects and providers used by the DRT
|
|
//
|
|
//********************************************************************************************
|
|
void CleanupDrt(DRT_CONTEXT *Drt)
|
|
{
|
|
for(UINT i=0; i<Drt->registrations.size(); i++)
|
|
{
|
|
DrtUnregisterKey(Drt->registrations[i].hDrtReg);
|
|
|
|
if(Drt->registrations[i].regInfo.key.pb)
|
|
free(Drt->registrations[i].regInfo.key.pb);
|
|
if(Drt->registrations[i].regInfo.appData.pb)
|
|
free(Drt->registrations[i].regInfo.appData.pb);
|
|
}
|
|
Drt->registrations.clear();
|
|
|
|
if (Drt->DrtWaitEvent != NULL)
|
|
{
|
|
UnregisterWait(Drt->DrtWaitEvent);
|
|
}
|
|
|
|
if (Drt->hDrt != NULL)
|
|
{
|
|
DrtClose(Drt->hDrt);
|
|
Drt->hDrt = NULL;
|
|
}
|
|
|
|
if (Drt->eventHandle!= NULL)
|
|
{
|
|
CloseHandle(Drt->eventHandle);
|
|
Drt->eventHandle = NULL;
|
|
}
|
|
|
|
if (Drt->settings.pBootstrapProvider != NULL)
|
|
{
|
|
if(Drt->BootstrapProviderType == 0)
|
|
DrtDeleteDnsBootstrapResolver(Drt->settings.pBootstrapProvider);
|
|
else if(Drt->BootstrapProviderType == 1)
|
|
DrtDeletePnrpBootstrapResolver(Drt->settings.pBootstrapProvider);
|
|
else if(Drt->BootstrapProviderType == 2)
|
|
DrtDeleteCustomBootstrapResolver(Drt->settings.pBootstrapProvider);
|
|
}
|
|
|
|
if (Drt->settings.pSecurityProvider != NULL)
|
|
{
|
|
if(Drt->SecurityProviderType == 0)
|
|
DrtDeleteNullSecurityProvider(Drt->settings.pSecurityProvider);
|
|
else if(Drt->SecurityProviderType == 1)
|
|
DrtDeleteDerivedKeySecurityProvider(Drt->settings.pSecurityProvider);
|
|
else if(Drt->SecurityProviderType == 2)
|
|
DrtDeleteCustomSecurityProvider(Drt->settings.pSecurityProvider);
|
|
}
|
|
|
|
if (Drt->pRoot != NULL)
|
|
{
|
|
CertFreeCertificateContext(Drt->pRoot);
|
|
}
|
|
|
|
if (Drt->pLocal != NULL)
|
|
{
|
|
CertFreeCertificateContext(Drt->pLocal);
|
|
}
|
|
}
|
|
|
|
|
|
//********************************************************************************************
|
|
// Function: Main
|
|
//
|
|
// Description: The main function, initializes a DRT according to user specifications and
|
|
// loops allowing the user to interact with the DRT.
|
|
//
|
|
//********************************************************************************************
|
|
int __cdecl main()
|
|
{
|
|
int nSearchType;
|
|
|
|
DRT_CONTEXT LocalDrt = { 0 };
|
|
|
|
PCWSTR ppcwzSecurityProviderChoices[] = {
|
|
L"Initialize DRT with Null Security Provider",
|
|
L"Initialize DRT with Derived Key Security Provider",
|
|
L"Initialize DRT with Custom Security Provider",
|
|
L"Exit" };
|
|
|
|
PCWSTR ppcwzBootStrapProviderChoices[] = {
|
|
L"Bootstrap with Builtin DNS Bootstrap Provider",
|
|
L"Bootstrap with Builtin PNRP Bootstrap Provider",
|
|
L"Bootstrap with Custom Bootstrap Provider",
|
|
L"Exit" };
|
|
|
|
PCWSTR ppcwzSearchChoices[] = {
|
|
L"Register a new key",
|
|
L"Unregister a key",
|
|
L"Simple DRT Search",
|
|
L"Nearest Match Search",
|
|
L"Iterative Search",
|
|
L"Range Search",
|
|
L"Hide DRT Events",
|
|
L"Display DRT Events",
|
|
L"Exit" };
|
|
|
|
SetConsoleTitle(L"DrtSdkSample Current Drt Status: Initializing");
|
|
|
|
LocalDrt.SecurityProviderType = GetUserChoice(ppcwzSecurityProviderChoices, 4);
|
|
if(LocalDrt.SecurityProviderType==-1 || LocalDrt.SecurityProviderType==3)
|
|
goto Cleanup;
|
|
|
|
LocalDrt.BootstrapProviderType = GetUserChoice(ppcwzBootStrapProviderChoices, 4);
|
|
if(LocalDrt.BootstrapProviderType==-1 || LocalDrt.BootstrapProviderType==3)
|
|
goto Cleanup;
|
|
|
|
if(!InitializeDrt(&LocalDrt))
|
|
goto Cleanup;
|
|
|
|
wprintf(L"DRT Initialization Complete\n");
|
|
|
|
SetConsoleTitle(L"DrtSdkSample Current Drt Status: Bootstrapping");
|
|
|
|
for(;;)
|
|
{
|
|
nSearchType = GetUserChoice(ppcwzSearchChoices, 9);
|
|
if(nSearchType==0)
|
|
{
|
|
if(!RegisterKey(&LocalDrt))
|
|
goto Cleanup;
|
|
}
|
|
else if(nSearchType==1)
|
|
{
|
|
if(!UnRegisterKey(&LocalDrt))
|
|
goto Cleanup;
|
|
}
|
|
else if( 1 < nSearchType && nSearchType < 6 )
|
|
{
|
|
if(!PerformDrtSearch(&LocalDrt, nSearchType))
|
|
goto Cleanup;
|
|
}
|
|
else if(nSearchType==6)
|
|
{
|
|
wprintf(L"DRT Events will not be displayed\n");
|
|
g_DisplayEvents = 0;
|
|
}
|
|
else if(nSearchType==7)
|
|
{
|
|
wprintf(L"DRT Events will be displayed asynchronously\n");
|
|
g_DisplayEvents = 1;
|
|
}
|
|
else if(nSearchType==8)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
CleanupDrt(&LocalDrt);
|
|
return 0;
|
|
}
|