//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1999 - 1999 // // File: keyenum.cpp // //-------------------------------------------------------------------------- //+--------------------------------------------------------------------------- // // File: keyenum.cpp // // Contents: key container and cert store operations // // History: 08/97 xtan // //---------------------------------------------------------------------------- #include "pch.cpp" #pragma hdrstop #include "cscsp.h" #include "csdisp.h" #define __dwFILE__ __dwFILE_INITLIB_KEYENUM_CPP__ // Key Enumeration // move point to top KEY_LIST* topKeyList(KEY_LIST *pKeyList) { while (pKeyList->last) { pKeyList = pKeyList->last; } return pKeyList; } // move point to end KEY_LIST* endKeyList(KEY_LIST *pKeyList) { while (pKeyList->next) { pKeyList = pKeyList->next; } return pKeyList; } // add to end void addKeyList(KEY_LIST **ppKeyList, KEY_LIST *pKey) { KEY_LIST *pKeyList = *ppKeyList; if (NULL == pKeyList) { *ppKeyList = pKey; } else { // go to end pKeyList = endKeyList(pKeyList); // add pKeyList->next = pKey; pKey->last = pKeyList; } } KEY_LIST * newKey( CHAR *pszName) { HRESULT hr = S_OK; KEY_LIST *pKey = NULL; if (NULL != pszName) { pKey = (KEY_LIST *) LocalAlloc(LMEM_FIXED, sizeof(*pKey)); if (NULL == pKey) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } if (!myConvertSzToWsz(&pKey->pwszName, pszName, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "myConvertSzToWsz"); } pKey->last = NULL; pKey->next = NULL; } error: if (S_OK != hr) { if (NULL != pKey) { LocalFree(pKey); pKey = NULL; } SetLastError(hr); } return(pKey); } void freeKey(KEY_LIST *pKey) { if (pKey) { if (pKey->pwszName) { LocalFree(pKey->pwszName); } LocalFree(pKey); } } VOID csiFreeKeyList( IN OUT KEY_LIST *pKeyList) { KEY_LIST *pNext; if (pKeyList) { // go top pKeyList = topKeyList(pKeyList); do { pNext = pKeyList->next; freeKey(pKeyList); pKeyList = pNext; } while (pKeyList); } } HRESULT csiGetKeyList( IN DWORD dwProvType, IN WCHAR const *pwszProvName, IN BOOL fMachineKeySet, IN BOOL fSilent, OUT KEY_LIST **ppKeyList) { HCRYPTPROV hProv = NULL; BYTE *pbData = NULL; DWORD cbData; DWORD cb; DWORD dwFirstKeyFlag; HRESULT hr; BOOL bRetVal; KEY_LIST * pklTravel; BOOL fFoundDefaultKey; DWORD dwSilent = fSilent? CRYPT_SILENT : 0; DWORD dwFlags; KEY_LIST *pKeyList = NULL; KEY_LIST *pKey = NULL; *ppKeyList = NULL; if (NULL == pwszProvName) { // explicitly disallowed because NULL is valid for CryptAcquireContext hr = E_INVALIDARG; _JumpError(hr, error, "NULL parm"); } // get a prov handle for key enum dwFlags = CRYPT_VERIFYCONTEXT; for (;;) { DBGPRINT(( DBG_SS_CERTLIBI, "myCertSrvCryptAcquireContext(%ws, f=%x, m=%x)\n", pwszProvName, dwFlags | dwSilent, fMachineKeySet)); if (myCertSrvCryptAcquireContext( &hProv, NULL, pwszProvName, dwProvType, dwFlags | dwSilent, fMachineKeySet)) { break; // Success! } hr = myHLastError(); _PrintErrorStr2(hr, "myCertSrvCryptAcquireContext", pwszProvName, hr); // MITVcsp can't support a verify context, create a dummy container if ((CRYPT_VERIFYCONTEXT & dwFlags) && 0 == LSTRCMPIS(pwszProvName, L"MITV Smartcard Crypto Provider V0.2")) { dwFlags &= ~CRYPT_VERIFYCONTEXT; dwFlags |= CRYPT_NEWKEYSET; continue; } // Exchange can't handle fMachineKeySet or CRYPT_SILENT if ((fMachineKeySet || (CRYPT_SILENT & dwSilent)) && NTE_BAD_FLAGS == hr && 0 == LSTRCMPIS(pwszProvName, L"Microsoft Exchange Cryptographic Provider v1.0")) { dwSilent &= ~CRYPT_SILENT; fMachineKeySet = FALSE; continue; } _JumpErrorStr(hr, error, "myCertSrvCryptAcquireContext", pwszProvName); } // Enumerate a key so we can get the maximum buffer size required. // The first key may be a bad one, so we may have to assume a fixed buffer. hr = S_OK; cbData = 0; bRetVal = CryptGetProvParam( hProv, PP_ENUMCONTAINERS, NULL, &cbData, CRYPT_FIRST); DBGPRINT(( DBG_SS_CERTLIBI, "CryptGetProvParam(%ws) -> cb=%d, bRet=%d\n", pwszProvName, cbData, bRetVal)); if (!bRetVal) { // We'd like to skip the bad key (key container with long name?), // but we get stuck enumerating the same entry over and over again. // Guess at the maximum size... hr = myHLastError(); _PrintErrorStr2( hr, "CryptGetProvParam(ignored: use 2 * MAX_PATH)", pwszProvName, HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)); if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) != hr) { cbData = 0; hr = S_OK; } } if (S_OK == hr) { if (0 == cbData) { cbData = 2 * MAX_PATH * sizeof(CHAR); } // allocate the buffer pbData = (BYTE *) LocalAlloc(LMEM_FIXED, cbData); if (NULL == pbData) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } // enumerate all the keys for this container dwFirstKeyFlag = CRYPT_FIRST; for (;;) { // get the key name *pbData = '\0'; cb = cbData; bRetVal = CryptGetProvParam( hProv, PP_ENUMCONTAINERS, pbData, &cb, dwFirstKeyFlag); DBGPRINT(( DBG_SS_CERTLIBI, "CryptGetProvParam(pb=%x, f=%d) -> cb=%d->%d, key=%hs, bRet=%d\n", pbData, dwFirstKeyFlag, cbData, cb, pbData, bRetVal)); DBGDUMPHEX(( DBG_SS_CERTLIBI, 0, pbData, strlen((char const *) pbData))); dwFirstKeyFlag = 0; if (!bRetVal) { hr = myHLastError(); if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { // no more keys to get break; } else if (NTE_BAD_KEYSET == hr || HRESULT_FROM_WIN32(ERROR_MORE_DATA) == hr ) { // skip the bad key (key container with long name?) _PrintError(hr, "bad key"); continue; } _JumpError(hr, error, "CryptGetProvParam"); } pKey = newKey((CHAR *) pbData); if (NULL == pKey) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } DBGDUMPHEX(( DBG_SS_CERTLIBI, 0, (BYTE const *) pKey->pwszName, sizeof(WCHAR) * wcslen(pKey->pwszName))); addKeyList(&pKeyList, pKey); } // <- End of enumeration loop // clean up: // free the old buffer if (NULL != pbData) { LocalFree(pbData); pbData = NULL; } } // release the old context CryptReleaseContext(hProv, 0); hProv = NULL; // get the default key container and make sure it is in the key list if (!myCertSrvCryptAcquireContext( &hProv, NULL, pwszProvName, dwProvType, dwSilent, fMachineKeySet)) { hr = myHLastError(); _PrintError2(hr, "myCertSrvCryptAcquireContext", hr); goto done; } // find out its name cbData = 0; for (;;) { if (!CryptGetProvParam(hProv, PP_CONTAINER, pbData, &cbData, 0)) { hr = myHLastError(); _PrintError2(hr, "CryptGetProvParam", hr); goto done; } if (NULL != pbData) { // got it break; } pbData = (BYTE *) LocalAlloc(LMEM_FIXED, cbData); if (NULL == pbData) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } } // create a (temporary) key structure pKey = newKey((CHAR *) pbData); if (NULL == pKey) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } // walk the key list and see if this key is there fFoundDefaultKey = FALSE; for (pklTravel = pKeyList; NULL != pklTravel; pklTravel = pklTravel->next) { if (0 == wcscmp(pKey->pwszName, pklTravel->pwszName)) { fFoundDefaultKey = TRUE; break; } } if (fFoundDefaultKey) { // we found it - delete the temp structure. freeKey(pKey); } else { // we didn't find it, so add the key to the list. addKeyList(&pKeyList, pKey); } done: // pass list back to caller *ppKeyList = pKeyList; pKeyList = NULL; hr = S_OK; error: if (NULL != hProv) { CryptReleaseContext(hProv, 0); } if (NULL != pKeyList) { csiFreeKeyList(pKeyList); } if (NULL != pbData) { LocalFree(pbData); } return(hr); }