|
|
//+--------------------------------------------------------------------------
//
// 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; }
|