windows-nt/Source/XPSP1/NT/ds/security/cryptoapi/ui/cryptui/cps.cpp
2020-09-26 16:20:57 +08:00

612 lines
20 KiB
C++

//+-------------------------------------------------------------------------
//
// 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 <dbgdef.h>
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;
}