3.5 電子証明書の鍵用途の確認
電子証明書には、その鍵の利用方法が記載されています。
この項目は、必須項目ではありませんが多くの電子証明書にKeyUsage として記載されています。KeyUsageは、電子証明書が証明している鍵がどのような用途に使用されるかを指定しています。KeyUsageを重要(Critical)と指定された場合は、指定された用途以外で使用してはいけないことを示しています。
言い方を変えますと、重要(Critical)と指定されていなければ、この項目を確認する必要はありませんが、重要(Critical)と指定されていた場合は必ず確認しなければなりません。この「確認」は、電子証明書の利用者に義務付けられています。そのため多くの場合は、アプリケーションがその「確認機構」を実装しています。しかし、その機能を実装することは、必須ではありません。
ここでは、電子証明書の keyUsage の確認方法とその意味を説明します。
この項目は、必須項目ではありませんが多くの電子証明書にKeyUsage として記載されています。KeyUsageは、電子証明書が証明している鍵がどのような用途に使用されるかを指定しています。KeyUsageを重要(Critical)と指定された場合は、指定された用途以外で使用してはいけないことを示しています。
言い方を変えますと、重要(Critical)と指定されていなければ、この項目を確認する必要はありませんが、重要(Critical)と指定されていた場合は必ず確認しなければなりません。この「確認」は、電子証明書の利用者に義務付けられています。そのため多くの場合は、アプリケーションがその「確認機構」を実装しています。しかし、その機能を実装することは、必須ではありません。
ここでは、電子証明書の keyUsage の確認方法とその意味を説明します。
3.5.1 KeyUsage(鍵用途) の意味
KeyUsageは、9ビットのデータで表されます。そして、各ビットがその利用方法を示しています。以下に、ビット位置とその意味を記します。
ビット | 意味 |
---|---|
Digital Signature (0) | 電子署名 |
Non Repudiation (1) | 否認防止 |
Key Encipherment (2) | 鍵暗号 |
Data Encipherment (3) | データ暗号 |
Key Agreement (4) | 鍵交換 |
Key Cert Sign (5) | 電子証明書の検証 |
CRL Sign (6) | CRLの署名検証 |
Encipher Only (7) | 鍵交換時のデータ暗号用 |
Decipher Only (8) | 鍵交換時のデータ復号用 |
数字は、ビットの位置です。
3.5.2 KeyUsage(鍵用途) 情報の取り出し
// 鍵用途の取り出し BYTE pbKeyUsage[2]; DWORD cbKeyUsage = 2; if(!CertGetIntendedKeyUsage( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pcCert->pCertInfo, // 電子証明書情報 pbKeyUsage, // 鍵用途が格納される領域 cbKeyUsage)) // 鍵用途の領域のサイズ { fprintf(stderr, "Error: CertGetIntendedKeyUsage\n"); }まず鍵用途が格納される領域を用意します。鍵用途は9ビットのデータですから、1バイトもしくは、2バイトのデータです。
関数の第1引数には、エンコーディングタイプを指定します。
第2引数には、証明書情報を指定します。証明書の取り出しで取り出したPCCERT_CONTEXTのメンバーを指定します。この詳細は、次の項目で説明します。
第3引数には、鍵用途が格納される領域を指定します。
第4引数には、鍵用途の領域のサイズを指定します。現在は、最大でも2バイトですので、1または、2を指定します。
鍵用途のビットを検査するために以下の定数が用意されています。
- CERT_DATA_ENCIPHERMENT_KEY_USAGE
- CERT_DIGITAL_SIGNATURE_KEY_USAGE
- CERT_KEY_AGREEMENT_KEY_USAGE
- CERT_KEY_CERT_SIGN_KEY_USAGE
- CERT_KEY_ENCIPHERMENT_KEY_USAGE
- CERT_NON_REPUDIATION_KEY_USAGE
- CERT_OFFLINE_CRL_SIGN_KEY_USAGE
それぞれの意味は、上記の項目で説明した内容と同じです。
例えば、電子署名が可能か否かを確認するためには、以下のようなコードにします。
例えば、電子署名が可能か否かを確認するためには、以下のようなコードにします。
if((pbKeyUsage[0] & CERT_DIGITAL_SIGNATURE_KEY_USAGE) == CERT_DIGITAL_SIGNATURE_KEY_USAGE) printf("電子署名 可能\n"); else printf("電子署名 不可\n");
3.5.3 電子証明書コンテキスト
PCCERT_CONTEXTは、電子証明書データのポインターです。この構造体には、電子証明書データそのものが格納されています。この構造体は、以下のように定義されています。
dwCertEncodingType は、電子証明書のエンコーディングタイプです。今までに説明したものと同様です。
pbCertEncoded は、エンコードされた電子証明書のデータです。例えば、このデータをファイルに書き出せば、そのまま電子証明書ファイルになるデータです。
cbCertEncoded は、エンコードされた電子証明書のバイト長です。
pCertInfo は、CryptoAPIで利用できるようにデコードされた電子証明書のデータが入っています。ここで説明しています関数のように、電子証明書の内容をみるためには、このデータを使います。
hCertStore は、電子証明書が格納されている証明書ストアのハンドルです。
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 は、電子証明書のエンコーディングタイプです。今までに説明したものと同様です。
pbCertEncoded は、エンコードされた電子証明書のデータです。例えば、このデータをファイルに書き出せば、そのまま電子証明書ファイルになるデータです。
cbCertEncoded は、エンコードされた電子証明書のバイト長です。
pCertInfo は、CryptoAPIで利用できるようにデコードされた電子証明書のデータが入っています。ここで説明しています関数のように、電子証明書の内容をみるためには、このデータを使います。
hCertStore は、電子証明書が格納されている証明書ストアのハンドルです。
3.5.4 鍵用途の重要性を確認する
先に説明しましたように、鍵用途が重要(Critical)と指定されていた場合は、鍵の用途を確認しそれ以外の用途で使わないようにしなければなりません。この確認は、必ずしもアプリケーションが行わなければならないものではありませんが、アプリケーションで確認することがユーザーフレンドリーです。
ここから少し詳しく説明しなければなりませんが、鍵用途(KeyUsage)は電子証明書の拡張フィールドに記載されています。その拡張フィールドには、鍵用途以外の情報も記載されています。それらの情報は、OIDという識別子がつけられて記載されていますので、KeyUsageというOID(別に説明を予定していますが"2.5.29.15"という値です)で記載されており、その中にCriticalか否かのフラグと鍵情報データがあります。
CryptoAPIでその値を取り出すためには、以下の関数を使います。
関数の第1引数に、KeyUsageのOIDを指定します。szOID_KEY_USAGEと指定することもできます。
第2引数には、電子証明書の拡張フィールドの数を与えます。これは、証明書情報(pCertInfo)のメンバーです。
第3引数には、拡張情報の配列を与えます。この情報も証明書情報(pCertInfo)のメンバーです。
関数の返値が求める拡張情報です。このメンバーに、fCriticalがありこの値がTRUEであれば指定された鍵用途どおりに使用しなければなりませんが、FALSEであれば、鍵用途を無視してもかまいません。
ここから少し詳しく説明しなければなりませんが、鍵用途(KeyUsage)は電子証明書の拡張フィールドに記載されています。その拡張フィールドには、鍵用途以外の情報も記載されています。それらの情報は、OIDという識別子がつけられて記載されていますので、KeyUsageというOID(別に説明を予定していますが"2.5.29.15"という値です)で記載されており、その中にCriticalか否かのフラグと鍵情報データがあります。
CryptoAPIでその値を取り出すためには、以下の関数を使います。
// 鍵用途の重要性を確認する 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"); }まず、目的の拡張フィールドのポインター受け取れるようにします。
関数の第1引数に、KeyUsageのOIDを指定します。szOID_KEY_USAGEと指定することもできます。
第2引数には、電子証明書の拡張フィールドの数を与えます。これは、証明書情報(pCertInfo)のメンバーです。
第3引数には、拡張情報の配列を与えます。この情報も証明書情報(pCertInfo)のメンバーです。
関数の返値が求める拡張情報です。このメンバーに、fCriticalがありこの値がTRUEであれば指定された鍵用途どおりに使用しなければなりませんが、FALSEであれば、鍵用途を無視してもかまいません。
3.5.5 サンプル
上記のサンプルコードです。
サンプルコードの商業利用および転載を禁止します。
サンプルコードの商業利用および転載を禁止します。
3.5.6 ご質問・ご要望
ご質問やご要望は、こちらからお送りください。(匿名でも可能です。)