//+---------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996-1998 // // File: prottest.c // // Contents: Test program for hydra licensing protocol // // History: 01-07-98 FredCh Created // //----------------------------------------------------------------------------- #include #include #include #include #include #include "license.h" #include "hslice.h" #include "cryptkey.h" #include "hccontxt.h" #include "licecert.h" #include "lscsp.h" #include "sysapi.h" #include "prottest.h" #define MSG_SIZE 2048 BOOL LsCsp_UnpackServerCert( LPBYTE pbCert, DWORD dwCertLen, PHydra_Server_Cert pServerCert ); /////////////////////////////////////////////////////////////////////////////// HANDLE g_hServerEvent = NULL, g_hClientEvent = NULL; BYTE * pbServerMessage = NULL; PBYTE ClientMessage;//[MSG_SIZE]; DWORD cbServerMessage = 0; DWORD cbClientMessage; LPBYTE g_pbPubKey = NULL; DWORD g_cbPubKey = 0; Hydra_Server_Cert g_ServerCertificate; const BYTE g_abServerCertificate[184] = { 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x5C, 0x00, 0x52, 0x53, 0x41, 0x31, 0x48, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x83, 0x76, 0x5B, 0x09, 0x8F, 0xC1, 0x74, 0x12, 0x1B, 0xD3, 0x4E, 0x72, 0x72, 0x4D, 0xBE, 0xCE, 0x55, 0x1D, 0x29, 0x3D, 0x0E, 0xED, 0x28, 0x09, 0x50, 0x66, 0x32, 0xFA, 0x1D, 0xD2, 0xCC, 0x42, 0xDE, 0x5B, 0x4E, 0x3C, 0x35, 0xF6, 0x73, 0x5B, 0x0C, 0x0D, 0xB0, 0xA6, 0x4D, 0x76, 0xBA, 0xC0, 0x88, 0x5F, 0xC4, 0x67, 0x0B, 0xB8, 0xA3, 0x23, 0xA6, 0xC7, 0x79, 0xBD, 0x80, 0xD1, 0xA8, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x48, 0x00, 0x19, 0x50, 0x2E, 0x2E, 0x82, 0xB4, 0xEB, 0xB3, 0x87, 0x85, 0xB9, 0x31, 0x4C, 0x29, 0x07, 0x05, 0xD7, 0x37, 0x99, 0x86, 0x15, 0x30, 0x56, 0xE4, 0x47, 0x7A, 0x2C, 0x2F, 0x4C, 0xBD, 0xF0, 0x37, 0xD3, 0x94, 0x01, 0xC8, 0x73, 0xEA, 0x5C, 0x2C, 0x3F, 0x60, 0x27, 0x1E, 0x5D, 0xA9, 0x54, 0x32, 0xDC, 0x49, 0xA4, 0x7E, 0x26, 0xAF, 0xEA, 0x07, 0xCA, 0x4E, 0xE9, 0x95, 0x8E, 0x66, 0xF0, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /////////////////////////////////////////////////////////////////////////////// void _stdcall HydraServerThread(); void _stdcall HydraClientThread(); BOOL TsIssueLicenseExpirationWarning( LPDWORD lpdwDays, PTS_LICENSE_INFO pTsLicenseInfo ); BOOL FileTimeToUnixTime( LPFILETIME pft, time_t * t ); VOID DisplayLicenseMessage( DWORD dwDaysLeft ); /////////////////////////////////////////////////////////////////////////////// void _cdecl main(int argc, char *argv[]) { DWORD ServerThreadID, ClientThreadID; HANDLE ThreadHandles[2]; DWORD WaitStatus = 0; Binary_Blob CertBlob; LICENSE_STATUS Status; DWORD dwFlag = CERT_DATE_DONT_VALIDATE; // // Create the server and client events // ThreadHandles[0] = NULL; ThreadHandles[1] = NULL; g_hServerEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); g_hClientEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); if( ( NULL == g_hServerEvent ) || ( NULL == g_hClientEvent ) ) { printf( "Cannot create events\n" ); return; } InitializeLicenseLib( TRUE ); memset( &CertBlob, 0, sizeof( CertBlob ) ); // // get the X509 certificate // Status = GetServerCertificate( CERT_TYPE_X509, &CertBlob, KEY_EXCHANGE_ALG_RSA ); if( LICENSE_STATUS_OK == Status ) { Status = VerifyCertChain( CertBlob.pBlob, CertBlob.wBlobLen, NULL, &g_cbPubKey, &dwFlag ); if( LICENSE_STATUS_INSUFFICIENT_BUFFER == Status ) { g_pbPubKey = LocalAlloc( LPTR, g_cbPubKey ); if( NULL == g_pbPubKey ) { goto done; } Status = VerifyCertChain( CertBlob.pBlob, CertBlob.wBlobLen, g_pbPubKey, &g_cbPubKey, &dwFlag ); } if( LICENSE_STATUS_OK != Status ) { printf( "Cannot verify X509 certificate chain: %x\n", Status ); goto done; } } // // unpack the hardcoded certificate // if( !LsCsp_UnpackServerCert( ( LPBYTE )g_abServerCertificate, sizeof( g_abServerCertificate ), &g_ServerCertificate ) ) { printf( "cannot unpack server certificate\n" ); } // // Create the server and client threads // ThreadHandles[0] = CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE )HydraServerThread, NULL, 0, &ServerThreadID ); ThreadHandles[1] = CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE )HydraClientThread, NULL, 0, &ClientThreadID ); // // wait for the server and client thread to die // WaitStatus = WaitForMultipleObjects( 2, ThreadHandles, TRUE, INFINITE ); // // close the event handles // done: if( g_hServerEvent ) { CloseHandle( g_hServerEvent ); } if( g_hClientEvent ) { CloseHandle( g_hClientEvent ); } if( ThreadHandles[0] ) { CloseHandle( ThreadHandles[0] ); } if( ThreadHandles[1] ) { CloseHandle( ThreadHandles[1] ); } ShutdownLicenseLib(); if( pbServerMessage ) { LocalFree( pbServerMessage ); } if( CertBlob.pBlob ) { LocalFree( CertBlob.pBlob ); } if( g_pbPubKey ) { LocalFree( g_pbPubKey ); } return; } #define HYDRA_40_LICENSING_PROTOCOL_FLAG 0 #define HYDRA_40_LICENSING_PROTOCOL_VERSION LICENSE_PROTOCOL_VERSION_1_0 | PREAMBLE_VERSION_2_0 /////////////////////////////////////////////////////////////////////////////// void _stdcall HydraServerThread() { LICENSE_STATUS Status; HANDLE hContext = NULL; LICENSE_CAPABILITIES LicenseCap; TS_LICENSE_INFO TsLicenseInfo; Status = CreateLicenseContext( &hContext, LICENSE_CONTEXT_PER_SEAT ); if( LICENSE_STATUS_OK != Status ) { printf( "HydraServerThread(): error creating license context\n" ); return; } memset( &LicenseCap, 0, sizeof( LicenseCap ) ); LicenseCap.KeyExchangeAlg = KEY_EXCHANGE_ALG_RSA; #ifdef HYDRA_40_TEST // // talking to a Hydra 4.0 client // LicenseCap.ProtocolVer = HYDRA_40_LICENSING_PROTOCOL_VERSION; LicenseCap.fAuthenticateServer = TRUE; Status = InitializeLicenseContext( hContext, 0, &LicenseCap ); #else #ifdef HYDRA_50_NO_SERVER_AUTHEN_X509 // // talking to a Hydra 5.0 client and don't send certificate // LicenseCap.ProtocolVer = LICENSE_HIGHEST_PROTOCOL_VERSION; LicenseCap.fAuthenticateServer = FALSE; LicenseCap.CertType = CERT_TYPE_X509; Status = InitializeLicenseContext( hContext, 0, &LicenseCap ); #else #ifdef HYDRA_50_NO_SERVER_AUTHEN_PROPRIETORY // // talking to a Hydra 5.0 client and don't send certificate // LicenseCap.ProtocolVer = LICENSE_HIGHEST_PROTOCOL_VERSION; LicenseCap.fAuthenticateServer = FALSE; LicenseCap.CertType = CERT_TYPE_PROPRIETORY; Status = InitializeLicenseContext( hContext, 0, &LicenseCap ); #else // // talking to a Hydra 5.0 client and also send certificate // LicenseCap.ProtocolVer = LICENSE_HIGHEST_PROTOCOL_VERSION; LicenseCap.fAuthenticateServer = TRUE; Status = InitializeLicenseContext( hContext, 0, &LicenseCap ); #endif // HYDRA_50_NO_SERVER_AUTHEN_X509 #endif // HYDRA_50_NO_SERVER_AUTHEN_PROPRIETORY #endif // HYDRA_40_TEST if( LICENSE_STATUS_OK != Status ) { printf( "HydraServerThread(): cannot initialize license context: %x\n", Status ); goto done; } Status = AcceptLicenseContext( hContext, 0, NULL, &cbServerMessage, &pbServerMessage ); while( LICENSE_STATUS_CONTINUE == Status ) { SetEvent( g_hClientEvent ); WaitForSingleObject( g_hServerEvent, INFINITE ); if( pbServerMessage ) { LocalFree( pbServerMessage ); pbServerMessage = NULL; cbServerMessage = 0; } Status = AcceptLicenseContext( hContext, cbClientMessage, ClientMessage, &cbServerMessage, &pbServerMessage ); } done: if( hContext ) { DWORD dwDaysLeft = 0; memset( &TsLicenseInfo, 0, sizeof( TsLicenseInfo ) ); Status = QueryLicenseInfo( hContext, &TsLicenseInfo ); if( LICENSE_STATUS_OK != Status ) { printf( "HydraSeverThread: cannot query license info: %x\n", Status ); } if( TsIssueLicenseExpirationWarning( &dwDaysLeft, &TsLicenseInfo ) ) { DisplayLicenseMessage( dwDaysLeft ); } FreeLicenseInfo( &TsLicenseInfo ); DeleteLicenseContext( hContext ); } if( ( LICENSE_STATUS_ISSUED_LICENSE == Status ) || ( LICENSE_STATUS_OK == Status ) ) { // // issueing a license or the license has been successfully validated // printf( "HydraServerThread: Protocol completed successfully\n" ); SetEvent( g_hClientEvent ); } else if( LICENSE_STATUS_SEND_ERROR == Status ) { printf( "HydraServerThread: sending error to client\n" ); SetEvent( g_hClientEvent ); } else { printf( "HydraServerThread: protocol error: aborted\n" ); } return; } /////////////////////////////////////////////////////////////////////////////// void _stdcall HydraClientThread() { LICENSE_STATUS Status; HANDLE hContext; #ifdef HYDRA_50_NO_SERVER_AUTHEN_X509 // // no server authentication required. Use the public key in the // X509 certificate // Status = LicenseInitializeContext( &hContext, LICENSE_CONTEXT_NO_SERVER_AUTHENTICATION ); if( LICENSE_STATUS_OK != Status ) { printf( "Cannot initialize client context: %x\n", Status ); return; } // // set the public key // Status = LicenseSetPublicKey( hContext, g_cbPubKey, g_pbPubKey ); if( LICENSE_STATUS_OK != Status ) { printf( "Cannot set public key: %x\n", Status ); goto done; } #else #ifdef HYDRA_50_NO_SERVER_AUTHEN_PROPRIETORY // // no server authentication required. Use the proprietory certificate // Status = LicenseInitializeContext( &hContext, LICENSE_CONTEXT_NO_SERVER_AUTHENTICATION ); if( LICENSE_STATUS_OK != Status ) { printf( "Cannot initialize client context: %x\n", Status ); return; } // // set the proprietory certificate // Status = LicenseSetCertificate( hContext, &g_ServerCertificate ); if( LICENSE_STATUS_OK != Status ) { printf( "cannot set certificate: %x\n", Status ); goto done; } #else // // hydra 4.0/5.0 licensing protocol.with certificate validation // Status = LicenseInitializeContext( &hContext, 0 ); if( LICENSE_STATUS_OK != Status ) { printf( "Cannot initialize client context: %x\n", Status ); return; } #endif #endif if( NULL == hContext ) { printf( "HydraClientThread(): error creating license context\n" ); return; } if( LICENSE_STATUS_OK != Status ) { printf( "HydraClientThread(): error setting certificate: %x\n", Status ); LicenseDeleteContext( hContext ); return; } WaitForSingleObject( g_hClientEvent, INFINITE ); cbClientMessage = 0;//MSG_SIZE; if( LICENSE_STATUS_CONTINUE != (Status = LicenseAcceptContext( hContext, 0, pbServerMessage, cbServerMessage, NULL,//ClientMessage, &cbClientMessage )) ) { printf("Error handling Server request\n"); return; } if( NULL == (ClientMessage = (PBYTE)GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, cbClientMessage)) ) { printf("Error allocating memory\n"); return; } //memset(ClientMessage, 0x00, cbClientMessage); Status = LicenseAcceptContext(hContext, 0, pbServerMessage, cbServerMessage, ClientMessage, &cbClientMessage); while( LICENSE_STATUS_CONTINUE == Status ) { SetEvent( g_hServerEvent ); WaitForSingleObject( g_hClientEvent, INFINITE ); cbClientMessage = 0; if(ClientMessage) { GlobalFree((HGLOBAL)ClientMessage); ClientMessage = NULL; } Status = LicenseAcceptContext( hContext, 0, pbServerMessage, cbServerMessage, NULL,//ClientMessage, &cbClientMessage); if( ( Status == LICENSE_STATUS_OK ) || ( Status != LICENSE_STATUS_CONTINUE ) ) { break; } if( NULL == (ClientMessage = (PBYTE)GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, cbClientMessage)) ) { printf("Error allocating memory\n"); break; } memset(ClientMessage, 0x00, cbClientMessage); Status = LicenseAcceptContext( hContext, 0, pbServerMessage, cbServerMessage, ClientMessage, &cbClientMessage ); } done: LicenseDeleteContext( hContext ); if( LICENSE_STATUS_OK == Status ) { printf( "HydraClientThread: license protocol completed successfully\n" ); } else { printf( "HydraClientThread: license protocol failed: 0x%x\n", Status ); } if( ClientMessage ) { GlobalFree( ( HGLOBAL )ClientMessage ); } return; } #define SECONDS_IN_A_DAY 86400 // number of seconds in a day #define ISSUE_LICENSE_WARNING_PERIOD 150 // days to expiration when warning should be issued. /////////////////////////////////////////////////////////////////////////////// BOOL TsIssueLicenseExpirationWarning( LPDWORD lpdwDays, PTS_LICENSE_INFO pTsLicenseInfo ) { time_t Expiration, CurrentTime; DWORD dwDaysLeft; if( NULL == pTsLicenseInfo ) { return( FALSE ); } if( FALSE == pTsLicenseInfo->fTempLicense ) { return( FALSE ); } // // The client license is temporary, figure out how long more // the license is valid // if( FALSE == FileTimeToUnixTime( &pTsLicenseInfo->NotAfter, &Expiration ) ) { return( FALSE ); } time( &CurrentTime ); if( CurrentTime >= Expiration ) { // // license already expired // *lpdwDays = 0xFFFFFFFF; return( TRUE ); } dwDaysLeft = ( Expiration - CurrentTime ) / SECONDS_IN_A_DAY; printf( "Number of days left for temporary license expiration: %d\n", dwDaysLeft ); if( ISSUE_LICENSE_WARNING_PERIOD >= dwDaysLeft ) { *lpdwDays = dwDaysLeft; return( TRUE ); } return( FALSE ); } /////////////////////////////////////////////////////////////////////////////// BOOL FileTimeToUnixTime( LPFILETIME pft, time_t * t ) { SYSTEMTIME sysTime; struct tm gmTime; if( FileTimeToSystemTime( pft, &sysTime ) == FALSE ) { return( FALSE ); } if( sysTime.wYear >= 2038 ) { *t = INT_MAX; } else { // // Unix time support up to 2038/1/18 // restrict any expiration data // memset( &gmTime, 0, sizeof( gmTime ) ); gmTime.tm_sec = sysTime.wSecond; gmTime.tm_min = sysTime.wMinute; gmTime.tm_hour = sysTime.wHour; gmTime.tm_year = sysTime.wYear - 1900; gmTime.tm_mon = sysTime.wMonth - 1; gmTime.tm_mday = sysTime.wDay; *t = mktime( &gmTime ); } return( *t != ( time_t )-1 ); } /////////////////////////////////////////////////////////////////////////////// VOID DisplayLicenseMessage( DWORD dwDaysLeft ) { TCHAR szMsgCaption[512], szMsgTitle[256]; HMODULE hModule = GetModuleHandle( NULL ); LPDWORD lpdw; TCHAR tszDays[ 10 ]; if( 0xFFFFFFFF == dwDaysLeft ) { printf( "Temporary License has expired!\n" ); LoadString( hModule, STR_TEMP_LICENSE_EXPIRED_MSG, szMsgCaption, 512 ); } else { printf( "%d days left before temporary license expires\n", dwDaysLeft ); // // convert the number of days left to UNICODE character // _ultow( dwDaysLeft, tszDays, 10 ); lpdw = ( LPDWORD )&tszDays[0]; // // prepare license about to expire message // LoadString( hModule, STR_TEMP_LICENSE_EXPIRATION_MSG, szMsgCaption, 512 ); FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, szMsgCaption, 0, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), ( LPTSTR )szMsgCaption, sizeof( szMsgCaption ), ( va_list * )&lpdw ); } // // prepare message title // LoadString( hModule, STR_TEMP_LICENSE_MSG_TITLE, szMsgTitle, 256 ); MessageBox( NULL, szMsgCaption, szMsgTitle, MB_OK ); return; }