//+------------------------------------------------------------------------- // // Microsoft Windows NT // // Copyright (C) Microsoft Corporation, 1995 - 1998 // // File: ceppswrd.cpp // // Contents: Cisco enrollment protocol implementation. This module // implement the password hash table. // //-------------------------------------------------------------------------- #include "global.hxx" #include DWORD g_dwPasswordCount=0; DWORD g_dwMaxPassword=0; DWORD g_dwPasswordValidity=0; CEP_PASSWORD_TABLE_INFO g_CEPPasswordTable; //*************************************************************************** // // The following are APIs called internally. // // //*************************************************************************** //-------------------------------------------------------------------------- // // CEPPasswordFreePasswordEntry // //-------------------------------------------------------------------------- void CEPPasswordFreePasswordEntry(CEP_PASSWORD_ENTRY *pPasswordEntry) { if(pPasswordEntry) { if(pPasswordEntry->pwszPassword) free(pPasswordEntry->pwszPassword); free(pPasswordEntry); } } //-------------------------------------------------------------------------- // // CEPPasswordFreeValidityEntry // //-------------------------------------------------------------------------- void CEPPasswordFreeValidityEntry(CEP_PASSWORD_VALIDITY_ENTRY *pValidityEntry, BOOL fFreePasswordEntry) { if(pValidityEntry) { if(fFreePasswordEntry) CEPPasswordFreePasswordEntry(pValidityEntry->pPasswordEntry); free(pValidityEntry); } } //-------------------------------------------------------------------------- // // CEPHashPassword // // For any cases that we can not convert the psz, we use index 0. //-------------------------------------------------------------------------- BOOL CEPHashPassword(LPWSTR pwsz, DWORD *pdw) { WCHAR wsz[3]; *pdw=0; if(!pwsz) return FALSE; if(2 <= wcslen(pwsz)) { memcpy(wsz, pwsz, 2 * sizeof(WCHAR)); wsz[2]=L'\0'; *pdw=wcstoul(wsz, NULL, 16); if(ULONG_MAX == *pdw) *pdw=0; } if(*pdw >= CEP_HASH_TABLE_SIZE) *pdw=0; return TRUE; } //-------------------------------------------------------------------------- // // CEPSearchPassword // //-------------------------------------------------------------------------- CEP_PASSWORD_ENTRY *CEPSearchPassword(LPWSTR pwszPassword, DWORD *pdwIndex) { CEP_PASSWORD_ENTRY *pPasswordEntry=NULL; DWORD dwHashIndex=0; if(pdwIndex) *pdwIndex=0; if(NULL==pwszPassword) return NULL; //hash based on the 1st and 2nd character if(!CEPHashPassword(pwszPassword, &dwHashIndex)) return NULL; for(pPasswordEntry=g_CEPPasswordTable.rgPasswordEntry[dwHashIndex]; NULL != pPasswordEntry; pPasswordEntry=pPasswordEntry->pNext) { if(0==wcscmp(pwszPassword, pPasswordEntry->pwszPassword)) { break; } } if(pPasswordEntry) { if(pdwIndex) *pdwIndex=dwHashIndex; } return pPasswordEntry; } //-------------------------------------------------------------------------- // // CEPInsertValidityEntry // //-------------------------------------------------------------------------- BOOL CEPInsertValidityEntry(CEP_PASSWORD_VALIDITY_ENTRY *pValidityEntry) { if(!pValidityEntry) return FALSE; if(g_CEPPasswordTable.pTimeNew) { g_CEPPasswordTable.pTimeNew->pNext=pValidityEntry; pValidityEntry->pPrevious=g_CEPPasswordTable.pTimeNew; g_CEPPasswordTable.pTimeNew=pValidityEntry; } else { //no item in the list yet g_CEPPasswordTable.pTimeOld=pValidityEntry; g_CEPPasswordTable.pTimeNew=pValidityEntry; } return TRUE; } //-------------------------------------------------------------------------- // // CEPInsertPasswordEntry // //-------------------------------------------------------------------------- BOOL CEPInsertPasswordEntry(CEP_PASSWORD_ENTRY *pPasswordEntry, DWORD dwHashIndex) { if(!pPasswordEntry) return FALSE; if(g_CEPPasswordTable.rgPasswordEntry[dwHashIndex]) { g_CEPPasswordTable.rgPasswordEntry[dwHashIndex]->pPrevious=pPasswordEntry; pPasswordEntry->pNext=g_CEPPasswordTable.rgPasswordEntry[dwHashIndex]; g_CEPPasswordTable.rgPasswordEntry[dwHashIndex]=pPasswordEntry; } else { //1st item g_CEPPasswordTable.rgPasswordEntry[dwHashIndex]=pPasswordEntry; } return TRUE; } //-------------------------------------------------------------------------- // // CEPPasswordRemoveValidityEntry // //-------------------------------------------------------------------------- BOOL CEPPasswordRemoveValidityEntry(CEP_PASSWORD_VALIDITY_ENTRY *pValidityEntry) { BOOL fResult=FALSE; if(!pValidityEntry) goto InvalidArgErr; if(pValidityEntry->pPrevious) pValidityEntry->pPrevious->pNext=pValidityEntry->pNext; else { //1st item g_CEPPasswordTable.pTimeOld=pValidityEntry->pNext; } if(pValidityEntry->pNext) pValidityEntry->pNext->pPrevious=pValidityEntry->pPrevious; else { //last itme g_CEPPasswordTable.pTimeNew=pValidityEntry->pPrevious; } fResult=TRUE; CommonReturn: return fResult; ErrorReturn: fResult=FALSE; goto CommonReturn; SET_ERROR(InvalidArgErr, E_INVALIDARG); } //-------------------------------------------------------------------------- // // CEPPasswordRemovePasswordEntry // //-------------------------------------------------------------------------- BOOL CEPPasswordRemovePasswordEntry(CEP_PASSWORD_ENTRY *pPasswordEntry, DWORD dwIndex) { BOOL fResult=FALSE; if(!pPasswordEntry) goto InvalidArgErr; if(pPasswordEntry->pPrevious) pPasswordEntry->pPrevious->pNext=pPasswordEntry->pNext; else g_CEPPasswordTable.rgPasswordEntry[dwIndex]=pPasswordEntry->pNext; if(pPasswordEntry->pNext) pPasswordEntry->pNext->pPrevious=pPasswordEntry->pPrevious; fResult=TRUE; CommonReturn: return fResult; ErrorReturn: fResult=FALSE; goto CommonReturn; SET_ERROR(InvalidArgErr, E_INVALIDARG); } //-------------------------------------------------------------------------- // // CEPPasswordRefresh // //-------------------------------------------------------------------------- BOOL CEPPasswordRefresh() { BOOL fResult=FALSE; DWORD dwHashIndex=0; CEP_PASSWORD_VALIDITY_ENTRY *pValidityEntry=NULL; while(g_CEPPasswordTable.pTimeOld) { if(!CEPHashIsCurrentTimeEntry(&(g_CEPPasswordTable.pTimeOld->TimeStamp), 0, g_dwPasswordValidity)) { if(!CEPHashPassword(g_CEPPasswordTable.pTimeOld->pPasswordEntry->pwszPassword, &dwHashIndex)) { g_CEPPasswordTable.pTimeOld->pPrevious=NULL; goto InvalidArgErr; } CEPPasswordRemovePasswordEntry(g_CEPPasswordTable.pTimeOld->pPasswordEntry, dwHashIndex); CEPPasswordFreePasswordEntry(g_CEPPasswordTable.pTimeOld->pPasswordEntry); pValidityEntry=g_CEPPasswordTable.pTimeOld; g_CEPPasswordTable.pTimeOld=g_CEPPasswordTable.pTimeOld->pNext; CEPPasswordFreeValidityEntry(pValidityEntry, FALSE); if(g_dwPasswordCount >= 1) g_dwPasswordCount--; } else { //we find a new enough entry g_CEPPasswordTable.pTimeOld->pPrevious=NULL; break; } } //we have get rid of all items if(NULL == g_CEPPasswordTable.pTimeOld) { g_CEPPasswordTable.pTimeNew=NULL; g_dwPasswordCount=0; } fResult=TRUE; CommonReturn: return fResult; ErrorReturn: fResult=FALSE; goto CommonReturn; SET_ERROR(InvalidArgErr, E_INVALIDARG); } //*************************************************************************** // // The following are APIs called by the upper (external) layer // // //*************************************************************************** //-------------------------------------------------------------------------- // // InitPasswordTable // //-------------------------------------------------------------------------- BOOL WINAPI InitPasswordTable() { DWORD cbData=0; DWORD dwData=0; DWORD dwType=0; HKEY hKey=NULL; memset(&g_CEPPasswordTable, 0, sizeof(CEP_PASSWORD_TABLE_INFO)); g_dwPasswordCount=0; g_dwMaxPassword=CEP_MAX_PASSWORD; g_dwPasswordValidity=CEP_PASSWORD_VALIDITY; if(ERROR_SUCCESS == RegOpenKeyExU( HKEY_LOCAL_MACHINE, MSCEP_PASSWORD_MAX_LOCATION, 0, KEY_READ, &hKey)) { cbData=sizeof(dwData); if(ERROR_SUCCESS == RegQueryValueExU( hKey, MSCEP_KEY_PASSWORD_MAX, NULL, &dwType, (BYTE *)&dwData, &cbData)) { if ((dwType == REG_DWORD) || (dwType == REG_BINARY)) { g_dwMaxPassword=dwData; } } } dwType=0; dwData=0; if(hKey) RegCloseKey(hKey); hKey=NULL; if(ERROR_SUCCESS == RegOpenKeyExU( HKEY_LOCAL_MACHINE, MSCEP_PASSWORD_VALIDITY_LOCATION, 0, KEY_READ, &hKey)) { cbData=sizeof(dwData); if(ERROR_SUCCESS == RegQueryValueExU( hKey, MSCEP_KEY_PASSWORD_VALIDITY, NULL, &dwType, (BYTE *)&dwData, &cbData)) { if ((dwType == REG_DWORD) || (dwType == REG_BINARY)) { g_dwPasswordValidity=dwData; } } } if(hKey) RegCloseKey(hKey); return TRUE; } //-------------------------------------------------------------------------- // // ReleasePasswordTable // //-------------------------------------------------------------------------- BOOL WINAPI ReleasePasswordTable() { CEP_PASSWORD_VALIDITY_ENTRY *pValidityEntry=NULL; //free the timestamp list and the password table's doublie linked lists if(g_CEPPasswordTable.pTimeOld) { do{ pValidityEntry=g_CEPPasswordTable.pTimeOld; g_CEPPasswordTable.pTimeOld = g_CEPPasswordTable.pTimeOld->pNext; CEPPasswordFreeValidityEntry(pValidityEntry, TRUE); } while(g_CEPPasswordTable.pTimeOld); } memset(&g_CEPPasswordTable, 0, sizeof(CEP_PASSWORD_TABLE_INFO)); return TRUE; } //-------------------------------------------------------------------------- // // CEPAddPasswordToTable // // Need to be protected by the critical section. // // Last error is set to CRYPT_E_NO_MATCH if the max number of password is // reached. // //-------------------------------------------------------------------------- BOOL WINAPI CEPAddPasswordToTable(LPWSTR pwszPassword) { BOOL fResult=FALSE; SYSTEMTIME SystemTime; DWORD dwHashIndex=0; CEP_PASSWORD_ENTRY *pPasswordEntry=NULL; CEP_PASSWORD_VALIDITY_ENTRY *pValidityEntry=NULL; EnterCriticalSection(&PasswordCriticalSec); if(NULL==pwszPassword) goto InvalidArgErr; //delete all expired passwords CEPPasswordRefresh(); if(g_dwPasswordCount >= g_dwMaxPassword) goto NoMatchErr; g_dwPasswordCount++; if(!CEPHashPassword(pwszPassword, &dwHashIndex)) goto InvalidArgErr; pPasswordEntry=(CEP_PASSWORD_ENTRY *)malloc(sizeof(CEP_PASSWORD_ENTRY)); if(!pPasswordEntry) goto MemoryErr; memset(pPasswordEntry, 0, sizeof(CEP_PASSWORD_ENTRY)); pValidityEntry=(CEP_PASSWORD_VALIDITY_ENTRY *)malloc(sizeof(CEP_PASSWORD_VALIDITY_ENTRY)); if(!pValidityEntry) goto MemoryErr; memset(pValidityEntry, 0, sizeof(CEP_PASSWORD_VALIDITY_ENTRY)); pPasswordEntry->pwszPassword=(LPWSTR)malloc(sizeof(WCHAR) * (wcslen(pwszPassword)+1)); if(!(pPasswordEntry->pwszPassword)) goto MemoryErr; wcscpy(pPasswordEntry->pwszPassword,pwszPassword); //no usage has been requested pPasswordEntry->dwUsageRequested=0; pPasswordEntry->pValidityEntry=pValidityEntry; pPasswordEntry->pNext=NULL; pPasswordEntry->pPrevious=NULL; GetSystemTime(&SystemTime); if(!SystemTimeToFileTime(&SystemTime, &(pValidityEntry->TimeStamp))) goto TraceErr; pValidityEntry->pPasswordEntry=pPasswordEntry; pValidityEntry->pNext=NULL; pValidityEntry->pPrevious=NULL; CEPInsertValidityEntry(pValidityEntry); CEPInsertPasswordEntry(pPasswordEntry, dwHashIndex); fResult=TRUE; CommonReturn: LeaveCriticalSection(&PasswordCriticalSec); return fResult; ErrorReturn: if(pPasswordEntry) CEPPasswordFreePasswordEntry(pPasswordEntry); if(pValidityEntry) CEPPasswordFreeValidityEntry(pValidityEntry, FALSE); fResult=FALSE; goto CommonReturn; SET_ERROR(NoMatchErr, CRYPT_E_NO_MATCH); TRACE_ERROR(TraceErr); SET_ERROR(InvalidArgErr, E_INVALIDARG); SET_ERROR(MemoryErr, E_OUTOFMEMORY); } //-------------------------------------------------------------------------- // // CEPVerifyPasswordAndDeleteFromTable // // Need to be protected by the critical section. // //-------------------------------------------------------------------------- BOOL WINAPI CEPVerifyPasswordAndDeleteFromTable(LPWSTR pwszPassword, DWORD dwUsage) { BOOL fResult=FALSE; CEP_PASSWORD_ENTRY *pPasswordEntry=NULL; DWORD dwIndex=0; EnterCriticalSection(&PasswordCriticalSec); //delete all expired passwords CEPPasswordRefresh(); if(NULL == (pPasswordEntry=CEPSearchPassword(pwszPassword, &dwIndex))) goto InvalidArgErr; //verify the usage. //only one signature and one exchange key per password if(0 != ((pPasswordEntry->dwUsageRequested) & dwUsage)) goto InvalidArgErr; pPasswordEntry->dwUsageRequested = (pPasswordEntry->dwUsageRequested) | dwUsage; //remove the password only if both signature and exchange key are requested if(((pPasswordEntry->dwUsageRequested) & CEP_REQUEST_SIGNATURE) && ((pPasswordEntry->dwUsageRequested) & CEP_REQUEST_EXCHANGE)) { CEPPasswordRemoveValidityEntry(pPasswordEntry->pValidityEntry); CEPPasswordRemovePasswordEntry(pPasswordEntry, dwIndex); CEPPasswordFreeValidityEntry(pPasswordEntry->pValidityEntry, FALSE); CEPPasswordFreePasswordEntry(pPasswordEntry); if(g_dwPasswordCount >= 1) g_dwPasswordCount--; } fResult=TRUE; CommonReturn: LeaveCriticalSection(&PasswordCriticalSec); return fResult; ErrorReturn: fResult=FALSE; goto CommonReturn; SET_ERROR(InvalidArgErr, E_INVALIDARG); }