4.1 電子証明書のデータ形式
電子証明書の形式は、インターネット標準 RFC3280 (X.509 Public Key Infrastructure Certificate and CRL Profile) によって規定されています。CryptoAPI は、この形式のデータを取り扱うようになっています。CryptoAPIを使って電子証明書を扱う場合は、この形式を正しく理解している必要があります。
4.1.1 電子証明書の概要
電子証明書は、1988年に最初のバージョンが定義され、1997年に現在のバージョン3(v3)が定義されました。このバージョン3がRFC3280によって、X.509 Public Key Infrastructure Certificate and CRL Profile(X.509 公開鍵基盤 証明書およびCRLプロファイル)として規定されています。
この電子証明書は、以下に示すフィールドで構成されています。
この電子証明書は、以下に示すフィールドで構成されています。
| バージョン |
| シリアル番号 |
| 署名アルゴリズム |
| 証明書発行者 |
| 有効期間 |
| 所有者名 |
| 公開鍵 |
| 拡張情報 |
以下では、これらのフィールドを説明します。
4.1.2 フォーマットの表記 (ASN.1)
フォーマットは、ASN.1(Abstract Syntax Notation One)という抽象構文記法によって定義されています。このASN.1という記法は、電子証明書ばかりではなく、署名データ、暗号化データ、さらに、SNMPやLDAPといったプロトコルの記述などにも用いられています。
対象となるデータは、ASN.1で表記されたものをBER(Basic Encoding Roule)という規則をつかってバイナリーのデータに変換しています。また、BERは、1オクテット(1バイト)を最小単位として扱います。
ASN.1は、情報の構造を定義するために、その構造を情報の名前と型という属性を使って定義します。ASN.1は、言語ですので、テキストで以下のように表記されます。
詳細については、フォーマットの説明の中で説明します。
対象となるデータは、ASN.1で表記されたものをBER(Basic Encoding Roule)という規則をつかってバイナリーのデータに変換しています。また、BERは、1オクテット(1バイト)を最小単位として扱います。
ASN.1は、情報の構造を定義するために、その構造を情報の名前と型という属性を使って定義します。ASN.1は、言語ですので、テキストで以下のように表記されます。
情報の名前 ::= 情報の型(の組み合わせ)や
情報の名前 ::= 定義済みの情報の名前(の組み合わせ)といった方法で記述します。定義は、プリミティブな型で表記されるまで繰り返されます。
詳細については、フォーマットの説明の中で説明します。
4.1.3 電子証明書
電子証明書は、RFC3280で以下のように定義されています。
Windowsで電子証明書の詳細を確認する。[https://www.trustss.co.jp/smnEncrypt112_.html]
Windowsで電子証明書の詳細を確認する。[https://www.trustss.co.jp/smnEncrypt112_.html]
Certificate ::= SEQUENCE {
tbsCertificate TBSCertificate,
signatureAlgorithm AlgorithmIdentifier,
signatureValue BIT STRING }
これは、電子証明書(Certificate)が、署名されるべき電子証明書情報(tbsCertificate)と、署名アルゴリズム(signatureAlgorithm)と、署名値(signatureValue)で構成されていることを表しています。ただし、それらがSEQUENCEでまとめられていますので、上記のものが表記された順番で現れることを示しています。
tbsCertificateは、TBSCertificateという型の情報の名前です。具体的には、後に説明しますが、その名前から、署名される(TBS;To Be Signed)証明書(Certificate)と連想できます。TBSCertificateという型は、更に別の名前や型の組み合わせで定義されています。
signatureAlgorithmは、CA(Certification Authority;証明書発行機関)が署名する際に用いられる書名アルゴリズムが記されています。以下のように定義されています。
tbsCertificateは、TBSCertificateという型の情報の名前です。具体的には、後に説明しますが、その名前から、署名される(TBS;To Be Signed)証明書(Certificate)と連想できます。TBSCertificateという型は、更に別の名前や型の組み合わせで定義されています。
signatureAlgorithmは、CA(Certification Authority;証明書発行機関)が署名する際に用いられる書名アルゴリズムが記されています。以下のように定義されています。
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL }
algorithmは、具体的なアルゴリズムを示す識別子です。parametersは、そのアルゴリズム固有のパラメータです。
アルゴリズムを表す識別子は、国際機関により一意に割り当てられている値です。例えば、MD5withRSAのアルゴリズムは、
アルゴリズムを表す識別子は、国際機関により一意に割り当てられている値です。例えば、MD5withRSAのアルゴリズムは、
md5withRSAEncryption OBJECT IDENTIFIER ::= {
iso(1) member-bidy(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1) 4}
となり、parametersはNULLになります。上記の識別子は、オブジェクト識別子といい、OIDと略記されます。また、上記のOIDは、"1.2.840.113549.1.1.4"などと記述されます。CryptoAPIは、この記述方法でOIDを指定します。
4.1.4 CryptoAPIとの関係
WindowsのCryptAPIでは、電子証明書をCERT_CONTEXTという構造体に格納しています。その定義は、以下の通りです。
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;
この中のpbCertEncodedがBERエンコードされた証明書(Certificate)です。このデータをバイトごとにデコードすると、ASN.1の実体データになります。
ASN.1記載された構造は、あくまで定義ですので実際の値を持ちません。値を持たせるのが、アプリケーションの仕事であり、その手伝いをしてくれるのが、CryptoAPIです。CryptoAPIが取り扱っているのは、ASN.1定義された構造ではなく、それによって実体(インスタンス)化されたデータです。
ちなみに、pCertInfoは、をpbCertEncodedにあるデータを解析した結果が格納されています。このデータは、CryptoAPI固有のデータ形式です。しかし、部分的には、DERエンコードされたデータがそのまま格納されています。従いまして、CryptoAPIを使って電子証明書を取り扱う場合でも、場合によっては、電子証明書のデータフォーマットの知識が必要です。
ASN.1記載された構造は、あくまで定義ですので実際の値を持ちません。値を持たせるのが、アプリケーションの仕事であり、その手伝いをしてくれるのが、CryptoAPIです。CryptoAPIが取り扱っているのは、ASN.1定義された構造ではなく、それによって実体(インスタンス)化されたデータです。
ちなみに、pCertInfoは、をpbCertEncodedにあるデータを解析した結果が格納されています。このデータは、CryptoAPI固有のデータ形式です。しかし、部分的には、DERエンコードされたデータがそのまま格納されています。従いまして、CryptoAPIを使って電子証明書を取り扱う場合でも、場合によっては、電子証明書のデータフォーマットの知識が必要です。
4.1.5 証明書情報
ここでは、TBSCertificate について説明します。以下のように定義されています。
TBSCertificate ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
serialNumber CertificateSerialNumber,
signature AlgorithmIdentifier,
issuer Name,
validity Validity,
subject Name,
subjectPublicKeyInfo SubjectPublicKeyInfo,
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version MUST be v2 or v3
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version MUST be v2 or v3
extensions [3] EXPLICIT Extensions OPTIONAL
-- If present, version MUST be v3
}
順に説明します。
version は、証明書のバージョンを示します。以下のように定義されています。
バージョン番号の取り出し方
serialNumber は、電子証明書のシリアル番号を示します。この番号は、同一のCAで発行された電子証明書で一意にしなければなりません。そのため、発行者の名前とシリアル番号を組み合わせると唯一の証明書を識別できます。
唯一の証明書を識別するために、シリアル番号は大きな桁数になることが予想されますが、規定では、20オクテットまでの値となっており、アプリケーションはこの桁数の値が扱えなければなりません。また、シリアル番号は、正の整数でなければなりませんが、CAは負か0(ゼロ)のシリアル番号を持った証明書を発行するかもしれませんので、アプリケーション(証明書ユーザー)は、そのような証明書を支障なく取り扱えるように準備すべきであることも規定に注記されています。
シリアル番号の取り出し方
signatureは、証明書にCAが署名するために使用する署名アルゴリズムを示します。この値は、4.1.3で説明しましたsignatureAlgorithmフィールドと同じアルゴリズムを含まなければなりません。
署名アルゴリズムの取り出し方
issuerは、証明書を発行したCAの名前です。このフィールドには、空でないDN(Distinguished Name)が含まれていなければなりません。詳細は、Nameデータ型で説明します。
発行者情報の取り出し方
validityは、証明書の有効期間を示しています。有効期間とは、CAがその証明書の状態に関する情報を維持することを保証する時間的間隔です。
このフィールドは、以下のように定義され、有効期間が始まる日付( notBefore)と、有効期間が終わる日付(notAfter)で構成されています。
また、Time型は以下のように定義されています。
有効期限の取り出し方
subjectは、公開鍵フィールド(後述)に保管される公開鍵に関連付けられるエンティティを識別します。このエンティティは、所有者と考えると理解しやすいと思います。
エンティティは、空でないDNでなければなりません。Nameデータ型です。
サブジェクトの名前は、拡張フィールド(後述)のsubjectAltNameで示されるかもしれません。
同一のCAは、エンティティごとにユニークなサブジェクトを持った証明書を発行しなければなりません。しか、CAは、同一のエンティティに同一のDNを持った証明書を1枚以上発行してもかまいません。
サブジェクトの取り出し方
subjectPublicKeyInfoは、公開鍵の情報です。暗号化のアルゴリズムと公開鍵のビット列で構成され、以下のように定義されています。
RSAキーの場合は、以下のように規定されています。
OIDは、
公開鍵情報の取り出し方
issuerUniqueIDおよびsubjectUniqueIDは、同じ発行者名や所有者名を区別するために使用します。規定では、同じ名前を別のエンティティ(発行者や所有者それぞれ)に使用すべきではないとされています。しかしながら、アプリケーションは、その区別ができるようにすべきでしょう。
なお、これら名フィールドは、バージョンが2または、3の場合にのみ現れ、バージョン1の場合名は現れてはなりません。
UniqueIdentifierは、BIT Stringとして、以下のとおりに定義されています。
拡張フィールド数の取り出し方、5.2拡張情報とCryptoAPI[https://www.trustss.co.jp/smnDataFormat520.html]
version は、証明書のバージョンを示します。以下のように定義されています。
Version ::= INTEGER { v1(0), v2(1), v3(2) }
INTEGERが指定されていますので、整数値ですが、具体的な値(バージョン1の場合に値0、バージン2では値1、バージョン3で値2)が指定されていますので、これ以外の値をとることはありません。BERにエンコードされた場合は、1オクテット(1バイト)のデータになります。BERエンコードされるときには、「冗長なオクテットを含めない」というルールによってversionが1バイト長を超えた大きさになることはありません。バージョン番号の取り出し方
serialNumber は、電子証明書のシリアル番号を示します。この番号は、同一のCAで発行された電子証明書で一意にしなければなりません。そのため、発行者の名前とシリアル番号を組み合わせると唯一の証明書を識別できます。
唯一の証明書を識別するために、シリアル番号は大きな桁数になることが予想されますが、規定では、20オクテットまでの値となっており、アプリケーションはこの桁数の値が扱えなければなりません。また、シリアル番号は、正の整数でなければなりませんが、CAは負か0(ゼロ)のシリアル番号を持った証明書を発行するかもしれませんので、アプリケーション(証明書ユーザー)は、そのような証明書を支障なく取り扱えるように準備すべきであることも規定に注記されています。
シリアル番号の取り出し方
signatureは、証明書にCAが署名するために使用する署名アルゴリズムを示します。この値は、4.1.3で説明しましたsignatureAlgorithmフィールドと同じアルゴリズムを含まなければなりません。
署名アルゴリズムの取り出し方
issuerは、証明書を発行したCAの名前です。このフィールドには、空でないDN(Distinguished Name)が含まれていなければなりません。詳細は、Nameデータ型で説明します。
発行者情報の取り出し方
validityは、証明書の有効期間を示しています。有効期間とは、CAがその証明書の状態に関する情報を維持することを保証する時間的間隔です。
このフィールドは、以下のように定義され、有効期間が始まる日付( notBefore)と、有効期間が終わる日付(notAfter)で構成されています。
Validity ::= SEQUENCE {
notBefore Time,
notAfter Time }
有効期間は、notBeforeからnotAfterまでの機関でその両端を含みます。また、Time型は以下のように定義されています。
Time ::= CHOICE {
utcTime UTCTime,
generalTime GeneralizedTime }
日付は、utcTimeもしくは、generalTimeを選択(CHOICE)します。RFC3280に準拠した証明書は、西暦2049年まではこの日付をUTCTimeとしてエンコードしなければなりません。また、西暦2050年もしくはそれ以降の日付をGeneralizedTimeとしてエンコードしなければならないとされています。有効期限の取り出し方
subjectは、公開鍵フィールド(後述)に保管される公開鍵に関連付けられるエンティティを識別します。このエンティティは、所有者と考えると理解しやすいと思います。
エンティティは、空でないDNでなければなりません。Nameデータ型です。
サブジェクトの名前は、拡張フィールド(後述)のsubjectAltNameで示されるかもしれません。
同一のCAは、エンティティごとにユニークなサブジェクトを持った証明書を発行しなければなりません。しか、CAは、同一のエンティティに同一のDNを持った証明書を1枚以上発行してもかまいません。
サブジェクトの取り出し方
subjectPublicKeyInfoは、公開鍵の情報です。暗号化のアルゴリズムと公開鍵のビット列で構成され、以下のように定義されています。
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING }
このように電子証明書には、公開鍵とその暗号アルゴリズムが記載されていますので、電子証明書を使うアプリケーションが自動的に判断できるようになっています。RSAキーの場合は、以下のように規定されています。
OIDは、
pkcs-1 OBJECT IDENTIFIER ::=
{ iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 }
すなわち、"1.2.840.113549.1.1.1"となり、parameterには、NULLが入ります。subjectPublicKeyには、以下のRSAPublicKeyを指定しなければなりません。RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
publicExponent INTEGER } -- e
n と e は、公開鍵の場合に必要となる2つの値です。公開鍵情報の取り出し方
issuerUniqueIDおよびsubjectUniqueIDは、同じ発行者名や所有者名を区別するために使用します。規定では、同じ名前を別のエンティティ(発行者や所有者それぞれ)に使用すべきではないとされています。しかしながら、アプリケーションは、その区別ができるようにすべきでしょう。
なお、これら名フィールドは、バージョンが2または、3の場合にのみ現れ、バージョン1の場合名は現れてはなりません。
UniqueIdentifierは、BIT Stringとして、以下のとおりに定義されています。
UniqueIdentifier ::= BIT STRINGextensionsは、バージョンが3の場合にのみ現れそれ以外の場合には現れてはなら内フィールドです。このフィールドは、1つもしくはそれ以上のSEQUENCEによって構成されます。詳しくは、4.2 拡張情報のデータ形式[https://www.trustss.co.jp/smnDataFormat420.html]で詳しく説明します。
拡張フィールド数の取り出し方、5.2拡張情報とCryptoAPI[https://www.trustss.co.jp/smnDataFormat520.html]
4.1.6 Name データ型
Nameは、以下のように規定されています。
この規則に従うと、以下のように表記されます。
CN=FirstName LastName, O=Trust Software System, C=jp
Name ::= CHOICE {
RDNSequence }
RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
AttributeTypeAndValue ::= SEQUENCE {
type AttributeType,
value AttributeValue}
AttributeType ::= OBJECT IDENTIFIER
AttributeValue ::= ANY DEFINED BY AttributeType
DirectoryString ::= CHOICE {
teletexString TeletexString (SIZE (1..MAX)),
printableString PrintableString (SIZE (1..MAX)),
universalString UniversalString (SIZE (1..MAX)),
utf8String UTF8String (SIZE (1..MAX)),
bmpString BMPString (SIZE (1..MAX)) }
AttributeTypeは、以下のようなものがあります。 C Country 国名コード
O OrganizationName 組織名
OU OrganizationalUnitName 組織単位名
CN CommnName 一般名
また、規定では値としての文字は、2004年1月1日以降に発行される証明書では、UTF8Stringを使用しなければなりません。
この規則に従うと、以下のように表記されます。
CN=FirstName LastName, O=Trust Software System, C=jp
4.1.7 UTCTime型
時刻を表す型ですが、西暦を下位の2桁だけを使って以下のような表記法です。
050727123456Z (2005年7月27日12時34分56秒、グリニッジ時)UTCTime型は、グリニッジ時との差を表現できますが、RFC3280ではグリニッジ時による表記をしなければならないとされています。従いまして、以下のような表記は許されません。
050727123456+900 (2005年7月27日12時34分56秒、日本時)また、時刻の表記におきましても、秒までの時刻を表記しなければなりません。先頭の2桁が西暦を現しますが、その値が50以上(50を含む)の場合は、1900年代を表します。50未満(50を含まない)場合は、2000年代を表します。従いまして、2050年以降の日時はこの型で表現できません。
4.1.8 GeneralizedTime型
時刻を表す型で西暦を4桁で以下のように表現する型です。
20050727123456Z (2005年7月27日12時34分56秒、グリニッジ時間)GeneralizedTime型は、グリニッジ時との差を表現できますが、RFC3280ではグリニッジ時による表記をしなければならないとされています。従いまして、以下のような表記は許されません。
20050727123456+900 (2005年7月27日12時34分56秒、日本時)また、時刻の表記におきましても、秒までの時刻を表記しなければなりません。
総合目次[https://www.trustss.co.jp/smnIndex.html] <<< >>> 次のページ[https://www.trustss.co.jp/smnDataFormat420.html]
4.1.9 ご質問・ご要望
ご質問やご要望は、こちらからお送りください。(匿名でも可能です。)