/*++ Copyright (c) 1995 Microsoft Corporation Module Name: schnlui.cxx Abstract: Contains immplimentation of generic Windows Dialog Manipulation Code. This code supports SCHANNEL (Secure Channel SSL/PCT) specific UI for Certifcates. Contents: CertPickDialogProc Author: Arthur L Bierer (arthurbi) 27-Jun-1996 Revision History: 27-Jun-1996 arthurbi Created --*/ #include #include #include "resource.h" #include "ierrui.hxx" #include "inethelp.h" #include #include #define USE_NT5_CRYPTOUI #ifdef USE_NT5_CRYPTOUI #include HINSTANCE g_hCryptoUI = NULL; // handle for cryptui.dll #endif // // private prototypes, and defines. // #define TYPICAL_MD5_HASH_SIZE 16 #define NUM_DN_UNITS 6 #define MAX_ITEM_LEN 1000 #define DN_COMMON_NAME 0 #define DN_COUNTRY 1 #define DN_ORG 2 #define DN_ORGUNIT 3 #define DN_LOCALE 4 #define DN_STATE 5 #define MAX_CERT_FIELDS 20 typedef struct _ATTR_MAP { DWORD dwAttr; DWORD dwStringID; } ATTR_MAP; // Now for some common attribute maps ATTR_MAP ProtocolAttrMap[] = { {SP_PROT_SSL2_CLIENT, IDS_PROTOCOL_SSL2}, {SP_PROT_SSL3_CLIENT, IDS_PROTOCOL_SSL3}, {SP_PROT_PCT1_CLIENT, IDS_PROTOCOL_PCT1}, {SP_PROT_TLS1_CLIENT, IDS_PROTOCOL_TLS1} }; ATTR_MAP AlgAttrMap[] = { {CALG_MD2, IDS_ALG_MD2}, {CALG_MD4, IDS_ALG_MD4}, {CALG_MD5, IDS_ALG_MD5}, {CALG_SHA, IDS_ALG_SHA}, {CALG_SHA1, IDS_ALG_SHA}, {CALG_MAC, IDS_ALG_MAC}, {CALG_HMAC, IDS_ALG_HMAC}, {CALG_RSA_SIGN, IDS_ALG_RSA_SIGN}, {CALG_DSS_SIGN, IDS_ALG_DSS_SIGN}, {CALG_RSA_KEYX, IDS_ALG_RSA_KEYX}, {CALG_DES, IDS_ALG_DES}, {CALG_3DES_112, IDS_ALG_3DES_112}, {CALG_3DES, IDS_ALG_3DES}, {CALG_RC2, IDS_ALG_RC2}, {CALG_RC4, IDS_ALG_RC4}, {CALG_RC5, IDS_ALG_RC5}, {CALG_SEAL, IDS_ALG_SEAL}, {CALG_DH_SF, IDS_ALG_DH_SF}, {CALG_DH_EPHEM, IDS_ALG_DH_EPHEM}, {CALG_KEA_KEYX, IDS_ALG_KEA_KEYX}, {CALG_SKIPJACK, IDS_ALG_SKIPJACK}, {CALG_TEK, IDS_ALG_TEK} }; typedef struct { LPWSTR lpszListBoxText; LPWSTR lpszEditBoxText; DWORD dwSpcCtlId; // special id for item to be placed in ctl. } ShowCertMapping; #define szHelpFile "iexplore.hlp" // // private function declariations // PRIVATE BOOL PlaceCertContextsInListBox( IN HWND hWndListBox, IN HWND hWndViewCertButton, IN HWND hWndExportButton, IN CERT_CONTEXT_ARRAY* pCertContexts ); PRIVATE BOOL PlaceCertificateDataIntoListBox( IN HWND hWndDlg, IN HWND hWndListBox, IN ShowCertMapping *pMapCertFields ); PRIVATE DWORD OnSelectionOfACertField( IN HWND hWndListBox, IN HWND hWndEditBox, IN ShowCertMapping *pMapCertFields ); PRIVATE BOOL CALLBACK ViewCertDlgProc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ); LPWSTR GetCertStatus(LPINTERNET_SECURITY_INFO pciCert); // // public functions // #ifdef USE_NT5_CRYPTOUI //+------------------------------------------------------------------------- // Returns TRUE if cryptui.dll was found //-------------------------------------------------------------------------- BOOL UseCryptoUI() { static long fTriedOnce = FALSE; // Only try to load the dll once if (!fTriedOnce) { // // Note: if this gets called by multiple threads the worst that will // happen is that load library will be called twice. Apparently, // there is is no danger of the global getting mangled because // writes are atomic. // g_hCryptoUI = LoadLibrary("cryptui.dll"); fTriedOnce = TRUE; } return (g_hCryptoUI != NULL); } //+------------------------------------------------------------------------- // Delay load version of the function in cryptui.dll //-------------------------------------------------------------------------- BOOL _CryptUIDlgViewCertificate( IN PCCRYPTUI_VIEWCERTIFICATE_STRUCT pCertViewInfo, OUT BOOL *pfPropertiesChanged // OPTIONAL ) { // Caller must call UseCryptoUI() first to load the dll! INET_ASSERT(g_hCryptoUI); typedef BOOL (CALLBACK* CRYPTUIDLGVIEWCERTIFICATE)(PCCRYPTUI_VIEWCERTIFICATE_STRUCT, BOOL*); static CRYPTUIDLGVIEWCERTIFICATE fnCryptUIDlgViewCertificate = NULL; if (fnCryptUIDlgViewCertificate == NULL) { // // Note: if this gets called by multiple threads the worst that will // happen is that GetProcAddress will be called twice. Apparently, // there is is no danger of the global getting mangled because // writes are atomic. // fnCryptUIDlgViewCertificate = (CRYPTUIDLGVIEWCERTIFICATE)GetProcAddress(g_hCryptoUI, "CryptUIDlgViewCertificateA"); if (fnCryptUIDlgViewCertificate == NULL) { return FALSE; } } // Call the real function return fnCryptUIDlgViewCertificate(pCertViewInfo, pfPropertiesChanged); } #endif USE_NT5_CRYPTOUI INTERNETAPI_(BOOL) InternetAlgIdToStringA( IN ALG_ID ai, IN LPSTR lpstr, IN OUT LPDWORD lpdwstrLength, IN DWORD dwReserved /* Must be 0 */ ) /*++ Routine Description: Converts a algid to a user-displayable string. Arguments: ai - Algorithm identifiers ( defined in wincrypt.h) lpstr - Buffer to copy string into. lpdwstrLength - pass in num of characters, return no of characters copied if successful, else no of chars required (including null terminator) dwReserved = Must be 0 Return Value: DWORD Win32 or WININET error code. --*/ { DEBUG_ENTER_API((DBG_API, Bool, "InternetAlgIdToStringA", "%#x, %q, %#x, %#x", ai, lpstr, lpdwstrLength, dwReserved )); DWORD error = ERROR_SUCCESS; if ((dwReserved!=0) || (lpdwstrLength == NULL)) { error = ERROR_INVALID_PARAMETER; goto quit; } if (lpstr == NULL) *lpdwstrLength = 0; int i; for (i=0; i < ARRAY_ELEMENTS(AlgAttrMap) ; i++ ) { if (ai == AlgAttrMap[i].dwAttr) break; } if ( i == ARRAY_ELEMENTS(AlgAttrMap) ) { INET_ASSERT(FALSE); // Could be because our table is not up to date. error = ERROR_INVALID_PARAMETER; goto quit; } CHAR szTempBuffer[100]; int nRet; nRet = LoadStringA(GlobalDllHandle, AlgAttrMap[i].dwStringID, szTempBuffer, ARRAY_ELEMENTS(szTempBuffer) ); // If the return value is within one less than the arraysize, it implies the // string could have been terminated by LoadString. This should not happen // since we have allocated a large enough buffer. If it does we need to bump the // size of the temporary array above. INET_ASSERT(nRet < ARRAY_ELEMENTS(szTempBuffer) - 1); if (*lpdwstrLength > (DWORD)nRet) { memcpy(lpstr, szTempBuffer, (nRet + 1)); *lpdwstrLength = nRet; error = ERROR_SUCCESS; } else { *lpdwstrLength = nRet + 1; error = ERROR_INSUFFICIENT_BUFFER; } quit: if (ERROR_SUCCESS != error) { SetLastError(error); DEBUG_ERROR(API, error); } DEBUG_LEAVE_API(error==ERROR_SUCCESS); return (error == ERROR_SUCCESS); } INTERNETAPI_(BOOL) InternetSecurityProtocolToStringA( IN DWORD dwProtocol, IN LPSTR lpstr, IN OUT LPDWORD lpdwstrLength, IN DWORD dwReserved /* Must be 0 */ ) /*++ Routine Description: Converts a security protocol to a user-displayable string. Arguments: dwProtocol - Security protocol identifier ( defined in wincrypt.h) lpstr - Buffer to copy string into. lpdwstrLength - pass in num of characters, return no of characters copied if successful, else no of chars required (including null terminator) dwReserved = Must be 0 Return Value: DWORD Win32 or WININET error code. --*/ { DEBUG_ENTER_API((DBG_API, Bool, "InternetSecurityProtocolToStringA", "%d, %q, %#x, %#x", dwProtocol, lpstr, lpdwstrLength, dwReserved )); DWORD error = ERROR_SUCCESS; if ((dwReserved!=0) || (lpdwstrLength == NULL)) { error = ERROR_INVALID_PARAMETER; goto quit; } if (lpstr == NULL) *lpdwstrLength = 0; int i; for (i=0; i < ARRAY_ELEMENTS(ProtocolAttrMap) ; i++ ) { if (dwProtocol == ProtocolAttrMap[i].dwAttr) break; } if ( i == ARRAY_ELEMENTS(ProtocolAttrMap) ) { INET_ASSERT(FALSE); // Could be because our table is not up to date. error = ERROR_INVALID_PARAMETER; goto quit; } CHAR szTempBuffer[100]; int nRet; nRet = LoadStringA(GlobalDllHandle, ProtocolAttrMap[i].dwStringID, szTempBuffer, ARRAY_ELEMENTS(szTempBuffer) ); // If the return value is within one less than the arraysize, it implies the // string could have been terminated by LoadString. This should not happen // since we have allocated a large enough buffer. If it does we need to bump the // size of the temporary array above. INET_ASSERT(nRet < ARRAY_ELEMENTS(szTempBuffer) - 1); if (*lpdwstrLength > (DWORD)nRet) { memcpy(lpstr, szTempBuffer, (nRet + 1)); *lpdwstrLength = nRet; error = ERROR_SUCCESS; } else { *lpdwstrLength = nRet + 1; error = ERROR_INSUFFICIENT_BUFFER; } quit: if (ERROR_SUCCESS != error) { SetLastError(error); DEBUG_ERROR(API, error); } DEBUG_LEAVE_API(error==ERROR_SUCCESS); return (error == ERROR_SUCCESS); } LPWSTR DupAnsiToUnicode( char *lpszAnsi, INT iLen ) { DWORD cbSize = (iLen > 0 ) ? iLen : (lstrlen(lpszAnsi) + 1); WCHAR *pwszUnicode = NULL; pwszUnicode = new WCHAR[cbSize]; if(pwszUnicode) { SHAnsiToUnicode(lpszAnsi, pwszUnicode, cbSize); } return pwszUnicode; } DWORD ShowSecurityInfo( IN HWND hWndParent, IN LPINTERNET_SECURITY_INFO pSecurityInfo ) /*++ Routine Description: Displays a dialog box that shows the information found inside of a certificate. Arguments: hWndParent - Parent Window Handle pCertInfoEx - Certificate Information structure, containing the fields of info to show. Return Value: DWORD Win32 or WININET error code. --*/ { #ifdef USE_NT5_CRYPTOUI // // For now, we use the new UI only if we can load the DLL. Otherwise we // resort to the old UI. Eventually, we may nuke the old UI. // if (UseCryptoUI()) { CRYPTUI_VIEWCERTIFICATE_STRUCT cert; if(pWTHelperProvDataFromStateData && g_fDoSpecialMagicForSGCCerts) { WINTRUST_DATA sWTD; WINTRUST_CERT_INFO sWTCI; HTTPSPolicyCallbackData polHttps; LPCSTR pszPurpose = szOID_PKIX_KP_SERVER_AUTH; DWORD status; memset(&sWTD, 0x00, sizeof(WINTRUST_DATA)); sWTD.cbStruct = sizeof(WINTRUST_DATA); sWTD.dwUIChoice = WTD_UI_NONE; sWTD.pPolicyCallbackData = (LPVOID)&polHttps; sWTD.dwUnionChoice = WTD_CHOICE_CERT; sWTD.pCert = &sWTCI; sWTD.pwszURLReference = NULL; sWTD.dwStateAction = WTD_STATEACTION_VERIFY; memset(&sWTCI, 0x00, sizeof(WINTRUST_CERT_INFO)); sWTCI.cbStruct = sizeof(WINTRUST_CERT_INFO); sWTCI.psCertContext = (CERT_CONTEXT *)pSecurityInfo->pCertificate; sWTCI.chStores = 1; sWTCI.pahStores = (HCERTSTORE *)&pSecurityInfo->pCertificate->hCertStore; memset(&polHttps, 0x00, sizeof(HTTPSPolicyCallbackData)); polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData); polHttps.dwAuthType = AUTHTYPE_SERVER; polHttps.fdwChecks = INTERNET_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_WRONG_USAGE; polHttps.pwszServerName = NULL; status = WinVerifySecureChannel(NULL, &sWTD); ZeroMemory(&cert, sizeof(cert)); cert.dwSize = sizeof(cert); cert.hwndParent = hWndParent; cert.pCertContext = pSecurityInfo->pCertificate; cert.hWVTStateData = pWTHelperProvDataFromStateData(sWTD.hWVTStateData); cert.fpCryptProviderDataTrustedUsage = (status == ERROR_SUCCESS) ? TRUE : FALSE; cert.rgszPurposes = &pszPurpose; cert.cPurposes = 1; status = _CryptUIDlgViewCertificate(&cert, NULL); sWTD.dwStateAction = WTD_STATEACTION_CLOSE; WinVerifySecureChannel(NULL, &sWTD); return status; } else { ZeroMemory(&cert, sizeof(cert)); cert.dwSize = sizeof(cert); cert.hwndParent = hWndParent; cert.pCertContext = pSecurityInfo->pCertificate; cert.cStores = 1; cert.rghStores = (HCERTSTORE *) & (cert.pCertContext->hCertStore); return _CryptUIDlgViewCertificate(&cert, NULL); } } #endif #ifdef _WIN64 return ERROR_INTERNET_INTERNAL_ERROR; #else LPTSTR szResult = NULL; PLOCAL_STRINGS plszStrings; ShowCertMapping MapCertFields[MAX_CERT_FIELDS]; WCHAR szTempBuffer[100]; INT i = 0, j=0; DWORD error; LPTSTR lpszSubject = NULL; LPWSTR lpwszTempSubject = NULL; LPTSTR lpszIssuer = NULL; LPWSTR lpwszTempIssuer = NULL; WCHAR lpszProtocol[100]; LPWSTR lpwszCipher = NULL; LPWSTR lpwszHash = NULL; LPWSTR lpwszExch = NULL; LPTSTR szFrom = NULL; LPWSTR pwszTempFrom = NULL; LPTSTR szUntil = NULL; LPWSTR pwszTempUntil = NULL; LPWSTR pwszStatus = NULL; LPSTR lpszHashStr = NULL; LPWSTR pwszTempHashStr = NULL; DWORD adwFormatParams[3]; PCERT_INFO pCertInfo = NULL; DWORD dwProtocolID = IDS_PROTOCOL_UNKNOWN; DWORD dwHashID = IDS_HASH_UNKNOWN; DWORD dwCipherID = IDS_CIPHER_UNKNOWN; DWORD dwExchID = IDS_EXCH_UNKNOWN; DWORD cbSize; error = ERROR_SUCCESS; if((pSecurityInfo == NULL) || (pSecurityInfo->pCertificate == NULL)) { return ERROR_INTERNET_INTERNAL_ERROR; } pCertInfo = pSecurityInfo->pCertificate->pCertInfo; if(pCertInfo == NULL) { return ERROR_INTERNET_INTERNAL_ERROR; } // // Get the Certificate Information. // plszStrings = FetchLocalStrings(); if ( plszStrings == NULL ) { error = ERROR_NOT_ENOUGH_MEMORY; goto quit; } szFrom = FTtoString(&pCertInfo->NotBefore); szUntil = FTtoString(&pCertInfo->NotAfter); // // Put a comment string about the certificate if there is one availble. // // // BUGBUG [arthurbi] This is broken. We never determnine the host name, // so therefore we never show a Comment for bad CA certificates. // pwszStatus = GetCertStatus(pSecurityInfo); if(pwszStatus) { MapCertFields[i].lpszListBoxText = plszStrings->szCertComment; MapCertFields[i].lpszEditBoxText = pwszStatus; MapCertFields[i].dwSpcCtlId = 0;//IDC_CERT_COMMENT; i++; } if ( pCertInfo->Subject.cbData ) { cbSize = CertNameToStr(pSecurityInfo->pCertificate->dwCertEncodingType, &pCertInfo->Subject, CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG | CERT_NAME_STR_NO_PLUS_FLAG, NULL, 0); lpszSubject = new TCHAR[cbSize]; if ( lpszSubject ) { CertNameToStr(pSecurityInfo->pCertificate->dwCertEncodingType, &pCertInfo->Subject, CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG | CERT_NAME_STR_NO_PLUS_FLAG , lpszSubject, cbSize); MapCertFields[i].lpszListBoxText = plszStrings->szCertSubject; lpwszTempSubject = DupAnsiToUnicode(lpszSubject, cbSize); MapCertFields[i].lpszEditBoxText = lpwszTempSubject; MapCertFields[i].dwSpcCtlId = 0;//IDC_CERT_SUBJECT; i++; } } if ( pCertInfo->Issuer.cbData ) { cbSize = CertNameToStr(pSecurityInfo->pCertificate->dwCertEncodingType, &pCertInfo->Issuer, CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG | CERT_NAME_STR_NO_PLUS_FLAG, NULL, 0); lpszIssuer = new TCHAR[cbSize]; if ( lpszIssuer ) { CertNameToStr(pSecurityInfo->pCertificate->dwCertEncodingType, &pCertInfo->Issuer, CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG | CERT_NAME_STR_NO_PLUS_FLAG , lpszIssuer, cbSize); MapCertFields[i].lpszListBoxText = plszStrings->szCertIssuer; lpwszTempIssuer = DupAnsiToUnicode(lpszIssuer, cbSize); MapCertFields[i].lpszEditBoxText = lpwszTempIssuer; MapCertFields[i].dwSpcCtlId = 0;//IDC_CERT_ISSUER; i++; } } if ( szFrom ) { MapCertFields[i].lpszListBoxText = plszStrings->szCertEffectiveDate; pwszTempFrom = DupAnsiToUnicode(szFrom, 0); MapCertFields[i].lpszEditBoxText = pwszTempFrom; MapCertFields[i].dwSpcCtlId = 0; i++; } if ( szUntil ) { MapCertFields[i].lpszListBoxText = plszStrings->szCertExpirationDate; pwszTempUntil = DupAnsiToUnicode(szUntil, 0); MapCertFields[i].lpszEditBoxText = pwszTempUntil; MapCertFields[i].dwSpcCtlId = 0;//IDC_CERT_EXPIRES; i++; } // // Get the fingerprint... aka MD5 Hash // { CHAR lpMD5Hash[TYPICAL_MD5_HASH_SIZE]; DWORD dwMD5HashSize = TYPICAL_MD5_HASH_SIZE; BOOL fSuccess; fSuccess = CertGetCertificateContextProperty( pSecurityInfo->pCertificate, CERT_MD5_HASH_PROP_ID, (LPVOID) lpMD5Hash, &dwMD5HashSize ); if ( fSuccess ) { CertHashToStr( lpMD5Hash, dwMD5HashSize, &lpszHashStr ); if ( lpszHashStr ) { MapCertFields[i].lpszListBoxText = plszStrings->szFingerprint; pwszTempHashStr = DupAnsiToUnicode(lpszHashStr, 0); MapCertFields[i].lpszEditBoxText = pwszTempHashStr; MapCertFields[i].dwSpcCtlId = 0; i++; } } } // Now fill in the connection attributes if(pSecurityInfo->dwProtocol) { for(j=0; j < sizeof(ProtocolAttrMap)/sizeof(ProtocolAttrMap[0]); j++) { if(ProtocolAttrMap[j].dwAttr == pSecurityInfo->dwProtocol) { dwProtocolID = ProtocolAttrMap[j].dwStringID; break; } } if(LoadStringWrapW(GlobalDllHandle, dwProtocolID, lpszProtocol, sizeof(lpszProtocol)/sizeof(lpszProtocol[0]))) { MapCertFields[i].lpszEditBoxText = lpszProtocol; MapCertFields[i].lpszListBoxText = plszStrings->szCertProtocol; MapCertFields[i].dwSpcCtlId = 0; i++; } } if(pSecurityInfo->aiCipher) { for(j=0; j < sizeof(AlgAttrMap)/sizeof(AlgAttrMap[0]); j++) { if(AlgAttrMap[j].dwAttr == pSecurityInfo->aiCipher) { dwCipherID = AlgAttrMap[j].dwStringID; break; } } LoadStringWrapW(GlobalDllHandle, dwCipherID, szTempBuffer, sizeof(szTempBuffer)/sizeof(szTempBuffer[0])); adwFormatParams[0] = (DWORD)szTempBuffer; adwFormatParams[1] = (DWORD)pSecurityInfo->dwCipherStrength; if (96 <= pSecurityInfo->dwCipherStrength) // Recommended Key strength adwFormatParams[2] = (DWORD)plszStrings->szStrengthHigh; else if (64 <= pSecurityInfo->dwCipherStrength) // Passable key strength adwFormatParams[2] = (DWORD)plszStrings->szStrengthMedium; else // Ick! Low key strength. adwFormatParams[2] = (DWORD)plszStrings->szStrengthLow; if(FormatMessageWrapW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, plszStrings->szCiphMsg, 0, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpwszCipher, 0, (va_list *)adwFormatParams)) { MapCertFields[i].lpszEditBoxText = lpwszCipher; MapCertFields[i].lpszListBoxText = plszStrings->szHttpsEncryptAlg; MapCertFields[i].dwSpcCtlId = 0; i++; } } if(pSecurityInfo->aiHash) { for(j=0; j < sizeof(AlgAttrMap)/sizeof(AlgAttrMap[0]); j++) { if(AlgAttrMap[j].dwAttr == pSecurityInfo->aiHash) { dwHashID = AlgAttrMap[j].dwStringID; break; } } LoadStringWrapW(GlobalDllHandle, dwHashID, szTempBuffer, sizeof(szTempBuffer)/sizeof(szTempBuffer[0])); adwFormatParams[0] = (DWORD)szTempBuffer; adwFormatParams[1] = (DWORD)pSecurityInfo->dwHashStrength; if (96 <= pSecurityInfo->dwHashStrength) // Recommended Key strength adwFormatParams[2] = (DWORD)plszStrings->szStrengthHigh; else if (64 <= pSecurityInfo->dwHashStrength) // Passable key strength adwFormatParams[2] = (DWORD)plszStrings->szStrengthMedium; else // Ick! Low key strength. adwFormatParams[2] = (DWORD)plszStrings->szStrengthLow; if(FormatMessageWrapW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, plszStrings->szHashMsg, 0, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpwszHash, 0, (va_list *)adwFormatParams)) { MapCertFields[i].lpszEditBoxText = lpwszHash; MapCertFields[i].lpszListBoxText = plszStrings->szHttpsHashAlg; MapCertFields[i].dwSpcCtlId = 0; i++; } } if(pSecurityInfo->aiExch) { for(j=0; j < sizeof(AlgAttrMap)/sizeof(AlgAttrMap[0]); j++) { if(AlgAttrMap[j].dwAttr == pSecurityInfo->aiExch) { dwExchID = AlgAttrMap[j].dwStringID; break; } } LoadStringWrapW(GlobalDllHandle, dwExchID, szTempBuffer, sizeof(szTempBuffer)/sizeof(szTempBuffer[0])); adwFormatParams[0] = (DWORD)szTempBuffer; adwFormatParams[1] = (DWORD)pSecurityInfo->dwExchStrength; if (1024 <= pSecurityInfo->dwExchStrength) // Recommended Key strength adwFormatParams[2] = (DWORD)plszStrings->szStrengthHigh; else // Ick! Low key strength. adwFormatParams[2] = (DWORD)plszStrings->szStrengthLow; if(FormatMessageWrapW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, plszStrings->szExchMsg, 0, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpwszExch, 0, (va_list *)adwFormatParams)) { MapCertFields[i].lpszEditBoxText = lpwszExch; MapCertFields[i].lpszListBoxText = plszStrings->szHttpsExchAlg; MapCertFields[i].dwSpcCtlId = 0; i++; } } // // Last Array Item is marked with 2 NULLs // MapCertFields[i].lpszListBoxText = NULL; MapCertFields[i].lpszEditBoxText = NULL; MapCertFields[i].dwSpcCtlId = 0; INET_ASSERT(i < MAX_CERT_FIELDS); // // Now Launch the Dlg so we can show it. // ERRORINFODLGTYPE CertDlgInfo; CertDlgInfo.dwDlgFlags = DLG_FLAGS_HAS_CERT_INFO; CertDlgInfo.dwDlgId = IDD_SHOW_CERT; CertDlgInfo.hInternetMapped = NULL; CertDlgInfo.lpVoid = (LPVOID) MapCertFields; LaunchDlg( hWndParent, (LPVOID) &CertDlgInfo, IDD_VIEW_CERT, ViewCertDlgProc ); quit: if(lpszIssuer) { FREE_MEMORY(lpszIssuer); } if(lpwszTempIssuer) { FREE_MEMORY(lpwszTempIssuer); } if(lpszSubject) { FREE_MEMORY(lpszSubject); } if(lpwszTempSubject) { FREE_MEMORY(lpwszTempSubject); } if (szFrom) { FREE_MEMORY(szFrom); } if(pwszTempFrom) { FREE_MEMORY(pwszTempFrom); } if (szUntil) { FREE_MEMORY(szUntil); } if(pwszTempUntil) { FREE_MEMORY(pwszTempUntil); } if (lpwszCipher) { FREE_MEMORY(lpwszCipher); } if (lpwszHash) { FREE_MEMORY(lpwszHash); } if (lpwszExch) { FREE_MEMORY(lpwszExch); } if (lpszHashStr) { delete lpszHashStr; } if(pwszTempHashStr) { FREE_MEMORY(pwszTempHashStr); } return error; #endif } STDAPI_(DWORD) ShowCertificate( IN HWND hWndParent, IN LPVOID pCertInfoEx ) /*++ Routine Description: Displays a dialog box that shows the information found inside of a certificate. Arguments: hWndParent - Parent Window Handle pCertInfoEx - Certificate Information structure, containing the fields of info to show. Return Value: DWORD Win32 or WININET error code. --*/ { //DWORD error = ShowSecurityInfo( // hWndParent, // (LPINTERNET_SECURITY_INFO) pCertInfoEx // BAD.. // ); //return error; return ERROR_INTERNET_INTERNAL_ERROR; } BOOL CALLBACK ViewCertDlgProc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) /*++ Routine Description: Shows a Certificate, and relevent security information to the user. Arguments: hwnd - standard dialog params msg - " wparam - " lparam - " Return Value: BOOL TRUE - we handled message FALSE - Windows should handle message --*/ { PERRORINFODLGTYPE pDlgInfo; const static DWORD mapIDCsToIDHs[] = { IDC_CERTPICKLIST ,IDH_LIST_CERT, ID_SHOW_CERTIFICATE ,IDH_VIEW_CERT, IDC_DELETE_CERT ,IDH_DEL_CERT, 0,0 }; switch (msg) { case WM_INITDIALOG: INET_ASSERT(lparam); pDlgInfo = (PERRORINFODLGTYPE)lparam; (void)SetWindowLongPtr(hwnd, DWLP_USER, lparam); INET_ASSERT(pDlgInfo->dwDlgFlags & DLG_FLAGS_HAS_CERT_INFO ); INET_ASSERT(pDlgInfo->lpVoid); PlaceCertificateDataIntoListBox( hwnd, GetDlgItem(hwnd,IDC_FIELDLIST), (ShowCertMapping *) pDlgInfo->lpVoid ); OnSelectionOfACertField( GetDlgItem(hwnd,IDC_FIELDLIST), GetDlgItem(hwnd,IDC_DETAILSLIST), (ShowCertMapping *) pDlgInfo->lpVoid ); return TRUE; case WM_HELP: // F1 WinHelp( (HWND)((LPHELPINFO)lparam)->hItemHandle, szHelpFile, HELP_WM_HELP, (ULONG_PTR)(LPSTR)mapIDCsToIDHs ); break; case WM_CONTEXTMENU: // right mouse click WinHelp( (HWND) wparam, szHelpFile, HELP_CONTEXTMENU, (ULONG_PTR)(LPSTR)mapIDCsToIDHs ); break; case WM_COMMAND: { WORD wID = LOWORD(wparam); WORD wNotificationCode = HIWORD(wparam); HWND hWndCtrl = (HWND) lparam; pDlgInfo = (PERRORINFODLGTYPE) GetWindowLongPtr(hwnd,DWLP_USER); switch (wID) { case ID_TELL_ME_ABOUT_SECURITY: // // Launches help for this button. // WinHelp( hwnd, szHelpFile, HELP_CONTEXT, (ULONG_PTR)HELP_TOPIC_SECURITY ); break; case IDC_FIELDLIST: // // If the user changes the selection of the listbox // move the edit control field data to the correct // entry. // if ( wNotificationCode == LBN_SELCHANGE ) { OnSelectionOfACertField( hWndCtrl, GetDlgItem(hwnd,IDC_DETAILSLIST), (ShowCertMapping *) pDlgInfo->lpVoid ); } break; case IDOK: case IDYES: INET_ASSERT(pDlgInfo); INET_ASSERT(pDlgInfo->dwDlgId != 0); EndDialog(hwnd, TRUE); break; case IDCANCEL: case IDNO: EndDialog(hwnd, FALSE); break; } return TRUE; } } return FALSE; } DWORD ShowClientAuthCerts( IN HWND hWndParent ) /*++ Routine Description: Shows the Client Authentication Certificates found in the system. Arguments: hWndParent - Parent Window Handle Return Value: DWORD Win32 or WININET error code. --*/ { // With the NT5 crypto UI we don't need to display client-auth certs anymore. // I left this in code in the source file in case we switch back to the old // crypto dlls for some reason. Once we decide to move on to the new crypto dlls // this code can be removed. - sgs #ifndef USE_NT5_CRYPTOUI DWORD error; ERRORINFODLGTYPE ErrorInfoDlgInfo; ErrorInfoDlgInfo.hInternetMapped = NULL; ErrorInfoDlgInfo.dwDlgId = IDD_CERTVIEWER; ErrorInfoDlgInfo.lpVoid = NULL; ErrorInfoDlgInfo.dwDlgFlags = 0; CliAuthAquireCertChains( NULL, NULL, (CERT_CHAIN_ARRAY **) &ErrorInfoDlgInfo.lpVoid ); // // Don't Care about error code, from function. // error = LaunchDlg( hWndParent, (LPVOID) &ErrorInfoDlgInfo, ErrorInfoDlgInfo.dwDlgId, CertPickDialogProc ); if ( ErrorInfoDlgInfo.lpVoid ) delete ErrorInfoDlgInfo.lpVoid; return error; #else INET_ASSERT(FALSE); return ERROR_CALL_NOT_IMPLEMENTED; #endif } DWORD ParseX509EncodedCertificateForListBoxEntry( IN LPBYTE lpCert, IN DWORD cbCert, OUT LPSTR lpszListBoxEntry, IN LPDWORD lpdwListBoxEntry ) /*++ Routine Description: Parses an X509 certificate, into a single text entry that can be displayed on a line in a listbox. Arguments: lpCert - Certificte bytes to parse cbCert - Size of certificate to parse lpszListBoxEntry - Formated text to use in List Box. lpdwListBoxEntry - IN: size of lpszListBoxEntry, OUT: actual size of string. Return Value: DWORD Win32 or WININET error code. --*/ { BOOL fSuccess; DWORD error = ERROR_SUCCESS; PCCERT_CONTEXT pCert; PCERT_NAME_INFO pName = NULL; PCERT_RDN pIdentRDN; PCERT_RDN_ATTR pIdentifier; DWORD cbIdentifier; DWORD cbName, cbName2; INET_ASSERT(lpdwListBoxEntry); if (lpszListBoxEntry == NULL) *lpdwListBoxEntry = 0; // // 30-Aug-1997 pberkman: // we need to do this to be backwards compatible with this function. // however, becuase the create context function does not get us properties // when we are creating it from a already existing context, we need the // ability to just pass in the pre-existing context. To do this, just // pass "-1" in for the cbCert and we'll do the "right thing". // if (cbCert == (-1)) { pCert = (PCCERT_CONTEXT)lpCert; } else { pCert = CertCreateCertificateContext(X509_ASN_ENCODING, lpCert, cbCert); } // // 30-Aug-1997 pberkman: // look at the "Friendly Name" property first. // cbName = 0; CertGetCertificateContextProperty(pCert, CERT_FRIENDLY_NAME_PROP_ID, NULL, &cbName); if (cbName > 0) { WCHAR *pbFName; if (pbFName = (WCHAR *)new BYTE[cbName]) { if (CertGetCertificateContextProperty(pCert, CERT_FRIENDLY_NAME_PROP_ID, pbFName, &cbName)) { cbName2 = WideCharToMultiByte(0, 0, (WCHAR *)pbFName, wcslen((WCHAR *)pbFName) + 1, lpszListBoxEntry, *lpdwListBoxEntry, NULL, NULL); if (cbName2 > *lpdwListBoxEntry) { error = ERROR_INSUFFICIENT_BUFFER; *lpdwListBoxEntry = cbName2; } delete pbFName; if ((pCert) && (cbCert != (-1))) { CertFreeCertificateContext(pCert); } return(error); } delete pbFName; } } if(CryptDecodeObject(pCert->dwCertEncodingType, X509_NAME, pCert->pCertInfo->Subject.pbData, pCert->pCertInfo->Subject.cbData, 0, NULL, &cbName)) { pName = (PCERT_NAME_INFO)new BYTE[cbName]; if(pName == NULL) { error = ERROR_NOT_ENOUGH_MEMORY; } else if(!CryptDecodeObject(pCert->dwCertEncodingType, X509_NAME, pCert->pCertInfo->Subject.pbData, pCert->pCertInfo->Subject.cbData, 0, pName, &cbName)) { delete pName; pName = NULL; error = GetLastError(); } } else { error = GetLastError(); } if((NULL != pName) && (pName->cRDN > 0)) { pIdentifier = CertFindRDNAttr(szOID_COMMON_NAME, pName); if(pIdentifier == NULL) { pIdentifier = CertFindRDNAttr(szOID_ORGANIZATIONAL_UNIT_NAME, pName); if(pIdentifier == NULL) { pIdentifier = CertFindRDNAttr(szOID_ORGANIZATION_NAME, pName); if(pIdentifier == NULL) { pIdentRDN = &pName->rgRDN[pName->cRDN-1]; pIdentifier = &pIdentRDN->rgRDNAttr[pIdentRDN->cRDNAttr-1]; } } } if(pIdentifier != NULL) { cbIdentifier = CertRDNValueToStr(pIdentifier->dwValueType, &pIdentifier->Value, NULL, 0); if(cbIdentifier == 0) { error = GetLastError(); } else if ( (lpszListBoxEntry != NULL) && (cbIdentifier > (*lpdwListBoxEntry)) ) { error = ERROR_INSUFFICIENT_BUFFER; *lpdwListBoxEntry = cbIdentifier; } else { *lpdwListBoxEntry = CertRDNValueToStr(pIdentifier->dwValueType, &pIdentifier->Value, lpszListBoxEntry, cbIdentifier); error = ERROR_SUCCESS; } } else { *lpdwListBoxEntry = 0; error = ERROR_INTERNET_INVALID_OPERATION; } delete pName; } // // 30-Aug-1997 pberkman: // we have to free this thing! // if ((pCert) && (cbCert != (-1))) { CertFreeCertificateContext(pCert); } return error; } DWORD ShowX509EncodedCertificate( IN HWND hWndParent, IN LPBYTE lpCert, IN DWORD cbCert ) /*++ Routine Description: Shows an encoded set of bytes which represent a certificate, in a dialog box. Arguments: hWndParent lpCert cbCert Return Value: DWORD ERROR_SUCCESS --*/ { DWORD error; #ifdef USE_NT5_CRYPTOUI // // For now, we use the new UI only if we can load the DLL. Otherwise we // resort to the old UI. Eventually, we may nuke the old UI. // if (UseCryptoUI()) { CRYPTUI_VIEWCERTIFICATE_STRUCT cert; ZeroMemory(&cert, sizeof(cert)); cert.dwSize = sizeof(cert); cert.hwndParent = hWndParent; cert.pCertContext = (PCCERT_CONTEXT)lpCert; cert.cStores = 1; cert.rghStores = (HCERTSTORE *) & (cert.pCertContext->hCertStore); return _CryptUIDlgViewCertificate(&cert, NULL); } else #endif { X509Certificate *pCertData = NULL; INTERNET_SECURITY_INFO ciInfo; ZeroMemory(&ciInfo, sizeof(ciInfo)); ciInfo.dwSize = sizeof(ciInfo); ciInfo.pCertificate = CertCreateCertificateContext(X509_ASN_ENCODING, lpCert, cbCert); error = ShowSecurityInfo( hWndParent, &ciInfo ); } return error; } BOOL _GetSelectedCertContext(HWND hwnd, PERRORINFODLGTYPE pDlgInfo, PCCERT_CONTEXT *ppCertContext) { CERT_CONTEXT_ARRAY* pCertContextArray; if (ppCertContext == NULL) return FALSE; *ppCertContext = NULL; pCertContextArray = ((HTTP_REQUEST_HANDLE_OBJECT *)pDlgInfo->hInternetMapped)->GetCertContextArray(); PCERT_CHAIN pcCertChain; LRESULT index; INET_ASSERT(pCertContextArray); if (!pCertContextArray) return FALSE; // // Retrieve the Cert from List box // index = SendDlgItemMessage(hwnd, IDC_CERTPICKLIST, LB_GETCURSEL, 0, 0); if ( index == LB_ERR ) index = 0; if ( index >= (INT) pCertContextArray->GetArraySize()) { INET_ASSERT(FALSE); return FALSE; } *ppCertContext = pCertContextArray->GetCertContext((INT)index); if (!*ppCertContext) return FALSE; else return TRUE; } INT_PTR CALLBACK CertPickDialogProc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) /*++ Routine Description: Supports Ok/Cancel decisions for the Client Authentication UI. Allows the User to select a specific Certificate that he wishes to use for Client Auth. Arguments: hwnd - standard dialog params msg - " wparam - " lparam - " Return Value: BOOL TRUE - we handled message FALSE - Windows should handle message --*/ { PERRORINFODLGTYPE pDlgInfo; CERT_CONTEXT_ARRAY* pCertContextArray; LRESULT index; const static DWORD mapIDCsToIDHs[] = { IDC_CERTPICKLIST, IDH_CLIENT_AUTHENTICATION_LIST, ID_SHOW_CERTIFICATE, IDH_CLIENT_AUTHENTICATION_CERT_PROPS, IDCLOSE, IDH_ORG_FAVORITES_CLOSE, IDC_BUTTON_IMPORT, IDH_CLIENTAUTH_IMPORT, IDC_BUTTON_EXPORT, IDH_CLIENTAUTH_EXPORT, 0,0 }; switch (msg) { case WM_INITDIALOG: { INET_ASSERT(lparam); pDlgInfo = (PERRORINFODLGTYPE)lparam; (void)SetWindowLongPtr(hwnd, DWLP_USER, lparam); // We used to have other dialogs use the same dialog proc, but this // shouldn't happen with the removal of the personal certs dialog. INET_ASSERT(pDlgInfo->dwDlgId == IDD_CERTPICKER); pCertContextArray = ((HTTP_REQUEST_HANDLE_OBJECT *)pDlgInfo->hInternetMapped)->GetCertContextArray(); PlaceCertContextsInListBox( GetDlgItem(hwnd, IDC_CERTPICKLIST), GetDlgItem(hwnd, ID_SHOW_CERTIFICATE), GetDlgItem(hwnd, IDC_BUTTON_EXPORT), pCertContextArray ); return TRUE; } case WM_HELP: // F1 WinHelp( (HWND)((LPHELPINFO)lparam)->hItemHandle, szHelpFile, HELP_WM_HELP, (ULONG_PTR)(LPSTR)mapIDCsToIDHs ); break; case WM_CONTEXTMENU: // right mouse click WinHelp( (HWND) wparam, szHelpFile, HELP_CONTEXTMENU, (ULONG_PTR)(LPSTR)mapIDCsToIDHs ); break; case WM_COMMAND: { WORD wID = LOWORD(wparam); WORD wNotificationCode = HIWORD(wparam); HWND hWndCtrl = (HWND) lparam; pDlgInfo = (PERRORINFODLGTYPE) GetWindowLongPtr(hwnd,DWLP_USER); switch (wID) { case ID_TELL_ME_ABOUT_SECURITY: // // Launches help for this button. // WinHelp( hwnd, szHelpFile, HELP_CONTEXT, (ULONG_PTR)HELP_TOPIC_SECURITY ); break; case ID_SHOW_CERTIFICATE: { // // If this dialog supports this behavior, then launch // a show certficate dlg. // PCCERT_CONTEXT pCertContext; if ( wNotificationCode == BN_CLICKED && _GetSelectedCertContext(hwnd, pDlgInfo, &pCertContext )) { ShowX509EncodedCertificate( hwnd, (LPBYTE)pCertContext, sizeof(pCertContext) ); } break; } case ID_CERT_MORE_INFO: HtmlHelp(hwnd, TEXT("iexplore.chm > iedefault"), HH_DISPLAY_TOPIC, (DWORD_PTR)TEXT("cert_ovr.htm")); break; case IDCANCEL: index = -1; goto lskip_getcursel; case IDOK: // // Get the selected Cert. // index = SendDlgItemMessage(hwnd, IDC_CERTPICKLIST, LB_GETCURSEL, 0, 0); if ( index == LB_ERR ) index = -1; lskip_getcursel: INET_ASSERT(pDlgInfo); INET_ASSERT(pDlgInfo->dwDlgId != 0); // // Select the Client Auth Cert to use, // but only if we've got the cert picker dialog. // pCertContextArray = ((HTTP_REQUEST_HANDLE_OBJECT *)pDlgInfo->hInternetMapped)->GetCertContextArray(); if (pCertContextArray) { pCertContextArray->SelectCertContext((INT)index); } EndDialog(hwnd, TRUE); break; case IDCLOSE: // // We're done, so return FALSE. // EndDialog(hwnd, FALSE); break; } return TRUE; } } return FALSE; } // // private functions // PRIVATE BOOL PlaceCertContextsInListBox( IN HWND hWndListBox, IN HWND hWndViewCertButton, IN HWND hWndExportButton, IN CERT_CONTEXT_ARRAY* pCertContextArray ) /*++ Routine Description: Takes an array of CertContext's and puts them into a listbox, by cracking their contents one at a time. Arguments: hWndListBox - Window Handle to ListBox to add items to. pCertContext's - Pointer to array of cert chains. hWndViewCertButton - Window handle to ViewCert Button, NULL if no button is around Return Value: BOOL TRUE - success. FALSE - failure. --*/ { DWORD i = 0; if ( !pCertContextArray) { goto quit; } SendMessage(hWndListBox, LB_RESETCONTENT, 0, 0 ); for ( i = 0; i < pCertContextArray->GetArraySize(); i++ ) { PCCERT_CONTEXT pCert; // PCERT_NAME_INFO pName = NULL; // PCERT_RDN_ATTR pCommonName; DWORD cbName; DWORD dwRet; pCert = pCertContextArray->GetCertContext(i); INET_ASSERT(pCert); LPSTR lpszSubject; cbName = 0; ParseX509EncodedCertificateForListBoxEntry(pCert->pbCertEncoded, pCert->cbCertEncoded, NULL, &cbName); if (cbName > 0) { if (lpszSubject = new TCHAR[cbName]) { if (ParseX509EncodedCertificateForListBoxEntry(pCert->pbCertEncoded, pCert->cbCertEncoded, lpszSubject, &cbName) == ERROR_SUCCESS) { SendMessage(hWndListBox, LB_INSERTSTRING, (WPARAM)-1, (LPARAM) lpszSubject); } FREE_MEMORY(lpszSubject); } } } quit: // Select the first item in the list box // TODO: move selection to current default item. SendMessage(hWndListBox, LB_SETCURSEL, 0, 0 ); // If nothing was added, disable the windows, otherwise enable them EnableWindow(hWndListBox, (i != 0)); if ( hWndViewCertButton ) EnableWindow(hWndViewCertButton, (i != 0)); if ( hWndExportButton ) EnableWindow(hWndExportButton, (i != 0)); return TRUE; } PRIVATE BOOL PlaceCertificateDataIntoListBox( IN HWND hWndDlg, IN HWND hWndListBox, IN ShowCertMapping *pMapCertFields ) { DWORD i; INET_ASSERT(pMapCertFields); INET_ASSERT(IsWindow(hWndListBox)); for ( i = 0; pMapCertFields[i].lpszListBoxText != NULL; i++ ) { if ( pMapCertFields[i].dwSpcCtlId != 0 ) { SetDlgItemTextWrapW(hWndDlg,pMapCertFields[i].dwSpcCtlId, pMapCertFields[i].lpszEditBoxText ); SetWindowLong(GetDlgItem(hWndDlg,pMapCertFields[i].dwSpcCtlId), GWL_STYLE, ES_READONLY | GetWindowLong(GetDlgItem(hWndDlg,pMapCertFields[i].dwSpcCtlId), GWL_STYLE)); } SendMessage(hWndListBox, LB_ADDSTRING, 0, (LPARAM)pMapCertFields[i].lpszListBoxText); } INET_ASSERT(i>0); SendMessage(hWndListBox, LB_SETCURSEL, 0, 0 ); return TRUE; } PRIVATE DWORD OnSelectionOfACertField( IN HWND hWndListBox, IN HWND hWndEditBox, IN ShowCertMapping *pMapCertFields ) { LRESULT index; index = SendMessage(hWndListBox, LB_GETCURSEL, 0, 0); if (index == LB_ERR ) index = 0; if ( pMapCertFields[index].lpszListBoxText != NULL ) { SetWindowTextWrapW(hWndEditBox, pMapCertFields[index].lpszEditBoxText ); SetWindowLong(hWndEditBox, GWL_STYLE, ES_READONLY | GetWindowLong(hWndEditBox, GWL_STYLE)); } return ERROR_SUCCESS; } #ifndef CERT_E_WRONG_USAGE # define CERT_E_WRONG_USAGE _HRESULT_TYPEDEF_(0x800B0110L) #endif #ifndef SECURITY_FLAG_IGNORE_WRONG_USAGE # define SECURITY_FLAG_IGNORE_WRONG_USAGE 0x00010000 #endif /* get a string representing the status of a certificate */ LPWSTR GetCertStatus(LPINTERNET_SECURITY_INFO pciCert) { // We've done our handshake, now update the security info DWORD dwCertFlags; PLOCAL_STRINGS plszStrings; GUID gHTTPS = HTTPSPROV_ACTION; WINTRUST_DATA sWTD; WINTRUST_CERT_INFO sWTCI; HTTPSPolicyCallbackData polHttps; DWORD cbServerName; DWORD error; plszStrings = FetchLocalStrings(); if(plszStrings == NULL) { return NULL; } if((pciCert == NULL) || (pciCert->pCertificate == NULL)) { return NULL; } // // initialize the structures for forward/backward support of wintrust.dll!!! // memset(&sWTD, 0x00, sizeof(WINTRUST_DATA)); sWTD.cbStruct = sizeof(WINTRUST_DATA); sWTD.dwUIChoice = WTD_UI_NONE; sWTD.pPolicyCallbackData = (LPVOID)&polHttps; sWTD.dwUnionChoice = WTD_CHOICE_CERT; sWTD.pCert = &sWTCI; sWTD.pwszURLReference = NULL; memset(&sWTCI, 0x00, sizeof(WINTRUST_CERT_INFO)); sWTCI.cbStruct = sizeof(WINTRUST_CERT_INFO); sWTCI.psCertContext = (CERT_CONTEXT *)pciCert->pCertificate; sWTCI.chStores = 1; sWTCI.pahStores = (HCERTSTORE *)&pciCert->pCertificate->hCertStore; memset(&polHttps, 0x00, sizeof(HTTPSPolicyCallbackData)); polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData); polHttps.dwAuthType = AUTHTYPE_SERVER; polHttps.fdwChecks = INTERNET_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_WRONG_USAGE; polHttps.pwszServerName = NULL; sWTCI.pcwszDisplayName = NULL; error = LoadWinTrust(); if(ERROR_SUCCESS == error) { error = WinVerifySecureChannel(NULL, &sWTD); } // If we are unable to verify revocation, then ignore. if(error == CERT_E_REVOCATION_FAILURE) { error = ERROR_SUCCESS; } switch(error) { case CERT_E_EXPIRED: case CERT_E_VALIDITYPERIODNESTING: return plszStrings->szCommentExpires; case CERT_E_UNTRUSTEDROOT: return plszStrings->szCommentBadCA; case CERT_E_CN_NO_MATCH: return plszStrings->szCommentBadCN; case CRYPT_E_REVOKED: return plszStrings->szCommentRevoked; case CERT_E_WRONG_USAGE: return plszStrings->szCertUsage; case CERT_E_ROLE: case CERT_E_PATHLENCONST: case CERT_E_CRITICAL: case CERT_E_PURPOSE: case CERT_E_ISSUERCHAINING: case CERT_E_MALFORMED: case CERT_E_CHAINING: return plszStrings->szCommentNotValid; case ERROR_SUCCESS: return NULL; default: return plszStrings->szCommentNotValid; } }