晴耕雨読

working in the fields on fine days and reading books on rainy days

ASN.1 でのオブジェクトID (OID) とバイト列の表記

オブジェクトID (OID) のドット表記とDER形式のバイト列の変換規則について説明します。 OIDはオブジェクト識別子のことで例えば「1.2.3.4.16」のように書きます。 しかし、OIDをX.509証明書をDER形式で読み書きするときは、ドット表記ではなくバイト列による表記を使います。 例えばOID「1.2.3.4.16」をバイト列に変換すると16進数表記で「01 02 03 04 10」になります。とても簡単です。 ただし、変換の表記にあたって次の2つの特殊ルールが優先して適用されます。

  1. 先頭から1つ目の数字Xと2つ目の数字Yについては、まとめて1バイトで表記され、その値は X * 40 + Y を16進数表記にしたものです。 例えば先頭が「1.2.」のときは、40*1 + 2 = 42 = 0x2A となり、16進数表記で「2A」となります。
  2. 7bit以上の数字 (10進数で128以上の数字) は7bit毎に分けて複数のバイトで表記されます。 それぞれのバイトの最上位ビットが1のときは継続を、0のときは終端を表します。 例えば 840 のとき、840 = 0b1101001000 となり、7bit以上なので分割すると「110」と「1001000」になります。1つ目は継続、2つ目は終端になるので、1つ目の最上位ビットを1にし、2つ目の最上位ビットを0にすると、「10000110」と「01001000」となり、16進数表記で「86 48」となります。

この特殊ルールを適用した上で、OID「1.2.3.4.16」をバイト列に変換すると16進数表記で「2A 03 04 10」になります。

以上のルールをPythonに書くと以下のようになります。

def byte2str_OID(oid_bytes):
    hex_list = [ch for ch in oid_bytes]
    x = int(hex_list[0] / 40)
    y = int(hex_list[0] % 40)
    if x > 2:
        y += (x-2)*40
        x = 2
    OID_str = str(x) + '.' + str(y)
    val = 0
    for byte in range(1, len(hex_list)):
        val = ((val<<7) | ((hex_list[byte] & 0x7F)))
        if (hex_list[byte] & 0x80) != 0x80:
            OID_str += "." + str(val)
            val = 0
    return OID_str

def str2byte_OID(oid_str):
    import math
    hex_list = []
    numbers = oid_str.split('.')
    a, b = numbers[0:2]
    hex_list.append(int(a)*40 + int(b))
    for num in numbers[2:]:
        num_bin = bin(int(num, 10))[2:]
        chunk_count = math.ceil(len(num_bin) / 7)
        num_zeropad = str(num_bin).zfill(chunk_count * 7)
        for i in range(chunk_count):
            msb = 1
            if i == chunk_count - 1: # if last chunk
                msb = 0
            a_num = int(num_zeropad[i*7:(i+1)*7], 2)
            a_num |= msb << 7
            hex_list.append(a_num)
    return bytearray(hex_list)

使い方はバイト列からOIDを表示させたいときは byte2str_OID(バイト列) を、OIDからバイト列を出力したいときは str2byte_OID(文字列) とするだけです。

byte2str_OID(b'\x2A\x86\x48\x86\xF7\x0D\x02\x05')
str2byte_OID('1.2.840.113549.2.5').hex()

実際にASN.1で使用する場合は、Tag-Length-Valueの形式で表されます。 OIDの場合は、Tag が 0x06 となり、上記の例(長さが8のデータ)をASN.1で表すと「06 08 2A 86 48 86 F7 0D 02 05」のように先頭の2バイトが新たに追加されることに注意が必要です。

以下はよく使う(と思われる)OIDとそのバイト列の一覧です。

ハッシュアルゴリズム

説明 OID バイト列
MD2 1.2.840.113549.2.2 2A 86 48 86 F7 0D 02 02
MD5 1.2.840.113549.2.5 2A 86 48 86 F7 0D 02 05
SHA-1 1.3.14.3.2.26 2B 0E 03 02 1A
SHA-224 2.16.840.1.101.3.4.2.4 60 86 48 01 65 03 04 02 04
SHA-256 2.16.840.1.101.3.4.2.1 60 86 48 01 65 03 04 02 01
SHA-394 2.16.840.1.101.3.4.2.2 60 86 48 01 65 03 04 02 02
SHA-512 2.16.840.1.101.3.4.2.3 60 86 48 01 65 03 04 02 03

公開鍵暗号アルゴリズム

説明 OID バイト列
RSA 1.2.840.113549.1.1.1 2A 86 48 86 F7 0D 01 01 01
DSA 1.2.840.10040.4.1 2A 86 48 CE 38 04 01
Diffie-Hellman 1.2.840.10046.2.1 2A 86 48 CE 3E 02 01
ECC 1.2.840.10045.2.1 2A 86 48 CE 3D 02 01

署名アルゴリズム

