EternalWindows
証明書管理 / システムストアの位置

証明書ストアの実体は、ファイルやレジストリキー、メモリ上に展開されたデータなど様々です。 システムストアと呼ばれる証明書ストアの実体はレジストリキーであり、 一定の固定された位置に作成されることになっています。

位置を表す定数 実際の位置
CERT_SYSTEM_STORE_CURRENT_USER HKEY_CURRENT_USER\Software\Microsoft\SystemCertificates
CERT_SYSTEM_STORE_LOCAL_MACHINE HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates
CERT_SYSTEM_STORE_CURRENT_SERVICE HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Services\[ServiceName]\SystemCertificates
CERT_SYSTEM_CURRENT_USER_GROUP_POLICY HKEY_CURRENT_USER\Software\Policy\Microsoft\SystemCertificates
CERT_SYSTEM_LOCAL_MACHINE_GROUP_POLICY HKEY_LOCAL_MACHINE\SOFTWARE\Policy\Microsoft\SystemCertificates

次の図は、CERT_SYSTEM_STORE_CURRENT_USERに存在するシステムストアを示しています。

見て分かるように、CertOpenSystemStoreに指定できるMYやCAといったシステムストアが実際に存在しています。 Certificatesサブキー以下には実際に証明書を格納するキーが存在し、 CTLやCRLサブキーにおいても同じ要領となります。 詳しくは次節で取り上げますが、システムストアの名前を持ったキーの下にさらにサブキーがある場合、 そのシステムストアは.Default物理ストアを持っているということになります。

アプリケーションからシステムストアを列挙するには、CertEnumSystemStoreを呼び出します。 先に述べたように、システムストアは特定の位置に格納されているため、 その位置を示す定数を指定することになります。

BOOL WINAPI CertEnumSystemStore(
  DWORD dwFlags, 
  void *pvSystemStoreLocationPara, 
  void *pvArg, 
  PFN_CERT_ENUM_SYSTEM_STORE pfnEnum 
);

dwFlagsは、システムストアが格納されている位置を表す定数を指定します。 pvSystemStoreLocationParaは、NULLを指定して構いません。 pvArgは、pfnEnumで示されるコールバック関数へ渡したいデータを指定します。 pfnEnumは、列挙されたシステムストアの情報を受け取るコールバック関数のアドレスです。 PFN_CERT_ENUM_SYSTEM_STORE型は、次のようなプロトタイプを持ちます。

BOOL WINAPI CertEnumSystemStoreCallback(
  const void *pvSystemStore, 
  DWORD dwFlags, 
  PCERT_SYSTEM_STORE_INFO pStoreInfo, 
  void *pvReserved, 
  void *pvArg 
);

pvSystemStoreは、システムストアの名前を指すアドレスです。 dwFlagsは、CertEnumSystemStoreの第1引数が格納されます。 pStoreInfoは、CERT_SYSTEM_STORE_INFO構造体へのアドレスです。 この構造体は、構造体のサイズを表すただ1つのメンバを持っています。 pvReservedは、NULLを指定します。 pvArgは、CertEnumSystemStoreの第3引数が格納されます。

今回のプログラムは、CertEnumSystemStoreでシステムストアを列挙しています。

#include <windows.h>

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

BOOL WINAPI CertEnumSystemStoreCallback(const void *pvSystemStore, DWORD dwFlags, PCERT_SYSTEM_STORE_INFO pStoreInfo, void *pvReserved, void *pvArg);
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	TCHAR      szAppName[] = TEXT("sample");
	HWND       hwnd;
	MSG        msg;
	WNDCLASSEX wc;

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = WindowProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hinst;
	wc.hIcon         = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	wc.hCursor       = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = szAppName;
	wc.hIconSm       = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	
	if (RegisterClassEx(&wc) == 0)
		return 0;

	hwnd = CreateWindowEx(0, szAppName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
	if (hwnd == NULL)
		return 0;

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);
	
	while (GetMessage(&msg, NULL, 0, 0) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return (int)msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static HWND hwndListBox = NULL;

	switch (uMsg) {

	case WM_CREATE:
		hwndListBox = CreateWindowEx(0, TEXT("LISTBOX"), NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL, 0, 0, 0, 0, hwnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
		CertEnumSystemStore(CERT_SYSTEM_STORE_CURRENT_USER, NULL, hwndListBox, CertEnumSystemStoreCallback);
		return 0;
	
	case WM_SIZE:
		MoveWindow(hwndListBox, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;

	default:
		break;

	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

BOOL WINAPI CertEnumSystemStoreCallback(const void *pvSystemStore, DWORD dwFlags, PCERT_SYSTEM_STORE_INFO pStoreInfo, void *pvReserved, void *pvArg)
{
	TCHAR szBuf[256];

	wsprintf(szBuf, TEXT("%s (%s)"), pvSystemStore, CryptFindLocalizedName(pvSystemStore));
	SendMessage((HWND)pvArg, LB_ADDSTRING, 0, (LPARAM)szBuf);

	return TRUE;
}

CERT_SYSTEM_STORE_CURRENT_USERのシステムストアを列挙するものとし、 CertEnumSystemStoreにこの定数を指定します。 リストボックスに文字列を追加する関係上、 コールバック関数の引数としてリストボックスのハンドルを指定します。 コールバック関数ではシステムストアの名前を表示するため、 pvSystemStoreを参照しています。 多くのシステムストアはローカライズされた名前を持っているため、 CryptFindLocalizedNameを呼び出せば、見慣れた名前を取得することができます。

CertEnumSystemStoreで得られたシステムストアの名前をレジストリキーで確認した場合、 いくつかのシステムストアはレジストリキーとして存在しないことが分かります。 そのようなシステムストアは、システムで内部的に存在するものかもしれませんし、 将来作成できる特別なシステムストアということを意味しているのかもしれません。 システムストアを作成する関数を呼び出すと必ずレジストリキーに反映されることから、 後者の予想が正しいかと思います。


戻る