//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1997 - 1999 // // File: cps.cpp // //-------------------------------------------------------------------------- // // File: select.cpp // // Description: This file contains the implmentation code for the // "Certificate Select" dialog. // #pragma warning (disable: 4201) // nameless struct/union #pragma warning (disable: 4514) // remove inline functions #pragma warning (disable: 4127) // conditional expression is constant #include "global.hxx" #include extern HINSTANCE HinstDll; extern HMODULE HmodRichEdit; typedef struct _CPS_STATE_STRUCT { LPWSTR pwszURL; LPWSTR pwszDisplayText; DWORD dwChainError; BOOL fNoCOM; } CPS_STATE_STRUCT, *PCPS_STATE_STRUCT; INT_PTR CALLBACK CPSDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { BOOL f; CPS_STATE_STRUCT *pcpsStateStruct; switch (msg) { case WM_INITDIALOG: pcpsStateStruct = (CPS_STATE_STRUCT *) lParam; SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR) pcpsStateStruct); // set the text for the CPS CryptUISetRicheditTextW(hwndDlg, IDC_CPS_TEXT, pcpsStateStruct->pwszDisplayText); // if there is no URL then hide the more info button, // // DSIE: Bug 364742, also hide if the URL is not safe to be execute. if (!pcpsStateStruct->pwszURL || !IsOKToFormatAsLinkW(pcpsStateStruct->pwszURL, pcpsStateStruct->dwChainError)) { EnableWindow(GetDlgItem(hwndDlg, ID_MORE_INFO), FALSE); } break; case WM_NOTIFY: //if (((NMHDR FAR *) lParam)->code == EN_LINK) break; case WM_COMMAND: switch (LOWORD(wParam)) { case ID_MORE_INFO: if (HIWORD(wParam) == BN_CLICKED) { DWORD numBytes = 0; LPSTR pszURL = NULL; pcpsStateStruct = (CPS_STATE_STRUCT *) GetWindowLongPtr(hwndDlg, DWLP_USER); pszURL = CertUIMkMBStr(pcpsStateStruct->pwszURL); if (pszURL == NULL) { return TRUE; } CryptuiGoLink(hwndDlg, pszURL, pcpsStateStruct->fNoCOM); free(pszURL); return TRUE; } break; case IDOK: case IDCANCEL: case IDOK_CPS: case IDCANCEL_CPS: EndDialog(hwndDlg, IDOK); return TRUE; } break; // // Use the default handler -- we don't do anything for it // default: return FALSE; } return FALSE; } DWORD GetCPSInfo(PCCERT_CONTEXT pCertContext, LPWSTR * ppwszUrlString, LPWSTR * ppwszDisplayText) { DWORD dwRetCode = 0; PCERT_EXTENSION pExt = NULL; DWORD i,j,k; DWORD cbCertPolicyInfo = 0; CERT_POLICIES_INFO * pCertPolicyInfo = NULL; CERT_NAME_VALUE * pCertName = NULL; DWORD cbCertName = 0; CERT_POLICY_QUALIFIER_USER_NOTICE * pUserNotice = NULL; DWORD cbUserNotice = 0; PSPC_SP_AGENCY_INFO pInfo = NULL; DWORD cbInfo = 0; CERT_POLICY95_QUALIFIER1 * pCertPolicy95Qualifier = NULL; DWORD cbCertPolicy95Qualifier = 0; // // Check parameters and intialize return values. // if (NULL == pCertContext || NULL == ppwszUrlString || NULL == ppwszDisplayText) { return ERROR_INVALID_PARAMETER; } *ppwszUrlString = *ppwszDisplayText = NULL; // // first look for the PKIX policy extension and see if it has an URL // if ((pExt = CertFindExtension(szOID_CERT_POLICIES, pCertContext->pCertInfo->cExtension, pCertContext->pCertInfo->rgExtension))) { // // decode the policy extension // CryptDecodeObject(X509_ASN_ENCODING, szOID_CERT_POLICIES, pExt->Value.pbData, pExt->Value.cbData, 0, NULL, &cbCertPolicyInfo); if (!(pCertPolicyInfo = (CERT_POLICIES_INFO *) malloc(cbCertPolicyInfo))) { dwRetCode = ERROR_OUTOFMEMORY; goto ErrorExit; } if (!(CryptDecodeObject(X509_ASN_ENCODING, szOID_CERT_POLICIES, pExt->Value.pbData, pExt->Value.cbData, 0, pCertPolicyInfo, &cbCertPolicyInfo))) { dwRetCode = GetLastError(); goto ErrorExit; } // // look for display text and/or and URL in the extension // for (i = 0; i < pCertPolicyInfo->cPolicyInfo ; i++) { for (j = 0; j < pCertPolicyInfo->rgPolicyInfo[i].cPolicyQualifier; j++) { // check to see what type of qualifier it is if (0 == strcmp(szOID_PKIX_POLICY_QUALIFIER_CPS, pCertPolicyInfo->rgPolicyInfo[i].rgPolicyQualifier[j].pszPolicyQualifierId)) { // decode as an anystring CryptDecodeObject(X509_ASN_ENCODING, X509_UNICODE_ANY_STRING, pCertPolicyInfo->rgPolicyInfo[i].rgPolicyQualifier[j].Qualifier.pbData, pCertPolicyInfo->rgPolicyInfo[i].rgPolicyQualifier[j].Qualifier.cbData, 0, NULL, &cbCertName); if (!(pCertName = (CERT_NAME_VALUE *) malloc(cbCertName))) { dwRetCode = ERROR_OUTOFMEMORY; goto ErrorExit; } if (!(CryptDecodeObject(X509_ASN_ENCODING, X509_UNICODE_ANY_STRING, pCertPolicyInfo->rgPolicyInfo[i].rgPolicyQualifier[j].Qualifier.pbData, pCertPolicyInfo->rgPolicyInfo[i].rgPolicyQualifier[j].Qualifier.cbData, 0, pCertName, &cbCertName))) { dwRetCode = GetLastError(); goto ErrorExit; } if (pCertName->Value.cbData && NULL == *ppwszUrlString) { if (!(*ppwszUrlString = (LPWSTR) malloc(pCertName->Value.cbData + sizeof(WCHAR)))) { dwRetCode = ERROR_OUTOFMEMORY; goto ErrorExit; } wcscpy(*ppwszUrlString, (LPWSTR) pCertName->Value.pbData); } free(pCertName); pCertName = NULL; } else if (0 == strcmp(szOID_PKIX_POLICY_QUALIFIER_USERNOTICE, pCertPolicyInfo->rgPolicyInfo[i].rgPolicyQualifier[j].pszPolicyQualifierId)) { // decode as user notice CryptDecodeObject(X509_ASN_ENCODING, szOID_PKIX_POLICY_QUALIFIER_USERNOTICE, pCertPolicyInfo->rgPolicyInfo[i].rgPolicyQualifier[j].Qualifier.pbData, pCertPolicyInfo->rgPolicyInfo[i].rgPolicyQualifier[j].Qualifier.cbData, 0, NULL, &cbUserNotice); if (!(pUserNotice = (CERT_POLICY_QUALIFIER_USER_NOTICE *) malloc(cbUserNotice))) { dwRetCode = ERROR_OUTOFMEMORY; goto ErrorExit; } if (!(CryptDecodeObject(X509_ASN_ENCODING, szOID_PKIX_POLICY_QUALIFIER_USERNOTICE, pCertPolicyInfo->rgPolicyInfo[i].rgPolicyQualifier[j].Qualifier.pbData, pCertPolicyInfo->rgPolicyInfo[i].rgPolicyQualifier[j].Qualifier.cbData, 0, pUserNotice, &cbUserNotice))) { dwRetCode = GetLastError(); goto ErrorExit; } // NOTE: pUserNotice->pszDisplayText may be NULL if (pUserNotice->pszDisplayText && NULL == *ppwszDisplayText) { if (!(*ppwszDisplayText = (LPWSTR) malloc((wcslen(pUserNotice->pszDisplayText) + 1) * sizeof(WCHAR)))) { dwRetCode = ERROR_OUTOFMEMORY; goto ErrorExit; } wcscpy(*ppwszDisplayText, pUserNotice->pszDisplayText); } free(pUserNotice); pUserNotice = NULL; } } } } // // next look for display information in the SPC Agency Info // else if ((pExt = CertFindExtension(SPC_SP_AGENCY_INFO_OBJID, pCertContext->pCertInfo->cExtension, pCertContext->pCertInfo->rgExtension))) { CryptDecodeObject(X509_ASN_ENCODING, SPC_SP_AGENCY_INFO_STRUCT, pExt->Value.pbData, pExt->Value.cbData, 0, NULL, &cbInfo); if (!(pInfo = (PSPC_SP_AGENCY_INFO) malloc(cbInfo))) { dwRetCode = ERROR_OUTOFMEMORY; goto ErrorExit; } if (!(CryptDecodeObject(X509_ASN_ENCODING, SPC_SP_AGENCY_INFO_STRUCT, pExt->Value.pbData, pExt->Value.cbData, 0, pInfo, &cbInfo))) { dwRetCode = GetLastError(); goto ErrorExit; } if (!(pInfo->pPolicyInformation)) { dwRetCode = CRYPT_E_NOT_FOUND; goto ErrorExit; } if (pInfo->pwszPolicyDisplayText) { if (!(*ppwszDisplayText = (LPWSTR) malloc((wcslen(pInfo->pwszPolicyDisplayText) + 1) * sizeof(WCHAR)))) { dwRetCode = ERROR_OUTOFMEMORY; goto ErrorExit; } wcscpy(*ppwszDisplayText, pInfo->pwszPolicyDisplayText); } switch (pInfo->pPolicyInformation->dwLinkChoice) { case SPC_URL_LINK_CHOICE: { if (pInfo->pPolicyInformation->pwszUrl) { if (!(*ppwszUrlString = (LPWSTR) malloc((wcslen(pInfo->pPolicyInformation->pwszUrl) + 1) * sizeof(WCHAR)))) { dwRetCode = ERROR_OUTOFMEMORY; goto ErrorExit; } wcscpy(*ppwszUrlString, pInfo->pPolicyInformation->pwszUrl); } break; } case SPC_FILE_LINK_CHOICE: { if (pInfo->pPolicyInformation->pwszFile) { if (!(*ppwszUrlString = (LPWSTR) malloc((wcslen(pInfo->pPolicyInformation->pwszFile) + 1) * sizeof(WCHAR)))) { dwRetCode = ERROR_OUTOFMEMORY; goto ErrorExit; } wcscpy(*ppwszUrlString, pInfo->pPolicyInformation->pwszFile); } break; } } } // // finally, look for info in the 2.5.29.3 extension // else if ((pExt = CertFindExtension(szOID_CERT_POLICIES_95, pCertContext->pCertInfo->cExtension, pCertContext->pCertInfo->rgExtension))) { CryptDecodeObject(X509_ASN_ENCODING, szOID_CERT_POLICIES_95, pExt->Value.pbData, pExt->Value.cbData, 0, NULL, &cbCertPolicyInfo); if (!(pCertPolicyInfo = (CERT_POLICIES_INFO *) malloc(cbCertPolicyInfo))) { dwRetCode = ERROR_OUTOFMEMORY; goto ErrorExit; } if (!(CryptDecodeObject(X509_ASN_ENCODING, szOID_CERT_POLICIES_95, pExt->Value.pbData, pExt->Value.cbData, 0, pCertPolicyInfo, &cbCertPolicyInfo))) { dwRetCode = GetLastError(); goto ErrorExit; } // now decode the qualifiers for (i = 0; i < pCertPolicyInfo->cPolicyInfo; i++) { for (j = 0; j < pCertPolicyInfo->rgPolicyInfo[i].cPolicyQualifier; j++) { if (0 == strcmp(szOID_CERT_POLICIES_95_QUALIFIER1, pCertPolicyInfo->rgPolicyInfo[i].rgPolicyQualifier[j].pszPolicyQualifierId)) { CryptDecodeObject(X509_ASN_ENCODING, szOID_CERT_POLICIES_95_QUALIFIER1, pCertPolicyInfo->rgPolicyInfo[i].rgPolicyQualifier[j].Qualifier.pbData, pCertPolicyInfo->rgPolicyInfo[i].rgPolicyQualifier[j].Qualifier.cbData, 0, NULL, &cbCertPolicy95Qualifier); if (!(pCertPolicy95Qualifier = (CERT_POLICY95_QUALIFIER1 *) malloc(cbCertPolicy95Qualifier))) { dwRetCode = ERROR_OUTOFMEMORY; goto ErrorExit; } if (!(CryptDecodeObject(X509_ASN_ENCODING, szOID_CERT_POLICIES_95_QUALIFIER1, pCertPolicyInfo->rgPolicyInfo[i].rgPolicyQualifier[j].Qualifier.pbData, pCertPolicyInfo->rgPolicyInfo[i].rgPolicyQualifier[j].Qualifier.cbData, 0, pCertPolicy95Qualifier, &cbCertPolicy95Qualifier))) { dwRetCode = GetLastError(); goto ErrorExit; } // check to see what is available if ((NULL != pCertPolicy95Qualifier->pszPracticesReference) && (NULL == *ppwszDisplayText)) { if (!(*ppwszDisplayText = (LPWSTR) malloc((wcslen(pCertPolicy95Qualifier->pszPracticesReference) + 1) * sizeof(WCHAR)))) { dwRetCode = ERROR_OUTOFMEMORY; goto ErrorExit; } wcscpy(*ppwszDisplayText, pCertPolicy95Qualifier->pszPracticesReference); } for (k = 0; k < pCertPolicy95Qualifier->cCPSURLs; k++) { if ((NULL != pCertPolicy95Qualifier->rgCPSURLs[k].pszURL) && (NULL == *ppwszUrlString)) { if (!(*ppwszUrlString = (LPWSTR) malloc((wcslen(pCertPolicy95Qualifier->rgCPSURLs[k].pszURL) + 1) * sizeof(WCHAR)))) { dwRetCode = ERROR_OUTOFMEMORY; goto ErrorExit; } wcscpy(*ppwszUrlString, pCertPolicy95Qualifier->rgCPSURLs[k].pszURL); } } free(pCertPolicy95Qualifier); pCertPolicy95Qualifier = NULL; } } } } // // If there is neither display text nor an URL, then return CRYPT_E_NOT_FOUND. // if ((NULL == *ppwszUrlString) && (NULL == *ppwszDisplayText)) { dwRetCode = CRYPT_E_NOT_FOUND; } CommonExit: if (pInfo) free(pInfo); if (pCertPolicyInfo) free(pCertPolicyInfo); if (pUserNotice) free(pUserNotice); if (pCertName) free(pCertName); if (pCertPolicy95Qualifier) free(pCertPolicy95Qualifier); return dwRetCode; ErrorExit: if (*ppwszUrlString) { free(*ppwszUrlString); *ppwszUrlString = NULL; } if (*ppwszDisplayText) { free(*ppwszDisplayText); *ppwszDisplayText = NULL; } goto CommonExit; } BOOL IsOKToDisplayCPS(PCCERT_CONTEXT pCertContext, DWORD dwChainError) { BOOL fResult = FALSE; LPWSTR pwszUrlString = NULL; LPWSTR pwszDisplayText = NULL; // // Check parameters and initialize. // if (NULL == pCertContext) { goto CommonExit; } // // Get CPS info. // if ((0 == GetCPSInfo(pCertContext, &pwszUrlString, &pwszDisplayText)) && (pwszDisplayText || IsOKToFormatAsLinkW(pwszUrlString, dwChainError))) { fResult = TRUE; } CommonExit: if (pwszUrlString) { free(pwszUrlString); } if (pwszDisplayText) { free(pwszDisplayText); } return fResult; } BOOL DisplayCPS(HWND hwnd, PCCERT_CONTEXT pCertContext, DWORD dwChainError, BOOL fNoCOM) { BOOL fRet = FALSE; DWORD dwRetCode = 0; CPS_STATE_STRUCT cpsStateStruct; // // Initialize and check parameters. // memset(&cpsStateStruct, 0, sizeof(cpsStateStruct)); if (NULL == pCertContext) { goto Return; } // // Get CPS info. // if (0 != (dwRetCode = GetCPSInfo(pCertContext, &cpsStateStruct.pwszURL, &cpsStateStruct.pwszDisplayText))) { goto Return; } // NOW, set up for, and launch that dialog if ((HmodRichEdit == NULL) && (NULL == (HmodRichEdit = LoadLibraryA("RichEd20.dll")))) { goto Return; } // // If there is an URL but no text then just invoke the browser and don't bring // up the dialog // if ((cpsStateStruct.pwszDisplayText == NULL) && (cpsStateStruct.pwszURL != NULL)) { DWORD numBytes = 0; LPSTR pszURL = NULL; pszURL = CertUIMkMBStr(cpsStateStruct.pwszURL); if (pszURL == NULL) { goto Return; } CryptuiGoLink(hwnd, pszURL, fNoCOM); free(pszURL); } else { cpsStateStruct.fNoCOM = fNoCOM; cpsStateStruct.dwChainError = dwChainError; DialogBoxParamU(HinstDll, (LPWSTR) MAKEINTRESOURCE(IDD_CPS_DIALOG), hwnd, CPSDlgProc, (LPARAM) &cpsStateStruct); } fRet = TRUE; Return: if (cpsStateStruct.pwszURL) free(cpsStateStruct.pwszURL); if (cpsStateStruct.pwszDisplayText) free(cpsStateStruct.pwszDisplayText); return fRet; }