windows-nt/Source/XPSP1/NT/termsrv/license/tlserver/tlsapi/csp.c
2020-09-26 16:20:57 +08:00

3452 lines
76 KiB
C

/*++
File name:
csp.c
Description:
Contains routines to support cryptographic routines for termserv
Copyright:
Microsoft Confidential
Copyright (c) Microsoft Corporation 1991-1998
All rights reserved
History:
Frederick Chong( FredCh ) 07/29/98 Added functions to install
X509 certificate.
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntlsa.h>
#include <windows.h>
#include <winbase.h>
#include <winerror.h>
#include <tchar.h>
#include <stdio.h>
#include "license.h"
#include "cryptkey.h"
#include "rng.h"
#include "lscsp.h"
#include "tlsapip.h"
#include "certutil.h"
#include "hydrakey.h"
#include <md5.h>
#include <sha.h>
#include <rsa.h>
#include <secdbg.h>
#include "global.h"
#ifdef OS_WIN16
#include <string.h>
#endif // OS_WIN16
#include "licecert.h"
#define LS_DISCOVERY_TIMEOUT (1*1000)
//-----------------------------------------------------------------------------
//
// Internal Functions
//
//-----------------------------------------------------------------------------
NTSTATUS
OpenPolicy(
LPWSTR ServerName,
DWORD DesiredAccess,
PLSA_HANDLE PolicyHandle );
void
InitLsaString(
PLSA_UNICODE_STRING LsaString,
LPWSTR String );
LICENSE_STATUS
GenerateRsaKeyPair(
LPBYTE * ppbPublicKey,
LPDWORD pcbPublicKey,
LPBYTE * ppbPrivateKey,
LPDWORD pcbPrivateKey,
DWORD dwKeyLen );
LICENSE_STATUS
Bsafe2CapiPubKey(
PCERT_PUBLIC_KEY_INFO pCapiPubKeyInfo,
LPBYTE pbBsafePubKey,
DWORD cbBsafePubKey );
VOID
FreeCapiPubKey(
PCERT_PUBLIC_KEY_INFO pCapiPubKeyInfo );
LICENSE_STATUS
RequestCertificate(
TLS_HANDLE hServer,
PCERT_PUBLIC_KEY_INFO pPubKeyInfo,
LPBYTE * ppbCertificate,
LPDWORD pcbCertificate,
HWID * pHwid );
LICENSE_STATUS
GetSubjectRdn(
LPTSTR * ppSubjectRdn );
LICENSE_STATUS
GenerateMachineHWID(
PHWID pHwid );
LICENSE_STATUS
ReloadCSPCertificateAndData();
LICENSE_STATUS
CreateProprietaryKeyAndCert(
PBYTE *ppbPrivateKey,
DWORD *pcbPrivateKey,
PBYTE *ppbServerCert,
DWORD *pcbServerCert);
BOOL IsSystemService();
/*++
Function:
LsCsp_ValidateServerCert
Routine Description:
This function validate the server public key.
Arguments:
pSserverCert - pointer to a server certificate.
Return Value:
TRUE - if the server public key is valid.
FALSE - otherwise.
--*/
BOOL
LsCsp_ValidateServerCert(
PHydra_Server_Cert pServerCert
)
{
BOOL bResult = TRUE;
DWORD dwLen;
LPBYTE pbSignature;
MD5_CTX HashState;
BYTE SignHash[0x48];
DWORD buff[64];
LPBYTE pbScan;
//
// pack the certificate data into a byte blob excluding the signature info.
//
dwLen =
3 * sizeof(DWORD) +
2 * sizeof(WORD) +
pServerCert->PublicKeyData.wBlobLen;
//
// allocated space for the binary blob.
//
if (dwLen < sizeof(buff)) {
pbSignature = (PBYTE)buff;
} else {
pbSignature = LocalAlloc( LPTR, (UINT)dwLen );
if( pbSignature == NULL ) {
#if DBG
DbgPrint("LSCSP: LsCsp_ValidateServerCert buffer alloc failed.\n");
#endif
bResult = FALSE;
goto vsc_done;
}
}
pbScan = pbSignature;
memcpy( pbScan, &pServerCert->dwVersion, sizeof(DWORD));
pbScan += sizeof(DWORD);
memcpy( pbScan, &pServerCert->dwSigAlgID, sizeof(DWORD));
pbScan += sizeof(DWORD);
memcpy( pbScan, &pServerCert->dwKeyAlgID, sizeof(DWORD));
pbScan += sizeof(DWORD);
memcpy( pbScan, &pServerCert->PublicKeyData.wBlobType, sizeof(WORD));
pbScan += sizeof(WORD);
memcpy( pbScan, &pServerCert->PublicKeyData.wBlobLen, sizeof(WORD));
pbScan += sizeof(WORD);
memcpy(
pbScan,
pServerCert->PublicKeyData.pBlob,
pServerCert->PublicKeyData.wBlobLen);
//
// generate the hash on the data.
//
MD5Init( &HashState );
MD5Update( &HashState, pbSignature, dwLen );
MD5Final( &HashState );
//
// free the signature blob, we don't need it anymore.
//
if (pbSignature != (LPBYTE)buff) {
LocalFree( pbSignature );
}
//
// decrypt the signature.
//
memset(SignHash, 0x00, 0x48);
BSafeEncPublic( csp_pRootPublicKey, pServerCert->SignatureBlob.pBlob, SignHash);
//
// compare the hash value.
//
if( memcmp( SignHash, HashState.digest, 16 )) {
bResult = FALSE;
} else {
bResult = TRUE;
}
vsc_done:
return( bResult );
}
/*++
Function:
LsCsp_UnpackServerCert
Routine Description:
This function unpacks the blob of server certicate to server certificate
structure.
Arguments:
pbCert - pointer to the server public key blob.
dwCertLen - length of the above server public key.
pServerCert - pointer to a server certificate structure.
Return Value:
TRUE - if successfully unpacked.
FALSE - otherwise.
--*/
BOOL
LsCsp_UnpackServerCert(
LPBYTE pbCert,
DWORD dwCertLen,
PHydra_Server_Cert pServerCert
)
{
LPBYTE pbScan;
BOOL bResult = TRUE;
ASSERT(pbCert != NULL);
ASSERT(dwCertLen < (3 * sizeof(DWORD) + 4 * sizeof(WORD)));
ASSERT(pServerCert != NULL);
pbScan = pbCert;
//
// Assign dwVersion
//
pServerCert->dwVersion = *(DWORD UNALIGNED FAR *)pbScan;
pbScan += sizeof(DWORD);
ASSERT(pServerCert->dwVersion == 0x01);
//
// Assign dwSigAlgID
//
pServerCert->dwSigAlgID = *(DWORD UNALIGNED FAR *)pbScan;
pbScan += sizeof(DWORD);
//
// Assign dwSignID
//
pServerCert->dwKeyAlgID = *(DWORD UNALIGNED FAR *)pbScan;
pbScan += sizeof(DWORD);
//
// Assign PublicKeyData
//
pServerCert->PublicKeyData.wBlobType = *(WORD UNALIGNED FAR *)pbScan;
pbScan += sizeof(WORD);
if( pServerCert->PublicKeyData.wBlobType != BB_RSA_KEY_BLOB ) {
#if DBG
DbgPrint("LSCSP: LsCsp_UnpackServerCert PublicKey not BB_RSA_KEY_BLOB\n");
#endif
bResult = FALSE;
goto usc_done;
}
pServerCert->PublicKeyData.wBlobLen = *(WORD UNALIGNED FAR *)pbScan;
pbScan += sizeof(WORD);
if( pServerCert->PublicKeyData.wBlobLen > 0 ) {
pServerCert->PublicKeyData.pBlob = pbScan;
pbScan += pServerCert->PublicKeyData.wBlobLen;
}
else {
pServerCert->PublicKeyData.pBlob = NULL;
}
//
// Assign SignatureBlob
//
pServerCert->SignatureBlob.wBlobType = *(WORD UNALIGNED *)pbScan;
pbScan += sizeof(WORD);
if( pServerCert->SignatureBlob.wBlobType != BB_RSA_SIGNATURE_BLOB ) {
#if DBG
DbgPrint("LSCSP: LsCsp_UnpackServerCert Signature Blob not BB_RSA_SIGNATURE_BLOB\n");
#endif
bResult = FALSE;
goto usc_done;
}
pServerCert->SignatureBlob.wBlobLen = *(WORD UNALIGNED FAR *)pbScan;
pbScan += sizeof(WORD);
if( pServerCert->SignatureBlob.wBlobLen > 0 ) {
pServerCert->SignatureBlob.pBlob = pbScan;
pbScan += pServerCert->SignatureBlob.wBlobLen;
}
else {
pServerCert->SignatureBlob.pBlob = NULL;
}
usc_done:
return( bResult );
}
/*++
Function:
LsCsp_DecryptEnvelopedData
Routine Description:
Decrypt the client random that is encrypted by the server public key.
Arguments:
dwCertType - The type of certificate that is used in the encryption.
pbEnvelopedData - pointer to a buffer where the encrypted random key is
passed in.
cbEnvelopedDataLen - length of the random key passed in/out.
pbData - pointer to a buffer where the decrypted data returned.
pcbDataLen - pointer a DWORD location where the length of the above
buffer is passed in and the length of the decrypted data is returned.
Return Value:
TRUE - if the key is decrypted successfully.
FALSE - otherwise.
--*/
BOOL
LsCsp_DecryptEnvelopedData(
CERT_TYPE CertType,
LPBYTE pbEnvelopedData,
DWORD cbEnvelopedDataLen,
LPBYTE pbData,
LPDWORD pcbDataLen
)
{
LPBSAFE_PRV_KEY pSrvPrivateKey = NULL;
BOOL bResult = TRUE;
ACQUIRE_EXCLUSIVE_ACCESS(csp_hMutex);
//
// determine the correct private key to use for the decryption operation
//
if( CERT_TYPE_PROPRIETORY == CertType )
{
pSrvPrivateKey = (LPBSAFE_PRV_KEY)csp_abServerPrivateKey;
}
else if( CERT_TYPE_X509 == CertType )
{
if( csp_abX509CertPrivateKey == NULL )
{
if( ReloadCSPCertificateAndData() != LICENSE_STATUS_OK )
{
ASSERT( FALSE );
}
}
pSrvPrivateKey = (LPBSAFE_PRV_KEY)csp_abX509CertPrivateKey;
}
else
{
bResult = FALSE;
goto ded_done;
}
if( NULL == pSrvPrivateKey )
{
bResult = FALSE;
goto ded_done;
}
//
// check to see the output buffer length pointer is valid.
//
if( pcbDataLen == NULL ) {
bResult = FALSE;
goto ded_done;
}
//
// check to see the output buffer is valid and its length is sufficient.
//
if( (pbData == NULL) || (*pcbDataLen < pSrvPrivateKey->keylen) ) {
*pcbDataLen = pSrvPrivateKey->keylen;
bResult = FALSE;
goto ded_done;
}
//
// encrypted data length should be equal to server private key length.
//
if( cbEnvelopedDataLen != pSrvPrivateKey->keylen ) {
*pcbDataLen = 0;
bResult = FALSE;
goto ded_done;
}
ASSERT( pbData != NULL );
//
// init the output buffer.
//
memset( pbData, 0x0, (UINT)pSrvPrivateKey->keylen );
if( !BSafeDecPrivate(
pSrvPrivateKey,
pbEnvelopedData,
pbData) ) {
*pcbDataLen = 0;
bResult = FALSE;
goto ded_done;
}
//
// successfully decrypted the client random.
// set the encrypted data length before returning.
//
*pcbDataLen = pSrvPrivateKey->keylen;
ded_done:
RELEASE_EXCLUSIVE_ACCESS( csp_hMutex );
return( bResult );
}
BOOL
LsCsp_EncryptEnvelopedData(
LPBYTE pbData,
DWORD cbDataLen,
LPBYTE pbEnvelopedData,
LPDWORD pcbEnvelopedDataLen
)
{
return FALSE;
}
/*++
Function:
LsCsp_DumpBinaryData
Description:
Display the binary data in the given buffer at the debugger output screen
Arguments:
pBuffer - Buffer containing the binary data to be displayed.
uLen - Length of th binary data
Return:
Nothing.
--*/
#if DBG
#ifdef DUMP
VOID LsCsp_DumpBinaryData( PBYTE pBuffer, ULONG uLen )
{
UNALIGNED CHAR *p = (UNALIGNED CHAR *)pBuffer;
CHAR c;
DWORD dw;
UINT i = 0;
DbgPrint("{\n ");
while( i < uLen ) {
c = *p;
dw = (DWORD)(c);
DbgPrint( "0x%02X, ", dw & 0xFF );
i++;
p++;
if ((i % 8) == 0)
DbgPrint( "\n " );
}
DbgPrint( "\n}\n" );
}
#endif
#endif
/*++
Function:
LsCsp_GetBinaryData
Description:
Retrieve binary data from the registry
Arguments:
hKey - Handle to the registry key
szValue - The registry value to read
ppBuffer - Return pointer to the binary data
pdwBufferLen - The length of the binary data.
Return:
A LICENSE_STATUS return code.
--*/
LICENSE_STATUS
LsCsp_GetBinaryData(
HKEY hKey,
LPTSTR szValue,
LPBYTE * ppBuffer,
LPDWORD pdwBufferLen )
{
LICENSE_STATUS Status = LICENSE_STATUS_OK;
DWORD dwType;
DWORD cbBuffer;
LPBYTE lpBuffer;
ASSERT( ppBuffer != NULL );
ASSERT( pdwBufferLen != NULL );
ASSERT( szValue != NULL );
ASSERT( hKey != NULL );
*ppBuffer = NULL;
cbBuffer = 0;
if ( RegQueryValueEx(
hKey,
szValue,
0,
&dwType,
(LPBYTE)NULL,
&cbBuffer) != ERROR_SUCCESS ||
dwType != REG_BINARY ||
cbBuffer == 0 )
{
Status = LICENSE_STATUS_NO_CERTIFICATE;
goto gbd_done;
}
lpBuffer = (LPBYTE)LocalAlloc( LPTR, cbBuffer );
if (lpBuffer == NULL) {
Status = LICENSE_STATUS_OUT_OF_MEMORY;
goto gbd_done;
}
if ( RegQueryValueEx(
hKey,
szValue,
0,
&dwType,
(LPBYTE)lpBuffer,
&cbBuffer) != ERROR_SUCCESS ||
dwType != REG_BINARY)
{
LocalFree( lpBuffer );
Status = LICENSE_STATUS_NO_CERTIFICATE;
goto gbd_done;
}
*ppBuffer = lpBuffer;
*pdwBufferLen = cbBuffer;
gbd_done:
return( Status );
}
/*++
Function:
LsCsp_Initialize
Description:
Initialize this library.
Arguments:
Nothing.
Return:
A LICENSE_STATUS return code.
--*/
LICENSE_STATUS
LsCsp_Initialize( void )
{
DWORD Status = LICENSE_STATUS_OK;
DWORD dwResult, dwDisp;
if( InterlockedIncrement( &csp_InitCount ) > 1 )
{
//
// already initialized
//
return( LICENSE_STATUS_OK );
}
//
// Create a global mutex for sync.
//
csp_hMutex = CreateMutex(
NULL,
FALSE,
NULL
);
if(NULL == csp_hMutex)
{
#if DBG
DbgPrint("LSCSP: CreateMutex() failed with error code %d\n", GetLastError());
#endif
Status = LICENSE_STATUS_OUT_OF_MEMORY;
goto ErrorExit;
}
//
// initialize the Hydra Server Root Public key.
//
csp_pRootPublicKey = (LPBSAFE_PUB_KEY)csp_abPublicKeyModulus;
csp_pRootPublicKey->magic = RSA1;
csp_pRootPublicKey->keylen = 0x48;
csp_pRootPublicKey->bitlen = 0x0200;
csp_pRootPublicKey->datalen = 0x3f;
csp_pRootPublicKey->pubexp = 0xc0887b5b;
#if DBG
#ifdef DUMP
DbgPrint("Data0\n");
LsCsp_DumpBinaryData( (LPBYTE)csp_pRootPublicKey, 92 );
#endif
#endif
//
// Initialize the proprietory certificate with the built in certificate
//
if( !LsCsp_UseBuiltInCert() )
{
Status = LICENSE_STATUS_NO_CERTIFICATE;
goto ErrorExit;
}
//
// Unpack and Validate the certificate
//
try {
if (!LsCsp_UnpackServerCert(
csp_abServerCertificate,
csp_dwServerCertificateLen,
&csp_hscData )) {
Status = LICENSE_STATUS_INVALID_CERTIFICATE;
goto ErrorExit;
}
if (!LsCsp_ValidateServerCert( &csp_hscData )) {
Status = LICENSE_STATUS_INVALID_CERTIFICATE;
}
} except( EXCEPTION_EXECUTE_HANDLER ) {
#if DBG
DbgPrint("LSCSP: LsCsp_Initialize bad cert data!\n");
#endif
Status = LICENSE_STATUS_INVALID_CERTIFICATE;
}
Status = ReloadCSPCertificateAndData();
if (LICENSE_STATUS_NO_CERTIFICATE == Status)
{
//
// No X509 certificate. Not a failure, as the discovery
// thread will soon install it.
//
Status = LICENSE_STATUS_OK;
}
else if(LICENSE_STATUS_OUT_OF_MEMORY == Status)
{
//
// out of memory at initialization time,
// this is critical error
//
goto ErrorExit;
}
//
// Let initalization go thru if it can retrieve
// private key from LSA, this is OK since we will try to install
// certificate again in LsCsp_InstallX509Certificate()
//
Status = LICENSE_STATUS_OK;
goto i_done;
ErrorExit:
LsCsp_Exit();
i_done:
return( Status );
}
/*++
Function:
LsCsp_Exit
Description:
Free all resources used by this library.
Arguments:
Nothing.
Return:
A LICENSE_STATUS return code.
--*/
VOID LsCsp_Exit( void )
{
if( InterlockedDecrement( &csp_InitCount ) > 0 )
{
//
// someone is still using it.
//
return;
}
if ( csp_abServerPrivateKey)
{
LocalFree( csp_abServerPrivateKey );
}
csp_abServerPrivateKey = NULL;
if ( csp_abServerCertificate )
{
LocalFree( csp_abServerCertificate );
}
csp_abServerCertificate = NULL;
if( csp_abServerX509Cert )
{
LocalFree( csp_abServerX509Cert );
}
csp_abServerX509Cert = NULL;
if( csp_abX509CertPrivateKey )
{
LocalFree( csp_abX509CertPrivateKey );
}
csp_abX509CertPrivateKey = NULL;
if( csp_abX509CertID )
{
LocalFree( csp_abX509CertID );
}
csp_abX509CertID = NULL;
if( csp_hMutex )
{
CloseHandle( csp_hMutex );
}
csp_hMutex = NULL;
return;
}
/*++
Function:
LsCsp_GetServerData
Routine Description:
This function makes and return the microsoft terminal server certificate
blob of data.
Arguments:
dwInfoDesired - What type of information to return.
pBlob - pointer to a location where the certificate blob data
pointer is returned.
pdwServerCertLen - pointer to a location where the length of the above data
is returned.
Return Value:
Windows Error Code.
--*/
LICENSE_STATUS
LsCsp_GetServerData(
LSCSPINFO Info,
LPBYTE pBlob,
LPDWORD pdwBlobLen
)
{
LICENSE_STATUS Status = LICENSE_STATUS_OK;
DWORD dwDataLen;
LPBYTE pbData;
ASSERT( pdwBlobLen != NULL );
if ((Info == LsCspInfo_PrivateKey) || (Info == LsCspInfo_X509CertPrivateKey))
{
if (!IsSystemService())
{
return LICENSE_STATUS_NO_PRIVATE_KEY;
}
}
ACQUIRE_EXCLUSIVE_ACCESS(csp_hMutex);
switch (Info) {
case LsCspInfo_Certificate:
if( NULL == csp_abServerCertificate )
{
Status = LICENSE_STATUS_NO_CERTIFICATE;
goto gsd_done;
}
pbData = csp_abServerCertificate;
dwDataLen = csp_dwServerCertificateLen;
break;
case LsCspInfo_X509Certificate:
//
// We may not have an X509 certificate if the hydra server has not
// requested one from the license server
//
if( NULL == csp_abServerX509Cert )
{
Status = LICENSE_STATUS_NO_CERTIFICATE;
goto gsd_done;
}
pbData = csp_abServerX509Cert;
dwDataLen = csp_dwServerX509CertLen;
break;
case LsCspInfo_X509CertID:
//
// we will not have a certificate ID if the X509 certificate is not present
//
if( NULL == csp_abX509CertID )
{
Status = LICENSE_STATUS_NO_CERTIFICATE;
goto gsd_done;
}
pbData = csp_abX509CertID;
dwDataLen = csp_dwX509CertIDLen;
break;
case LsCspInfo_PublicKey:
pbData = csp_hscData.PublicKeyData.pBlob;
dwDataLen = csp_hscData.PublicKeyData.wBlobLen;
break;
case LsCspInfo_PrivateKey:
if( NULL == csp_abServerPrivateKey )
{
Status = LICENSE_STATUS_NO_PRIVATE_KEY;
goto gsd_done;
}
pbData = csp_abServerPrivateKey;
dwDataLen = csp_dwServerPrivateKeyLen;
break;
case LsCspInfo_X509CertPrivateKey:
//
// The X509 certificate private key may not have been created.
//
if( NULL == csp_abX509CertPrivateKey )
{
Status = LICENSE_STATUS_NO_PRIVATE_KEY;
goto gsd_done;
}
pbData = csp_abX509CertPrivateKey;
dwDataLen = csp_dwX509CertPrivateKeyLen;
break;
default:
Status = LICENSE_STATUS_INVALID_INPUT;
goto gsd_done;
}
if (pBlob != NULL) {
if (*pdwBlobLen < dwDataLen) {
*pdwBlobLen = dwDataLen;
Status = LICENSE_STATUS_INSUFFICIENT_BUFFER;
} else {
memcpy(pBlob, pbData, dwDataLen);
*pdwBlobLen = dwDataLen;
}
} else {
*pdwBlobLen = dwDataLen;
}
gsd_done:
RELEASE_EXCLUSIVE_ACCESS( csp_hMutex );
return( Status );
}
/*++
Function:
LsCsp_ReadProprietaryDataFromStorage
Description:
Read proprietary public/private info from registry/LSA secret
Arguments:
None.
Return:
LICENSE_STATUS
--*/
LICENSE_STATUS
LsCsp_ReadProprietaryDataFromStorage(PBYTE *ppbCert,
DWORD *pcbCert,
PBYTE *ppbPrivateKey,
DWORD *pcbPrivateKey)
{
LICENSE_STATUS Status;
HKEY hKey = NULL;
DWORD dwDisp;
*ppbCert = *ppbPrivateKey = NULL;
*pcbCert = *pcbPrivateKey = 0;
//
// Open the Registry
//
if( RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
TEXT( HYDRA_CERT_REG_KEY ),
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&hKey,
&dwDisp ) != ERROR_SUCCESS )
{
Status = LICENSE_STATUS_NO_CERTIFICATE;
goto done;
}
if ( RegQueryValueEx(
hKey,
TEXT( HYDRA_CERTIFICATE_VALUE ),
NULL, // lpReserved
NULL, // lpType
NULL, // lpData
pcbCert) != ERROR_SUCCESS )
{
Status = LICENSE_STATUS_NO_CERTIFICATE;
goto done;
}
Status = LsCsp_RetrieveSecret(PRIVATE_KEY_NAME,
NULL, // pbKey
pcbPrivateKey);
if (LICENSE_STATUS_OK != Status)
{
goto done;
}
*ppbCert = ( LPBYTE )LocalAlloc(LPTR,*pcbCert);
if (NULL == *ppbCert)
{
Status = LICENSE_STATUS_OUT_OF_MEMORY;
goto done;
}
*ppbPrivateKey = ( LPBYTE )LocalAlloc(LPTR,*pcbPrivateKey);
if (NULL == *ppbPrivateKey)
{
Status = LICENSE_STATUS_OUT_OF_MEMORY;
goto done;
}
if ( RegQueryValueEx(
hKey,
TEXT( HYDRA_CERTIFICATE_VALUE ),
NULL, // lpReserved
NULL, // lpType
*ppbCert,
pcbCert) != ERROR_SUCCESS )
{
Status = LICENSE_STATUS_NO_CERTIFICATE;
goto done;
}
Status = LsCsp_RetrieveSecret(PRIVATE_KEY_NAME,
*ppbPrivateKey,
pcbPrivateKey);
done:
if (NULL != hKey)
RegCloseKey(hKey);
if (Status != LICENSE_STATUS_OK)
{
if (NULL != *ppbCert)
{
LocalFree(*ppbCert);
*ppbCert = NULL;
*pcbCert = 0;
}
if (NULL != *ppbPrivateKey)
{
LocalFree(*ppbPrivateKey);
*ppbPrivateKey = NULL;
*pcbPrivateKey = 0;
}
}
return Status;
}
/*++
Function:
LsCsp_UseBuiltInCert
Description:
Initialize the global variables with hardcoded certificate.
Arguments:
None.
Return:
TRUE if the initialization is successful.
--*/
BOOL
LsCsp_UseBuiltInCert( void )
{
LICENSE_STATUS Status;
ACQUIRE_EXCLUSIVE_ACCESS(csp_hMutex);
//
// Step 1, cleanup and initialization that happened
//
if (csp_abServerPrivateKey)
{
LocalFree( csp_abServerPrivateKey );
csp_abServerPrivateKey = NULL;
}
if (csp_abServerCertificate)
{
LocalFree( csp_abServerCertificate );
csp_abServerCertificate = NULL;
}
//
// Step 2, check for stored key and certificate
//
Status = LsCsp_ReadProprietaryDataFromStorage(&csp_abServerCertificate, &csp_dwServerCertificateLen,&csp_abServerPrivateKey, &csp_dwServerPrivateKeyLen);
if (LICENSE_STATUS_OK != Status)
{
PBYTE pbPrivateKey, pbCertificate;
DWORD cbPrivateKey, cbCertificate;
//
// Step 3, if no stored info found, generate new info and store it
//
Status = CreateProprietaryKeyAndCert(&pbPrivateKey,&cbPrivateKey,&pbCertificate,&cbCertificate);
if (LICENSE_STATUS_OK == Status)
{
LsCsp_SetServerData(LsCspInfo_PrivateKey,pbPrivateKey,cbPrivateKey);
LsCsp_SetServerData(LsCspInfo_Certificate,pbCertificate,cbCertificate);
}
}
RELEASE_EXCLUSIVE_ACCESS( csp_hMutex );
return( Status == LICENSE_STATUS_OK );
}
/*++
Function:
LsCsp_InstallX509Certificate
Routine Description:
This function generates a private/public key pair and then finds a
license server to issue an X509 certificate for the public key.
It then stores the private key and certificate.
Arguments:
None.
Return Value:
LSCSP return code.
--*/
LICENSE_STATUS
LsCsp_InstallX509Certificate(LPVOID lpParam)
{
DWORD
cbPubKey,
cbPrivKey,
cbCertificate;
LICENSE_STATUS
Status;
LPBYTE
pbPubKey = NULL,
pbPrivKey = NULL,
pbCertificate = NULL;
CERT_PUBLIC_KEY_INFO
CapiPubKeyInfo;
HWID
Hwid;
TLS_HANDLE
hServer;
//
// before we go through the trouble of generating private and public
// keys, check if the license server is available.
//
hServer = TLSConnectToAnyLsServer(LS_DISCOVERY_TIMEOUT);
if (NULL == hServer)
{
return( LICENSE_STATUS_NO_LICENSE_SERVER );
}
memset(&CapiPubKeyInfo, 0, sizeof(CapiPubKeyInfo));
//
// acquire exclusive access
//
ACQUIRE_EXCLUSIVE_ACCESS(csp_hMutex);
//
// Try to reload the certificate again, some other thread might have
// install the certificate already.
//
Status = ReloadCSPCertificateAndData();
if( LICENSE_STATUS_OK == Status )
{
goto done;
}
//
// Generate a private/public key pair
//
Status = GenerateRsaKeyPair(
&pbPubKey,
&cbPubKey,
&pbPrivKey,
&cbPrivKey,
RSA_KEY_LEN );
if( LICENSE_STATUS_OK != Status )
{
#if DBG
DbgPrint( "LSCSP: LsCsp_InstallX509Certificate: cannot generate RSA keypair\n" );
#endif
goto done;
}
//
// convert the Bsafe public key into a CAPI public key
//
Status = Bsafe2CapiPubKey( &CapiPubKeyInfo, pbPubKey, cbPubKey );
if( LICENSE_STATUS_OK != Status )
{
#if DBG
DbgPrint( "LSCSP: LsCsp_InstallX509Certificate: cannot convert Bsafe Key to CAPI key\n" );
#endif
goto done;
}
//
// generate a new hardware ID
//
Status = GenerateMachineHWID( &Hwid );
if( LICENSE_STATUS_OK != Status )
{
#if DBG
DbgPrint( "LSCSP: LsCsp_InstallX509Certificate: cannot generate certificate ID\n" );
#endif
goto done;
}
//
// sends the certificate request to the license server
//
Status = RequestCertificate( hServer, &CapiPubKeyInfo, &pbCertificate, &cbCertificate, &Hwid );
TLSDisconnectFromServer( hServer );
hServer = NULL;
if( LICENSE_STATUS_OK != Status )
{
#if DBG
DbgPrint( "LSCSP: LsCsp_InstallX509Certificate: error requesting terminal server certificate: %x\n", Status );
#endif
goto done;
}
//
// store the certificate identifier
//
Status = LsCsp_SetServerData(
LsCspInfo_X509CertID,
( LPBYTE )&Hwid,
sizeof( Hwid ) );
if( LICENSE_STATUS_OK != Status )
{
#if DBG
DbgPrint( "LSCSP: LsCsp_InstallX509Certificate: cannot store terminal server certificate ID : %d\n", Status );
#endif
goto done;
}
//
// Stores the certificate and resets the global variable pointing
// to the X509 certificate.
//
Status = LsCsp_SetServerData(
LsCspInfo_X509Certificate,
pbCertificate,
cbCertificate );
if( LICENSE_STATUS_OK != Status )
{
#if DBG
DbgPrint( "LSCSP: LsCsp_InstallX509Certificate: cannot store terminal server certificate : %d\n", Status );
#endif
goto done;
}
//
// Stores the private key and resets the global variable pointing to the
// private key.
//
Status = LsCsp_SetServerData(
LsCspInfo_X509CertPrivateKey,
pbPrivKey,
cbPrivKey );
if( LICENSE_STATUS_OK != Status )
{
#if DBG
DbgPrint( "LSCSP: LsCsp_InstallX509Certificate: cannot store terminal server private key %d\n", Status );
#endif
goto done;
}
//
// Store the public key so we can verify at startup time
//
Status = LsCsp_StoreSecret(
X509_CERT_PUBLIC_KEY_NAME,
pbPubKey,
cbPubKey
);
if( LICENSE_STATUS_OK != Status )
{
#if DBG
DbgPrint( "LSCSP: LsCsp_InstallX509Certificate: cannot store terminal server public key : %d\n", Status );
#endif
}
done:
if (NULL != hServer)
{
TLSDisconnectFromServer( hServer );
hServer = NULL;
}
//
// release exclusive access
//
RELEASE_EXCLUSIVE_ACCESS( csp_hMutex );
if( pbCertificate )
{
LocalFree(pbCertificate);
}
if( pbPrivKey )
{
LocalFree( pbPrivKey );
}
if( pbPubKey )
{
LocalFree( pbPubKey );
}
FreeCapiPubKey( &CapiPubKeyInfo );
return( Status );
}
/*++
Function:
RequestCertificate
Routine Description:
Request a certificate from the license server
Arguments:
hServer - handle to license server
pPubKeyInfo - The public key info to be included in the certificate
ppbCertificate - The new certificate
pcbCertificate - size of the certificate
pHwid - The hardware ID that is used to identify the certificate
Return:
LICENSE_STATUS return code
--*/
LICENSE_STATUS
RequestCertificate(
TLS_HANDLE hServer,
PCERT_PUBLIC_KEY_INFO pPubKeyInfo,
LPBYTE * ppbCertificate,
LPDWORD pcbCertificate,
HWID * pHwid )
{
LSHydraCertRequest
CertRequest;
LICENSE_STATUS
Status;
DWORD
dwRpcCode,
dwResult,
cbChallengeData;
LPBYTE
pbChallengeData = NULL;
if( ( NULL == ppbCertificate ) ||
( NULL == hServer ) ||
( NULL == pPubKeyInfo ) ||
( NULL == pcbCertificate ) )
{
return( LICENSE_STATUS_INVALID_INPUT );
}
*ppbCertificate = NULL;
*pcbCertificate = 0;
memset( &CertRequest, 0, sizeof( CertRequest ) );
CertRequest.dwHydraVersion = 0x00050000;
LsCsp_EncryptHwid( pHwid, NULL, &CertRequest.cbEncryptedHwid );
CertRequest.pbEncryptedHwid = LocalAlloc( LPTR, CertRequest.cbEncryptedHwid );
if( NULL == CertRequest.pbEncryptedHwid )
{
return LICENSE_STATUS_OUT_OF_MEMORY;
}
Status = LsCsp_EncryptHwid(
pHwid,
CertRequest.pbEncryptedHwid,
&CertRequest.cbEncryptedHwid );
if( LICENSE_STATUS_OK != Status )
{
goto done;
}
//
// get the subject RDN
//
Status = GetSubjectRdn( &CertRequest.szSubjectRdn );
if( LICENSE_STATUS_OK != Status )
{
goto done;
}
CertRequest.SubjectPublicKeyInfo = pPubKeyInfo;
//
// request an X509 certificate from the license server
//
dwRpcCode = TLSRequestTermServCert(hServer,
&CertRequest,
&cbChallengeData,
&pbChallengeData,
&dwResult );
if( ( RPC_S_OK != dwRpcCode ) || ( LSERVER_S_SUCCESS != dwResult ) )
{
Status = LICENSE_STATUS_CERTIFICATE_REQUEST_ERROR;
goto done;
}
dwRpcCode = TLSRetrieveTermServCert(
hServer,
cbChallengeData,
pbChallengeData,
pcbCertificate,
ppbCertificate,
&dwResult );
if( ( RPC_S_OK != dwRpcCode ) || ( LSERVER_ERROR_BASE <= dwResult ) )
{
Status = LICENSE_STATUS_CERTIFICATE_REQUEST_ERROR;
}
done:
if( CertRequest.pbEncryptedHwid )
{
LocalFree( CertRequest.pbEncryptedHwid );
}
if( CertRequest.szSubjectRdn )
{
LocalFree( CertRequest.szSubjectRdn );
}
if( pbChallengeData )
{
LocalFree( pbChallengeData );
}
return( Status );
}
/*++
Function:
GetSubjectRdn
Routine Description:
Construct the subject RDN for a certificate request
Argument:
ppSubjectRdn - Return pointer to the subject RDN
Return:
LICENSE_STATUS_OK if successful or a LICENSE_STATUS error code.
--*/
LICENSE_STATUS
GetSubjectRdn(
LPTSTR * ppSubjectRdn )
{
TCHAR
ComputerName[ MAX_COMPUTERNAME_LENGTH + 1 ];
DWORD
RdnLen = 0,
ComputerNameLen = MAX_COMPUTERNAME_LENGTH + 1;
//
// use the computer name uas the common name
//
GetComputerName( ComputerName, &ComputerNameLen );
RdnLen += wcslen( TEXT( RDN_COMMON_NAME ) );
RdnLen += ComputerNameLen + 1;
RdnLen = RdnLen * sizeof( TCHAR );
*ppSubjectRdn = LocalAlloc( LPTR, RdnLen );
if( NULL == *ppSubjectRdn )
{
return( LICENSE_STATUS_OUT_OF_MEMORY );
}
wsprintf( *ppSubjectRdn, L"%s%s", TEXT( RDN_COMMON_NAME ), ComputerName );
return( LICENSE_STATUS_OK );
}
/*++
Function:
GenerateMachineHWID
Routine Description:
Generate a hardware ID for this machine
Arguments:
pHwid - Return value of the HWID
Return:
LICENSE_STATUS_OK if successful or a LICENSE_STATUS error code
--*/
LICENSE_STATUS
GenerateMachineHWID(
PHWID pHwid )
{
OSVERSIONINFO
osvInfo;
DWORD
cbCertId;
LPBYTE
pbCertId = NULL;
if( NULL == pHwid )
{
return( LICENSE_STATUS_INVALID_INPUT );
}
//
// Create the HWID
//
memset( &osvInfo, 0, sizeof( OSVERSIONINFO ) );
osvInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
GetVersionEx( &osvInfo );
pHwid->dwPlatformID = osvInfo.dwPlatformId;
GenerateRandomBits( ( LPBYTE )&( pHwid->Data1 ), sizeof( DWORD ) );
GenerateRandomBits( ( LPBYTE )&( pHwid->Data2 ), sizeof( DWORD ) );
GenerateRandomBits( ( LPBYTE )&( pHwid->Data3 ), sizeof( DWORD ) );
GenerateRandomBits( ( LPBYTE )&( pHwid->Data4 ), sizeof( DWORD ) );
return( LICENSE_STATUS_OK );
}
/*++
Function:
LsCsp_EncryptHwid
Routine Description:
Encrypt the given hardward ID using the secret key shared by terminal
and license servers.
Arguments:
pHwid - The Hardware ID
pbEncryptedHwid - The encrypted HWID
pcbEncryptedHwid - Length of the encrypted HWID
Return:
LICENSE_STATUS_OK if successful or a LICENSE_STATUS error code otherwise.
--*/
LICENSE_STATUS
LsCsp_EncryptHwid(
PHWID pHwid,
LPBYTE pbEncryptedHwid,
LPDWORD pcbEncryptedHwid )
{
LICENSE_STATUS
Status;
LPBYTE
pbSecretKey = NULL;
DWORD
cbSecretKey = 0;
if( NULL == pcbEncryptedHwid )
{
return( LICENSE_STATUS_INVALID_INPUT );
}
if( ( NULL == pbEncryptedHwid ) ||
( sizeof( HWID ) > *pcbEncryptedHwid ) )
{
*pcbEncryptedHwid = sizeof( HWID );
return( LICENSE_STATUS_INSUFFICIENT_BUFFER );
}
LicenseGetSecretKey( &cbSecretKey, NULL );
pbSecretKey = LocalAlloc( LPTR, cbSecretKey );
if( NULL == pbSecretKey )
{
return( LICENSE_STATUS_OUT_OF_MEMORY );
}
//
// Get the secret key used for encrypting the HWID
//
Status = LicenseGetSecretKey( &cbSecretKey, pbSecretKey );
if( LICENSE_STATUS_OK != Status )
{
goto done;
}
Status = LicenseEncryptHwid(
pHwid,
pcbEncryptedHwid,
pbEncryptedHwid,
cbSecretKey,
pbSecretKey );
done:
if( pbSecretKey )
{
LocalFree( pbSecretKey );
}
return( Status );
}
/*++
Function:
LsCsp_DecryptHwid
Routine Description:
Decrypt the given hardware ID
Arguments:
pHwid - The decrypted hardware ID
pbEncryptedHwid - The encrypted hardware ID
cbEncryptedHwid - Length of the encrypted hardware ID
Return:
LICENSE_STATUS_OK if successful or a LICENSE_STATUS error code.
--*/
LICENSE_STATUS
LsCsp_DecryptHwid(
PHWID pHwid,
LPBYTE pbEncryptedHwid,
LPDWORD pcbEncryptedHwid )
{
return( LICENSE_STATUS_OK );
}
/*++
Function:
LsCsp_StoreSecret
Description:
Use LSA to store a secret private key.
Arguments:
ptszKeyName - Name used to identify the secret private key.
pbKey - Points to the secret private key.
cbKey - Length of the private key.
Return:
A LICENSE_STATUS return code.
--*/
LICENSE_STATUS
LsCsp_StoreSecret(
PTCHAR ptszKeyName,
BYTE * pbKey,
DWORD cbKey )
{
LSA_HANDLE
PolicyHandle;
UNICODE_STRING
SecretKeyName;
UNICODE_STRING
SecretData;
DWORD
Status;
if( ( NULL == ptszKeyName ) || ( 0xffff < cbKey) )
{
return( LICENSE_STATUS_INVALID_INPUT );
}
//
// setup the UNICODE_STRINGs for the call.
//
InitLsaString( &SecretKeyName, ptszKeyName );
SecretData.Buffer = ( LPWSTR )pbKey;
SecretData.Length = ( USHORT )cbKey;
SecretData.MaximumLength = ( USHORT )cbKey;
Status = OpenPolicy( NULL, POLICY_CREATE_SECRET, &PolicyHandle );
if( ERROR_SUCCESS != Status )
{
return ( LICENSE_STATUS_CANNOT_OPEN_SECRET_STORE );
}
Status = LsaStorePrivateData(
PolicyHandle,
&SecretKeyName,
&SecretData
);
LsaClose( PolicyHandle );
Status = LsaNtStatusToWinError( Status );
if( ERROR_SUCCESS != Status )
{
return( LICENSE_STATUS_CANNOT_STORE_SECRET );
}
return( LICENSE_STATUS_OK );
}
/*++
Function:
LsCsp_RetrieveSecret
Description:
Retrieve the secret private key that is stored by LSA.
Arguments:
ptszKeyName - The name used to identify the secret private key.
ppbKey - Return value of the private key
pcbKey - Length of the private key.
Return:
A LICENSE_STATUS return code.
--*/
LICENSE_STATUS
LsCsp_RetrieveSecret(
PTCHAR ptszKeyName,
PBYTE pbKey,
DWORD * pcbKey )
{
LSA_HANDLE
PolicyHandle;
UNICODE_STRING
SecretKeyName;
UNICODE_STRING *
pSecretData = NULL;
DWORD
Status;
LICENSE_STATUS
LicenseStatus = LICENSE_STATUS_OK;
if( ( NULL == ptszKeyName ) || ( NULL == pcbKey ) )
{
return( ERROR_INVALID_PARAMETER );
}
//
// setup the UNICODE_STRINGs for the call.
//
InitLsaString( &SecretKeyName, ptszKeyName );
Status = OpenPolicy( NULL, POLICY_GET_PRIVATE_INFORMATION, &PolicyHandle );
if( ERROR_SUCCESS != Status )
{
#if DBG
DbgPrint( "LSCSP: cannot open LSA policy handle: %x\n", Status );
#endif
return( LICENSE_STATUS_CANNOT_OPEN_SECRET_STORE );
}
Status = LsaNtStatusToWinError( LsaRetrievePrivateData(
PolicyHandle,
&SecretKeyName,
&pSecretData ) );
LsaClose( PolicyHandle );
if (( ERROR_SUCCESS != Status ) || (NULL == pSecretData) || (pSecretData->Length == 0))
{
#if DBG
DbgPrint( "LSCSP: cannot retrieve LSA data: %x\n", Status );
#endif
return( LICENSE_STATUS_CANNOT_RETRIEVE_SECRET );
}
if( NULL == pbKey )
{
*pcbKey = pSecretData->Length;
}
else
{
if( pSecretData->Length > *pcbKey )
{
LicenseStatus = LICENSE_STATUS_INSUFFICIENT_BUFFER;
}
else
{
CopyMemory( pbKey, pSecretData->Buffer, pSecretData->Length );
}
*pcbKey = pSecretData->Length;
}
ZeroMemory( pSecretData->Buffer, pSecretData->Length );
LsaFreeMemory( pSecretData );
return( LicenseStatus );
}
/*++
Function:
OpenPolicy
Description:
Obtain an LSA policy handle used to perform subsequent LSA operations.
Arguments:
ServerName - The server which the handle should be obtained from.
DesiredAccess - The access given to the handle
PolicyHandle - The policy handle
Return:
A Win32 return code.
--*/
NTSTATUS
OpenPolicy(
LPWSTR ServerName,
DWORD DesiredAccess,
PLSA_HANDLE PolicyHandle )
{
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
LSA_UNICODE_STRING ServerString;
PLSA_UNICODE_STRING Server;
//
// Always initialize the object attributes to all zeroes.
//
ZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) );
if( NULL != ServerName )
{
//
// Make a LSA_UNICODE_STRING out of the LPWSTR passed in
//
InitLsaString(&ServerString, ServerName);
Server = &ServerString;
}
else
{
Server = NULL;
}
//
// Attempt to open the policy.
//
return( LsaNtStatusToWinError( LsaOpenPolicy(
Server,
&ObjectAttributes,
DesiredAccess,
PolicyHandle ) ) );
}
/*++
Function:
InitLsaString
Description:
Initialize a UNICODE string to LSA UNICODE string format.
Arguments:
LsaString - the LSA UNICODE string.
String - UNICODE string
Return:
Nothing.
--*/
void
InitLsaString(
PLSA_UNICODE_STRING LsaString,
LPWSTR String )
{
DWORD StringLength;
if( NULL == String )
{
LsaString->Buffer = NULL;
LsaString->Length = 0;
LsaString->MaximumLength = 0;
return;
}
StringLength = lstrlenW( String );
LsaString->Buffer = String;
LsaString->Length = ( USHORT ) StringLength * sizeof( WCHAR );
LsaString->MaximumLength=( USHORT )( StringLength + 1 ) * sizeof( WCHAR );
}
/*++
Function:
LsCsp_SetServerData
Description:
Saves the specified data.
Arguments:
Info - The data type of the data to be saved.
pBlob - Points to the data to be saved.
dwBlobLen - Length of the data to be saved.
Return:
A LICENSE_STATUS return code.
--*/
LICENSE_STATUS
LsCsp_SetServerData(
LSCSPINFO Info,
LPBYTE pBlob,
DWORD dwBlobLen )
{
LICENSE_STATUS
Status = LICENSE_STATUS_OK;
DWORD
dwResult,
dwDisp,
* pdwCspDataLen;
LPTSTR
lpRegValue;
PWCHAR
pwszKeyName;
LPBYTE *
ppCspData;
HKEY
hKey = NULL;
ASSERT( dwBlobLen != 0 );
ASSERT( pBlob != NULL );
ACQUIRE_EXCLUSIVE_ACCESS(csp_hMutex);
switch (Info) {
case LsCspInfo_Certificate:
//
// set proprietory certificate data
//
lpRegValue = TEXT( HYDRA_CERTIFICATE_VALUE );
ppCspData = &csp_abServerCertificate;
pdwCspDataLen = &csp_dwServerCertificateLen;
break;
case LsCspInfo_X509Certificate:
//
// set X509 certificate data
//
lpRegValue = TEXT( HYDRA_X509_CERTIFICATE );
ppCspData = &csp_abServerX509Cert;
pdwCspDataLen = &csp_dwServerX509CertLen;
break;
case LsCspInfo_PrivateKey:
//
// set the private key that corresponds to the proprietory certificate
//
pwszKeyName = PRIVATE_KEY_NAME;
ppCspData = &csp_abServerPrivateKey;
pdwCspDataLen = &csp_dwServerPrivateKeyLen;
break;
case LsCspInfo_X509CertPrivateKey:
//
// set private key that corresponds to the X509 certificate
//
pwszKeyName = X509_CERT_PRIVATE_KEY_NAME;
ppCspData = &csp_abX509CertPrivateKey;
pdwCspDataLen = &csp_dwX509CertPrivateKeyLen;
break;
case LsCspInfo_X509CertID:
//
// Set the X509 certificate ID
//
lpRegValue = TEXT( HYDRA_X509_CERT_ID );
ppCspData = &csp_abX509CertID;
pdwCspDataLen = &csp_dwX509CertIDLen;
break;
default:
Status = LICENSE_STATUS_INVALID_INPUT;
goto i_done;
}
if( ( LsCspInfo_X509CertPrivateKey == Info ) ||
( LsCspInfo_PrivateKey == Info ) )
{
//
// store secret key information
//
dwResult = LsCsp_StoreSecret( pwszKeyName, pBlob, dwBlobLen );
if( ERROR_SUCCESS != dwResult )
{
Status = LICENSE_STATUS_WRITE_STORE_ERROR;
goto i_done;
}
}
else
{
//
// Open the Registry
//
if( RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
TEXT( HYDRA_CERT_REG_KEY ),
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hKey,
&dwDisp ) != ERROR_SUCCESS )
{
Status = LICENSE_STATUS_WRITE_STORE_ERROR;
goto i_done;
}
//
// Sets the value in the registry
//
if( ERROR_SUCCESS != RegSetValueEx(
hKey,
lpRegValue,
0,
REG_BINARY,
pBlob,
dwBlobLen ) )
{
Status = LICENSE_STATUS_WRITE_STORE_ERROR;
goto i_done;
}
}
//
// reset the global data with the new data that we have just set
//
if ( *ppCspData )
{
LocalFree( *ppCspData );
}
*ppCspData = ( LPBYTE )LocalAlloc( LPTR, dwBlobLen );
if( NULL == *ppCspData )
{
Status = LICENSE_STATUS_OUT_OF_MEMORY;
goto i_done;
}
memcpy( *ppCspData, pBlob, dwBlobLen );
*pdwCspDataLen = dwBlobLen;
i_done:
RELEASE_EXCLUSIVE_ACCESS( csp_hMutex );
if( hKey )
{
RegCloseKey( hKey );
}
return( Status );
}
/*++
Function:
LsCsp_NukeServerData
Description:
Permanently deletes the specified server data.
Arguments:
Info - The type of data to nuke.
Returns:
A LICENSE_STATUS return code.
--*/
LICENSE_STATUS
LsCsp_NukeServerData(
LSCSPINFO Info )
{
LICENSE_STATUS
Status = LICENSE_STATUS_OK;
LPTSTR
lpRegValue;
PWCHAR
pwszKeyName;
HKEY
hKey = NULL;
LPBYTE *
ppCspData;
DWORD *
pdwCspDataLen;
DWORD
dwResult;
ACQUIRE_EXCLUSIVE_ACCESS(csp_hMutex);
switch (Info) {
case LsCspInfo_X509Certificate:
//
// delete X509 certificate data
//
lpRegValue = TEXT( HYDRA_X509_CERTIFICATE );
ppCspData = &csp_abServerX509Cert;
pdwCspDataLen = &csp_dwServerX509CertLen;
break;
case LsCspInfo_X509CertPrivateKey:
//
// delete the private key that corresponds to the X509 certificate
//
pwszKeyName = X509_CERT_PRIVATE_KEY_NAME;
ppCspData = &csp_abX509CertPrivateKey;
pdwCspDataLen = &csp_dwX509CertPrivateKeyLen;
break;
case LsCspInfo_X509CertID:
//
// delete the X509 certificate ID
//
lpRegValue = TEXT( HYDRA_X509_CERT_ID );
ppCspData = &csp_abX509CertID;
pdwCspDataLen = &csp_dwX509CertIDLen;
break;
default:
Status = LICENSE_STATUS_INVALID_INPUT;
goto i_done;
}
if( (LsCspInfo_X509CertPrivateKey == Info ) ||
( LsCspInfo_PrivateKey == Info ) )
{
//
// delete secret info stored by LSA
//
dwResult = LsCsp_StoreSecret( pwszKeyName, NULL, 0 );
if( ERROR_SUCCESS != dwResult )
{
Status = LICENSE_STATUS_WRITE_STORE_ERROR;
goto i_done;
}
}
else
{
//
// Delete the data kept in the registry
//
if( RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
TEXT( HYDRA_CERT_REG_KEY ),
0,
KEY_WRITE,
&hKey ) != ERROR_SUCCESS )
{
Status = LICENSE_STATUS_WRITE_STORE_ERROR;
goto i_done;
}
//
// Delete the value in the registry
//
if( ERROR_SUCCESS != RegDeleteValue( hKey, lpRegValue ) )
{
Status = LICENSE_STATUS_WRITE_STORE_ERROR;
goto i_done;
}
}
if ( *ppCspData )
{
//
// free the memory allocated for the global variable.
//
LocalFree( *ppCspData );
*ppCspData = NULL;
*pdwCspDataLen = 0;
}
i_done:
RELEASE_EXCLUSIVE_ACCESS( csp_hMutex );
if( hKey )
{
RegCloseKey( hKey );
}
return( Status );
}
/*++
Function:
GenerateKeyPair
Routine Description:
This function generates a private/public key pair.
Arguments:
ppbPublicKey - Return pointer to public Key
pcbPublicKey - Size of public key
ppbPrivateKey - Return pointer to private key
pcbPrivateKey - size of private key
dwKeyLen - Desired key length
Return Value:
LICENSE_STATUS return code.
--*/
LICENSE_STATUS
GenerateRsaKeyPair(
LPBYTE * ppbPublicKey,
LPDWORD pcbPublicKey,
LPBYTE * ppbPrivateKey,
LPDWORD pcbPrivateKey,
DWORD dwKeyLen )
{
DWORD
dwBits = dwKeyLen;
LICENSE_STATUS
Status = LICENSE_STATUS_OK;
*ppbPublicKey = NULL;
*ppbPrivateKey = NULL;
//
// find out the size of the private and public key sizes and allocate
// memory for them.
//
dwBits = BSafeComputeKeySizes( pcbPublicKey, pcbPrivateKey, &dwBits );
*ppbPrivateKey = ( LPBYTE )LocalAlloc( LPTR, *pcbPrivateKey );
if( NULL == *ppbPrivateKey )
{
Status = LICENSE_STATUS_OUT_OF_MEMORY;
goto ErrorExit;
}
*ppbPublicKey = ( LPBYTE )LocalAlloc( LPTR, *pcbPublicKey );
if( NULL == *ppbPublicKey )
{
Status = LICENSE_STATUS_OUT_OF_MEMORY;
goto ErrorExit;
}
//
// generate the private/public key pair
//
if( !BSafeMakeKeyPair( ( LPBSAFE_PUB_KEY )*ppbPublicKey,
( LPBSAFE_PRV_KEY )*ppbPrivateKey,
dwKeyLen) )
{
Status = LICENSE_STATUS_CANNOT_MAKE_KEY_PAIR;
goto ErrorExit;
}
return( Status );
ErrorExit:
if( *ppbPublicKey )
{
LocalFree( *ppbPublicKey );
*pcbPublicKey = 0;
*ppbPublicKey = NULL;
}
if( *ppbPrivateKey )
{
LocalFree( *ppbPrivateKey );
*pcbPrivateKey = 0;
*ppbPrivateKey = NULL;
}
return( Status );
}
/*++
Function:
Bsafe2CapiPubKey
Routine Description:
Converts a Bsafe public key to a CAPI public key info structure
Arguments:
pCapiPubKeyInfo - Pointer to the CAPI public key info structure
pbBsafePubKey - Pointer to the Bsafe public key
cbBsafePubKey - size of the Bsafe public key
Returns:
LICENSE_STATUS return code.
--*/
LICENSE_STATUS
Bsafe2CapiPubKey(
PCERT_PUBLIC_KEY_INFO pCapiPubKeyInfo,
LPBYTE pbBsafeKey,
DWORD cbBsafeKey )
{
PUBLICKEYSTRUC *
pCapiPublicKey;
RSAPUBKEY *
pRsaPublicKey;
LPBSAFE_PUB_KEY
pBsafePubKey = ( LPBSAFE_PUB_KEY )pbBsafeKey;
LPBYTE
pbKeyMem = NULL,
pbEncodedPubKey = NULL;
DWORD
cbKeyMem,
dwError,
cbEncodedPubKey = 0;
LICENSE_STATUS
Status;
if( ( NULL == pbBsafeKey ) || ( 0 == cbBsafeKey ) )
{
return( LICENSE_STATUS_INVALID_INPUT );
}
cbKeyMem = sizeof( PUBLICKEYSTRUC ) + sizeof( RSAPUBKEY ) + pBsafePubKey->keylen;
pbKeyMem = ( LPBYTE )LocalAlloc( LPTR, cbKeyMem );
if( NULL == pbKeyMem )
{
return( LICENSE_STATUS_OUT_OF_MEMORY );
}
//
// convert the Bsafe public key to a crypto API public key structure.
// Note: make this a key exchange public key
//
pCapiPublicKey = ( PUBLICKEYSTRUC * )pbKeyMem;
pCapiPublicKey->bType = PUBLICKEYBLOB;
pCapiPublicKey->bVersion = CAPI_MAX_VERSION;
pCapiPublicKey->reserved = 0;
pCapiPublicKey->aiKeyAlg = CALG_RSA_KEYX;
pRsaPublicKey = ( RSAPUBKEY * )( pbKeyMem + sizeof( PUBLICKEYSTRUC ) );
pRsaPublicKey->magic = RSA1;
pRsaPublicKey->bitlen = pBsafePubKey->bitlen;
pRsaPublicKey->pubexp = pBsafePubKey->pubexp;
memcpy( pbKeyMem + sizeof( PUBLICKEYSTRUC ) + sizeof( RSAPUBKEY ),
pbBsafeKey + sizeof( BSAFE_PUB_KEY ),
pBsafePubKey->keylen );
//
// encode the public key structure
//
__try
{
if( CryptEncodeObject( X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB , pbKeyMem,
NULL, &cbEncodedPubKey ) )
{
pbEncodedPubKey = ( LPBYTE )LocalAlloc( LPTR, cbEncodedPubKey );
if( NULL == pbEncodedPubKey )
{
Status = LICENSE_STATUS_OUT_OF_MEMORY;
goto done;
}
memset( pbEncodedPubKey, 0, cbEncodedPubKey );
if( !CryptEncodeObject( X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB , pbKeyMem,
pbEncodedPubKey, &cbEncodedPubKey ) )
{
Status = LICENSE_STATUS_ASN_ERROR;
goto done;
}
}
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
DWORD dwExceptionCode = GetExceptionCode();
#if DBG
DbgPrint( "LICECSP: cannot encode server key pair: 0x%x\n", dwExceptionCode );
#endif
Status = LICENSE_STATUS_ASN_ERROR;
goto done;
}
//
// now we can initialize the CAPI public key info structure
//
memset( pCapiPubKeyInfo, 0, sizeof( CERT_PUBLIC_KEY_INFO ) );
pCapiPubKeyInfo->Algorithm.pszObjId = szOID_RSA_MD5RSA;
pCapiPubKeyInfo->Algorithm.Parameters.cbData = 0;
pCapiPubKeyInfo->Algorithm.Parameters.pbData = NULL;
pCapiPubKeyInfo->PublicKey.cbData = cbEncodedPubKey;
pCapiPubKeyInfo->PublicKey.pbData = pbEncodedPubKey;
Status = LICENSE_STATUS_OK;
done:
if( pbKeyMem )
{
LocalFree( pbKeyMem );
}
return( Status );
}
/*++
Function:
FreeCapiPubKey
Routine Description:
Free the memory in a capi pub key structure
Arguments:
pCapiPubKeyInfo - Pointer to the CAPI public key info structure
Returns:
Windows return code.
--*/
VOID
FreeCapiPubKey(
PCERT_PUBLIC_KEY_INFO pCapiPubKeyInfo )
{
if( pCapiPubKeyInfo->Algorithm.Parameters.pbData )
{
LocalFree( pCapiPubKeyInfo->Algorithm.Parameters.pbData );
pCapiPubKeyInfo->Algorithm.Parameters.pbData = NULL;
}
if( pCapiPubKeyInfo->PublicKey.pbData )
{
LocalFree( pCapiPubKeyInfo->PublicKey.pbData );
pCapiPubKeyInfo->PublicKey.pbData = NULL;
}
return;
}
//////////////////////////////////////////////////////////////////
DWORD
VerifyTermServCertificate(
DWORD cbCertLen,
PBYTE pbCert,
DWORD cbPrivateKeyLen,
PBYTE pbPrivateKey
)
/*++
Function :
VerifyTermServCertificate
Routine Description:
Verify TermSrv's X509 Certificate issued License Server, caller
must protect this call with critical section or mutex.
Arguments:
cbCertLen : size of TermSrv certificate.
pbCertLen : Pointer to TermSrv certificate to be verify.
cbPrivateKeyLen : Size of TermSrv private key.
pbPrivateKey : pointer to TermSrv private key.
Returns:
TRUE/FALSE
--*/
{
LICENSE_STATUS dwStatus = LICENSE_STATUS_OK;
PBYTE pbPublicKeyInLsa = NULL;
DWORD cbPublicKeyInLsa = 0;
PBYTE pbPublicKeyInCert = NULL;
DWORD cbPublicKeyInCert = 0;
DWORD pfDates;
CERT_PUBLIC_KEY_INFO CapiPubKeyInfoLsa;
CERT_PUBLIC_KEY_INFO CapiPubKeyInfoCert;
if(0 == cbCertLen || NULL == pbCert || 0 == cbPrivateKeyLen || NULL == pbPrivateKey)
{
ASSERT( 0 != cbCertLen && NULL != pbCert && 0 != cbPrivateKeyLen && NULL != pbPrivateKey );
return LICENSE_STATUS_INVALID_INPUT;
}
//
// try except here is to prevent memory leak
//
__try {
memset(&CapiPubKeyInfoLsa, 0, sizeof(CapiPubKeyInfoLsa));
memset(&CapiPubKeyInfoCert, 0, sizeof(CapiPubKeyInfoCert));
//
// Load the public key from LSA
//
dwStatus = LsCsp_RetrieveSecret(
X509_CERT_PUBLIC_KEY_NAME,
NULL,
&cbPublicKeyInLsa
);
if( LICENSE_STATUS_OK != dwStatus || 0 == cbPublicKeyInLsa )
{
#if DBG
DbgPrint( "LSCSP: VerifyTermServCertificate() No public key...\n" );
#endif
dwStatus = LICENSE_STATUS_CANNOT_RETRIEVE_SECRET;
goto cleanup;
}
// allocate memory
pbPublicKeyInLsa = (PBYTE)LocalAlloc(LPTR, cbPublicKeyInLsa);
if(NULL == pbPublicKeyInLsa)
{
dwStatus = LICENSE_STATUS_OUT_OF_MEMORY;
goto cleanup;
}
dwStatus = LsCsp_RetrieveSecret(
X509_CERT_PUBLIC_KEY_NAME,
pbPublicKeyInLsa,
&cbPublicKeyInLsa
);
if( LICENSE_STATUS_OK != dwStatus || 0 == cbPublicKeyInLsa )
{
dwStatus = LICENSE_STATUS_CANNOT_RETRIEVE_SECRET;
goto cleanup;
}
//
// Verify certificate and compare public key
//
//
// Try to avoid calling VerifyCertChain() twice.
//
cbPublicKeyInCert = 1024;
pbPublicKeyInCert = (PBYTE)LocalAlloc(LPTR, cbPublicKeyInCert);
if(NULL == pbPublicKeyInCert)
{
dwStatus = LICENSE_STATUS_OUT_OF_MEMORY;
goto cleanup;
}
pfDates = CERT_DATE_DONT_VALIDATE;
dwStatus = VerifyCertChain(
pbCert,
cbCertLen,
pbPublicKeyInCert,
&cbPublicKeyInCert,
&pfDates
);
if(LICENSE_STATUS_OK != dwStatus && LICENSE_STATUS_INSUFFICIENT_BUFFER != dwStatus)
{
#if DBG
DbgPrint( "LSCSP: VerifyCertChain() failed with error code %d\n", dwStatus );
#endif
goto cleanup;
}
if( dwStatus == LICENSE_STATUS_INSUFFICIENT_BUFFER )
{
if( NULL != pbPublicKeyInCert )
{
LocalFree(pbPublicKeyInCert);
}
pbPublicKeyInCert = (PBYTE)LocalAlloc(LPTR, cbPublicKeyInCert);
if(NULL == pbPublicKeyInCert)
{
dwStatus = LICENSE_STATUS_OUT_OF_MEMORY;
goto cleanup;
}
pfDates = CERT_DATE_DONT_VALIDATE;
dwStatus = VerifyCertChain(
pbCert,
cbCertLen,
pbPublicKeyInCert,
&cbPublicKeyInCert,
&pfDates
);
if(LICENSE_STATUS_OK != dwStatus)
{
goto cleanup;
}
}
dwStatus = Bsafe2CapiPubKey(
&CapiPubKeyInfoCert,
pbPublicKeyInCert,
cbPublicKeyInCert
);
if(LICENSE_STATUS_OK != dwStatus)
{
#if DBG
DbgPrint(
"LSCSP: Bsafe2CapiPubKey() on public key in certificate failed with %d\n",
dwStatus
);
#endif
goto cleanup;
}
dwStatus = Bsafe2CapiPubKey(
&CapiPubKeyInfoLsa,
pbPublicKeyInLsa,
cbPublicKeyInLsa
);
if(LICENSE_STATUS_OK != dwStatus)
{
#if DBG
DbgPrint(
"LSCSP: Bsafe2CapiPubKey() on public key in LSA failed with %d\n",
dwStatus
);
#endif
goto cleanup;
}
//
// compare public key
//
if( CapiPubKeyInfoCert.PublicKey.cbData != CapiPubKeyInfoLsa.PublicKey.cbData )
{
#if DBG
DbgPrint(
"LSCSP: public key length mismatched %d %d\n",
CapiPubKeyInfoCert.PublicKey.cbData,
CapiPubKeyInfoLsa.PublicKey.cbData
);
#endif
dwStatus = LICENSE_STATUS_INVALID_CERTIFICATE;
}
else if( memcmp(
CapiPubKeyInfoCert.PublicKey.pbData,
CapiPubKeyInfoLsa.PublicKey.pbData,
CapiPubKeyInfoLsa.PublicKey.cbData
) != 0 )
{
#if DBG
DbgPrint( "LSCSP: public mismatched\n" );
#endif
dwStatus = LICENSE_STATUS_INVALID_CERTIFICATE;
}
}
__except( EXCEPTION_EXECUTE_HANDLER ) {
dwStatus = LICENSE_STATUS_INVALID_INPUT;
}
cleanup:
FreeCapiPubKey( &CapiPubKeyInfoCert );
FreeCapiPubKey( &CapiPubKeyInfoLsa );
if( NULL != pbPublicKeyInLsa )
{
LocalFree( pbPublicKeyInLsa );
}
if( NULL != pbPublicKeyInCert )
{
LocalFree( pbPublicKeyInCert );
}
return dwStatus;
}
//////////////////////////////////////////////////////////////////
LICENSE_STATUS
ReloadCSPCertificateAndData()
{
BOOL bSuccess;
DWORD Status = LICENSE_STATUS_OK;
LPBYTE i_csp_abServerX509Cert = NULL;
DWORD i_csp_dwServerX509CertLen = 0;
DWORD i_csp_dwX509CertPrivateKeyLen = 0;
LPBYTE i_csp_abX509CertPrivateKey = NULL;
LPBYTE i_csp_abX509CertID = NULL;
DWORD i_csp_dwX509CertIDLen = 0;
HKEY hKey = NULL;
DWORD dwResult, dwDisp;
//
// Acquire exclusive access
//
ACQUIRE_EXCLUSIVE_ACCESS( csp_hMutex );
//
// Prevent re-loading of same certificate/private key
//
if( NULL == csp_abServerX509Cert || 0 == csp_dwServerX509CertLen ||
NULL == csp_abX509CertPrivateKey || 0 == csp_dwX509CertPrivateKeyLen ||
NULL == csp_abX509CertID || 0 == csp_dwX509CertIDLen )
{
//
// Open the Registry
//
if( RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
TEXT( HYDRA_CERT_REG_KEY ),
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_READ | KEY_WRITE,
NULL,
&hKey,
&dwDisp ) != ERROR_SUCCESS )
{
Status = LICENSE_STATUS_NO_CERTIFICATE;
}
else
{
__try {
//
// Get the X509 certificate from the registry.
//
Status = LsCsp_GetBinaryData(
hKey,
TEXT( HYDRA_X509_CERTIFICATE ),
&i_csp_abServerX509Cert,
&i_csp_dwServerX509CertLen
);
if( LICENSE_STATUS_OK == Status && 0 != i_csp_dwServerX509CertLen )
{
//
// Get the corresponding private key from the store.
// It is not OK if we have the X509 certificate but not the
// private key that goes with it.
//
Status = LsCsp_RetrieveSecret(
X509_CERT_PRIVATE_KEY_NAME,
NULL,
&i_csp_dwX509CertPrivateKeyLen
);
if( LICENSE_STATUS_OK == Status )
{
i_csp_abX509CertPrivateKey = LocalAlloc( LPTR, i_csp_dwX509CertPrivateKeyLen );
if( NULL != i_csp_abX509CertPrivateKey )
{
Status = LsCsp_RetrieveSecret(
X509_CERT_PRIVATE_KEY_NAME,
i_csp_abX509CertPrivateKey,
&i_csp_dwX509CertPrivateKeyLen
);
if(LICENSE_STATUS_OK == Status)
{
//
// Get the certificate ID for the X509 certificate
//
Status = LsCsp_GetBinaryData(
hKey,
TEXT( HYDRA_X509_CERT_ID ),
&i_csp_abX509CertID,
&i_csp_dwX509CertIDLen
);
}
}
else // memory allocate
{
Status = LICENSE_STATUS_OUT_OF_MEMORY;
}
}
}
else
{
Status = LICENSE_STATUS_NO_CERTIFICATE;
}
}
__except( EXCEPTION_EXECUTE_HANDLER ) {
Status = LICENSE_STATUS_INVALID_INPUT;
}
}
//
// verify our certificate
//
if(LICENSE_STATUS_OK == Status)
{
Status = VerifyTermServCertificate(
i_csp_dwServerX509CertLen,
i_csp_abServerX509Cert,
i_csp_dwX509CertPrivateKeyLen,
i_csp_abX509CertPrivateKey
);
if( LICENSE_STATUS_OK != Status )
{
//
// Deleting the X509 certificate is enough.
//
RegDeleteValue( hKey, TEXT( HYDRA_X509_CERTIFICATE ) );
}
}
if(LICENSE_STATUS_OK != Status)
{
if( NULL != i_csp_abServerX509Cert )
{
LocalFree( i_csp_abServerX509Cert );
}
if( NULL != i_csp_abX509CertPrivateKey )
{
LocalFree( i_csp_abX509CertPrivateKey );
}
if( NULL != i_csp_abX509CertID )
{
LocalFree( i_csp_abX509CertID );
}
}
else
{
csp_abServerX509Cert = i_csp_abServerX509Cert;
csp_dwServerX509CertLen = i_csp_dwServerX509CertLen;
csp_dwX509CertPrivateKeyLen = i_csp_dwX509CertPrivateKeyLen;
csp_abX509CertPrivateKey = i_csp_abX509CertPrivateKey;
csp_abX509CertID = i_csp_abX509CertID;
csp_dwX509CertIDLen = i_csp_dwX509CertIDLen;
}
}
RELEASE_EXCLUSIVE_ACCESS( csp_hMutex );
if (hKey)
{
RegCloseKey(hKey);
}
return Status;
}
LICENSE_STATUS
CreateProprietaryKeyAndCert(
PBYTE *ppbPrivateKey,
DWORD *pcbPrivateKey,
PBYTE *ppbServerCert,
DWORD *pcbServerCert
)
{
#define MD5RSA 0x01;
#define RSAKEY 0x01;
LPBSAFE_PRV_KEY PRV;
Hydra_Server_Cert Cert;
DWORD KeyLen = 512;
DWORD bits, j;
DWORD dwPubSize, dwPrivSize;
BYTE *kPublic;
BYTE *kPrivate;
MD5_CTX HashState;
PBYTE pbData, pbTemp = NULL;
DWORD dwTemp = 0;
BYTE pbHash[0x48];
BYTE Output[0x48];
unsigned char prvmodulus[] =
{
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x3d, 0x3a, 0x5e, 0xbd,
0x72, 0x43, 0x3e, 0xc9, 0x4d, 0xbb, 0xc1, 0x1e,
0x4a, 0xba, 0x5f, 0xcb, 0x3e, 0x88, 0x20, 0x87,
0xef, 0xf5, 0xc1, 0xe2, 0xd7, 0xb7, 0x6b, 0x9a,
0xf2, 0x52, 0x45, 0x95, 0xce, 0x63, 0x65, 0x6b,
0x58, 0x3a, 0xfe, 0xef, 0x7c, 0xe7, 0xbf, 0xfe,
0x3d, 0xf6, 0x5c, 0x7d, 0x6c, 0x5e, 0x06, 0x09,
0x1a, 0xf5, 0x61, 0xbb, 0x20, 0x93, 0x09, 0x5f,
0x05, 0x6d, 0xea, 0x87, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3f, 0xbd, 0x29, 0x20,
0x57, 0xd2, 0x3b, 0xf1, 0x07, 0xfa, 0xdf, 0xc1,
0x16, 0x31, 0xe4, 0x95, 0xea, 0xc1, 0x2a, 0x46,
0x2b, 0xad, 0x88, 0x57, 0x55, 0xf0, 0x57, 0x58,
0xc6, 0x6f, 0x95, 0xeb, 0x00, 0x00, 0x00, 0x00,
0x83, 0xdd, 0x9d, 0xd0, 0x03, 0xb1, 0x5a, 0x9b,
0x9e, 0xb4, 0x63, 0x02, 0x43, 0x3e, 0xdf, 0xb0,
0x52, 0x83, 0x5f, 0x6a, 0x03, 0xe7, 0xd6, 0x78,
0x45, 0x83, 0x6a, 0x5b, 0xc4, 0xcb, 0xb1, 0x93,
0x00, 0x00, 0x00, 0x00, 0x65, 0x9d, 0x43, 0xe8,
0x48, 0x17, 0xcd, 0x29, 0x7e, 0xb9, 0x26, 0x5c,
0x79, 0x66, 0x58, 0x61, 0x72, 0x86, 0x6a, 0xa3,
0x63, 0xad, 0x63, 0xb8, 0xe1, 0x80, 0x4c, 0x0f,
0x36, 0x7d, 0xd9, 0xa6, 0x00, 0x00, 0x00, 0x00,
0x75, 0x3f, 0xef, 0x5a, 0x01, 0x5f, 0xf6, 0x0e,
0xd7, 0xcd, 0x59, 0x1c, 0xc6, 0xec, 0xde, 0xf3,
0x5a, 0x03, 0x09, 0xff, 0xf5, 0x23, 0xcc, 0x90,
0x27, 0x1d, 0xaa, 0x29, 0x60, 0xde, 0x05, 0x6e,
0x00, 0x00, 0x00, 0x00, 0xc0, 0x17, 0x0e, 0x57,
0xf8, 0x9e, 0xd9, 0x5c, 0xf5, 0xb9, 0x3a, 0xfc,
0x0e, 0xe2, 0x33, 0x27, 0x59, 0x1d, 0xd0, 0x97,
0x4a, 0xb1, 0xb1, 0x1f, 0xc3, 0x37, 0xd1, 0xd6,
0xe6, 0x9b, 0x35, 0xab, 0x00, 0x00, 0x00, 0x00,
0x87, 0xa7, 0x19, 0x32, 0xda, 0x11, 0x87, 0x55,
0x58, 0x00, 0x16, 0x16, 0x25, 0x65, 0x68, 0xf8,
0x24, 0x3e, 0xe6, 0xfa, 0xe9, 0x67, 0x49, 0x94,
0xcf, 0x92, 0xcc, 0x33, 0x99, 0xe8, 0x08, 0x60,
0x17, 0x9a, 0x12, 0x9f, 0x24, 0xdd, 0xb1, 0x24,
0x99, 0xc7, 0x3a, 0xb8, 0x0a, 0x7b, 0x0d, 0xdd,
0x35, 0x07, 0x79, 0x17, 0x0b, 0x51, 0x9b, 0xb3,
0xc7, 0x10, 0x01, 0x13, 0xe7, 0x3f, 0xf3, 0x5f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
PRV = (LPBSAFE_PRV_KEY)prvmodulus;
PRV->magic = RSA2;
PRV->keylen = 0x48;
PRV->bitlen = 0x0200;
PRV->datalen = 0x3f;
PRV->pubexp = 0xc0887b5b;
Cert.dwVersion = 0x01;
Cert.dwSigAlgID = MD5RSA;
Cert.dwKeyAlgID = RSAKEY;
bits = KeyLen;
if (!BSafeComputeKeySizes(&dwPubSize, &dwPrivSize, &bits))
{
return LICENSE_STATUS_INVALID_INPUT;
}
if ((kPrivate = (BYTE *)LocalAlloc(LPTR,dwPrivSize)) == NULL)
{
return LICENSE_STATUS_OUT_OF_MEMORY;
}
if ((kPublic = (BYTE *)LocalAlloc(LPTR,dwPubSize)) == NULL)
{
LocalFree(kPrivate);
return LICENSE_STATUS_OUT_OF_MEMORY;
}
if (!BSafeMakeKeyPair((LPBSAFE_PUB_KEY)kPublic,
(LPBSAFE_PRV_KEY)kPrivate,
KeyLen))
{
LocalFree(kPrivate);
LocalFree(kPublic);
return LICENSE_STATUS_OUT_OF_MEMORY;
}
// make proprietary format cert
Cert.PublicKeyData.wBlobType = BB_RSA_KEY_BLOB;
Cert.PublicKeyData.wBlobLen = (WORD)dwPubSize;
if( NULL == (Cert.PublicKeyData.pBlob = (PBYTE)LocalAlloc(LPTR,dwPubSize) ) )
{
LocalFree(kPrivate);
LocalFree(kPublic);
return LICENSE_STATUS_OUT_OF_MEMORY;
}
memcpy(Cert.PublicKeyData.pBlob, kPublic, dwPubSize);
dwTemp = 3*sizeof(DWORD) + 2*sizeof(WORD) + dwPubSize;
if( NULL == (pbData = (PBYTE)LocalAlloc(LPTR,dwTemp)) )
{
LocalFree(kPrivate);
LocalFree(kPublic);
LocalFree(Cert.PublicKeyData.pBlob);
return LICENSE_STATUS_OUT_OF_MEMORY;
}
pbTemp = pbData;
memcpy(pbTemp, &Cert.dwVersion, sizeof(DWORD));
pbTemp += sizeof(DWORD);
memcpy(pbTemp, &Cert.dwSigAlgID, sizeof(DWORD));
pbTemp += sizeof(DWORD);
memcpy(pbTemp, &Cert.dwKeyAlgID, sizeof(DWORD));
pbTemp += sizeof(DWORD);
memcpy(pbTemp, &Cert.PublicKeyData.wBlobType, sizeof(WORD));
pbTemp += sizeof(WORD);
memcpy(pbTemp, &Cert.PublicKeyData.wBlobLen, sizeof(WORD));
pbTemp += sizeof(WORD);
memcpy(pbTemp, Cert.PublicKeyData.pBlob, Cert.PublicKeyData.wBlobLen);
pbTemp += Cert.PublicKeyData.wBlobLen;
// sign the cert
MD5Init(&HashState);
MD5Update(&HashState, pbData, dwTemp);
MD5Final(&HashState);
LocalFree(pbData);
memset(pbHash, 0x00, 0x48);
memset(pbHash, 0xff, 0x40);
pbHash[0x40-1] = 0;
pbHash[0x40-2] = 1;
pbHash[16] = 0;
memcpy(pbHash, HashState.digest, 16);
BSafeDecPrivate(PRV, pbHash, Output);
Cert.SignatureBlob.wBlobType = BB_RSA_SIGNATURE_BLOB;
Cert.SignatureBlob.wBlobLen = 0x48;
if( NULL == (Cert.SignatureBlob.pBlob = (PBYTE)LocalAlloc(LPTR,Cert.SignatureBlob.wBlobLen)) )
{
LocalFree(kPrivate);
LocalFree(kPublic);
LocalFree(Cert.PublicKeyData.pBlob);
return LICENSE_STATUS_OUT_OF_MEMORY;
}
memcpy(Cert.SignatureBlob.pBlob, Output, Cert.SignatureBlob.wBlobLen);
// Pack the Hydra_Server_Cert
dwTemp = 3*sizeof(DWORD) + 4*sizeof(WORD) + dwPubSize + 0x48;
if( NULL == (pbData = (PBYTE)LocalAlloc(LPTR,dwTemp)) )
{
LocalFree(kPrivate);
LocalFree(kPublic);
LocalFree(Cert.PublicKeyData.pBlob);
return LICENSE_STATUS_OUT_OF_MEMORY;
}
pbTemp = pbData;
memcpy(pbTemp, &Cert.dwVersion, sizeof(DWORD));
pbTemp += sizeof(DWORD);
memcpy(pbTemp, &Cert.dwSigAlgID, sizeof(DWORD));
pbTemp += sizeof(DWORD);
memcpy(pbTemp, &Cert.dwKeyAlgID, sizeof(DWORD));
pbTemp += sizeof(DWORD);
memcpy(pbTemp, &Cert.PublicKeyData.wBlobType, sizeof(WORD));
pbTemp += sizeof(WORD);
memcpy(pbTemp, &Cert.PublicKeyData.wBlobLen, sizeof(WORD));
pbTemp += sizeof(WORD);
memcpy(pbTemp, Cert.PublicKeyData.pBlob, Cert.PublicKeyData.wBlobLen);
pbTemp += Cert.PublicKeyData.wBlobLen;
memcpy(pbTemp, &Cert.SignatureBlob.wBlobType, sizeof(WORD));
pbTemp += sizeof(WORD);
memcpy(pbTemp, &Cert.SignatureBlob.wBlobLen, sizeof(WORD));
pbTemp += sizeof(WORD);
memcpy(pbTemp, Cert.SignatureBlob.pBlob, Cert.SignatureBlob.wBlobLen);
*ppbPrivateKey = kPrivate;
*pcbPrivateKey = dwPrivSize;
*ppbServerCert = pbData;
*pcbServerCert = dwTemp;
LocalFree(kPublic);
return LICENSE_STATUS_OK;
}
//***************************************************************************
//
// IsSystemService
//
// returns TRUE if we are running as local system
//
//***************************************************************************
BOOL IsSystemService()
{
BOOL bOK = FALSE;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construct the local system SID
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SID LocalSystemSid = { SID_REVISION,
1,
SECURITY_NT_AUTHORITY,
SECURITY_LOCAL_SYSTEM_RID };
if ( !CheckTokenMembership ( NULL, &LocalSystemSid, &bOK ) )
{
bOK = FALSE;
}
return bOK;
}