説明 OID バイト列
md2WithRsaEncryption 1.2.840.113549.1.1.2 2A 86 48 86 F7 0D 01 01 02
md5WithRsaEncryption 1.2.840.113549.1.1.4 2A 86 48 86 F7 0D 01 01 04
sha1WithRsaEncryption 1.2.840.113549.1.1.5 2A 86 48 86 F7 0D 01 01 05
sha224WithRsaEncryption 1.2.840.113549.1.1.14 2A 86 48 86 F7 0D 01 01 0E
sha256WithRsaEncryption 1.2.840.113549.1.1.11 2A 86 48 86 F7 0D 01 01 0B
sha384WithRsaEncryption 1.2.840.113549.1.1.12 2A 86 48 86 F7 0D 01 01 0C
sha512WithRsaEncryption 1.2.840.113549.1.1.13 2A 86 48 86 F7 0D 01 01 0D
dsaWithSha1 1.2.840.10040.4.3 2A 86 48 CE 38 04 03
dsaWithSha224 2.16.840.1.101.3.4.3.1 60 86 48 01 65 03 04 03 01
dsaWithSha256 2.16.840.1.101.3.4.3.2 60 86 48 01 65 03 04 03 02
ecdsaWithSha1 1.2.840.10045.4.1 2A 86 48 CE 3D 04 01
ecdsaWithSha224 1.2.840.10045.4.3.1 2A 86 48 CE 3D 04 03 01
ecdsaWithSha256 1.2.840.10045.4.3.2 2A 86 48 CE 3D 04 03 02
ecdsaWithSha384 1.2.840.10045.4.3.3 2A 86 48 CE 3D 04 03 03
ecdsaWithSha512 1.2.840.10045.4.3.4 2A 86 48 CE 3D 04 03 04

対象鍵暗号アルゴリズム

説明 OID バイト列
DES CBC 1.3.14.3.2.7 2B 0E 03 02 07
3DES CBC 1.2.840.113549.3.7 2A 86 48 86 F7 0D 03 07
RC2 1.2.840.113549.3.2 2A 86 48 86 F7 0D 03 02
ArcFour 1.2.840.113549.3.4 2A 86 48 86 F7 0D 03 04
AES CBC 128 2.16.840.1.101.3.4.1.2 60 86 48 01 65 03 04 01 02
AES CBC 256 2.16.840.1.101.3.4.1.42 60 86 48 01 65 03 04 01 2A

x.500 識別名属性

説明 OID バイト列
名前 2.5.4.41 55 04 29
2.5.4.4 55 04 04
2.5.4.42 55 04 2A
イニシャル 2.5.4.43 55 04 2B
生成修飾子 2.5.4.44 55 04 2C
共通名 2.5.4.3 55 04 03
住所 2.5.4.7 55 04 07
都道府県名 2.5.4.8 55 04 08
組織名 2.5.4.10 55 04 0A
組織単位名 2.5.4.11 55 04 0B
タイトル 2.5.4.12 55 04 0C
dnQualifier 2.5.4.46 55 04 2E
国名 2.5.4.6 55 04 06
Eメール・アドレス 1.2.840.113549.1.9.1 2A 86 48 86 F7 0D 01 09 01
ドメイン・コンポーネント 0.9.2342.19200300.100.1.25 09 92 26 89 93 F2 2C 64 01 19
番地 2.5.4.9 55 04 09
郵便番号 2.5.4.17 55 04 11
メール 0.9.2342.19200300.100.1.3 09 92 26 89 93 F2 2C 64 01 03
シリアル番号 2.5.4.5 55 04 05

ECC名前曲線

説明 OID バイト列
secp192r1 1.2.840.10045.3.1.1 2A 86 48 CE 3D 03 01 01
secp224r1 1.3.132.0.33 2B 81 04 00 21
secp256r1 1.2.840.10045.3.1.7 2A 86 48 CE 3D 03 01 07
secp384r1 1.3.132.0.34 2B 81 04 00 22
secp521r1 1.3.132.0.35 2B 81 04 00 23
brainpoolP160r1 1.3.36.3.3.2.8.1.1.1 2B 24 03 03 02 08 01 01 01
brainpoolP192r1 1.3.36.3.3.2.8.1.1.3 2B 24 03 03 02 08 01 01 03
brainpoolP224r1 1.3.36.3.3.2.8.1.1.5 2B 24 03 03 02 08 01 01 05
brainpoolP256r1 1.3.36.3.3.2.8.1.1.7 2B 24 03 03 02 08 01 01 07
brainpoolP320r1 1.3.36.3.3.2.8.1.1.9 2B 24 03 03 02 08 01 01 09
brainpoolP384r1 1.3.36.3.3.2.8.1.1.11 2B 24 03 03 02 08 01 01 0B
brainpoolP512r1 1.3.36.3.3.2.8.1.1.13 2B 24 03 03 02 08 01 01 0D


OIDの割り当て規則

ドット表記のOID「X.Y.〜」のうち、最初の2つについては、次のように割り当て規則があります。

X (1番目の値) Y (2番目の値)
0: ITU-T が規定 0: 勧告(recommendation)
1: 課題(question)
2: 管理組織(administration)
3: ネットワークオペレータ
1: ISO が規定 0: 標準 (standard)
1: 登録機関 (registration-authority)
2: 加盟団体 (member-body)
3: 身元が明らかな組織 (identified-organization)
2: ITU-T と ISO が規定 -

例えば、OID の先頭が 1.2 のオブジェクトは、ISO の加盟団体によって管理されていることになります。


参考文献