EternalWindows
証明書管理 / 証明書リンク

証明書ストアという存在は、証明書をCAやRootというような種類分けができるという点で 重要な役割を持っていますが、それ故に時として柔軟性に欠ける場合があります。 たとえば、MY、CA、Rootの各証明書ストアから証明書を1つずつ取得するアプリケーションの場合、 証明書ストアを3回オープンしなければならず、煩わしく思えます。 このような仕様を緩和する1つの方法は、独自の証明書ストアを作成し、 そこに必要となる証明書を予め追加しておくことです。 このようにすれば、その証明書ストアをオープンするだけで必要な証明書を取得することができます。

上記のような方法を用いる場合、独自の証明書ストアに追加する証明書は、 証明書リンクであることが望まれます。 証明書リンクというのは、いわば証明書へのポインタであり、 そのリンク先の証明書が変更された場合は、リンク元の証明書も変更されているように見えることになります。 このような仕組みが必要なのは、ユーザーから見える証明書というものが、 既存証明書ストアに格納されている証明書であるからであり、 変更を加えるとしたら、既存証明書ストアの証明書に限られるのが一般的だからです。 証明書ストアに証明書リンクを追加する場合は、CertAddCertificateLinkToStoreを呼び出します。

BOOL WINAPI CertAddCertificateLinkToStore(
  HCERTSTORE hCertStore, 
  PCCERT_CONTEXT pCertContext, 
  DWORD dwAddDisposition, 
  PCCERT_CONTEXT *ppStoreContext 
); 

hCertStoreは、証明書ストアのハンドルを指定します。 pCertContextは、リンク先とする証明書コンテキストを指定します。 この証明書へのリンクとなる証明書リンクが、証明書ストアに格納されます。 dwAddDispositionは、証明書リンクが既に存在する場合の処理を表す定数を指定します。 ppStoreContextは、実際に証明書ストアに作成された証明書リンクを受け取る変数を指定します。 不要である場合は、NULLを指定することができます。

今回のプログラムは、独自に作成した証明書ストアに証明書リンクを追加して保存するコードと、 追加された証明書リンクの情報を表示するコードで構成されています。

#include <windows.h>

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

void SaveStore(LPTSTR lpszStoreName);
void LoadStore(LPTSTR lpszStoreName);

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	TCHAR szStoreName[] = TEXT("sample.sto");
	BOOL  bSaveStore = TRUE;

	if (bSaveStore)
		SaveStore(szStoreName);
	else
		LoadStore(szStoreName);

	return 0;
}

void SaveStore(LPTSTR lpszStoreName)
{
	HCERTSTORE     hMemoryStore;
	HCERTSTORE     hStore;
	PCCERT_CONTEXT pContext;
	HANDLE         hFile;
	
	hMemoryStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 0, NULL);

	hStore = CertOpenSystemStore(0, TEXT("CA"));
	pContext = CertEnumCertificatesInStore(hStore, NULL);
	CertAddCertificateLinkToStore(hMemoryStore, pContext, CERT_STORE_ADD_USE_EXISTING, NULL);
	CertFreeCertificateContext(pContext);
	CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);

	hStore = CertOpenSystemStore(0, TEXT("Root"));
	pContext = CertEnumCertificatesInStore(hStore, NULL);
	CertAddCertificateLinkToStore(hMemoryStore, pContext, CERT_STORE_ADD_USE_EXISTING, NULL);
	CertFreeCertificateContext(pContext);
	CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);

	hFile = CreateFile(lpszStoreName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	
	CertSaveStore(hMemoryStore, 0, CERT_STORE_SAVE_AS_STORE, CERT_STORE_SAVE_TO_FILE, hFile, 0);
	CertCloseStore(hMemoryStore, CERT_CLOSE_STORE_CHECK_FLAG);
	CloseHandle(hFile);

	MessageBox(NULL, TEXT("証明書ストアを保存しました。"), TEXT("OK"), MB_OK);
}

