/*++ Copyright (c) 1998 Microsoft Corporation (c) Copyright Schlumberger Technology Corp., unpublished work, created 1999. This computer program includes Confidential, Proprietary Information and is a Trade Secret of Schlumberger Technology Corp. All use, disclosure, and/or reproduction is prohibited unless authorized in writing. All Rights Reserved. Module Name: autoreg Abstract: This module provides autoregistration capabilities to a CSP. It allows regsvr32 to call the DLL directly to add and remove Registry settings. Author: Doug Barlow (dbarlow) 3/11/1998 Environment: Win32 Notes: Look for "?vendor?" tags and edit appropriately. --*/ #if defined(_UNICODE) #if !defined(UNICODE) #define UNICODE #endif //!UNICODE #endif //_UNICODE #if defined(UNICODE) #if !defined(_UNICODE) #define _UNICODE #endif //!_UNICODE #endif //UNICODE #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #ifdef _AFXDLL #include "stdafx.h" #else #include #endif #include #include #include #include // CRYPT_SIG_RESOURCE_NUMBER #include #include #include "CspProfile.h" #include "Blob.h" #include "StResource.h" using namespace std; using namespace ProviderProfile; namespace { typedef DWORD (*LPSETCARDTYPEPROVIDERNAME)(IN SCARDCONTEXT hContext, IN LPCTSTR szCardName, IN DWORD dwProviderId, IN LPCTSTR szProvider); LPCTSTR szCardRegPath = TEXT("SOFTWARE\\Microsoft\\Cryptography\\Calais\\SmartCards"); // Remove the legacy Cryptoflex card from the registry. This // will ease transition of W2K beta users to its commercial // release as well as Cryptoflex SDK 1.x users. The supported // cards are added by IntroduceVendorCard. LPCTSTR aCardsToForget[] = { TEXT("Schlumberger Cryptoflex"), TEXT("Schlumberger Cryptoflex 4k"), TEXT("Schlumberger Cryptoflex 8k"), TEXT("Schlumberger Cryptoflex 8k v2") }; HRESULT ForgetVendorCard(LPCTSTR szCardToForget) { bool fCardIsForgotten = false; HRESULT hReturnStatus = NO_ERROR; #if !defined(UNICODE) string #else wstring #endif // !defined(UNICODE) sRegCardToForget(szCardRegPath); sRegCardToForget.append(TEXT("\\")); sRegCardToForget.append(szCardToForget); for (DWORD dwIndex = 0; !fCardIsForgotten; dwIndex += 1) { HKEY hCalais(0); SCARDCONTEXT hCtx(0); DWORD dwStatus; LONG nStatus; switch (dwIndex) { case 0: dwStatus = SCardEstablishContext(SCARD_SCOPE_SYSTEM, 0, 0, &hCtx); if (ERROR_SUCCESS != dwStatus) continue; dwStatus = SCardForgetCardType(hCtx, szCardToForget); if (ERROR_SUCCESS != dwStatus) continue; dwStatus = SCardReleaseContext(hCtx); hCtx = NULL; if (ERROR_SUCCESS != dwStatus) { if (0 == (dwStatus & 0xffff0000)) hReturnStatus = HRESULT_FROM_WIN32(dwStatus); else hReturnStatus = (HRESULT)dwStatus; goto ErrorExit; } // Ignore the return code since the previous probably deleted it. nStatus = RegDeleteKey(HKEY_LOCAL_MACHINE, sRegCardToForget.c_str()); fCardIsForgotten = true; break; case 1: // Last try, if not successful then it must not exist... nStatus = RegDeleteKey(HKEY_LOCAL_MACHINE, sRegCardToForget.c_str()); fCardIsForgotten = true; break; default: hReturnStatus = ERROR_ACCESS_DENIED; goto ErrorExit; } ErrorExit: if (NULL != hCtx) SCardReleaseContext(hCtx); if (NULL != hCalais) RegCloseKey(hCalais); break; } return hReturnStatus; } HRESULT IntroduceVendorCard(CString const &rsCspName, CardProfile const &rcp) { // Try various techniques until one works. ATR const &ratr = rcp.ATR(); bool fCardIntroduced = false; HRESULT hReturnStatus = NO_ERROR; for (DWORD dwIndex = 0; !fCardIntroduced; dwIndex += 1) { HKEY hCalais(0); SCARDCONTEXT hCtx(0); DWORD dwDisp; DWORD dwStatus; LONG nStatus; HKEY hVendor(0); switch (dwIndex) { case 0: { HMODULE hWinSCard = NULL; LPSETCARDTYPEPROVIDERNAME pfSetCardTypeProviderName = NULL; hWinSCard = GetModuleHandle(TEXT("WinSCard.DLL")); if (NULL == hWinSCard) continue; #if defined(UNICODE) pfSetCardTypeProviderName = reinterpret_cast(GetProcAddress(hWinSCard, AsCCharP(TEXT("SCardSetCardTypeProviderNameW")))); #else pfSetCardTypeProviderName = reinterpret_cast(GetProcAddress(hWinSCard, TEXT("SCardSetCardTypeProviderNameA"))); #endif if (!pfSetCardTypeProviderName) continue; dwStatus = SCardIntroduceCardType(NULL, (LPCTSTR)rcp.csRegistryName(), NULL, NULL, 0, ratr.String(), ratr.Mask(), ratr.Size()); if ((ERROR_SUCCESS != dwStatus) && (ERROR_ALREADY_EXISTS != dwStatus)) continue; dwStatus = (*pfSetCardTypeProviderName)(NULL, (LPCTSTR)rcp.csRegistryName(), SCARD_PROVIDER_CSP, (LPCTSTR)rsCspName); if (ERROR_SUCCESS != dwStatus) { if (0 == (dwStatus & 0xffff0000)) hReturnStatus = HRESULT_FROM_WIN32(dwStatus); else hReturnStatus = (HRESULT)dwStatus; goto ErrorExit; } fCardIntroduced = TRUE; break; } case 1: dwStatus = SCardEstablishContext(SCARD_SCOPE_SYSTEM, 0, 0, &hCtx); if (ERROR_SUCCESS != dwStatus) continue; dwStatus = SCardIntroduceCardType(hCtx, (LPCTSTR)rcp.csRegistryName(), &rcp.PrimaryProvider(), NULL, 0, ratr.String(), ratr.Mask(), ratr.Size()); if ((ERROR_SUCCESS != dwStatus) && (ERROR_ALREADY_EXISTS != dwStatus)) { if (0 == (dwStatus & 0xffff0000)) hReturnStatus = HRESULT_FROM_WIN32(dwStatus); else hReturnStatus = (HRESULT)dwStatus; goto ErrorExit; } dwStatus = SCardReleaseContext(hCtx); hCtx = NULL; if (ERROR_SUCCESS != dwStatus) { if (0 == (dwStatus & 0xffff0000)) hReturnStatus = HRESULT_FROM_WIN32(dwStatus); else hReturnStatus = (HRESULT)dwStatus; goto ErrorExit; } nStatus = RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Cryptography\\Calais\\SmartCards"), 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hCalais, &dwDisp); if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } nStatus = RegCreateKeyEx(hCalais, (LPCTSTR)rcp.csRegistryName(), 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hVendor, &dwDisp); if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } nStatus = RegCloseKey(hCalais); hCalais = NULL; if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } nStatus = RegSetValueEx(hVendor, TEXT("Crypto Provider"), 0, REG_SZ, reinterpret_cast((LPCTSTR)rsCspName), (_tcslen((LPCTSTR)rsCspName) + 1) * sizeof TCHAR); if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } nStatus = RegCloseKey(hVendor); hVendor = NULL; if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } fCardIntroduced = TRUE; break; case 2: nStatus = RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Cryptography\\Calais\\SmartCards"), 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hCalais, &dwDisp); if (ERROR_SUCCESS != nStatus) continue; nStatus = RegCreateKeyEx(hCalais, (LPCTSTR)rcp.csRegistryName(), 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hVendor, &dwDisp); if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } nStatus = RegCloseKey(hCalais); hCalais = NULL; if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } nStatus = RegSetValueEx(hVendor, TEXT("Primary Provider"), 0, REG_BINARY, (LPCBYTE)&rcp.PrimaryProvider(), sizeof LPCBYTE); if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } nStatus = RegSetValueEx(hVendor, TEXT("ATR"), 0, REG_BINARY, ratr.String(), ratr.Size()); if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } nStatus = RegSetValueEx(hVendor, TEXT("ATRMask"), 0, REG_BINARY, ratr.Mask(), ratr.Size()); if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } nStatus = RegSetValueEx(hVendor, TEXT("Crypto Provider"), 0, REG_SZ, reinterpret_cast((LPCTSTR)rsCspName), (_tcslen((LPCTSTR)rsCspName) + 1) * sizeof TCHAR); if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } nStatus = RegCloseKey(hVendor); hVendor = NULL; if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } fCardIntroduced = TRUE; break; default: hReturnStatus = ERROR_ACCESS_DENIED; goto ErrorExit; } ErrorExit: if (NULL != hCtx) SCardReleaseContext(hCtx); if (NULL != hCalais) RegCloseKey(hCalais); if (NULL != hVendor) RegCloseKey(hVendor); break; } return hReturnStatus; } } // namespace /*++ DllUnregisterServer: This service removes the registry entries associated with this CSP. Arguments: None Return Value: Status code as an HRESULT. Author: Doug Barlow (dbarlow) 3/11/1998 --*/ STDAPI DllUnregisterServer(void) { LONG nStatus; DWORD dwDisp; HRESULT hReturnStatus = NO_ERROR; HKEY hProviders = NULL; SCARDCONTEXT hCtx = NULL; CString sProvName; #ifdef _AFXDLL AFX_MANAGE_STATE(AfxGetStaticModuleState()); #endif CspProfile const &rProfile = CspProfile::Instance(); sProvName = rProfile.Name(); // // Delete the Registry key for this CSP. // nStatus = RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider"), 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hProviders, &dwDisp); if (ERROR_SUCCESS == nStatus) { RegDeleteKey(hProviders, (LPCTSTR)sProvName); RegCloseKey(hProviders); hProviders = NULL; } // // Remove the cards introduced. // { vector const &rvcp = rProfile.Cards(); for (vector::const_iterator it = rvcp.begin(); it != rvcp.end(); ++it) { hReturnStatus = ForgetVendorCard((LPCTSTR)(it->csRegistryName())); if (NO_ERROR != hReturnStatus) break; } if (NO_ERROR != hReturnStatus) goto ErrorExit; } // // Forget the card type. // hCtx = NULL; SCardEstablishContext(SCARD_SCOPE_SYSTEM, 0, 0, &hCtx); SCardForgetCardType(hCtx, (LPCTSTR)sProvName); if (NULL != hCtx) { SCardReleaseContext(hCtx); hCtx = NULL; } // // All done! // ErrorExit: return hReturnStatus; } /*++ DllRegisterServer: This function installs the proper registry entries to enable this CSP. Arguments: None Return Value: Status code as an HRESULT. Author: Doug Barlow (dbarlow) 3/11/1998 --*/ STDAPI DllRegisterServer(void) { TCHAR szModulePath[MAX_PATH+1]; // Security: Leave room to zero // terminate the buffer for // subsequent operations. BYTE pbSignature[136]; // Room for a 1024 bit signature, with padding. OSVERSIONINFO osVer; LPTSTR szFileName, szFileExt; HINSTANCE hThisDll; HRSRC hSigResource; DWORD dwStatus; LONG nStatus; BOOL fStatus; DWORD dwDisp; DWORD dwIndex; DWORD dwSigLength = 0; HRESULT hReturnStatus = NO_ERROR; HKEY hProviders = NULL; HKEY hMyCsp = NULL; HKEY hCalais = NULL; HKEY hVendor = NULL; BOOL fSignatureFound = FALSE; HANDLE hSigFile = INVALID_HANDLE_VALUE; SCARDCONTEXT hCtx = NULL; CString sProvName; // TO DO: Card registration should be made by the CCI/IOP, not // the CSP. #ifdef _AFXDLL AFX_MANAGE_STATE(AfxGetStaticModuleState()); #endif CspProfile const &rProfile = CspProfile::Instance(); // // Figure out the file name and path. // hThisDll = rProfile.DllInstance(); if (NULL == hThisDll) { hReturnStatus = HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE); goto ErrorExit; } dwStatus = GetModuleFileName(hThisDll, szModulePath, sizeof(szModulePath)/sizeof(TCHAR)); if (0 == dwStatus) { hReturnStatus = HRESULT_FROM_WIN32(GetLastError()); goto ErrorExit; } // Zero terminate buffer. szModulePath[dwStatus] = 0; szFileName = _tcsrchr(szModulePath, TEXT('\\')); if (NULL == szFileName) szFileName = szModulePath; else szFileName += 1; szFileExt = _tcsrchr(szFileName, TEXT('.')); if (NULL == szFileExt) { hReturnStatus = HRESULT_FROM_WIN32(ERROR_INVALID_NAME); goto ErrorExit; } else szFileExt += 1; // // Create the Registry key for this CSP. // nStatus = RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider"), 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hProviders, &dwDisp); if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } sProvName = rProfile.Name(); nStatus = RegCreateKeyEx(hProviders, (LPCTSTR)sProvName, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hMyCsp, &dwDisp); if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } nStatus = RegCloseKey(hProviders); hProviders = NULL; if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } // // Install the trivial registry values. // // Security/sysprep requirement: the module path must be replaced // with just the dll name to faclilitate sysprep. Corresponding // changes to LoadLibrary imply that there are no security risks // for system processes. The security implications of such // installation for applications is an open question. nStatus = RegSetValueEx(hMyCsp, TEXT("Image Path"), 0, REG_SZ, (LPBYTE)szFileName,//szModulePath, (_tcslen(szFileName/*szModulePath*/) + 1) * sizeof(TCHAR)); if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } { DWORD ProviderType = rProfile.Type(); nStatus = RegSetValueEx(hMyCsp, TEXT("Type"), 0, REG_DWORD, (LPBYTE)&ProviderType, sizeof ProviderType); if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } } // // See if we're self-signed. On NT5, CSP images can carry their own // signatures. // hSigResource = FindResource(hThisDll, MAKEINTRESOURCE(CRYPT_SIG_RESOURCE_NUMBER), RT_RCDATA); // // Install the file signature. // ZeroMemory(&osVer, sizeof(OSVERSIONINFO)); osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); fStatus = GetVersionEx(&osVer); if (fStatus && (VER_PLATFORM_WIN32_NT == osVer.dwPlatformId) && (5 <= osVer.dwMajorVersion) && (NULL != hSigResource)) { // // Signature in file flag is sufficient. // dwStatus = 0; nStatus = RegSetValueEx(hMyCsp, TEXT("SigInFile"), 0, REG_DWORD, (LPBYTE)&dwStatus, sizeof(DWORD)); if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } } else { // // We have to install a signature entry. // Try various techniques until one works. // for (dwIndex = 0; !fSignatureFound; dwIndex += 1) { switch (dwIndex) { // // Look for an external *.sig file and load that into the registry. // case 0: _tcscpy(szFileExt, TEXT("sig")); hSigFile = CreateFile( szModulePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hSigFile) continue; dwSigLength = GetFileSize(hSigFile, NULL); if ((dwSigLength > sizeof(pbSignature)) || (dwSigLength < 72)) // Accept a 512-bit signature { hReturnStatus = NTE_BAD_SIGNATURE; goto ErrorExit; } fStatus = ReadFile( hSigFile, pbSignature, sizeof(pbSignature), &dwSigLength, NULL); if (!fStatus) { hReturnStatus = HRESULT_FROM_WIN32(GetLastError()); goto ErrorExit; } fStatus = CloseHandle(hSigFile); hSigFile = NULL; if (!fStatus) { hReturnStatus = HRESULT_FROM_WIN32(GetLastError()); goto ErrorExit; } fSignatureFound = TRUE; break; // // Other cases may be added in the future. // default: hReturnStatus = NTE_BAD_SIGNATURE; goto ErrorExit; } if (fSignatureFound) { for (dwIndex = 0; dwIndex < dwSigLength; dwIndex += 1) { if (0 != pbSignature[dwIndex]) break; } if (dwIndex >= dwSigLength) fSignatureFound = FALSE; } } // // We've found a signature somewhere! Install it. // nStatus = RegSetValueEx( hMyCsp, TEXT("Signature"), 0, REG_BINARY, pbSignature, dwSigLength); if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } } nStatus = RegCloseKey(hMyCsp); hMyCsp = NULL; if (ERROR_SUCCESS != nStatus) { hReturnStatus = HRESULT_FROM_WIN32(nStatus); goto ErrorExit; } for (dwIndex = 0; dwIndex < (sizeof aCardsToForget / sizeof *aCardsToForget); dwIndex++) { hReturnStatus = ForgetVendorCard(aCardsToForget[dwIndex]); if (NO_ERROR != hReturnStatus) goto ErrorExit; } // // Introduce the vendor cards. Try various techniques until one works. // { vector const &rvcp = rProfile.Cards(); for (vector::const_iterator it = rvcp.begin(); it != rvcp.end(); ++it) { hReturnStatus = IntroduceVendorCard(rProfile.Name(), *it); if (NO_ERROR != hReturnStatus) break; } if (NO_ERROR != hReturnStatus) goto ErrorExit; } // // ?vendor? // Add any additional initialization required here. // // // All done! // return hReturnStatus; // // An error was detected. Clean up any outstanding resources and // return the error. // ErrorExit: if (NULL != hCtx) SCardReleaseContext(hCtx); if (NULL != hCalais) RegCloseKey(hCalais); if (NULL != hVendor) RegCloseKey(hVendor); if (INVALID_HANDLE_VALUE != hSigFile) CloseHandle(hSigFile); if (NULL != hMyCsp) RegCloseKey(hMyCsp); if (NULL != hProviders) RegCloseKey(hProviders); DllUnregisterServer(); return hReturnStatus; }