2179 lines
50 KiB
C++
2179 lines
50 KiB
C++
//+--------------------------------------------------------------------------
|
|
//
|
|
// Copyright (c) 1997-1999 Microsoft Corporation
|
|
//
|
|
// File: tlscert.cpp
|
|
//
|
|
// Contents: Certificate routines
|
|
//
|
|
// History:
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
#include "pch.cpp"
|
|
#include "server.h"
|
|
#include "globals.h"
|
|
#include "tlscert.h"
|
|
#include "gencert.h"
|
|
|
|
#define MAX_KEY_CONTAINER_LENGTH 25
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
BOOL
|
|
VerifyCertValidity(
|
|
IN PCCERT_CONTEXT pCertContext
|
|
)
|
|
|
|
/*++
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL bValid;
|
|
FILETIME ft;
|
|
|
|
GetSystemTimeAsFileTime(&ft);
|
|
|
|
bValid = (CompareFileTime(
|
|
&ft,
|
|
&(pCertContext->pCertInfo->NotAfter)
|
|
) < 0);
|
|
|
|
return bValid;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
void
|
|
DeleteBadIssuerCertFromStore(
|
|
IN HCERTSTORE hCertStore,
|
|
IN PCCERT_CONTEXT pSubjectContext
|
|
)
|
|
|
|
/*++
|
|
|
|
--*/
|
|
|
|
{
|
|
PCCERT_CONTEXT pCertIssuer = NULL;
|
|
DWORD dwFlags;
|
|
DWORD dwStatus;
|
|
BOOL bExpiredCert = FALSE;
|
|
|
|
do {
|
|
dwFlags = CERT_STORE_SIGNATURE_FLAG;
|
|
pCertIssuer = CertGetIssuerCertificateFromStore(
|
|
hCertStore,
|
|
pSubjectContext,
|
|
NULL,
|
|
&dwFlags
|
|
);
|
|
|
|
if(pCertIssuer == NULL)
|
|
{
|
|
// can't find issuer certificate
|
|
break;
|
|
}
|
|
|
|
bExpiredCert = (VerifyCertValidity(pCertIssuer) == FALSE);
|
|
|
|
if(dwFlags != 0 || bExpiredCert == TRUE)
|
|
{
|
|
CertDeleteCertificateFromStore(pCertIssuer);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
} while(TRUE);
|
|
|
|
return;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
PCCERT_CONTEXT
|
|
GetIssuerCertificateFromStore(
|
|
IN HCERTSTORE hCertStore,
|
|
IN PCCERT_CONTEXT pSubjectContext,
|
|
IN BOOL bDelBadIssuerCert
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PCCERT_CONTEXT pCertIssuer = NULL;
|
|
DWORD dwFlags;
|
|
BOOL bExpiredCert = FALSE;
|
|
|
|
SetLastError(ERROR_SUCCESS);
|
|
|
|
do {
|
|
dwFlags = CERT_STORE_SIGNATURE_FLAG;
|
|
pCertIssuer = CertGetIssuerCertificateFromStore(
|
|
hCertStore,
|
|
pSubjectContext,
|
|
pCertIssuer,
|
|
&dwFlags
|
|
);
|
|
|
|
if(pCertIssuer == NULL)
|
|
{
|
|
// can't find issuer certificate
|
|
break;
|
|
}
|
|
|
|
bExpiredCert = (VerifyCertValidity(pCertIssuer) == FALSE);
|
|
|
|
if(dwFlags == 0 && bExpiredCert == FALSE)
|
|
{
|
|
//
|
|
// find a good issuer's certificate
|
|
//
|
|
break;
|
|
}
|
|
|
|
//if(pCertIssuer != NULL)
|
|
//{
|
|
// CertFreeCertificateContext(pCertIssuer);
|
|
//}
|
|
|
|
} while(TRUE);
|
|
|
|
if(bDelBadIssuerCert == TRUE && pCertIssuer)
|
|
{
|
|
//
|
|
// Only delete bad certificate if we can't find a good one.
|
|
//
|
|
DeleteBadIssuerCertFromStore(
|
|
hCertStore,
|
|
pSubjectContext
|
|
);
|
|
}
|
|
|
|
if(bExpiredCert == TRUE && pCertIssuer == NULL)
|
|
{
|
|
SetLastError(TLS_E_EXPIRE_CERT);
|
|
}
|
|
|
|
return pCertIssuer;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
TLSVerifyCertChain(
|
|
IN HCRYPTPROV hCryptProv,
|
|
IN HCERTSTORE hCertStore,
|
|
IN PCCERT_CONTEXT pSubjectContext,
|
|
OUT FILETIME* pftMinExpireTime
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
PCCERT_CONTEXT pCertIssuer = NULL;
|
|
PCCERT_CONTEXT pCurrentSubject;
|
|
|
|
//
|
|
// Increase reference count on Subject context.
|
|
pCurrentSubject = CertDuplicateCertificateContext(
|
|
pSubjectContext
|
|
);
|
|
|
|
while( TRUE )
|
|
{
|
|
pCertIssuer = GetIssuerCertificateFromStore(
|
|
hCertStore,
|
|
pCurrentSubject,
|
|
FALSE
|
|
);
|
|
if(!pCertIssuer)
|
|
{
|
|
// Could not find issuer's certificate or
|
|
// a good issuer's certificate
|
|
dwStatus = GetLastError();
|
|
break;
|
|
}
|
|
|
|
if(CompareFileTime(pftMinExpireTime, &(pCertIssuer->pCertInfo->NotAfter)) > 0)
|
|
{
|
|
*pftMinExpireTime = pCertIssuer->pCertInfo->NotAfter;
|
|
}
|
|
|
|
if(pCurrentSubject != NULL)
|
|
{
|
|
CertFreeCertificateContext(pCurrentSubject);
|
|
}
|
|
|
|
pCurrentSubject = pCertIssuer;
|
|
}
|
|
|
|
if(dwStatus == CRYPT_E_SELF_SIGNED)
|
|
{
|
|
dwStatus = ERROR_SUCCESS;
|
|
}
|
|
|
|
if(pCertIssuer != NULL)
|
|
{
|
|
CertFreeCertificateContext(pCertIssuer);
|
|
}
|
|
|
|
if(pCurrentSubject != NULL)
|
|
{
|
|
CertFreeCertificateContext(pCurrentSubject);
|
|
}
|
|
|
|
SetLastError(dwStatus);
|
|
return dwStatus;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
VerifyLicenseServerCertificate(
|
|
IN HCRYPTPROV hCryptProv,
|
|
IN PCCERT_CONTEXT pCertContext,
|
|
IN DWORD dwCertType
|
|
)
|
|
|
|
/*++
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL bFound=FALSE;
|
|
PCERT_INFO pCertInfo = pCertContext->pCertInfo;
|
|
PCERT_EXTENSION pCertExtension=pCertInfo->rgExtension;
|
|
PCERT_PUBLIC_KEY_INFO pbPublicKey=NULL;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
DWORD dwSize = 0;
|
|
|
|
//
|
|
// Must have a CH root extension.
|
|
//
|
|
for(DWORD i=0;
|
|
i < pCertInfo->cExtension && bFound == FALSE;
|
|
i++, pCertExtension++)
|
|
{
|
|
bFound=(strcmp(pCertExtension->pszObjId, szOID_PKIX_HYDRA_CERT_ROOT) == 0);
|
|
}
|
|
|
|
if(bFound == TRUE)
|
|
{
|
|
//
|
|
// Public Key must be the same
|
|
//
|
|
dwStatus = TLSExportPublicKey(
|
|
hCryptProv,
|
|
dwCertType,
|
|
&dwSize,
|
|
&pbPublicKey
|
|
);
|
|
|
|
if(dwStatus == ERROR_SUCCESS)
|
|
{
|
|
bFound = CertComparePublicKeyInfo(
|
|
X509_ASN_ENCODING,
|
|
pbPublicKey,
|
|
&(pCertContext->pCertInfo->SubjectPublicKeyInfo)
|
|
);
|
|
|
|
if(bFound == FALSE)
|
|
{
|
|
dwStatus = TLS_E_MISMATCHPUBLICKEY;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwStatus = TLS_E_INVALIDLSCERT;
|
|
}
|
|
|
|
FreeMemory(pbPublicKey);
|
|
return dwStatus;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
TLSVerifyServerCertAndChain(
|
|
IN HCRYPTPROV hCryptProv,
|
|
IN HCERTSTORE hCertStore,
|
|
IN DWORD dwCertType,
|
|
IN PBYTE pbCert,
|
|
IN DWORD cbCert,
|
|
IN OUT FILETIME* pExpiredTime
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
|
|
//
|
|
// Verify License Server's own certificate
|
|
//
|
|
pCertContext = CertCreateCertificateContext(
|
|
X509_ASN_ENCODING,
|
|
pbCert,
|
|
cbCert
|
|
);
|
|
if(pCertContext == NULL)
|
|
{
|
|
dwStatus = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Verify License Server's certificate first
|
|
//
|
|
dwStatus = VerifyLicenseServerCertificate(
|
|
hCryptProv,
|
|
pCertContext,
|
|
dwCertType
|
|
);
|
|
|
|
if(dwStatus != ERROR_SUCCESS)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Verify Certificate Chain
|
|
//
|
|
dwStatus = TLSVerifyCertChain(
|
|
hCryptProv,
|
|
hCertStore,
|
|
pCertContext,
|
|
pExpiredTime
|
|
);
|
|
|
|
if(dwStatus != ERROR_SUCCESS)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if(pCertContext != NULL)
|
|
{
|
|
CertFreeCertificateContext(pCertContext);
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
TLSValidateServerCertficates(
|
|
IN HCRYPTPROV hCryptProv,
|
|
IN HCERTSTORE hCertStore,
|
|
IN PBYTE pbSignCert,
|
|
IN DWORD cbSignCert,
|
|
IN PBYTE pbExchCert,
|
|
IN DWORD cbExchCert,
|
|
OUT FILETIME* pftExpireTime
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
#if ENFORCE_LICENSING
|
|
|
|
DWORD dwStatus;
|
|
|
|
pftExpireTime->dwLowDateTime = 0xFFFFFFFF;
|
|
pftExpireTime->dwHighDateTime = 0xFFFFFFFF;
|
|
|
|
dwStatus = TLSVerifyServerCertAndChain(
|
|
hCryptProv,
|
|
hCertStore,
|
|
AT_SIGNATURE,
|
|
pbSignCert,
|
|
cbSignCert,
|
|
pftExpireTime
|
|
);
|
|
|
|
if(TLS_ERROR(dwStatus) == TRUE)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
dwStatus = TLSVerifyServerCertAndChain(
|
|
hCryptProv,
|
|
hCertStore,
|
|
AT_KEYEXCHANGE,
|
|
pbExchCert,
|
|
cbExchCert,
|
|
pftExpireTime
|
|
);
|
|
|
|
cleanup:
|
|
|
|
return dwStatus;
|
|
|
|
#else
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
#endif
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
TLSDestroyCryptContext(
|
|
HCRYPTPROV hCryptProv
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwStatus;
|
|
BOOL bSuccess;
|
|
PBYTE pbData = NULL;
|
|
DWORD cbData = 0;
|
|
|
|
if(hCryptProv == NULL)
|
|
{
|
|
SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Get the container name.
|
|
//
|
|
bSuccess = CryptGetProvParam(
|
|
hCryptProv,
|
|
PP_CONTAINER,
|
|
NULL,
|
|
&cbData,
|
|
0
|
|
);
|
|
|
|
if(bSuccess != FALSE)
|
|
{
|
|
dwStatus = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
pbData = (PBYTE)AllocateMemory(cbData + sizeof(TCHAR));
|
|
if(pbData == NULL)
|
|
{
|
|
dwStatus = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
bSuccess = CryptGetProvParam(
|
|
hCryptProv,
|
|
PP_CONTAINER,
|
|
pbData,
|
|
&cbData,
|
|
0
|
|
);
|
|
|
|
if(bSuccess == FALSE)
|
|
{
|
|
dwStatus = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Release the context
|
|
//
|
|
bSuccess = CryptReleaseContext(
|
|
hCryptProv,
|
|
0
|
|
);
|
|
if(bSuccess == FALSE)
|
|
{
|
|
dwStatus = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Delete key set
|
|
//
|
|
bSuccess = CryptAcquireContext(
|
|
&hCryptProv,
|
|
(LPCTSTR)pbData,
|
|
DEFAULT_CSP,
|
|
PROVIDER_TYPE,
|
|
CRYPT_DELETEKEYSET
|
|
);
|
|
|
|
if(bSuccess == FALSE)
|
|
{
|
|
dwStatus = GetLastError();
|
|
}
|
|
|
|
cleanup:
|
|
|
|
FreeMemory(pbData);
|
|
return dwStatus;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
InitCryptoProv(
|
|
LPCTSTR pszKeyContainer,
|
|
HCRYPTPROV* phCryptProv
|
|
)
|
|
/*++
|
|
|
|
--*/
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
TCHAR szKeyContainer[MAX_KEY_CONTAINER_LENGTH+1];
|
|
LPCTSTR pszContainer;
|
|
|
|
if(pszKeyContainer == NULL)
|
|
{
|
|
//
|
|
// Randomly create a key container
|
|
//
|
|
memset(szKeyContainer, 0, sizeof(szKeyContainer));
|
|
|
|
_sntprintf(
|
|
szKeyContainer,
|
|
MAX_KEY_CONTAINER_LENGTH,
|
|
_TEXT("TlsContainer%d"),
|
|
GetCurrentThreadId()
|
|
);
|
|
|
|
pszContainer = szKeyContainer;
|
|
}
|
|
else
|
|
{
|
|
pszContainer = pszKeyContainer;
|
|
}
|
|
|
|
|
|
//
|
|
// Delete the key container, ignore error here
|
|
//
|
|
CryptAcquireContext(
|
|
phCryptProv,
|
|
pszContainer,
|
|
DEFAULT_CSP,
|
|
PROVIDER_TYPE,
|
|
CRYPT_DELETEKEYSET
|
|
);
|
|
|
|
|
|
//
|
|
// Re-create key container
|
|
//
|
|
if(!CryptAcquireContext(
|
|
phCryptProv,
|
|
pszContainer,
|
|
DEFAULT_CSP,
|
|
PROVIDER_TYPE,
|
|
0))
|
|
{
|
|
// Create default key container.
|
|
if(!CryptAcquireContext(
|
|
phCryptProv,
|
|
pszContainer,
|
|
DEFAULT_CSP,
|
|
PROVIDER_TYPE,
|
|
CRYPT_NEWKEYSET))
|
|
{
|
|
dwStatus = GetLastError();
|
|
}
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
TLSLoadSavedCryptKeyFromLsa(
|
|
OUT PBYTE* ppbSignKey,
|
|
OUT PDWORD pcbSignKey,
|
|
OUT PBYTE* ppbExchKey,
|
|
OUT PDWORD pcbExchKey
|
|
)
|
|
/*++
|
|
|
|
++*/
|
|
{
|
|
DWORD dwStatus;
|
|
PBYTE pbSKey = NULL;
|
|
DWORD cbSKey = 0;
|
|
PBYTE pbEKey = NULL;
|
|
DWORD cbEKey = 0;
|
|
|
|
|
|
dwStatus = RetrieveKey(
|
|
LSERVER_LSA_PRIVATEKEY_EXCHANGE,
|
|
&pbEKey,
|
|
&cbEKey
|
|
);
|
|
|
|
if(dwStatus == ERROR_SUCCESS)
|
|
{
|
|
dwStatus = RetrieveKey(
|
|
LSERVER_LSA_PRIVATEKEY_SIGNATURE,
|
|
&pbSKey,
|
|
&cbSKey
|
|
);
|
|
}
|
|
|
|
if(dwStatus != ERROR_SUCCESS)
|
|
{
|
|
if(pbEKey != NULL)
|
|
{
|
|
LocalFree(pbEKey);
|
|
}
|
|
|
|
if(pbSKey != NULL)
|
|
{
|
|
LocalFree(pbSKey);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*ppbSignKey = pbSKey;
|
|
*pcbSignKey = cbEKey;
|
|
|
|
*ppbExchKey = pbEKey;
|
|
*pcbExchKey = cbEKey;
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
TLSSaveCryptKeyToLsa(
|
|
IN PBYTE pbSignKey,
|
|
IN DWORD cbSignKey,
|
|
IN PBYTE pbExchKey,
|
|
IN DWORD cbExchKey
|
|
)
|
|
|
|
/*++
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwStatus;
|
|
|
|
//
|
|
// Save the key to LSA.
|
|
//
|
|
dwStatus = StoreKey(
|
|
LSERVER_LSA_PRIVATEKEY_SIGNATURE,
|
|
pbSignKey,
|
|
cbSignKey
|
|
);
|
|
|
|
if(dwStatus == ERROR_SUCCESS)
|
|
{
|
|
dwStatus = StoreKey(
|
|
LSERVER_LSA_PRIVATEKEY_EXCHANGE,
|
|
pbExchKey,
|
|
cbExchKey
|
|
);
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
TLSCryptGenerateNewKeys(
|
|
OUT PBYTE* pbSignKey,
|
|
OUT DWORD* cbSignKey,
|
|
OUT PBYTE* pbExchKey,
|
|
OUT DWORD* cbExchKey
|
|
)
|
|
/*++
|
|
|
|
Abstract:
|
|
|
|
Generate a new pair of public/private key. First randomly create
|
|
a key container and use it to create new keys.
|
|
|
|
Parameters:
|
|
|
|
*pbSignKey : Pointer to PBYTE to receive new signature key.
|
|
*cbSignKey : Pointer to DWORD to receive size of new sign. key.
|
|
*pbExchKey : Pointer to PBYTE to receive new exchange key.
|
|
*cbExchKey : Pointer to DWORD to receive size of new exchange key.
|
|
|
|
Return:
|
|
|
|
ERROR_SUCCESS or CRYPTO Error Code.
|
|
|
|
--*/
|
|
{
|
|
TCHAR szKeyContainer[MAX_KEY_CONTAINER_LENGTH+1];
|
|
HCRYPTPROV hCryptProv = NULL;
|
|
HCRYPTKEY hSignKey = NULL;
|
|
HCRYPTKEY hExchKey = NULL;
|
|
DWORD dwStatus;
|
|
|
|
*pbSignKey = NULL;
|
|
*pbExchKey = NULL;
|
|
|
|
//
|
|
// Randomly create a key container
|
|
//
|
|
memset(szKeyContainer, 0, sizeof(szKeyContainer));
|
|
|
|
_sntprintf(
|
|
szKeyContainer,
|
|
MAX_KEY_CONTAINER_LENGTH,
|
|
_TEXT("TlsContainer%d"),
|
|
GetCurrentThreadId()
|
|
);
|
|
|
|
//
|
|
// Delete this key container, ignore error.
|
|
//
|
|
CryptAcquireContext(
|
|
&hCryptProv,
|
|
szKeyContainer,
|
|
DEFAULT_CSP,
|
|
PROVIDER_TYPE,
|
|
CRYPT_DELETEKEYSET
|
|
);
|
|
|
|
//
|
|
// Open a default key container
|
|
//
|
|
if(!CryptAcquireContext(
|
|
&hCryptProv,
|
|
szKeyContainer,
|
|
DEFAULT_CSP,
|
|
PROVIDER_TYPE,
|
|
CRYPT_NEWKEYSET
|
|
))
|
|
{
|
|
TLSLogEvent(
|
|
EVENTLOG_ERROR_TYPE,
|
|
TLS_E_GENERATEKEYS,
|
|
TLS_E_CRYPT_ACQUIRE_CONTEXT,
|
|
dwStatus = GetLastError()
|
|
);
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Generate a signature public/private key pair
|
|
//
|
|
if(!CryptGetUserKey(hCryptProv, AT_SIGNATURE, &hSignKey))
|
|
{
|
|
dwStatus=GetLastError();
|
|
|
|
if( GetLastError() != NTE_NO_KEY ||
|
|
!CryptGenKey(hCryptProv, AT_SIGNATURE, CRYPT_EXPORTABLE, &hSignKey))
|
|
{
|
|
TLSLogEvent(
|
|
EVENTLOG_ERROR_TYPE,
|
|
TLS_E_GENERATEKEYS,
|
|
TLS_E_CRYPT_CREATE_KEY,
|
|
dwStatus=GetLastError()
|
|
);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
dwStatus = ERROR_SUCCESS;
|
|
|
|
//
|
|
// export the public/private key of signature key
|
|
//
|
|
if( !CryptExportKey(hSignKey, NULL, PRIVATEKEYBLOB, 0, *pbSignKey, cbSignKey) &&
|
|
GetLastError() != ERROR_MORE_DATA)
|
|
{
|
|
TLSLogEvent(
|
|
EVENTLOG_ERROR_TYPE,
|
|
TLS_E_GENERATEKEYS,
|
|
TLS_E_EXPORT_KEY,
|
|
dwStatus=GetLastError()
|
|
);
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
*pbSignKey=(PBYTE)AllocateMemory(*cbSignKey);
|
|
if(*pbSignKey == NULL)
|
|
{
|
|
TLSLogErrorEvent(TLS_E_ALLOCATE_MEMORY);
|
|
dwStatus=GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
if(!CryptExportKey(hSignKey, NULL, PRIVATEKEYBLOB, 0, *pbSignKey, cbSignKey))
|
|
{
|
|
TLSLogEvent(
|
|
EVENTLOG_ERROR_TYPE,
|
|
TLS_E_GENERATEKEYS,
|
|
TLS_E_EXPORT_KEY,
|
|
dwStatus=GetLastError()
|
|
);
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Generate a exchange public/private key pair
|
|
if(!CryptGetUserKey(hCryptProv, AT_KEYEXCHANGE, &hExchKey))
|
|
{
|
|
dwStatus=GetLastError();
|
|
|
|
if( GetLastError() != NTE_NO_KEY ||
|
|
!CryptGenKey(hCryptProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hExchKey))
|
|
{
|
|
TLSLogEvent(
|
|
EVENTLOG_ERROR_TYPE,
|
|
TLS_E_GENERATEKEYS,
|
|
TLS_E_CRYPT_CREATE_KEY,
|
|
dwStatus=GetLastError()
|
|
);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
dwStatus = ERROR_SUCCESS;
|
|
|
|
//
|
|
// export the public/private key of exchange key
|
|
//
|
|
if( !CryptExportKey(hExchKey, NULL, PRIVATEKEYBLOB, 0, *pbExchKey, cbExchKey) &&
|
|
GetLastError() != ERROR_MORE_DATA)
|
|
{
|
|
TLSLogEvent(
|
|
EVENTLOG_ERROR_TYPE,
|
|
TLS_E_GENERATEKEYS,
|
|
TLS_E_EXPORT_KEY,
|
|
dwStatus=GetLastError()
|
|
);
|
|
goto cleanup;
|
|
}
|
|
|
|
*pbExchKey=(PBYTE)AllocateMemory(*cbExchKey);
|
|
if(*pbExchKey == NULL)
|
|
{
|
|
TLSLogErrorEvent(TLS_E_ALLOCATE_MEMORY);
|
|
dwStatus = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
if(!CryptExportKey(hExchKey, NULL, PRIVATEKEYBLOB, 0, *pbExchKey, cbExchKey))
|
|
{
|
|
TLSLogEvent(
|
|
EVENTLOG_ERROR_TYPE,
|
|
TLS_E_GENERATEKEYS,
|
|
TLS_E_EXPORT_KEY,
|
|
dwStatus=GetLastError()
|
|
);
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
cleanup:
|
|
|
|
if(hSignKey != NULL)
|
|
{
|
|
CryptDestroyKey(hSignKey);
|
|
}
|
|
|
|
if(hExchKey != NULL)
|
|
{
|
|
CryptDestroyKey(hExchKey);
|
|
}
|
|
|
|
if(hCryptProv)
|
|
{
|
|
CryptReleaseContext(hCryptProv, 0);
|
|
}
|
|
|
|
hCryptProv=NULL;
|
|
|
|
//
|
|
// Delete key container and ignore error
|
|
//
|
|
CryptAcquireContext(
|
|
&hCryptProv,
|
|
szKeyContainer,
|
|
DEFAULT_CSP,
|
|
PROVIDER_TYPE,
|
|
CRYPT_DELETEKEYSET
|
|
);
|
|
|
|
if(dwStatus != ERROR_SUCCESS)
|
|
{
|
|
FreeMemory(*pbSignKey);
|
|
FreeMemory(*pbExchKey);
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
TLSImportSavedKey(
|
|
IN HCRYPTPROV hCryptProv,
|
|
IN PBYTE pbSignKey,
|
|
IN DWORD cbSignKey,
|
|
IN PBYTE pbExchKey,
|
|
IN DWORD cbExchKey,
|
|
OUT HCRYPTKEY* pSignKey,
|
|
OUT HCRYPTKEY* pExchKey
|
|
)
|
|
/*
|
|
|
|
*/
|
|
{
|
|
DWORD status=ERROR_SUCCESS;
|
|
|
|
if(!CryptImportKey(
|
|
hCryptProv,
|
|
pbSignKey,
|
|
cbSignKey,
|
|
NULL,
|
|
0,
|
|
pSignKey
|
|
))
|
|
{
|
|
status = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
if(!CryptImportKey(
|
|
hCryptProv,
|
|
pbExchKey,
|
|
cbExchKey,
|
|
NULL,
|
|
0,
|
|
pExchKey
|
|
))
|
|
{
|
|
status = GetLastError();
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if(status != ERROR_SUCCESS)
|
|
{
|
|
TLSLogEvent(
|
|
EVENTLOG_ERROR_TYPE,
|
|
TLS_E_SERVICEINIT,
|
|
TLS_E_CRYPT_IMPORT_KEY,
|
|
status
|
|
);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
TLSLoadSelfSignCertificates(
|
|
IN HCRYPTPROV hCryptProv,
|
|
IN PBYTE pbSPK,
|
|
IN DWORD cbSPK,
|
|
OUT PDWORD pcbSignCert,
|
|
OUT PBYTE* ppbSignCert,
|
|
OUT PDWORD pcbExchCert,
|
|
OUT PBYTE* ppbExchCert
|
|
)
|
|
/*
|
|
|
|
Abstract:
|
|
|
|
Create a self-signed signature/exchange certificate.
|
|
|
|
Parameters:
|
|
|
|
pcbSignCert : Pointer to DWORD to receive size of sign. certificate.
|
|
ppbSignCert : Pointer to PBYTE to receive self-signed sign. certificate.
|
|
pcbExchCert : Pointer to DWORD to receive size of exch. certificate.
|
|
ppbExchCert : Pointer to PBYTE to receive self-signed exch. certificate.
|
|
|
|
Returns:
|
|
|
|
|
|
*/
|
|
{
|
|
DWORD status;
|
|
DWORD dwDisposition;
|
|
DWORD cbSign=0;
|
|
PBYTE pbSign=NULL;
|
|
DWORD cbExch=0;
|
|
PBYTE pbExch=NULL;
|
|
|
|
do {
|
|
//
|
|
// Create Signature and Exchange certificate
|
|
//
|
|
status=TLSCreateSelfSignCertificate(
|
|
hCryptProv,
|
|
AT_SIGNATURE,
|
|
pbSPK,
|
|
cbSPK,
|
|
0,
|
|
NULL,
|
|
&cbSign,
|
|
&pbSign
|
|
);
|
|
if(status != ERROR_SUCCESS)
|
|
{
|
|
status=TLS_E_CREATE_SELFSIGN_CERT;
|
|
break;
|
|
}
|
|
|
|
status=TLSCreateSelfSignCertificate(
|
|
hCryptProv,
|
|
AT_KEYEXCHANGE,
|
|
pbSPK,
|
|
cbSPK,
|
|
0,
|
|
NULL,
|
|
&cbExch,
|
|
&pbExch
|
|
);
|
|
if(status != ERROR_SUCCESS)
|
|
{
|
|
status=TLS_E_CREATE_SELFSIGN_CERT;
|
|
break;
|
|
}
|
|
|
|
} while(FALSE);
|
|
|
|
if(status == ERROR_SUCCESS)
|
|
{
|
|
*pcbSignCert = cbSign;
|
|
*ppbSignCert = pbSign;
|
|
*pcbExchCert = cbExch;
|
|
*ppbExchCert = pbExch;
|
|
}
|
|
else
|
|
{
|
|
FreeMemory(pbExch);
|
|
FreeMemory(pbSign);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
TLSLoadCHEndosedCertificate(
|
|
PDWORD pcbSignCert,
|
|
PBYTE* ppbSignCert,
|
|
PDWORD pcbExchCert,
|
|
PBYTE* ppbExchCert
|
|
)
|
|
/*
|
|
|
|
*/
|
|
{
|
|
LONG status;
|
|
|
|
#if ENFORCE_LICENSING
|
|
|
|
DWORD cbSign=0;
|
|
PBYTE pbSign=NULL;
|
|
DWORD cbExch=0;
|
|
PBYTE pbExch=NULL;
|
|
|
|
//
|
|
// look into registry to see if our certificate is there
|
|
//
|
|
HKEY hKey=NULL;
|
|
LPTSTR lpSubkey=LSERVER_SERVER_CERTIFICATE_REGKEY;
|
|
|
|
do {
|
|
status=RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
lpSubkey,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hKey
|
|
);
|
|
if(status != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Load Signature certificate
|
|
//
|
|
status = RegQueryValueEx(
|
|
hKey,
|
|
LSERVER_SIGNATURE_CERT_KEY,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&cbSign
|
|
);
|
|
|
|
if(status != ERROR_MORE_DATA && status != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(!(pbSign=(PBYTE)AllocateMemory(cbSign)))
|
|
{
|
|
status = GetLastError();
|
|
break;
|
|
}
|
|
|
|
status = RegQueryValueEx(
|
|
hKey,
|
|
LSERVER_SIGNATURE_CERT_KEY,
|
|
NULL,
|
|
NULL,
|
|
pbSign,
|
|
&cbSign
|
|
);
|
|
|
|
if(status != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Load Exchange certificate
|
|
//
|
|
status = RegQueryValueEx(
|
|
hKey,
|
|
LSERVER_EXCHANGE_CERT_KEY,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&cbExch
|
|
);
|
|
if(status != ERROR_MORE_DATA && status != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(!(pbExch=(PBYTE)AllocateMemory(cbExch)))
|
|
{
|
|
status = GetLastError();
|
|
break;
|
|
}
|
|
|
|
status = RegQueryValueEx(
|
|
hKey,
|
|
LSERVER_EXCHANGE_CERT_KEY,
|
|
NULL,
|
|
NULL,
|
|
pbExch,
|
|
&cbExch
|
|
);
|
|
if(status != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
} while(FALSE);
|
|
|
|
//
|
|
// Must have both certificate
|
|
//
|
|
if(status == ERROR_SUCCESS && pbExch && pbSign)
|
|
{
|
|
*pcbSignCert = cbSign;
|
|
*ppbSignCert = pbSign;
|
|
|
|
*pcbExchCert = cbExch;
|
|
*ppbExchCert = pbExch;
|
|
}
|
|
else
|
|
{
|
|
FreeMemory(pbExch);
|
|
FreeMemory(pbSign);
|
|
status = TLS_E_NO_CERTIFICATE;
|
|
}
|
|
|
|
if(hKey)
|
|
{
|
|
RegCloseKey(hKey);
|
|
}
|
|
#else
|
|
|
|
//
|
|
// Non enfoce version always return no certificate
|
|
//
|
|
status = TLS_E_NO_CERTIFICATE;
|
|
|
|
#endif
|
|
|
|
return status;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
TLSInstallLsCertificate(
|
|
DWORD cbLsSignCert,
|
|
PBYTE pbLsSignCert,
|
|
DWORD cbLsExchCert,
|
|
PBYTE pbLsExchCert
|
|
)
|
|
/*
|
|
|
|
*/
|
|
{
|
|
HKEY hKey=NULL;
|
|
LONG status=ERROR_SUCCESS;
|
|
DWORD dwDisposition;
|
|
PCCERT_CONTEXT pCertContext=NULL;
|
|
DWORD cbNameBlob=0;
|
|
LPTSTR pbNameBlob=NULL;
|
|
|
|
#if ENFORCE_LICENSING
|
|
|
|
do {
|
|
status = RegCreateKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
LSERVER_SERVER_CERTIFICATE_REGKEY,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
&dwDisposition
|
|
);
|
|
if(status != ERROR_SUCCESS)
|
|
{
|
|
TLSLogEvent(
|
|
EVENTLOG_ERROR_TYPE,
|
|
TLS_E_STORELSCERTIFICATE,
|
|
TLS_E_ACCESS_REGISTRY,
|
|
status
|
|
);
|
|
break;
|
|
}
|
|
|
|
if(pbLsExchCert)
|
|
{
|
|
status = RegSetValueEx(
|
|
hKey,
|
|
LSERVER_EXCHANGE_CERT_KEY,
|
|
0,
|
|
REG_BINARY,
|
|
pbLsExchCert,
|
|
cbLsExchCert
|
|
);
|
|
if(status != ERROR_SUCCESS)
|
|
{
|
|
TLSLogEvent(
|
|
EVENTLOG_ERROR_TYPE,
|
|
TLS_E_STORELSCERTIFICATE,
|
|
TLS_E_ACCESS_REGISTRY,
|
|
status
|
|
);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if(pbLsSignCert)
|
|
{
|
|
status = RegSetValueEx(
|
|
hKey,
|
|
LSERVER_SIGNATURE_CERT_KEY,
|
|
0,
|
|
REG_BINARY,
|
|
pbLsSignCert,
|
|
cbLsSignCert
|
|
);
|
|
if(status != ERROR_SUCCESS)
|
|
{
|
|
TLSLogEvent(
|
|
EVENTLOG_ERROR_TYPE,
|
|
TLS_E_STORELSCERTIFICATE,
|
|
TLS_E_ACCESS_REGISTRY,
|
|
status
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// extract Subject field in exchange certificate and save i registry
|
|
// When issuing new license, we need to use this as Issuer.
|
|
//
|
|
|
|
pCertContext = CertCreateCertificateContext(
|
|
X509_ASN_ENCODING,
|
|
pbLsSignCert,
|
|
cbLsSignCert
|
|
);
|
|
|
|
cbNameBlob=CertNameToStr(
|
|
X509_ASN_ENCODING,
|
|
&pCertContext->pCertInfo->Subject,
|
|
CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG,
|
|
NULL,
|
|
0
|
|
);
|
|
if(cbNameBlob)
|
|
{
|
|
pbNameBlob=(LPTSTR)AllocateMemory((cbNameBlob+1) * sizeof(TCHAR));
|
|
if(pbNameBlob)
|
|
{
|
|
CertNameToStr(
|
|
X509_ASN_ENCODING,
|
|
&pCertContext->pCertInfo->Subject,
|
|
CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG,
|
|
pbNameBlob,
|
|
cbNameBlob
|
|
);
|
|
}
|
|
}
|
|
|
|
status = RegSetValueEx(
|
|
hKey,
|
|
LSERVER_CLIENT_CERTIFICATE_ISSUER,
|
|
0,
|
|
REG_BINARY,
|
|
(PBYTE)pbNameBlob,
|
|
cbNameBlob+sizeof(TCHAR)
|
|
);
|
|
if(status != ERROR_SUCCESS)
|
|
{
|
|
TLSLogEvent(
|
|
EVENTLOG_ERROR_TYPE,
|
|
TLS_E_STORELSCERTIFICATE,
|
|
TLS_E_ACCESS_REGISTRY,
|
|
status
|
|
);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(hKey)
|
|
{
|
|
//
|
|
// Close registry, got error while try to load it again???
|
|
//
|
|
RegCloseKey(hKey);
|
|
hKey = NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Only reload certificate when we have both
|
|
//
|
|
if(pbLsSignCert && pbLsExchCert)
|
|
{
|
|
//
|
|
// All RPC calls are blocked.
|
|
//
|
|
FreeMemory(g_pbSignatureEncodedCert);
|
|
FreeMemory(g_pbExchangeEncodedCert);
|
|
g_cbSignatureEncodedCert = 0;
|
|
g_cbExchangeEncodedCert = 0;
|
|
//TLSLoadServerCertificate();
|
|
}
|
|
} while(FALSE);
|
|
|
|
FreeMemory(pbNameBlob);
|
|
|
|
if(pCertContext)
|
|
{
|
|
CertFreeCertificateContext(pCertContext);
|
|
}
|
|
|
|
if(hKey)
|
|
{
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
#endif
|
|
|
|
return status;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
TLSUninstallLsCertificate()
|
|
{
|
|
HKEY hKey=NULL;
|
|
DWORD status;
|
|
|
|
status=RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
LSERVER_SERVER_CERTIFICATE_REGKEY,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hKey
|
|
);
|
|
if(status == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Ignore error
|
|
RegDeleteValue(
|
|
hKey,
|
|
LSERVER_SIGNATURE_CERT_KEY
|
|
);
|
|
|
|
RegDeleteValue(
|
|
hKey,
|
|
LSERVER_EXCHANGE_CERT_KEY
|
|
);
|
|
|
|
RegDeleteValue(
|
|
hKey,
|
|
LSERVER_CLIENT_CERTIFICATE_ISSUER
|
|
);
|
|
}
|
|
|
|
if(hKey != NULL)
|
|
{
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
//
|
|
// Delete all certificate in registry store including all backup
|
|
// ignore error on deleting backup store.
|
|
//
|
|
TLSRegDeleteKey(
|
|
HKEY_LOCAL_MACHINE,
|
|
LSERVER_SERVER_CERTIFICATE_REGKEY_BACKUP1
|
|
);
|
|
|
|
TLSRegDeleteKey(
|
|
HKEY_LOCAL_MACHINE,
|
|
LSERVER_SERVER_CERTIFICATE_REGKEY_BACKUP2
|
|
);
|
|
|
|
status = TLSRegDeleteKey(
|
|
HKEY_LOCAL_MACHINE,
|
|
LSERVER_SERVER_CERTIFICATE_REGKEY
|
|
);
|
|
|
|
return status;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
TLSInitCryptoProv(
|
|
IN LPCTSTR pszKeyContainer,
|
|
IN PBYTE pbSignKey,
|
|
IN DWORD cbSignKey,
|
|
IN PBYTE pbExchKey,
|
|
IN DWORD cbExchKey,
|
|
OUT HCRYPTPROV* phCryptProv,
|
|
OUT HCRYPTKEY* phSignKey,
|
|
OUT HCRYPTKEY* phExchKey
|
|
)
|
|
/*
|
|
|
|
Abstract:
|
|
|
|
Routine to create a clean Crypto. Prov, generate a new pair of keys and
|
|
import these keys into newly created Crypt. prov.
|
|
|
|
Parameters:
|
|
|
|
pszKeyContainer : Name of the key container.
|
|
phCryptProv : Pointer to HCRYPTPROV to receive new handle to Crypto. prov.
|
|
|
|
*/
|
|
{
|
|
DWORD dwStatus;
|
|
|
|
if( pbSignKey == NULL || cbSignKey == NULL ||
|
|
pbExchKey == NULL || cbExchKey == NULL ||
|
|
phCryptProv == NULL || phSignKey == NULL ||
|
|
phExchKey == NULL )
|
|
{
|
|
SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Initialize a clean Crypt.
|
|
//
|
|
dwStatus = InitCryptoProv(
|
|
pszKeyContainer,
|
|
phCryptProv
|
|
);
|
|
|
|
if(dwStatus == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Import Key into Crypt.
|
|
//
|
|
dwStatus = TLSImportSavedKey(
|
|
*phCryptProv,
|
|
pbSignKey,
|
|
cbSignKey,
|
|
pbExchKey,
|
|
cbExchKey,
|
|
phSignKey,
|
|
phExchKey
|
|
);
|
|
}
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
|
|
DWORD
|
|
TLSVerifyCertChainInMomory(
|
|
IN HCRYPTPROV hCryptProv,
|
|
IN PBYTE pbData,
|
|
IN DWORD cbData
|
|
)
|
|
/*++
|
|
|
|
Abstract:
|
|
|
|
Verify PKCS7 certificate chain in memory.
|
|
|
|
Parameters:
|
|
|
|
pbData : Input PKCS7 ceritifcate chain.
|
|
cbData : size of pbData
|
|
|
|
Returns:
|
|
|
|
|
|
++*/
|
|
{
|
|
PCCERT_CONTEXT pCertContext=NULL;
|
|
PCCERT_CONTEXT pCertPrevContext=NULL;
|
|
|
|
HCERTSTORE hCertStore=NULL;
|
|
DWORD dwStatus=ERROR_SUCCESS;
|
|
DWORD dwLastVerification;
|
|
CRYPT_DATA_BLOB Serialized;
|
|
FILETIME ft;
|
|
|
|
if(hCryptProv == NULL || pbData == NULL || cbData == NULL)
|
|
{
|
|
SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
|
|
goto cleanup;
|
|
}
|
|
|
|
Serialized.pbData = pbData;
|
|
Serialized.cbData = cbData;
|
|
|
|
hCertStore=CertOpenStore(
|
|
szLICENSE_BLOB_SAVEAS_TYPE,
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
hCryptProv,
|
|
CERT_STORE_NO_CRYPT_RELEASE_FLAG,
|
|
&Serialized
|
|
);
|
|
|
|
if(!hCertStore)
|
|
{
|
|
dwStatus=GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Enumerate all certificates.
|
|
//
|
|
dwStatus = ERROR_SUCCESS;
|
|
|
|
do {
|
|
pCertPrevContext = pCertContext;
|
|
pCertContext = CertEnumCertificatesInStore(
|
|
hCertStore,
|
|
pCertPrevContext
|
|
);
|
|
|
|
if(pCertContext == NULL)
|
|
{
|
|
dwStatus = GetLastError();
|
|
if(dwStatus = CRYPT_E_NOT_FOUND)
|
|
{
|
|
dwStatus = ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
dwStatus = TLSVerifyCertChain(
|
|
hCryptProv,
|
|
hCertStore,
|
|
pCertContext,
|
|
&ft
|
|
);
|
|
} while (pCertContext != NULL && dwStatus == ERROR_SUCCESS);
|
|
|
|
cleanup:
|
|
|
|
if(pCertContext != NULL)
|
|
{
|
|
CertFreeCertificateContext(pCertContext);
|
|
}
|
|
|
|
if(hCertStore)
|
|
{
|
|
CertCloseStore(
|
|
hCertStore,
|
|
CERT_CLOSE_STORE_FORCE_FLAG
|
|
);
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
TLSRegDeleteKey(
|
|
IN HKEY hRegKey,
|
|
IN LPCTSTR pszSubKey
|
|
)
|
|
/*++
|
|
|
|
Abstract:
|
|
|
|
Recursively delete entire registry key.
|
|
|
|
Parameter:
|
|
|
|
HKEY :
|
|
pszSubKey :
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS or error code.
|
|
|
|
++*/
|
|
{
|
|
DWORD dwStatus;
|
|
HKEY hSubKey = NULL;
|
|
int index;
|
|
|
|
DWORD dwNumSubKeys;
|
|
DWORD dwMaxSubKeyLength;
|
|
DWORD dwSubKeyLength;
|
|
LPTSTR pszSubKeyName = NULL;
|
|
|
|
DWORD dwMaxValueNameLen;
|
|
LPTSTR pszValueName = NULL;
|
|
DWORD dwValueNameLength;
|
|
|
|
|
|
dwStatus = RegOpenKeyEx(
|
|
hRegKey,
|
|
pszSubKey,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hSubKey
|
|
);
|
|
|
|
if(dwStatus != ERROR_SUCCESS)
|
|
{
|
|
// key does not exist
|
|
return dwStatus;
|
|
}
|
|
|
|
//
|
|
// Query number of subkeys
|
|
//
|
|
dwStatus = RegQueryInfoKey(
|
|
hSubKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&dwNumSubKeys,
|
|
&dwMaxSubKeyLength,
|
|
NULL,
|
|
NULL,
|
|
&dwMaxValueNameLen,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if(dwStatus != ERROR_SUCCESS)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
dwMaxValueNameLen++;
|
|
pszValueName = (LPTSTR)AllocateMemory(dwMaxValueNameLen * sizeof(TCHAR));
|
|
if(pszValueName == NULL)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
if(dwNumSubKeys > 0)
|
|
{
|
|
// allocate buffer for subkeys.
|
|
|
|
dwMaxSubKeyLength++;
|
|
pszSubKeyName = (LPTSTR)AllocateMemory(dwMaxSubKeyLength * sizeof(TCHAR));
|
|
if(pszSubKeyName == NULL)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
//for(index = 0; index < dwNumSubKeys; index++)
|
|
for(;dwStatus == ERROR_SUCCESS;)
|
|
{
|
|
// delete this subkey.
|
|
dwSubKeyLength = dwMaxSubKeyLength;
|
|
memset(pszSubKeyName, 0, dwMaxSubKeyLength * sizeof(TCHAR));
|
|
|
|
// retrieve subkey name
|
|
dwStatus = RegEnumKeyEx(
|
|
hSubKey,
|
|
(DWORD)0,
|
|
pszSubKeyName,
|
|
&dwSubKeyLength,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if(dwStatus == ERROR_SUCCESS)
|
|
{
|
|
dwStatus = TLSRegDeleteKey( hSubKey, pszSubKeyName );
|
|
}
|
|
|
|
// ignore any error and continue on
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
|
|
for(dwStatus = ERROR_SUCCESS; pszValueName != NULL && dwStatus == ERROR_SUCCESS;)
|
|
{
|
|
dwValueNameLength = dwMaxValueNameLen;
|
|
memset(pszValueName, 0, dwMaxValueNameLen * sizeof(TCHAR));
|
|
|
|
dwStatus = RegEnumValue(
|
|
hSubKey,
|
|
0,
|
|
pszValueName,
|
|
&dwValueNameLength,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if(dwStatus == ERROR_SUCCESS)
|
|
{
|
|
RegDeleteValue(hSubKey, pszValueName);
|
|
}
|
|
}
|
|
|
|
// close the key before trying to delete it.
|
|
if(hSubKey != NULL)
|
|
{
|
|
RegCloseKey(hSubKey);
|
|
}
|
|
|
|
// try to delete this key, will fail if any of the subkey
|
|
// failed to delete in loop
|
|
dwStatus = RegDeleteKey(
|
|
hRegKey,
|
|
pszSubKey
|
|
);
|
|
|
|
|
|
|
|
if(pszValueName != NULL)
|
|
{
|
|
FreeMemory(pszValueName);
|
|
}
|
|
|
|
if(pszSubKeyName != NULL)
|
|
{
|
|
FreeMemory(pszSubKeyName);
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
TLSTreeCopyRegKey(
|
|
IN HKEY hSourceRegKey,
|
|
IN LPCTSTR pszSourceSubKey,
|
|
IN HKEY hDestRegKey,
|
|
IN LPCTSTR pszDestSubKey
|
|
)
|
|
/*++
|
|
|
|
Abstract:
|
|
|
|
Tree copy of a registry key to another.
|
|
|
|
Parameters:
|
|
|
|
hSourceRegKey : Source registry key.
|
|
pszSourceSubKey : Source subkey name.
|
|
hDestRegKey : Destination key.
|
|
pszDestSubKey : Destination key name
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS or WIN32 error code.
|
|
|
|
Note:
|
|
|
|
This routine doesn't deal with security...
|
|
|
|
++*/
|
|
{
|
|
DWORD dwStatus;
|
|
HKEY hSourceSubKey = NULL;
|
|
HKEY hDestSubKey = NULL;
|
|
int index;
|
|
|
|
DWORD dwNumSubKeys;
|
|
DWORD dwMaxSubKeyLength;
|
|
DWORD dwSubKeyLength;
|
|
LPTSTR pszSubKeyName = NULL;
|
|
|
|
DWORD dwMaxValueNameLen;
|
|
LPTSTR pszValueName = NULL;
|
|
DWORD dwValueNameLength;
|
|
DWORD dwNumValues = 0;
|
|
DWORD dwMaxValueLength;
|
|
PBYTE pbValue = NULL;
|
|
|
|
DWORD dwDisposition;
|
|
|
|
DWORD cbSecurityDescriptor;
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
|
|
|
|
|
|
//
|
|
// Open source registry key, must exist
|
|
//
|
|
dwStatus = RegOpenKeyEx(
|
|
hSourceRegKey,
|
|
pszSourceSubKey,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hSourceSubKey
|
|
);
|
|
|
|
if(dwStatus != ERROR_SUCCESS)
|
|
{
|
|
// key does not exist
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Query number of subkeys
|
|
//
|
|
dwStatus = RegQueryInfoKey(
|
|
hSourceSubKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&dwNumSubKeys, // number of subkey
|
|
&dwMaxSubKeyLength, // max. subkey length
|
|
NULL,
|
|
&dwNumValues,
|
|
&dwMaxValueNameLen, // max. value length
|
|
&dwMaxValueLength, // max. value size.
|
|
&cbSecurityDescriptor, // size of security descriptor
|
|
NULL
|
|
);
|
|
|
|
if(dwStatus != ERROR_SUCCESS)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
#if 0
|
|
|
|
//
|
|
// TODO - get this to work, currently, we don't need security
|
|
//
|
|
if(cbSecurityDescriptor > 0)
|
|
{
|
|
//
|
|
// Retrieve security descriptor for this key.
|
|
//
|
|
pSecurityDescriptor = (PSECURITY_DESCRIPTOR)AllocateMemory(cbSecurityDescriptor * sizeof(BYTE));
|
|
if(pSecurityDescriptor == NULL)
|
|
{
|
|
dwStatus = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
dwStatus = RegGetKeySecurity(
|
|
hSourceSubKey,
|
|
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
|
pSecurityDescriptor,
|
|
&cbSecurityDescriptor
|
|
);
|
|
|
|
if(dwStatus != ERROR_SUCCESS)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Create destination key
|
|
//
|
|
dwStatus = RegCreateKeyEx(
|
|
hDestRegKey,
|
|
pszDestSubKey,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hDestSubKey,
|
|
&dwDisposition
|
|
);
|
|
|
|
if(dwStatus != ERROR_SUCCESS)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
#if 0
|
|
|
|
//
|
|
// TODO - get this to work, currently, we don't need security.
|
|
//
|
|
|
|
if(pSecurityDescriptor != NULL)
|
|
{
|
|
dwStatus = RegSetKeySecurity(
|
|
hDestRegKey,
|
|
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
|
pSecurityDescriptor
|
|
);
|
|
if(dwStatus != ERROR_SUCCESS)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
if(pSecurityDescriptor != NULL)
|
|
{
|
|
FreeMemory(pSecurityDescriptor);
|
|
pSecurityDescriptor = NULL;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// Copy all subkeys first, we are doing recursive so copy subkey first will
|
|
// save us some memory.
|
|
//
|
|
if(dwNumSubKeys > 0)
|
|
{
|
|
// allocate buffer for subkeys.
|
|
dwMaxSubKeyLength++;
|
|
pszSubKeyName = (LPTSTR)AllocateMemory(dwMaxSubKeyLength * sizeof(TCHAR));
|
|
if(pszSubKeyName == NULL)
|
|
{
|
|
dwStatus = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
for(index = 0, dwStatus = ERROR_SUCCESS;
|
|
dwStatus == ERROR_SUCCESS;
|
|
index++)
|
|
{
|
|
dwSubKeyLength = dwMaxSubKeyLength;
|
|
memset(pszSubKeyName, 0, dwMaxSubKeyLength * sizeof(TCHAR));
|
|
|
|
// retrieve subkey name
|
|
dwStatus = RegEnumKeyEx(
|
|
hSourceSubKey,
|
|
(DWORD)index,
|
|
pszSubKeyName,
|
|
&dwSubKeyLength,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if(dwStatus == ERROR_SUCCESS)
|
|
{
|
|
dwStatus = TLSTreeCopyRegKey(
|
|
hSourceSubKey,
|
|
pszSubKeyName,
|
|
hDestSubKey,
|
|
pszSubKeyName
|
|
);
|
|
}
|
|
}
|
|
|
|
if(dwStatus == ERROR_NO_MORE_ITEMS)
|
|
{
|
|
dwStatus = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
if(pszSubKeyName != NULL)
|
|
{
|
|
FreeMemory(pszSubKeyName);
|
|
pszSubKeyName = NULL;
|
|
}
|
|
|
|
if(dwNumValues > 0)
|
|
{
|
|
//
|
|
// allocate space for value name.
|
|
//
|
|
dwMaxValueNameLen++;
|
|
pszValueName = (LPTSTR)AllocateMemory(dwMaxValueNameLen * sizeof(TCHAR));
|
|
if(pszValueName == NULL)
|
|
{
|
|
dwStatus = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// allocate buffer for value
|
|
//
|
|
dwMaxValueLength += 2 * sizeof(TCHAR); // in case of string
|
|
pbValue = (PBYTE)AllocateMemory(dwMaxValueLength * sizeof(BYTE));
|
|
if(pbValue == NULL)
|
|
{
|
|
dwStatus = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Copy all value first
|
|
//
|
|
for(index=0, dwStatus = ERROR_SUCCESS;
|
|
pszValueName != NULL && dwStatus == ERROR_SUCCESS;
|
|
index ++)
|
|
{
|
|
DWORD dwValueType = 0;
|
|
DWORD cbValue = dwMaxValueLength;
|
|
|
|
dwValueNameLength = dwMaxValueNameLen;
|
|
memset(pszValueName, 0, dwMaxValueNameLen * sizeof(TCHAR));
|
|
|
|
dwStatus = RegEnumValue(
|
|
hSourceSubKey,
|
|
index,
|
|
pszValueName,
|
|
&dwValueNameLength,
|
|
NULL,
|
|
&dwValueType,
|
|
pbValue,
|
|
&cbValue
|
|
);
|
|
|
|
if(dwStatus == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Copy value
|
|
//
|
|
dwStatus = RegSetValueEx(
|
|
hDestSubKey,
|
|
pszValueName,
|
|
0,
|
|
dwValueType,
|
|
pbValue,
|
|
cbValue
|
|
);
|
|
}
|
|
}
|
|
|
|
if(dwStatus == ERROR_NO_MORE_ITEMS)
|
|
{
|
|
dwStatus = ERROR_SUCCESS;
|
|
}
|
|
|
|
if(dwStatus != ERROR_SUCCESS)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
|
|
// close the key before trying to delete it.
|
|
if(hSourceSubKey != NULL)
|
|
{
|
|
RegCloseKey(hSourceSubKey);
|
|
}
|
|
|
|
if(hDestSubKey != NULL)
|
|
{
|
|
RegCloseKey(hDestSubKey);
|
|
}
|
|
|
|
if(pszValueName != NULL)
|
|
{
|
|
FreeMemory(pszValueName);
|
|
}
|
|
|
|
if(pszSubKeyName != NULL)
|
|
{
|
|
FreeMemory(pszSubKeyName);
|
|
}
|
|
|
|
if(pbValue != NULL)
|
|
{
|
|
FreeMemory(pbValue);
|
|
}
|
|
|
|
if(pSecurityDescriptor != NULL)
|
|
{
|
|
FreeMemory(pSecurityDescriptor);
|
|
pSecurityDescriptor = NULL;
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|