void LoadStore(LPTSTR lpszStoreName)
{
	HCERTSTORE     hStore;
	PCCERT_CONTEXT pContext = NULL;
	HANDLE         hFile;
	TCHAR          szBuf[256];
	
	hFile = CreateFile(lpszStoreName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
		return;
	
	hStore = CertOpenStore(CERT_STORE_PROV_FILE, 0, NULL, CERT_STORE_OPEN_EXISTING_FLAG, hFile);
	if (hStore == NULL) {
		CloseHandle(hFile);
		return;
	}

	for (;;) {
		pContext = CertEnumCertificatesInStore(hStore, pContext);
		if (pContext == NULL)
			break;

		CertGetNameString(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, szBuf, sizeof(szBuf));
		
		MessageBox(NULL, szBuf, TEXT("OK"), MB_OK);
	}

	CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
	CloseHandle(hFile);
}

SaveStoreは、独自の証明書をCertOpenStoreを呼び出して作成しています。 この関数にCERT_STORE_PROV_MEMORYを指定した場合、 メモリ上に証明書ストアが作成され、それに対して証明書を追加することができます。 既存証明書ストアはそれぞれCAとRootし、 各証明書ストア内で最初に見つかった証明書を メモリ上の証明書ストアに追加するようにしています。 この追加にCertAddCertificateLinkToStoreを使用していることから、 実際に追加されるのは既存証明書に対しての証明書リンクであり、 既存証明書の変更を常に反映した情報を持つことができます。 最後に、SaveStoreはメモリ上に作成した証明書ストアをファイルとして保存します。

LoadStoreでは、保存された証明書ストアをオープンし、 そこに格納されている証明書を列挙します。 SaveStoreでの処理の通り、ここにはCAとRootの証明書が含まれており、 本来別けられていた証明書を1つの証明書ストアに格納したことに等しいでしょう。 この証明書ストアは独自のものであるため、IEのインターネットオプションから表示できる ダイアログでは確認することができませんが、 CryptUIDlgSelectCertificateFromStoreを呼び出せばGUIで表示することができます。

コレクションストアについて

別の証明書ストアに格納されている証明書を1つの証明書ストアから参照したいような場合、 今回取り上げた方法以外に、コレクションストアを利用する方法もあります。 コレクションストアとは、いわば複数の証明書ストアを格納する証明書ストアのことで、 コレクションストアに含まれる証明書の数は、 コレクションストアに追加されている証明書ストアの証明書の数に比例します。 たとえば、次のようにCAとRootの証明書ストアをhCollectionStoreに 追加した場合、hCollectionStoreにはCAとRootの証明書が格納されているように見えることになります。

HCERTSTORE CreateCollectionStore(void)
{
	HCERTSTORE hCollectionStore;
	HCERTSTORE hStore;
	
	hCollectionStore = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, 0, NULL);

	hStore = CertOpenSystemStore(0, TEXT("CA"));
	CertAddStoreToCollection(hCollectionStore, hStore, 0, 0);
	CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);

	hStore = CertOpenSystemStore(0, TEXT("Root"));
	CertAddStoreToCollection(hCollectionStore, hStore, 0, 1);
	CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
	
	return hCollectionStore;
}

コレクションストアを作成するには、CertOpenStoreにCERT_STORE_PROV_COLLECTIONを指定します。 CertAddStoreToCollectionは、コレクションストアに証明書ストアを追加する関数で、 第3引数はコレクションストアに対しての証明書の追加を、 コレクションストアに含まれる証明書ストアに対して反映させるかどうかです。 0を指定した場合は反映されませんが、CERT_PHYSICAL_STORE_ADD_ENABLE_FLAGを指定した場合は反映されます。 第4引数は、追加した証明書ストアの優先順位を指定し、0が最も低い優先順位を表します。 証明書ストアの優先順位は、コレクションストアに対しての証明書の検索が どの証明書ストアから対象となるのかを判断する基準となります。 コレクションストアから証明書ストアを取り除く場合は、CertRemoveStoreFromCollectionを呼び出します。



戻る