mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1501 lines
45 KiB
1501 lines
45 KiB
//+--------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996-1996
|
|
//
|
|
// File: decode.c
|
|
//
|
|
// Contents: Routine related to decoding client certificate
|
|
//
|
|
// History: 03-18-98 HueiWang Created
|
|
//
|
|
// Note:
|
|
//---------------------------------------------------------------------------
|
|
#include <windows.h>
|
|
#include <wincrypt.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <tchar.h>
|
|
#include <shellapi.h>
|
|
#include <stddef.h>
|
|
#include <winnls.h>
|
|
#include "base64.h"
|
|
#include "license.h"
|
|
#include "cryptkey.h"
|
|
#include "certutil.h"
|
|
|
|
extern HCRYPTPROV g_hCertUtilCryptProv;
|
|
|
|
//
|
|
// Internal to this file only
|
|
//
|
|
typedef struct CertNameInfoEnumStruct10 {
|
|
PBYTE pbSecretKey;
|
|
DWORD cbSecretKey;
|
|
HWID hWid;
|
|
} CertNameInfoEnumStruct10, *PCertNameInfoEnumStruct10;
|
|
|
|
|
|
typedef struct CertNameInfoEnumStruct20 {
|
|
PBYTE pbSecretKey;
|
|
DWORD cbSecretKey;
|
|
|
|
PLICENSEDPRODUCT pLicensedProduct;
|
|
} CertNameInfoEnumStruct20, *PCertNameInfoEnumStruct20;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
int __cdecl
|
|
SortLicensedProduct(
|
|
const void* elem1,
|
|
const void* elem2
|
|
)
|
|
/*++
|
|
|
|
Abstract:
|
|
|
|
Sort licensed product array in decending order
|
|
|
|
++*/
|
|
{
|
|
PLICENSEDPRODUCT p1=(PLICENSEDPRODUCT) elem1;
|
|
PLICENSEDPRODUCT p2=(PLICENSEDPRODUCT) elem2;
|
|
|
|
if(p1->pLicensedVersion->wMajorVersion != p2->pLicensedVersion->wMinorVersion)
|
|
{
|
|
return p2->pLicensedVersion->wMajorVersion - p1->pLicensedVersion->wMinorVersion;
|
|
}
|
|
|
|
return p2->pLicensedVersion->wMinorVersion - p1->pLicensedVersion->wMinorVersion;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
LicenseGetSecretKey(
|
|
PDWORD pcbSecretKey,
|
|
BYTE FAR * pSecretKey )
|
|
{
|
|
static BYTE bSecretKey[] = { 0xCF, 0x08, 0x75, 0x4E, 0x5F, 0xDC, 0x2A, 0x57,
|
|
0x43, 0xEE, 0xE5, 0xA9, 0x8E, 0xD4, 0xF0, 0xD0 };
|
|
|
|
if( sizeof( bSecretKey ) > *pcbSecretKey )
|
|
{
|
|
*pcbSecretKey = sizeof( bSecretKey );
|
|
return( LICENSE_STATUS_INVALID_INPUT );
|
|
}
|
|
|
|
memcpy( pSecretKey, bSecretKey, sizeof( bSecretKey ) );
|
|
*pcbSecretKey = sizeof( bSecretKey );
|
|
|
|
return( LICENSE_STATUS_OK );
|
|
}
|
|
|
|
/***************************************************************************************
|
|
|
|
LSFreeLicensedProduct(PLICENSEDPRODUCT pLicensedProduct)
|
|
|
|
***************************************************************************************/
|
|
void
|
|
LSFreeLicensedProduct(
|
|
PLICENSEDPRODUCT pLicensedProduct
|
|
)
|
|
/*++
|
|
|
|
++*/
|
|
{
|
|
if(pLicensedProduct)
|
|
{
|
|
if(pLicensedProduct->pbOrgProductID)
|
|
{
|
|
FreeMemory(pLicensedProduct->pbOrgProductID);
|
|
pLicensedProduct->pbOrgProductID = NULL;
|
|
}
|
|
|
|
if(pLicensedProduct->pbPolicyData)
|
|
{
|
|
FreeMemory(pLicensedProduct->pbPolicyData);
|
|
pLicensedProduct->pbPolicyData = NULL;
|
|
}
|
|
|
|
if(pLicensedProduct->pLicensedVersion)
|
|
{
|
|
FreeMemory(pLicensedProduct->pLicensedVersion);
|
|
pLicensedProduct->pLicensedVersion = NULL;
|
|
}
|
|
|
|
FreeMemory(pLicensedProduct->szLicensedClient);
|
|
pLicensedProduct->szLicensedClient = NULL;
|
|
|
|
FreeMemory(pLicensedProduct->szLicensedUser);
|
|
pLicensedProduct->szLicensedUser = NULL;
|
|
|
|
if(pLicensedProduct->LicensedProduct.pProductInfo)
|
|
{
|
|
FreeMemory(pLicensedProduct->LicensedProduct.pProductInfo->pbCompanyName);
|
|
pLicensedProduct->LicensedProduct.pProductInfo->pbCompanyName = NULL;
|
|
|
|
FreeMemory(pLicensedProduct->LicensedProduct.pProductInfo->pbProductID);
|
|
pLicensedProduct->LicensedProduct.pProductInfo->pbProductID = NULL;
|
|
|
|
FreeMemory(pLicensedProduct->LicensedProduct.pProductInfo);
|
|
pLicensedProduct->LicensedProduct.pProductInfo = NULL;
|
|
}
|
|
|
|
FreeMemory(pLicensedProduct->szIssuer);
|
|
pLicensedProduct->szIssuer = NULL;
|
|
|
|
FreeMemory(pLicensedProduct->szIssuerId);
|
|
pLicensedProduct->szIssuerId = NULL;
|
|
|
|
FreeMemory(pLicensedProduct->szIssuerScope);
|
|
pLicensedProduct->szIssuerScope = NULL;
|
|
|
|
if(pLicensedProduct->LicensedProduct.pbEncryptedHwid)
|
|
{
|
|
FreeMemory(pLicensedProduct->LicensedProduct.pbEncryptedHwid);
|
|
pLicensedProduct->LicensedProduct.pbEncryptedHwid = NULL;
|
|
}
|
|
|
|
if(pLicensedProduct->szIssuerDnsName)
|
|
{
|
|
FreeMemory(pLicensedProduct->szIssuerDnsName);
|
|
pLicensedProduct->szIssuerDnsName = NULL;
|
|
}
|
|
|
|
//if(pLicensedProduct->pbEncodedHWID)
|
|
// FreeMemory(pLicensedProduct->pbEncodedHWID);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************************
|
|
|
|
BOOL WINAPI CryptDecodeObject( DWORD dwEncodingType, // in
|
|
LPCSTR lpszStructType, // in
|
|
const BYTE * pbEncoded, // in
|
|
DWORD cbEncoded, // in
|
|
DWORD dwFlags, // in
|
|
void * pvStructInfo, // out
|
|
DWORD * pcbStructInfo // in/out);
|
|
|
|
***************************************************************************************/
|
|
DWORD
|
|
LSCryptDecodeObject(
|
|
IN DWORD dwEncodingType,
|
|
IN LPCSTR lpszStructType,
|
|
IN const BYTE * pbEncoded,
|
|
IN DWORD cbEncoded,
|
|
IN DWORD dwFlags,
|
|
OUT void ** pvStructInfo,
|
|
IN OUT DWORD * pcbStructInfo
|
|
)
|
|
/*++
|
|
|
|
++*/
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
|
|
if(!CryptDecodeObject(dwEncodingType, lpszStructType, pbEncoded, cbEncoded, dwFlags, NULL, pcbStructInfo) ||
|
|
(*pvStructInfo=(PBYTE)AllocMemory(*pcbStructInfo)) == NULL ||
|
|
!CryptDecodeObject(dwEncodingType, lpszStructType, pbEncoded, cbEncoded, dwFlags, *pvStructInfo, pcbStructInfo))
|
|
{
|
|
dwStatus=GetLastError();
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
/***************************************************************************************
|
|
Function:
|
|
|
|
LSDecodeClientHWID(IN PBYTE pbData,
|
|
IN DWORD cbData,
|
|
IN PBYTE* pbSecretKey,
|
|
IN DWORD cbSecretKey,
|
|
IN OUT HWID* pHwid)
|
|
|
|
Abstract:
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
|
|
***************************************************************************************/
|
|
LICENSE_STATUS
|
|
LSDecodeClientHWID(
|
|
PBYTE pbData,
|
|
DWORD cbData,
|
|
PBYTE pbSecretKey,
|
|
DWORD cbSecretKey,
|
|
HWID* pHwid
|
|
)
|
|
/*++
|
|
++*/
|
|
{
|
|
CHAR pbDecodedHwid[1024];
|
|
DWORD cbDecodedHwid=sizeof(pbDecodedHwid);
|
|
|
|
//
|
|
// Client Encrypted HWID can't be more than 1K
|
|
//
|
|
if(cbData >= cbDecodedHwid)
|
|
{
|
|
return LICENSE_STATUS_INVALID_INPUT;
|
|
}
|
|
|
|
SetLastError(LICENSE_STATUS_OK);
|
|
memset(pbDecodedHwid, 0, sizeof(pbDecodedHwid));
|
|
|
|
__try {
|
|
if(LSBase64Decode(CAST_PBYTE pbData, cbData, (UCHAR *)pbDecodedHwid, &cbDecodedHwid) != LICENSE_STATUS_OK ||
|
|
LicenseDecryptHwid(pHwid, cbDecodedHwid, (UCHAR *)pbDecodedHwid, cbSecretKey, pbSecretKey) != 0)
|
|
{
|
|
SetLastError(LICENSE_STATUS_CANNOT_VERIFY_HWID);
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
SetLastError(LICENSE_STATUS_UNSPECIFIED_ERROR);
|
|
}
|
|
|
|
return GetLastError();
|
|
}
|
|
|
|
|
|
LICENSE_STATUS
|
|
LSEncryptClientHWID(
|
|
HWID* pHwid,
|
|
PBYTE pbData,
|
|
PDWORD cbData,
|
|
PBYTE pbSecretKey,
|
|
DWORD cbSecretKey
|
|
)
|
|
/*++
|
|
++*/
|
|
{
|
|
BYTE tmp_pbEncryptedHwid[sizeof(HWID)*2+2];
|
|
DWORD tmp_cbEncryptedHwid=sizeof(tmp_pbEncryptedHwid);
|
|
PBYTE pbKey=NULL;
|
|
DWORD cbKey=0;
|
|
DWORD status;
|
|
|
|
if(pbSecretKey)
|
|
{
|
|
pbKey = pbSecretKey;
|
|
cbKey = cbSecretKey;
|
|
}
|
|
else
|
|
{
|
|
LicenseGetSecretKey( &cbKey, NULL );
|
|
if((pbKey = (PBYTE)AllocMemory(cbKey)) == NULL)
|
|
{
|
|
return LICENSE_STATUS_OUT_OF_MEMORY;
|
|
}
|
|
|
|
status=LicenseGetSecretKey( &cbKey, pbKey );
|
|
if(status != LICENSE_STATUS_OK)
|
|
{
|
|
return status;
|
|
}
|
|
}
|
|
|
|
memset(tmp_pbEncryptedHwid, 0, sizeof(tmp_pbEncryptedHwid));
|
|
if((status=LicenseEncryptHwid(pHwid,
|
|
&tmp_cbEncryptedHwid,
|
|
tmp_pbEncryptedHwid,
|
|
cbKey,
|
|
pbKey) != LICENSE_STATUS_OK))
|
|
{
|
|
return status;
|
|
}
|
|
|
|
if(pbData && *cbData)
|
|
{
|
|
memcpy(pbData, tmp_pbEncryptedHwid, tmp_cbEncryptedHwid);
|
|
}
|
|
|
|
*cbData = tmp_cbEncryptedHwid;
|
|
if(pbKey != pbSecretKey)
|
|
FreeMemory(pbKey);
|
|
|
|
return LICENSE_STATUS_OK;
|
|
}
|
|
|
|
/*************************************************************************************
|
|
|
|
EnumDecodeHWID()
|
|
|
|
**************************************************************************************/
|
|
BOOL
|
|
ConvertUnicodeOIDToAnsi(
|
|
LPSTR szUnicodeOID,
|
|
LPSTR szAnsiOID,
|
|
DWORD cbAnsiOid
|
|
)
|
|
/*++
|
|
++*/
|
|
{
|
|
memset(szAnsiOID, 0, cbAnsiOid);
|
|
if(HIWORD(szUnicodeOID) == 0)
|
|
{
|
|
return WideCharToMultiByte(GetACP(),
|
|
0,
|
|
(WCHAR *)szUnicodeOID,
|
|
-1,
|
|
szAnsiOID,
|
|
cbAnsiOid,
|
|
NULL,
|
|
NULL) == 0;
|
|
}
|
|
|
|
strncpy(
|
|
szAnsiOID,
|
|
szUnicodeOID,
|
|
min(cbAnsiOid, strlen(szUnicodeOID))
|
|
);
|
|
return TRUE;
|
|
}
|
|
|
|
/*************************************************************************************
|
|
|
|
EnumDecodeHWID()
|
|
|
|
*************************************************************************************/
|
|
BOOL
|
|
EnumDecodeHWID(
|
|
IN PCERT_RDN_ATTR pCertRdnAttr,
|
|
IN HANDLE dwParm
|
|
)
|
|
/*++
|
|
++*/
|
|
{
|
|
PCertNameInfoEnumStruct20 pEnumParm = (PCertNameInfoEnumStruct20)dwParm;
|
|
BOOL bszOIDHwid=TRUE;
|
|
DWORD status=LICENSE_STATUS_OK;
|
|
int cmpResult;
|
|
CHAR ansiOID[4096]; // hardcoded for now.
|
|
|
|
if(!ConvertUnicodeOIDToAnsi(pCertRdnAttr->pszObjId, ansiOID, sizeof(ansiOID)/sizeof(ansiOID[0])))
|
|
return FALSE;
|
|
|
|
bszOIDHwid = (strcmp(ansiOID, szOID_COMMON_NAME) == 0);
|
|
|
|
if(bszOIDHwid)
|
|
{
|
|
pEnumParm->pLicensedProduct->LicensedProduct.pbEncryptedHwid = (PBYTE)AllocMemory(pCertRdnAttr->Value.cbData);
|
|
if(!pEnumParm->pLicensedProduct->LicensedProduct.pbEncryptedHwid)
|
|
{
|
|
status = LICENSE_STATUS_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
memcpy(pEnumParm->pLicensedProduct->LicensedProduct.pbEncryptedHwid,
|
|
pCertRdnAttr->Value.pbData,
|
|
pCertRdnAttr->Value.cbData);
|
|
|
|
pEnumParm->pLicensedProduct->LicensedProduct.cbEncryptedHwid=pCertRdnAttr->Value.cbData;
|
|
}
|
|
|
|
if(pEnumParm->pbSecretKey)
|
|
{
|
|
status = LSDecodeClientHWID(pCertRdnAttr->Value.pbData,
|
|
pCertRdnAttr->Value.cbData/sizeof(TCHAR),
|
|
pEnumParm->pbSecretKey,
|
|
pEnumParm->cbSecretKey,
|
|
&pEnumParm->pLicensedProduct->Hwid);
|
|
}
|
|
}
|
|
|
|
// continue if this is not our subject field.
|
|
return (status != LICENSE_STATUS_OK || !bszOIDHwid);
|
|
}
|
|
/*************************************************************************************
|
|
|
|
EnumIssuerLicense20()
|
|
|
|
**************************************************************************************/
|
|
BOOL
|
|
EnumIssuerLicense20(
|
|
IN PCERT_RDN_ATTR pCertRdnAttr,
|
|
IN HANDLE dwParm
|
|
)
|
|
/*++
|
|
++*/
|
|
{
|
|
PCertNameInfoEnumStruct20 pEnumParm=(PCertNameInfoEnumStruct20)dwParm;
|
|
CHAR ansiOID[4096];
|
|
DWORD status=LICENSE_STATUS_OK;
|
|
|
|
if(!ConvertUnicodeOIDToAnsi(pCertRdnAttr->pszObjId, ansiOID, sizeof(ansiOID)/sizeof(ansiOID[0])))
|
|
{
|
|
status=GetLastError();
|
|
}
|
|
else
|
|
{
|
|
if(strcmp(ansiOID, OID_ISSUER_LICENSE_SERVER_NAME) == 0)
|
|
{
|
|
pEnumParm->pLicensedProduct->szIssuer = (LPTSTR)AllocMemory( pCertRdnAttr->Value.cbData + sizeof(TCHAR) );
|
|
if(!pEnumParm->pLicensedProduct->szIssuer)
|
|
{
|
|
status = LICENSE_STATUS_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
memcpy(
|
|
pEnumParm->pLicensedProduct->szIssuer,
|
|
pCertRdnAttr->Value.pbData,
|
|
pCertRdnAttr->Value.cbData
|
|
);
|
|
}
|
|
}
|
|
else if(strcmp(ansiOID, OID_ISSUER_LICENSE_SERVER_SCOPE) == 0)
|
|
{
|
|
pEnumParm->pLicensedProduct->szIssuerScope = (LPTSTR)AllocMemory( pCertRdnAttr->Value.cbData + sizeof(TCHAR) );
|
|
if(!pEnumParm->pLicensedProduct->szIssuerScope)
|
|
{
|
|
status = LICENSE_STATUS_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
memcpy(
|
|
pEnumParm->pLicensedProduct->szIssuerScope,
|
|
pCertRdnAttr->Value.pbData,
|
|
pCertRdnAttr->Value.cbData
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
return status != LICENSE_STATUS_OK;
|
|
}
|
|
/*************************************************************************************
|
|
|
|
EnumSubjectLicense20()
|
|
|
|
**************************************************************************************/
|
|
BOOL
|
|
EnumSubjectLicense20(
|
|
IN PCERT_RDN_ATTR pCertRdnAttr,
|
|
IN HANDLE dwParm
|
|
)
|
|
/*++
|
|
++*/
|
|
{
|
|
PCertNameInfoEnumStruct20 pEnumParm=(PCertNameInfoEnumStruct20)dwParm;
|
|
CHAR ansiOID[4096];
|
|
DWORD status=LICENSE_STATUS_OK;
|
|
|
|
if(!ConvertUnicodeOIDToAnsi(pCertRdnAttr->pszObjId, ansiOID, sizeof(ansiOID)/sizeof(ansiOID[0])))
|
|
{
|
|
status=GetLastError();
|
|
}
|
|
else
|
|
{
|
|
DWORD cbData=pCertRdnAttr->Value.cbData;
|
|
PBYTE pbData=pCertRdnAttr->Value.pbData;
|
|
|
|
if(strcmp(ansiOID, OID_SUBJECT_CLIENT_COMPUTERNAME) == 0)
|
|
{
|
|
pEnumParm->pLicensedProduct->szLicensedClient=(LPTSTR)AllocMemory(cbData + sizeof(TCHAR));
|
|
if(!pEnumParm->pLicensedProduct->szLicensedClient)
|
|
{
|
|
status = LICENSE_STATUS_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
memcpy(
|
|
pEnumParm->pLicensedProduct->szLicensedClient,
|
|
pbData,
|
|
cbData
|
|
);
|
|
}
|
|
}
|
|
else if(strcmp(ansiOID, OID_SUBJECT_CLIENT_USERNAME) == 0)
|
|
{
|
|
pEnumParm->pLicensedProduct->szLicensedUser=(LPTSTR)AllocMemory(cbData + sizeof(TCHAR));
|
|
if(!pEnumParm->pLicensedProduct->szLicensedUser)
|
|
{
|
|
status = LICENSE_STATUS_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
memcpy(
|
|
pEnumParm->pLicensedProduct->szLicensedUser,
|
|
pbData,
|
|
cbData
|
|
);
|
|
}
|
|
}
|
|
else if(strcmp(ansiOID, OID_SUBJECT_CLIENT_HWID) == 0)
|
|
{
|
|
pEnumParm->pLicensedProduct->LicensedProduct.cbEncryptedHwid = 0;
|
|
LSBase64Decode(
|
|
CAST_PBYTE pCertRdnAttr->Value.pbData,
|
|
pCertRdnAttr->Value.cbData / sizeof(TCHAR),
|
|
NULL,
|
|
&(pEnumParm->pLicensedProduct->LicensedProduct.cbEncryptedHwid)
|
|
);
|
|
|
|
pEnumParm->pLicensedProduct->LicensedProduct.pbEncryptedHwid = (PBYTE)AllocMemory(
|
|
pEnumParm->pLicensedProduct->LicensedProduct.cbEncryptedHwid
|
|
);
|
|
if(!pEnumParm->pLicensedProduct->LicensedProduct.pbEncryptedHwid)
|
|
{
|
|
status = LICENSE_STATUS_OUT_OF_MEMORY;
|
|
return status;
|
|
}
|
|
|
|
status = LSBase64Decode(
|
|
CAST_PBYTE pCertRdnAttr->Value.pbData,
|
|
pCertRdnAttr->Value.cbData / sizeof(TCHAR),
|
|
pEnumParm->pLicensedProduct->LicensedProduct.pbEncryptedHwid,
|
|
&(pEnumParm->pLicensedProduct->LicensedProduct.cbEncryptedHwid)
|
|
);
|
|
|
|
if(status != LICENSE_STATUS_OK)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
if(pEnumParm->pbSecretKey)
|
|
{
|
|
status = LSDecodeClientHWID(
|
|
pCertRdnAttr->Value.pbData,
|
|
pCertRdnAttr->Value.cbData / sizeof(TCHAR),
|
|
pEnumParm->pbSecretKey,
|
|
pEnumParm->cbSecretKey,
|
|
&pEnumParm->pLicensedProduct->Hwid
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
return status != LICENSE_STATUS_OK;
|
|
}
|
|
/***************************************************************************************
|
|
Function:
|
|
LSEnumerateCertNameInfo()
|
|
|
|
Description:
|
|
Routine to enumerate all CERT_RDN_VALUE values in CERT_NAME_BLOB and pass it
|
|
to callback function specified in parameter
|
|
|
|
Arguments:
|
|
IN cbData - Count of bytes in the buffer pointed by pbData
|
|
IN pbData - Pointer to a block of data
|
|
IN EnumerateCertNameInfoCallBack - Enumeration call back routine, it is defined as
|
|
|
|
typedef BOOL (*EnumerateCertNameInfoCallBack)(PCERT_RDN_ATTR pCertRdnAttr,
|
|
DWORD dwUserData);
|
|
IN dwUserData - See EnumerateCertNameInfoCallBack
|
|
|
|
Return:
|
|
LICENSE_STATUS_OK
|
|
WIN32 error codes from CryptDecodeObject()
|
|
HLS_E_INTERNAL
|
|
Any error set by callback.
|
|
***************************************************************************************/
|
|
DWORD
|
|
LSEnumerateCertNameInfo(
|
|
IN LPBYTE pbData,
|
|
IN DWORD cbData,
|
|
IN EnumerateCertNameInfoCallBack func,
|
|
IN HANDLE dwUserData
|
|
)
|
|
/*++
|
|
|
|
++*/
|
|
{
|
|
BOOL bCryptSuccess=TRUE;
|
|
BOOL bCallbackCancel=FALSE;
|
|
DWORD status = LICENSE_STATUS_OK;
|
|
CERT_NAME_INFO CertNameBlob;
|
|
|
|
SetLastError(LICENSE_STATUS_OK);
|
|
|
|
__try {
|
|
memset(&CertNameBlob, 0, sizeof(CertNameBlob));
|
|
do {
|
|
bCryptSuccess=CryptDecodeObject(
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
X509_NAME,
|
|
pbData,
|
|
cbData,
|
|
0,
|
|
NULL,
|
|
&CertNameBlob.cRDN
|
|
);
|
|
if(!bCryptSuccess)
|
|
{
|
|
status = LICENSE_STATUS_CANNOT_DECODE_LICENSE;
|
|
break;
|
|
}
|
|
|
|
CertNameBlob.rgRDN=(PCERT_RDN)AllocMemory(CertNameBlob.cRDN);
|
|
if(!CertNameBlob.rgRDN)
|
|
{
|
|
SetLastError(status=LICENSE_STATUS_OUT_OF_MEMORY);
|
|
break;
|
|
}
|
|
|
|
bCryptSuccess=CryptDecodeObject(
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
X509_NAME,
|
|
pbData,
|
|
cbData,
|
|
CRYPT_DECODE_NOCOPY_FLAG,
|
|
(LPBYTE)CertNameBlob.rgRDN,
|
|
&CertNameBlob.cRDN
|
|
);
|
|
|
|
if(!bCryptSuccess)
|
|
{
|
|
status = LICENSE_STATUS_CANNOT_DECODE_LICENSE;
|
|
break;
|
|
}
|
|
|
|
PCERT_RDN pCertRdn=CertNameBlob.rgRDN;
|
|
int num_rdn=pCertRdn->cRDNAttr;
|
|
pCertRdn++;
|
|
|
|
for(int i=0; i < num_rdn && !bCallbackCancel; i++, pCertRdn++)
|
|
{
|
|
int num_attr=pCertRdn->cRDNAttr;
|
|
PCERT_RDN_ATTR pCertRdnAttr=pCertRdn->rgRDNAttr;
|
|
|
|
for(int j=0; j < num_attr && !bCallbackCancel; j++, pCertRdnAttr++)
|
|
{
|
|
bCallbackCancel=(func)(pCertRdnAttr, dwUserData);
|
|
}
|
|
}
|
|
} while(FALSE);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
SetLastError(LICENSE_STATUS_UNSPECIFIED_ERROR);
|
|
}
|
|
|
|
FreeMemory(CertNameBlob.rgRDN);
|
|
return GetLastError();
|
|
}
|
|
|
|
/*****************************************************************************
|
|
|
|
DecodeLicense20()
|
|
|
|
*****************************************************************************/
|
|
DWORD
|
|
DecodeGetIssuerDnsName(
|
|
PBYTE pbData,
|
|
DWORD cbData,
|
|
LPTSTR* pszIssuerDnsName
|
|
)
|
|
/*++
|
|
++*/
|
|
{
|
|
DWORD dwStatus=LICENSE_STATUS_OK;
|
|
PLSCERT_AUTHORITY_INFO_ACCESS pbAccessInfo=NULL;
|
|
DWORD cbAccessInfo=0;
|
|
|
|
*pszIssuerDnsName=NULL;
|
|
dwStatus=LSCryptDecodeObject(
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
szOID_X509_AUTHORITY_ACCESS_INFO,
|
|
pbData,
|
|
cbData,
|
|
CRYPT_DECODE_NOCOPY_FLAG,
|
|
(PVOID *)&pbAccessInfo,
|
|
&cbAccessInfo
|
|
);
|
|
|
|
if(dwStatus != ERROR_SUCCESS)
|
|
return dwStatus;
|
|
|
|
for(DWORD i=0; i < pbAccessInfo->cAccDescr; i++)
|
|
{
|
|
// we only use these for our license
|
|
if(strcmp(pbAccessInfo[i].rgAccDescr->pszAccessMethod, szOID_X509_ACCESS_PKIX_OCSP) == 0)
|
|
{
|
|
// our extension has only dns name entry...
|
|
if(pbAccessInfo[i].rgAccDescr->AccessLocation.dwAltNameChoice == LSCERT_ALT_NAME_DNS_NAME)
|
|
{
|
|
*pszIssuerDnsName = (LPTSTR)AllocMemory(
|
|
(wcslen(pbAccessInfo[i].rgAccDescr->AccessLocation.pwszDNSName)+1) * sizeof(TCHAR)
|
|
);
|
|
if(*pszIssuerDnsName == NULL)
|
|
{
|
|
dwStatus = LICENSE_STATUS_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
wcscpy(*pszIssuerDnsName, pbAccessInfo[i].rgAccDescr->AccessLocation.pwszDNSName);
|
|
}
|
|
|
|
break;
|
|
}
|
|
else if(pbAccessInfo[i].rgAccDescr->AccessLocation.dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME)
|
|
{
|
|
*pszIssuerDnsName = (LPTSTR)AllocMemory(
|
|
pbAccessInfo[i].rgAccDescr->AccessLocation.DirectoryName.cbData + sizeof(TCHAR)
|
|
);
|
|
if(*pszIssuerDnsName == NULL)
|
|
{
|
|
dwStatus = LICENSE_STATUS_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
memcpy(
|
|
*pszIssuerDnsName,
|
|
pbAccessInfo[i].rgAccDescr->AccessLocation.DirectoryName.pbData,
|
|
pbAccessInfo[i].rgAccDescr->AccessLocation.DirectoryName.cbData
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// always return success.
|
|
FreeMemory(pbAccessInfo);
|
|
return dwStatus;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
DecodeLicense20()
|
|
|
|
*****************************************************************************/
|
|
DWORD
|
|
GetClientLicenseVersion(
|
|
PCERT_EXTENSION pCertExtension,
|
|
DWORD dwNumExtension
|
|
)
|
|
/*++
|
|
++*/
|
|
{
|
|
DWORD dwVersion = TERMSERV_CERT_VERSION_UNKNOWN;
|
|
|
|
for(DWORD i=0; i < dwNumExtension; i++, pCertExtension++)
|
|
{
|
|
if(strcmp(pCertExtension->pszObjId, szOID_PKIX_HYDRA_CERT_VERSION) == 0)
|
|
{
|
|
if(pCertExtension->Value.cbData == sizeof(DWORD) &&
|
|
*(DWORD UNALIGNED *)pCertExtension->Value.pbData <= TERMSERV_CERT_VERSION_CURRENT)
|
|
{
|
|
//
|
|
// we don't support version 0x00020001, it never release
|
|
//
|
|
dwVersion = *(DWORD UNALIGNED *)pCertExtension->Value.pbData;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return dwVersion;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
|
|
DecodeLicense20()
|
|
|
|
*****************************************************************************/
|
|
LICENSE_STATUS
|
|
DecodeLicense20(
|
|
IN PCERT_INFO pCertInfo,
|
|
IN PBYTE pbSecretKey,
|
|
IN DWORD cbSecretKey,
|
|
IN OUT PLICENSEDPRODUCT pLicensedInfo
|
|
)
|
|
/*++
|
|
|
|
++*/
|
|
{
|
|
LICENSE_STATUS dwStatus=LICENSE_STATUS_OK;
|
|
PBYTE pbCompanyName=NULL;
|
|
DWORD cbCompanyName=0;
|
|
|
|
DWORD dwCertVersion=0;
|
|
|
|
LICENSED_PRODUCT_INFO* pLicensedProductInfo=NULL;
|
|
DWORD cbLicensedProductInfo=0;
|
|
|
|
PBYTE pbPolicyData=NULL;
|
|
DWORD cbPolicyData = 0;
|
|
|
|
CertNameInfoEnumStruct20 enumStruct;
|
|
ULARGE_INTEGER* pulSerialNumber;
|
|
DWORD i;
|
|
|
|
PCERT_EXTENSION pCertExtension=pCertInfo->rgExtension;
|
|
|
|
|
|
dwCertVersion = GetClientLicenseVersion(
|
|
pCertExtension,
|
|
pCertInfo->cExtension
|
|
);
|
|
|
|
if(dwCertVersion == TERMSERV_CERT_VERSION_UNKNOWN)
|
|
{
|
|
dwStatus = LICENSE_STATUS_INVALID_LICENSE;
|
|
goto cleanup;
|
|
}
|
|
|
|
if(dwCertVersion == 0x00020001)
|
|
{
|
|
dwStatus = LICENSE_STATUS_UNSUPPORTED_VERSION;
|
|
goto cleanup;
|
|
}
|
|
|
|
for(i=0; i < pCertInfo->cExtension && dwStatus == LICENSE_STATUS_OK; i++, pCertExtension++)
|
|
{
|
|
if(strcmp(pCertExtension->pszObjId, szOID_PKIS_PRODUCT_SPECIFIC_OID) == 0)
|
|
{
|
|
//
|
|
// product specific extension
|
|
//
|
|
pbPolicyData = pCertExtension->Value.pbData;
|
|
cbPolicyData = pCertExtension->Value.cbData;
|
|
}
|
|
else if(strcmp(pCertExtension->pszObjId, szOID_PKIX_MANUFACTURER) == 0)
|
|
{
|
|
//
|
|
// manufacturer of product
|
|
//
|
|
pbCompanyName = pCertExtension->Value.pbData;
|
|
cbCompanyName = pCertExtension->Value.cbData;
|
|
}
|
|
else if(strcmp(pCertExtension->pszObjId, szOID_PKIX_LICENSED_PRODUCT_INFO) == 0)
|
|
{
|
|
//
|
|
// Licensed product info
|
|
//
|
|
pLicensedProductInfo = (LICENSED_PRODUCT_INFO*) pCertExtension->Value.pbData;
|
|
cbLicensedProductInfo = pCertExtension->Value.cbData;
|
|
}
|
|
else if(strcmp(pCertExtension->pszObjId, szOID_X509_AUTHORITY_ACCESS_INFO) == 0)
|
|
{
|
|
//
|
|
// License Server access info,
|
|
//
|
|
dwStatus = DecodeGetIssuerDnsName(
|
|
pCertExtension->Value.pbData,
|
|
pCertExtension->Value.cbData,
|
|
&pLicensedInfo->szIssuerDnsName
|
|
);
|
|
|
|
}
|
|
else if(strcmp(pCertExtension->pszObjId, szOID_PKIX_MS_LICENSE_SERVER_INFO) == 0)
|
|
{
|
|
//
|
|
// HYDRA_CERT_VERSION_CURRENT use extension to store license server name
|
|
//
|
|
// extract license server info from this extension
|
|
//
|
|
|
|
dwStatus = LSExtensionToMsLicenseServerInfo(
|
|
pCertExtension->Value.pbData,
|
|
pCertExtension->Value.cbData,
|
|
&pLicensedInfo->szIssuer,
|
|
&pLicensedInfo->szIssuerId,
|
|
&pLicensedInfo->szIssuerScope
|
|
);
|
|
}
|
|
}
|
|
|
|
if(dwStatus != LICENSE_STATUS_OK)
|
|
{
|
|
//
|
|
// invalid license
|
|
//
|
|
goto cleanup;
|
|
}
|
|
|
|
if(pCertInfo->SerialNumber.cbData > sizeof(ULARGE_INTEGER))
|
|
{
|
|
//
|
|
// Our serial number if 64 bits
|
|
//
|
|
dwStatus = LICENSE_STATUS_NOT_HYDRA;
|
|
goto cleanup;
|
|
}
|
|
|
|
if(pbCompanyName == NULL || pLicensedProductInfo == NULL)
|
|
{
|
|
//
|
|
// not hydra certificate
|
|
//
|
|
dwStatus = LICENSE_STATUS_NOT_HYDRA;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Serial Number - Decoded as a multiple byte integer.
|
|
// SerialNumber.pbData[0] is the least significant byte.
|
|
// SerialNumber.pbData[SerialNumber.cbData - 1] is the most significant byte.)
|
|
//
|
|
pulSerialNumber = &(pLicensedInfo->ulSerialNumber);
|
|
memset(pulSerialNumber, 0, sizeof(ULARGE_INTEGER));
|
|
for(i=0; i < pCertInfo->SerialNumber.cbData; i++)
|
|
{
|
|
((PBYTE)pulSerialNumber)[i] = pCertInfo->SerialNumber.pbData[i];
|
|
}
|
|
|
|
//
|
|
// Extract validity of certificate
|
|
//
|
|
pLicensedInfo->NotBefore = pCertInfo->NotBefore;
|
|
pLicensedInfo->NotAfter = pCertInfo->NotAfter;
|
|
|
|
|
|
//
|
|
// Extract info from certificate.
|
|
//
|
|
enumStruct.pLicensedProduct=pLicensedInfo;
|
|
|
|
enumStruct.pbSecretKey = pbSecretKey;
|
|
enumStruct.cbSecretKey = cbSecretKey;
|
|
|
|
pLicensedInfo->dwLicenseVersion = dwCertVersion;
|
|
pLicensedInfo->LicensedProduct.pProductInfo=(PProduct_Info)AllocMemory(sizeof(Product_Info));
|
|
if(pLicensedInfo->LicensedProduct.pProductInfo == NULL)
|
|
{
|
|
dwStatus = LICENSE_STATUS_OUT_OF_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
if(pbPolicyData != NULL)
|
|
{
|
|
//
|
|
// Policy Module specific data
|
|
//
|
|
pLicensedInfo->pbPolicyData = (PBYTE)AllocMemory(cbPolicyData);
|
|
if(pLicensedInfo->pbPolicyData == NULL)
|
|
{
|
|
dwStatus = LICENSE_STATUS_OUT_OF_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
memcpy(pLicensedInfo->pbPolicyData, pbPolicyData, cbPolicyData);
|
|
pLicensedInfo->cbPolicyData = cbPolicyData;
|
|
}
|
|
|
|
if(dwCertVersion == TERMSERV_CERT_VERSION_RC1)
|
|
{
|
|
//
|
|
// HYDRA 4.0 RC1 - license server is stored in certificate's Issuer field
|
|
//
|
|
dwStatus=LSEnumerateCertNameInfo(
|
|
pCertInfo->Issuer.pbData,
|
|
pCertInfo->Issuer.cbData,
|
|
EnumIssuerLicense20,
|
|
&enumStruct
|
|
);
|
|
if(dwStatus != LICENSE_STATUS_OK)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
dwStatus=LSEnumerateCertNameInfo(
|
|
pCertInfo->Subject.pbData,
|
|
pCertInfo->Subject.cbData,
|
|
EnumSubjectLicense20,
|
|
&enumStruct
|
|
);
|
|
|
|
if(dwStatus != LICENSE_STATUS_OK)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
pLicensedInfo->LicensedProduct.pProductInfo->cbCompanyName = cbCompanyName;
|
|
pLicensedInfo->LicensedProduct.pProductInfo->pbCompanyName = (PBYTE)AllocMemory(cbCompanyName+sizeof(TCHAR));
|
|
if(!pLicensedInfo->LicensedProduct.pProductInfo->pbCompanyName)
|
|
{
|
|
dwStatus = LICENSE_STATUS_OUT_OF_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
memcpy(
|
|
pLicensedInfo->LicensedProduct.pProductInfo->pbCompanyName,
|
|
pbCompanyName,
|
|
cbCompanyName
|
|
);
|
|
|
|
dwStatus=LSExtensionToMsLicensedProductInfo(
|
|
(PBYTE)pLicensedProductInfo,
|
|
cbLicensedProductInfo,
|
|
&pLicensedInfo->dwQuantity,
|
|
&pLicensedInfo->LicensedProduct.dwPlatformID,
|
|
&pLicensedInfo->LicensedProduct.dwLanguageID,
|
|
&pLicensedInfo->pbOrgProductID,
|
|
&pLicensedInfo->cbOrgProductID,
|
|
&pLicensedInfo->LicensedProduct.pProductInfo->pbProductID,
|
|
&pLicensedInfo->LicensedProduct.pProductInfo->cbProductID,
|
|
&pLicensedInfo->pLicensedVersion,
|
|
&pLicensedInfo->dwNumLicensedVersion
|
|
);
|
|
if(dwStatus != LICENSE_STATUS_OK)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
pLicensedInfo->LicensedProduct.pProductInfo->dwVersion = MAKELONG(
|
|
pLicensedInfo->pLicensedVersion[0].wMinorVersion,
|
|
pLicensedInfo->pLicensedVersion[0].wMajorVersion
|
|
);
|
|
|
|
//
|
|
// assign product version to PLICENSEREQUEST
|
|
// backward ??? didn't bail out at 0.
|
|
//
|
|
for(i=1; i < pLicensedInfo->dwNumLicensedVersion; i++)
|
|
{
|
|
if(!(pLicensedInfo->pLicensedVersion[i].dwFlags & LICENSED_VERSION_TEMPORARY))
|
|
{
|
|
pLicensedInfo->LicensedProduct.pProductInfo->dwVersion = MAKELONG(
|
|
pLicensedInfo->pLicensedVersion[i].wMinorVersion,
|
|
pLicensedInfo->pLicensedVersion[i].wMajorVersion
|
|
);
|
|
}
|
|
}
|
|
|
|
if(pLicensedInfo->szIssuerDnsName == NULL && pLicensedInfo->szIssuer)
|
|
{
|
|
pLicensedInfo->szIssuerDnsName = (LPTSTR)AllocMemory((wcslen(pLicensedInfo->szIssuer)+1) * sizeof(TCHAR));
|
|
if(pLicensedInfo->szIssuerDnsName == NULL)
|
|
{
|
|
dwStatus = LICENSE_STATUS_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
wcscpy(pLicensedInfo->szIssuerDnsName, pLicensedInfo->szIssuer);
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
//------------------------------------------------------
|
|
DWORD
|
|
IsW2kLicenseIssuerNonEnforce(
|
|
IN HCRYPTPROV hCryptProv,
|
|
IN PCCERT_CONTEXT pCert,
|
|
IN HCERTSTORE hCertStore,
|
|
OUT PBOOL pbStatus
|
|
)
|
|
/*++
|
|
|
|
Abstract:
|
|
|
|
Verify client license is issued by a non-enforce
|
|
license server
|
|
|
|
Parameters:
|
|
|
|
hCryptProv - Crypo Provider.
|
|
pCert - Certificate to be verify
|
|
hCertStore - Certificate store that contains issuer's certificate
|
|
|
|
Returns:
|
|
|
|
LICENSE_STATUS_OK or error code.
|
|
|
|
++*/
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
DWORD dwFlags;
|
|
DWORD i;
|
|
PCCERT_CONTEXT pCertIssuer=NULL;
|
|
|
|
//
|
|
// There can only be one license server certificate.
|
|
//
|
|
dwFlags = CERT_STORE_SIGNATURE_FLAG;
|
|
pCertIssuer = CertGetIssuerCertificateFromStore(
|
|
hCertStore,
|
|
pCert,
|
|
NULL,
|
|
&dwFlags
|
|
);
|
|
if(pCertIssuer == NULL)
|
|
{
|
|
dwStatus = LICENSE_STATUS_NO_CERTIFICATE;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// A CH registered license server has szOID_PKIX_HYDRA_CERT_ROOT extension
|
|
// A telephone registered license server has szOID_PKIS_TLSERVER_SPK_OID extension
|
|
//
|
|
for(i=0; i < pCertIssuer->pCertInfo->cExtension; i++)
|
|
{
|
|
if(strcmp(pCertIssuer->pCertInfo->rgExtension[i].pszObjId, szOID_PKIX_HYDRA_CERT_ROOT) == 0 ||
|
|
strcmp(pCertIssuer->pCertInfo->rgExtension[i].pszObjId, szOID_PKIS_TLSERVER_SPK_OID) == 0 )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
*pbStatus = (i >= pCertIssuer->pCertInfo->cExtension) ? TRUE : FALSE;
|
|
|
|
if(pCertIssuer != NULL)
|
|
{
|
|
CertFreeCertificateContext(pCertIssuer);
|
|
}
|
|
|
|
cleanup:
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------
|
|
LICENSE_STATUS
|
|
LSVerifyTlsCertificate(
|
|
IN HCRYPTPROV hCryptProv,
|
|
IN PCCERT_CONTEXT pCert,
|
|
IN HCERTSTORE hCertStore
|
|
)
|
|
/*++
|
|
|
|
Abstract:
|
|
|
|
Given a certifcate and certificate store, this routine
|
|
verify that certificate chain up to root certificate.
|
|
|
|
Parameters:
|
|
|
|
hCryptProv - Crypo Provider.
|
|
pCert - Certificate to be verify
|
|
hCertStore - Certificate store that contains issuer's certificate
|
|
|
|
Returns:
|
|
|
|
++*/
|
|
{
|
|
PCCERT_CONTEXT pCertContext = pCert;
|
|
PCCERT_CONTEXT pCertIssuer=NULL, pCertIssuerNew;
|
|
DWORD dwStatus=ERROR_SUCCESS;
|
|
DWORD dwLastVerification=0;
|
|
|
|
pCertContext = CertDuplicateCertificateContext(pCert);
|
|
if(pCertContext == NULL)
|
|
{
|
|
dwStatus = GetLastError();
|
|
}
|
|
|
|
while(pCertContext != NULL)
|
|
{
|
|
//
|
|
// Verify against all issuer's certificate
|
|
//
|
|
DWORD dwFlags;
|
|
BOOL bVerify=FALSE;
|
|
|
|
dwStatus=ERROR_SUCCESS;
|
|
dwLastVerification=0;
|
|
pCertIssuer=NULL;
|
|
|
|
do {
|
|
dwFlags = CERT_STORE_SIGNATURE_FLAG; // | CERT_STORE_TIME_VALIDITY_FLAG;
|
|
|
|
pCertIssuerNew = CertGetIssuerCertificateFromStore(
|
|
hCertStore,
|
|
pCertContext,
|
|
pCertIssuer,
|
|
&dwFlags
|
|
);
|
|
|
|
if (NULL != pCertIssuer)
|
|
{
|
|
CertFreeCertificateContext(pCertIssuer);
|
|
}
|
|
|
|
// pass pCertIssuer back to CertGetIssuerCertificateFromStore()
|
|
// to prevent infinite loop.
|
|
pCertIssuer = pCertIssuerNew;
|
|
|
|
if(pCertIssuer == NULL)
|
|
{
|
|
dwStatus = GetLastError();
|
|
break;
|
|
}
|
|
|
|
dwLastVerification=dwFlags;
|
|
bVerify = (dwFlags == 0);
|
|
|
|
} while(!bVerify);
|
|
|
|
//
|
|
// Check against error return from CertGetIssuerCertificateFromStore()
|
|
//
|
|
if(dwStatus != ERROR_SUCCESS || dwLastVerification)
|
|
{
|
|
if(dwStatus == CRYPT_E_SELF_SIGNED)
|
|
{
|
|
// self-signed certificate
|
|
if( CryptVerifyCertificateSignature(
|
|
hCryptProv,
|
|
X509_ASN_ENCODING,
|
|
pCertContext->pbCertEncoded,
|
|
pCertContext->cbCertEncoded,
|
|
&pCertContext->pCertInfo->SubjectPublicKeyInfo
|
|
) )
|
|
{
|
|
dwStatus=ERROR_SUCCESS;
|
|
}
|
|
}
|
|
else if(dwStatus == CRYPT_E_NOT_FOUND)
|
|
{
|
|
// can't find issuer's certificate
|
|
dwStatus = LICENSE_STATUS_CANNOT_FIND_ISSUER_CERT;
|
|
}
|
|
else if(dwLastVerification & CERT_STORE_SIGNATURE_FLAG)
|
|
{
|
|
dwStatus=LICENSE_STATUS_INVALID_LICENSE;
|
|
}
|
|
else if(dwLastVerification & CERT_STORE_TIME_VALIDITY_FLAG)
|
|
{
|
|
dwStatus=LICENSE_STATUS_EXPIRED_LICENSE;
|
|
}
|
|
else
|
|
{
|
|
dwStatus=LICENSE_STATUS_UNSPECIFIED_ERROR;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// free cert. context ourself instead of relying on Crypto.
|
|
if(pCertContext != NULL)
|
|
{
|
|
CertFreeCertificateContext(pCertContext);
|
|
}
|
|
|
|
pCertContext = pCertIssuer;
|
|
|
|
} // while(pCertContext != NULL)
|
|
|
|
if(pCertContext != NULL)
|
|
{
|
|
CertFreeCertificateContext(pCertContext);
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------
|
|
|
|
LICENSE_STATUS
|
|
LSVerifyDecodeClientLicense(
|
|
IN PBYTE pbLicense,
|
|
IN DWORD cbLicense,
|
|
IN PBYTE pbSecretKey,
|
|
IN DWORD cbSecretKey,
|
|
IN OUT PDWORD pdwNumLicensedInfo,
|
|
IN OUT PLICENSEDPRODUCT pLicensedInfo
|
|
)
|
|
/*++
|
|
|
|
|
|
Verify and decode client licenses.
|
|
|
|
++*/
|
|
{
|
|
HCERTSTORE hCertStore=NULL;
|
|
LICENSE_STATUS dwStatus=LICENSE_STATUS_OK;
|
|
CRYPT_DATA_BLOB Serialized;
|
|
PCCERT_CONTEXT pCertContext=NULL;
|
|
PCCERT_CONTEXT pPrevCertContext=NULL;
|
|
PCERT_INFO pCertInfo;
|
|
DWORD dwCertVersion;
|
|
|
|
DWORD dwLicensedInfoSize=*pdwNumLicensedInfo;
|
|
*pdwNumLicensedInfo = 0;
|
|
|
|
Serialized.pbData = pbLicense;
|
|
Serialized.cbData = cbLicense;
|
|
|
|
if(g_hCertUtilCryptProv == NULL)
|
|
{
|
|
SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
|
|
goto cleanup;
|
|
}
|
|
|
|
hCertStore = CertOpenStore(
|
|
szLICENSE_BLOB_SAVEAS_TYPE,
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
g_hCertUtilCryptProv,
|
|
CERT_STORE_NO_CRYPT_RELEASE_FLAG,
|
|
&Serialized
|
|
);
|
|
|
|
if(!hCertStore)
|
|
{
|
|
dwStatus=GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
while( TRUE )
|
|
{
|
|
//
|
|
// Loop thru all certificates in blob
|
|
//
|
|
pCertContext = CertEnumCertificatesInStore(
|
|
hCertStore,
|
|
pPrevCertContext
|
|
);
|
|
if(pCertContext == NULL)
|
|
{
|
|
//
|
|
// end certificate in store or error
|
|
//
|
|
if((dwStatus=GetLastError()) == CRYPT_E_NOT_FOUND)
|
|
{
|
|
SetLastError(dwStatus = ERROR_SUCCESS);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Calculate number of license in this blob
|
|
//
|
|
dwCertVersion = GetClientLicenseVersion(
|
|
pCertContext->pCertInfo->rgExtension,
|
|
pCertContext->pCertInfo->cExtension
|
|
);
|
|
|
|
if(dwCertVersion == 0x00020001)
|
|
{
|
|
//
|
|
// This is internal test version, never got release
|
|
//
|
|
dwStatus = LICENSE_STATUS_UNSUPPORTED_VERSION;
|
|
break;
|
|
}
|
|
else if(dwCertVersion != TERMSERV_CERT_VERSION_UNKNOWN)
|
|
{
|
|
//
|
|
// This certificate is issued by license server,
|
|
// verify certificate chain.
|
|
//
|
|
dwStatus = LSVerifyTlsCertificate(
|
|
g_hCertUtilCryptProv,
|
|
pCertContext,
|
|
hCertStore
|
|
);
|
|
|
|
if(dwStatus != LICENSE_STATUS_OK)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(pLicensedInfo != NULL && *pdwNumLicensedInfo < dwLicensedInfoSize)
|
|
{
|
|
//
|
|
// Decode certificate
|
|
//
|
|
dwStatus=DecodeLicense20(
|
|
pCertContext->pCertInfo,
|
|
pbSecretKey,
|
|
cbSecretKey,
|
|
pLicensedInfo + *pdwNumLicensedInfo
|
|
);
|
|
|
|
if(dwStatus != LICENSE_STATUS_OK)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(dwCertVersion == 0x00050001)
|
|
{
|
|
DWORD dwFlags = (pLicensedInfo + *pdwNumLicensedInfo)->pLicensedVersion->dwFlags;
|
|
|
|
//
|
|
// License Server 5.2 or older does not set its enforce/noenforce so we need
|
|
// to figure out from its own certificate.
|
|
//
|
|
if( GET_LICENSE_ISSUER_MAJORVERSION(dwFlags) <= 5 &&
|
|
GET_LICENSE_ISSUER_MINORVERSION(dwFlags) <= 2 )
|
|
{
|
|
if( !(dwFlags & LICENSED_VERSION_TEMPORARY) )
|
|
{
|
|
BOOL bNonEnforce = FALSE;
|
|
|
|
dwStatus = IsW2kLicenseIssuerNonEnforce(
|
|
g_hCertUtilCryptProv,
|
|
pCertContext,
|
|
hCertStore,
|
|
&bNonEnforce
|
|
);
|
|
|
|
if(dwStatus != LICENSE_STATUS_OK)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(bNonEnforce == FALSE)
|
|
{
|
|
(pLicensedInfo + *pdwNumLicensedInfo)->pLicensedVersion->dwFlags |= LICENSE_ISSUER_ENFORCE_TYPE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
(*pdwNumLicensedInfo)++;
|
|
}
|
|
|
|
pPrevCertContext = pCertContext;
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if(hCertStore)
|
|
{
|
|
// Force close on all cert.
|
|
if(CertCloseStore(
|
|
hCertStore,
|
|
CERT_CLOSE_STORE_FORCE_FLAG) == FALSE)
|
|
{
|
|
dwStatus = GetLastError();
|
|
}
|
|
}
|
|
|
|
if(dwStatus != LICENSE_STATUS_OK)
|
|
{
|
|
//
|
|
// dwNumLicensedInfo is a DWORD.
|
|
//
|
|
int count = (int) *pdwNumLicensedInfo;
|
|
|
|
for(;count >= 0 && pLicensedInfo != NULL; count--)
|
|
{
|
|
LSFreeLicensedProduct(pLicensedInfo + count);
|
|
}
|
|
}
|
|
else if(pLicensedInfo != NULL)
|
|
{
|
|
qsort(
|
|
pLicensedInfo,
|
|
*pdwNumLicensedInfo,
|
|
sizeof(LICENSEDPRODUCT),
|
|
SortLicensedProduct
|
|
);
|
|
}
|
|
|
|
if(*pdwNumLicensedInfo == 0 && dwStatus == LICENSE_STATUS_OK)
|
|
{
|
|
dwStatus = LICENSE_STATUS_NO_LICENSE_ERROR;
|
|
}
|
|
|
|
//
|
|
// Force re-issue of client licenses.
|
|
//
|
|
return (dwStatus != LICENSE_STATUS_OK) ? LICENSE_STATUS_CANNOT_DECODE_LICENSE : dwStatus;
|
|
}
|