// 電子証明書のKeyUsage 鍵用途を取り出す。
//
//		Crypt32.lib と Cryptui.lib のリンクが必要です。
//

#include "stdafx.h"
#include <Windows.h>
#include <WinCrypt.h>
#include <CryptuiAPI.h>

#define	CERT_SUBJ_STR	L"電子証明書の所有者名に変えてください"

int _tmain(int argc, _TCHAR* argv[])
{
	HCRYPTPROV	hProv;
	HCERTSTORE	hStore;

	//	CSPハンドルの取得
	if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, NULL))
	{
		if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET))
		{
			fprintf(stderr, "CryptAcquireContext error\n");
			return 1;
		}
	}

	//	証明書ストアーのオープン
	hStore = CertOpenSystemStore(
				hProv,
				"MY");
	if(!hStore)
	{
		fprintf(stderr, "CertOpenSystemStore error\n");
		return 2;
	}

	//	電子証明書の取り出し
	PCCERT_CONTEXT	pcCert;
	pcCert = CryptUIDlgSelectCertificateFromStore(
							hStore,
							NULL,
							NULL,
							NULL,
							0,
							0,
							NULL);
	if(!pcCert)
	{
		CertCloseStore(hStore, 0);
		CryptReleaseContext(hProv, 0);
		return 1;
	}

	//	鍵用途の取り出し
	BYTE	pbKeyUsage[2];
	DWORD	cbKeyUsage = 2;

	if(!CertGetIntendedKeyUsage(
					X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
					pcCert->pCertInfo,		//	証明書情報
					pbKeyUsage,				//	鍵用途領域
					cbKeyUsage))			//	鍵用途領域のサイズ
	{
		fprintf(stderr, "Error: CertGetIntendedKeyUsage\n");
	}
	else
	{
		if((pbKeyUsage[0] & CERT_DATA_ENCIPHERMENT_KEY_USAGE) == CERT_DATA_ENCIPHERMENT_KEY_USAGE)
			printf("データ暗号\n");
		else if((pbKeyUsage[0] & CERT_DIGITAL_SIGNATURE_KEY_USAGE) == CERT_DIGITAL_SIGNATURE_KEY_USAGE)
			printf("電子署名\n");
		else if((pbKeyUsage[0] & CERT_KEY_AGREEMENT_KEY_USAGE) == CERT_KEY_AGREEMENT_KEY_USAGE)
			printf("鍵交換\n");
		else if((pbKeyUsage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE) == CERT_KEY_CERT_SIGN_KEY_USAGE)
			printf("電子証明書の検証\n");
		else if((pbKeyUsage[0] & CERT_KEY_ENCIPHERMENT_KEY_USAGE) == CERT_KEY_ENCIPHERMENT_KEY_USAGE)
			printf("鍵暗号\n");
		else if((pbKeyUsage[0] & CERT_NON_REPUDIATION_KEY_USAGE) == CERT_NON_REPUDIATION_KEY_USAGE)
			printf("否認防止\n");
		else if((pbKeyUsage[0] & CERT_OFFLINE_CRL_SIGN_KEY_USAGE) == CERT_OFFLINE_CRL_SIGN_KEY_USAGE)
			printf("CRLの署名検証\n");
	}

	//	鍵用途の重要性を確認する
	PCERT_EXTENSION	pcExtention;
	pcExtention = CertFindExtension(
							"2.5.29.15",					//	KeyUsageのOID
							pcCert->pCertInfo->cExtension,	//	拡張情報の数(電子証明書内の)
							pcCert->pCertInfo->rgExtension);//	拡張情報の配列(電子証明書内の)
	if(!pcExtention)
	{
		fprintf(stderr, "Error: CertFindExtension\n");
	}
	else
	{
		printf("KeyUsage is %s\n", pcExtention->fCritical ? "Critical" : "Non-Critical");
	}

	//	後始末
	CertFreeCertificateContext(pcCert);
	CertCloseStore(hStore, 0);
	CryptReleaseContext(hProv, 0);

	return 0;
}