5.1 電子証明書とCryptoAPI
電子証明書の形式は前項で説明いたしました。本稿では、電子証明書に記載されている項目をCrypto APIを使って読み出す方法を説明します。
5.1.1 電子証明書の準備
電子証明書は、あらかじめコンピュータにインストールしておき、利用できるようにしておいてください。その上で、記載項目を読み出す電子証明書のポインターを取得します。
まず、CSPを指定します。
まず、CSPを指定します。
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; } } // 電子証明書の取り出し PCCERT_CONTEXT pcCert; pcCert = CryptUIDlgSelectCertificateFromStore( hStore, NULL, NULL, NULL, 0, 0, NULL); if(!pcCert) { CertCloseStore(hStore, 0); CryptReleaseContext(hProv, 0); return 1; }
以降は、取得した電子証明書のポインター(PCCERT_CONTEXT pcCert)を使って電子証明書の内容を確認します。
参考:
Window98以前で、GUIを使って電子証明書を選択する場合は、Windows98で利用可能なダイアログ を参照してください。
Window98以前で、GUIを使って電子証明書を選択する場合は、Windows98で利用可能なダイアログ を参照してください。
5.1.2 電子証明書のポインター
電子証明書のポインターは、以下のように宣言されています。
typedef struct _CERT_CONTEXT { DWORD dwCertEncodingType; BYTE *pbCertEncoded; DWORD cbCertEncoded; PCERT_INFO pCertInfo; HCERTSTORE hCertStore; } CERT_CONTEXT, *PCERT_CONTEXT; typedef const CERT_CONTEXT *PCCERT_CONTEXT;
順に説明します。
dwCertEncodingTypeは、電子証明書のエンコード形式です。X509_ASN_ENCODING や PKCS_7_ASN_ENCODINGです。
pbCertEncodedは、エンコードされた電子証明書のデータへのポインターです。".cer"といった拡張子が付いて格納された電子証明書と同じデータです。したがって、このデータをファイルに書き出して、".cer"の拡張子をつけますと、電子証明書として扱うことができるようになります。
cbCertEncodedは、エンコードされた電子証明書データnバイトサイズです。
pCertInfoは、デコードされた電子証明書情報です。ここには、電子証明書に記載されたすべての情報が含まれています。
hCertStoreは、電子証明書が格納されている証明書ストアのハンドルです。
dwCertEncodingTypeは、電子証明書のエンコード形式です。X509_ASN_ENCODING や PKCS_7_ASN_ENCODINGです。
pbCertEncodedは、エンコードされた電子証明書のデータへのポインターです。".cer"といった拡張子が付いて格納された電子証明書と同じデータです。したがって、このデータをファイルに書き出して、".cer"の拡張子をつけますと、電子証明書として扱うことができるようになります。
cbCertEncodedは、エンコードされた電子証明書データnバイトサイズです。
pCertInfoは、デコードされた電子証明書情報です。ここには、電子証明書に記載されたすべての情報が含まれています。
hCertStoreは、電子証明書が格納されている証明書ストアのハンドルです。
5.1.3 証明書情報
証明書情報に格納された項目を確認します。PCERT_INFOは、以下のように宣言されています。
typedef struct _CERT_INFO { DWORD dwVersion; CRYPT_INTEGER_BLOB SerialNumber; CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm; CERT_NAME_BLOB Issuer; FILETIME NotBefore; FILETIME NotAfter; CERT_NAME_BLOB Subject; CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo; CRYPT_BIT_BLOB IssuerUniqueId; CRYPT_BIT_BLOB SubjectUniqueId; DWORD cExtension; PCERT_EXTENSION rgExtension; } CERT_INFO, *PCERT_INFO;
順に説明します。
dwVersionは、バージョンです。
SerialNumberは、シリアル番号です。
SignatureAlgorithmは、署名アルゴリズム情報です。
Issuerは、この電子証明書の発行者名です。
NotBeforeは、利用開始日時です。
NotAfterは、利用が終了する日時です。
Subjectは、この電子証明書の所有者名です。
SubjectPublicKeyInfoは、電子証明書が証明している公開鍵の情報です。
IssuerUniqueIdは、発行者のユニークIDです。
SubjectUniqueIdは、所有者のユニークIDです。
cExtensionは、この電子証明書に含まれる拡張情報の数量です。
rgExtensionは、拡張情報のポインターです。cExtensionで示された数だけ存在します。
dwVersionは、バージョンです。
SerialNumberは、シリアル番号です。
SignatureAlgorithmは、署名アルゴリズム情報です。
Issuerは、この電子証明書の発行者名です。
NotBeforeは、利用開始日時です。
NotAfterは、利用が終了する日時です。
Subjectは、この電子証明書の所有者名です。
SubjectPublicKeyInfoは、電子証明書が証明している公開鍵の情報です。
IssuerUniqueIdは、発行者のユニークIDです。
SubjectUniqueIdは、所有者のユニークIDです。
cExtensionは、この電子証明書に含まれる拡張情報の数量です。
rgExtensionは、拡張情報のポインターです。cExtensionで示された数だけ存在します。
5.1.4 バージョンの表示
電子証明書のバージョンを取り出します。バージョン番号は、DWORD型ですので、容易に確認できます。
// 表示 printf("バージョン = %d\n", pcCert->pCertInfo->dwVersion);結果は、
バージョン = 2となり、選択した電子証明書のバージョンが"3"であることがわかります。
5.1.5 シリアル番号の表示
シリアル番号は、バイナリーデータですので、CryptBinaryToString関数を使ってそれを表示させます。
char pstr[1000]; DWORD cstr = 1000; CryptBinaryToString(pcCert->pCertInfo->SerialNumber.pbData, pcCert->pCertInfo->SerialNumber.cbData, CRYPT_STRING_HEXASCIIADDR, pstr, &cstr); printf("Data =\n%s\n", pstr);結果(例)は、
Data = 0000 69 00 00 00 00 00 d7 34 04 61 i......4.aとなります。
5.1.6 署名アルゴリズムの表示
署名アルゴリズムは、以下のように宣言されています。
署名アルゴリズムは、sha-1WithRSAであることがわかります。
parameterは、ASN.1をBERエンコードしたデータで、05 00 ですのでNULLであることがわかります。
typedef struct _CRYPT_ALGORITHM_IDENTIFIER { LPSTR pszObjId; CRYPT_OBJID_BLOB Parameters; } CRYPT_ALGORITHM_IDENTIFIER, *PCRYPT_ALGORITHM_IDENTIFIER;OIDは、ASCII文字列ですが、parameterは、それぞれのOIDによってさまざまなデータがセットされます。
printf("アルゴリズム OID = %s\n", pcCert->pCertInfo->SignatureAlgorithm.pszObjId); CryptBinaryToString( pcCert->pCertInfo->SignatureAlgorithm.Parameters.pbData, pcCert->pCertInfo->SignatureAlgorithm.Parameters.cbData, CRYPT_STRING_HEXASCIIADDR, pstr, &cstr); printf("Data =\n%s\n", pstr);結果(例)は、
アルゴリズム OID = 1.2.840.113549.1.1.5 Data = 0000 05 00 ..このことから、
署名アルゴリズムは、sha-1WithRSAであることがわかります。
parameterは、ASN.1をBERエンコードしたデータで、05 00 ですのでNULLであることがわかります。
5.1.7 発行者名
発行者のデータをバイナリーで表示します。
CryptBinaryToString(pcCert->pCertInfo->Issuer.pbData, pcCert->pCertInfo->Issuer.cbData, CRYPT_STRING_HEXASCIIADDR, pstr, &cstr); printf("Data =\n%s\n", pstr);結果(例)は、
Data = 0000 30 47 31 12 30 10 06 0a 09 92 26 89 93 f2 2c 64 0G1.0.....&...,d 0010 01 19 16 02 6a 70 31 17 30 15 06 0a 09 92 26 89 ....jp1.0.....&. 0020 93 f2 2c 64 01 19 16 07 54 72 75 73 74 53 53 31 ..,d....TrustSS1 0030 18 30 16 06 03 55 04 03 13 0f 54 72 75 73 74 53 .0...U....TrustS 0040 6f 66 74 53 79 73 43 41 38 oftSysCA8となります。 このデータは、ASN.1をBERエンコードしたデータです。デコードすれば、内容はわかりますが、Crypto APIには、それをデコードする関数があります。それを使ってデコードします。
CertNameToStr(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &pcCert->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, pstr, cstr); printf("Name =\n%s\n", pstr);結果(例)は、
Name = jp, TrustSS, TrustSoftSysCA8となります。
5.1.8 有効期間
有効期間は、グリニッジ時刻で格納されていますので、日本時間への変換が必要です。
COleDateTime notBefore(pcCert->pCertInfo->NotBefore); COleDateTime notAfter(pcCert->pCertInfo->NotAfter); notBefore += COleDateTimeSpan(0, 9, 0, 0); // 日本時間への変換 notAfter += COleDateTimeSpan(0, 9, 0, 0); // 日本時間への変換 printf("有効期限の開始: %s\n", (LPCTSTR)notBefore.Format("%Y/%m/%d %H:%M:%S")); printf("有効期限の終了: %s\n", (LPCTSTR)notAfter.Format("%Y/%m/%d %H:%M:%S"));結果(例)は、
有効期限の開始: 2005/07/05 08:52:56 有効期限の終了: 2006/01/01 08:52:56となります。
5.1.9 サブジェクト
サブジェクト(所有者)は、発行者と同じ手順で確認できます。
CryptBinaryToString(pcCert->pCertInfo->Subject.pbData, pcCert->pCertInfo->Subject.cbData, CRYPT_STRING_HEXASCIIADDR, pstr, &cstr); printf("Data =\n%s\n", pstr); cstr = 1000; CertNameToStr(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &pcCert->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, pstr, cstr); printf("Name =\n%s\n", pstr);結果(例)は、
Name = jp, TrustSS, CertUsers, 821, LastName FirstNameとなります。
5.1.10 公開鍵情報
公開鍵は、ビット列です。
なお、上記のOIDは「RSA」をあらわします。
CryptBinaryToString( pcCert->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData, pcCert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData, CRYPT_STRING_HEXASCIIADDR, pstr, &cstr); printf("Data =\n%s\n", pstr); printf("アルゴリズム:%s\n", pcCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId); printf("サイズ = %d, 未使用ビット = %d\n", pcCert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData, pcCert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cUnusedBits);結果(例)は、
Data = 0000 30 81 89 02 81 81 00 d6 09 cc c8 cd 71 52 8c fb 0...........qR.. 0010 5f 6d a4 08 07 d2 77 0d c3 5e 22 41 d7 97 2b fe _m....w..^"A..+. 0020 5e 9d 3c 07 83 c2 33 5e b2 5d 75 0b 6c a3 ee 7e ^.<...3^.]u.l..~ 0030 56 87 80 af 4d be 66 0d b8 9d 24 66 f6 12 d6 b9 V...M.f...$f.... 0040 8c 7d 51 c2 7f ae b2 77 39 83 1a e2 f1 99 ae 57 .}Q....w9......W 0050 9a 29 da 29 f8 8e cd 92 f2 e2 65 95 5f 46 d2 2d .).)......e._F.- 0060 74 4b f3 97 5a 6c e8 56 8b 7a 54 be 6b 1f 39 87 tK..Zl.V.zT.k.9. 0070 b9 3b 7a 20 5a 69 35 d8 e4 66 1e 94 2e b0 dc 4d .;z Zi5..f.....M 0080 b5 22 96 bc 37 bd 75 02 03 01 00 01 ."..7.u..... アルゴリズム:1.2.840.113549.1.1.1 サイズ = 140, 未使用ビット = 0となります。
なお、上記のOIDは「RSA」をあらわします。
5.1.11 拡張情報
電子証明書の拡張情報は、いろいろなものがありますので、5.2 拡張情報とCryptoAPI で説明します。ここでは、電子証明書に含まれる拡張情報の数を確認します。
このことから、拡張情報は、10個含まれてることがわかります。
printf("Num = %d\n", pcCert->pCertInfo->cExtension);結果(例)は、
Num = 10となります。
このことから、拡張情報は、10個含まれてることがわかります。
5.1.12 サンプル
電子証明書から、情報を取り出すためのサンプルです。
WindowXP、WindowsVistaもしくは、Windows2003サーバーでのみ動作します。
ライブラリ Cryptui.lib を追加してください。
サンプルの商業利用および転載は禁止します。
WindowXP、WindowsVistaもしくは、Windows2003サーバーでのみ動作します。
ライブラリ Cryptui.lib を追加してください。
サンプルの商業利用および転載は禁止します。
5.1.13 ご質問・ご要望
ご質問やご要望は、こちらからお送りください。(匿名でも可能です。)
(記載の会社名および製品名は、各社の登録商標および商標です。)