EternalWindows
証明書管理 / 証明書表示ダイアログ

証明書が持っている情報をGUIで確認するような場合、 次のようなダイアログが表示されることがあります。

このダイアログでは、全般タブで証明書に含まれている情報を確認することができ、 詳細タブを選択するとより多くの情報を確認することができます。 CSP情報というタブは既定では存在しませんが、 今回紹介するCryptUIDlgViewCertificateという関数を呼び出せば、 このような独自のタブを追加するようなことも可能となります。 秘密鍵が関連付けられている証明書にとっては、 このようなタブは貴重な情報源となるでしょう。 単純にダイアログを表示したいだけであれば、 CryptUIDlgViewContextという関数の方が便利ですが、 この関数にはタブの追加やボタンの無効化などの機能はありません。

証明書表示ダイアログには証明のパスというタブがありますが、 特定の証明書においては、このパスが正しく構築されないことがあることに注意してください。 この問題については証明書検証の章で取り上げているため、 今回はパス情報を考慮しないCryptUIDlgViewCertificateの呼び出し方に注目します。

BOOL WINAPI CryptUIDlgViewCertificate(
  PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
  BOOL* pfPropertiesChanged
);

pCertViewInfoは、表示するダイアログの情報を含むCRYPTUI_VIEWCERTIFICATE_STRUCT構造体の アドレスを指定します。 pfPropertiesChangedは、証明のプロパティが変更されたかを受け取る変数のアドレスを指定します。 この変数は、NULLを指定することができます。

CRYPTUI_VIEWCERTIFICATE_STRUCT構造体の定義を次に示します。 WinTrustに関係するpCryptProviderDataからidxCounterSignerは、別の章で説明します。

typedef struct tagCRYPTUI_VIEWCERTIFICATE_STRUCT {
  DWORD dwSize;
  HWND hwndParent;
  DWORD dwFlags;
  LPCTSTR szTitle;
  PCCERT_CONTEXT pCertContext;
  LPCSTR* rgszPurposes;
  DWORD cPurposes;
  union {
    CRYPT_PROVIDER_DATA* pCryptProviderData;
    HANDLE hWVTStateData;
  };
  BOOL fpCryptProviderDataTrustedUsage;
  DWORD idxSigner;
  DWORD idxCert;
  BOOL fCounterSigner;
  DWORD idxCounterSigner;
  DWORD cStores;
  HCERTSTORE* rghStores;
  DWORD cPropSheetPages;
  LPCPROPSHEETPAGE rgPropSheetPages;
  DWORD nStartPage;
} CRYPTUI_VIEWCERTIFICATE_STRUCT,  *PCRYPTUI_VIEWCERTIFICATE_STRUCT;

dwSizeは、この構造体のサイズを指定します。 hwndParentは、ダイアログの親ウインドウするウインドウのハンドルを指定します。 dwFlagsは、ダイアログの動作を定義する定数を指定します。 szTitleは、ダイアログのタイトルとしたい文字列を指定します。 pCertContextは、表示したい証明書のコンテキストを指定します。 rgszPurposesは、拡張キー使用法を表すOIDの配列を指定します。 指定した目的を含まない証明書に対して警告を出したい場合に利用します。 cPurposesは、rgszPurposesの要素数を指定します。 cStoresは、rghStoresの要素数を指定します。 rghStoresは、証明書のパスを構築する際に参照する証明書ストアの配列を指定します。 cPropSheetPagesは、rgPropSheetPagesの要素数を指定します。 rgPropSheetPagesは、ダイアログに追加したいページを表すPROPSHEETPAGE構造体の配列を指定します。 nStartPageは、ダイアログの各ページにおいて、最初に表示したいページのインデックスを指定します。 0を指定すると、最初の「全般」タブのページが表示されます。

dwFlagsに指定できる定数の一部を次に示します。

定数 フラグ
CRYPTUI_HIDE_HIERARCHYPAGE 「証明のパス」タブを表示しない。
CRYPTUI_HIDE_DETAILPAGE 「詳細」タブを表示しない。
CRYPTUI_DISABLE_EDITPROPERTIES 「詳細」タブにおいて「プロパティの編集」ボタンを無効にする。
CRYPTUI_DISABLE_ADDTOSTORE 「全般」タブにおいて「証明書のインストール」ボタンを無効にする。
CRYPTUI_IGNORE_UNTRUSTED_ROOT 「全般」タブにおいて、証明書が信頼されていないときに表示される警告を無視する。

今回のプログラムは、CryptUIDlgViewCertificateを呼び出して証明書表示ダイアログを表示します。 また、オプションとして、プロパティシートを追加するコードが含まれています。

#include <windows.h>
#include <cryptuiapi.h>

#pragma comment (lib, "crypt32.lib")
#pragma comment (lib, "cryptui.lib")

INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{	
	PCCERT_CONTEXT                 pContext;
	CRYPTUI_VIEWCERTIFICATE_STRUCT viewCert;
	HCERTSTORE                     hStore;
	PROPSHEETPAGE                  propSheet;
	BOOL                           bAddPropertySheet = FALSE;
	
	hStore = CertOpenSystemStore(0, TEXT("CA"));
	if (hStore == NULL)
		return 0;
	
	pContext = CertEnumCertificatesInStore(hStore, 0);

	ZeroMemory(&viewCert, sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCT));
	viewCert.dwSize           = sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCT);
	viewCert.hwndParent       = NULL;
	viewCert.dwFlags          = CRYPTUI_DISABLE_EDITPROPERTIES;
	viewCert.szTitle          = NULL;
	viewCert.pCertContext     = pContext;
	viewCert.rgszPurposes     = 0;
	viewCert.cPurposes        = 0;
	viewCert.cStores          = 0;
	viewCert.rghStores        = NULL;
	viewCert.cPropSheetPages  = 0;
	viewCert.rgPropSheetPages = NULL;
	viewCert.nStartPage       = 0;

	if (bAddPropertySheet) {
		propSheet.dwSize      = sizeof(PROPSHEETPAGE);
		propSheet.dwFlags     = PSP_DEFAULT;
		propSheet.hInstance   = hinst;
		propSheet.pszTemplate = MAKEINTRESOURCE(100);
		propSheet.pfnDlgProc  = DialogProc;
		
		viewCert.cPropSheetPages  = 1;
		viewCert.rgPropSheetPages = &propSheet;
	}
	
	CryptUIDlgViewCertificate(&viewCert, NULL);

	CertFreeCertificateContext(pContext);
	CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);

	return 0;
}

INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg) {

	case WM_INITDIALOG:
		return TRUE;
	
	case WM_NOTIFY: {
		LPNMHDR lpNmhdr = (LPNMHDR)lParam;

		if (lpNmhdr->code == PSN_APPLY)
			MessageBox(NULL, TEXT("OKボタンが押されました。"), TEXT("OK"), MB_OK);
		else if (lpNmhdr->code == PSN_RESET)
			MessageBox(NULL, TEXT("ダイアログが閉じられました。"), TEXT("OK"), MB_OK);
		else
			;
		break;
	}

	default:
		break;

	}

	return FALSE;
}

表示対象とする証明書は、CertEnumCertificatesInStoreで最初に見つかった証明書としていますが、 実際にはユーザーの意思を反映した形で証明書を取得することになるでしょう。 CRYPTUI_VIEWCERTIFICATE_STRUCT構造体では、WinTrustに関するメンバを除いて全て明示的に初期化しています。 とはいえ、最低限必要なメンバはdwSizeとpCertContextであるため、 それ以外のメンバは0とNULLで初期化することができます。 dwFlagsにCRYPTUI_DISABLE_EDITPROPERTIESを指定していることから、 ダイアログでは証明書のプロパティの変更を行うことはできません。 よって、プロパティが変更されたかを知る必要もなくなるため、 CryptUIDlgViewCertificateの第2引数にはNULLを指定します。

bAddPropertySheetがTRUEになっている場合は、PROPSHEETPAGE構造体にプロパティシートの情報を設定し、 CRYPTUI_VIEWCERTIFICATE_STRUCT構造体の適切なメンバに関連付けます。 これにより、証明書表示ダイアログに新しいプロパティシートが追加され、 pfnDlgProcに指定したプロシージャが呼ばれることになります。 MAKEINTRESOURCEマクロにはダミーで100という値を指定していますが、 実際にはダイアログリソースのIDを指定するようにします。 WM_INITDIALOGのLPARAMには、CRYPTUI_INITDIALOG_STRUCT構造体のアドレスが格納されており、 表示している証明書コンテキストを表すメンバが含まれています。 しかし、実際に調べたところNULLが格納されており、利用することができないようにも思えます。 この他、終了処理検出の例としてPSN_APPLYとPSN_RESETを確認しています。

CryptUIDlgViewContextの利用

CryptUIDlgViewCertificateは、証明書表示ダイアログを表示することに加えて、 プロパティシートの追加などの拡張機能がありますが、 そのような機能が必要のない場合は、 呼び出し方が簡単なCryptUIDlgViewContextを利用するとよいでしょう。 次のコードは、CA証明書ストアの中で最初に見つかった証明書をCryptUIDlgViewContextで表示します。

#include <windows.h>
#include <cryptuiapi.h>

#pragma comment (lib, "crypt32.lib")
#pragma comment (lib, "cryptui.lib")

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	HCERTSTORE     hStore;
	PCCERT_CONTEXT pContext;
	
	hStore = CertOpenSystemStore(0, TEXT("CA"));
	if (hStore == NULL)
		return 0;
	
	pContext = CertEnumCertificatesInStore(hStore, NULL);
	if (pContext == NULL)
		return 0;

	CryptUIDlgViewContext(CERT_STORE_CERTIFICATE_CONTEXT, pContext, NULL, L"タイトル", 0, NULL);
	
	CertFreeCertificateContext(pContext);
	
	return 0;
}

第1引数は、第2引数で指定したデータが、証明書、CTL、CRLのどれであるかを表す定数を指定します。 CERT_STORE_CERTIFICATE_CONTEXTを指定した場合は、第2引数が証明書のコンテキストと解釈されます。 第3引数は、ダイアログの親ウインドウのハンドルでNULLを指定することができます。 第4引数は、ダイアログのタイトルです。 NULLを指定した場合、デフォルトのタイトルが表示されます。 第5引数と第6引数はそれぞれ使用されないので、0とNULLを指定します。 CryptUIDlgViewContextは、今回のCryptUIDlgViewCertificateの呼び出しに置き換えても問題なく動作します。



戻る