0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

Token Status List (TSL) という標準仕様が、そろそろ IETF の RFC として承認されそうです。

この仕様は、JOSE や COSE をベースとするトークン群 (JWT、SD-JWT VC、CWT、ISO mdoc など) のステータス情報 (有効、無効など) を取り扱うためのものです。

大量のトークンのステータスをまとめて表現できるようにするため、ステータス群はビット配列で表現され、DEFLATE で圧縮されます。

このステータスのリストを表現するためのデータ構造として、TSL 仕様は StatusList を定義しています。この記事では、この StatusList について見ていきます。

StatusListの構造

フォーマットが JSON か CBOR かに関わらず、StatusList は次のプロパティを持っています。

プロパティ 要否 説明
bits 必須 一つのステータスを表現するのに用いるビットの数。1、2、4 または 8。
lst 必須 バイト配列で表現されたステータス群を DEFLATE 圧縮したもの。CBOR ではバイト配列、JSON では base64url 文字列で表現される。
aggregation_uri 任意 ステータスリストトークン群を公開する URI 群のリストを得られる場所。

下記は仕様書から抜粋した JSON 形式の StatusList の例です。

JSON 形式の StatusList の例 (bits=1)
{
  "bits": 1,
  "lst": "eNrbuRgAAhcBXQ"
}
JSON 形式の StatusList の例 (bits=2)
{
  "bits": 2,
  "lst": "eNo76fITAAPfAgc"
}

bits プロパティは、一つのステータスを表現するのに用いるビット数を表しており、取りうる値は 1、2、4、または 8 です。ビット数を 1 とする場合、$2^1 = 2$ 種類のステータスを表現できます。例えば、有効・無効の二種類のステータスを表現できます。ビット数を 2 とする場合は $2^2 = 4$ 種類、4 なら $2^4 = 16$ 種類、8 なら $2^8 = 256$ 種類のステータスを表現できます。

lst プロパティは、ステータス群を列挙したバイト配列を DEFLATE 圧縮したものです。CBOR フォーマットでは DEFLATE の結果をそのままバイト配列として持ち、一方で JSON フォーマットでは base64url エンコードして文字列として持ちます。

例えば、ステータスを表現するのに用いるビット数を 1 とし、16 個のトークンのステータスが次の通りだとします。

インデックス ステータス
0 無効 1
1 有効 0
2 有効 0
3 無効 1
4 無効 1
5 無効 1
6 有効 0
7 無効 1
8 無効 1
9 無効 1
10 有効 0
11 有効 0
12 有効 0
13 無効 1
14 有効 0
15 無効 1

これらを次の図の要領でパックすると、[0xB9, 0xA3] というバイト配列が得られます。

compressed_byte_array_bits1.png

このバイト配列を DEFLATE で圧縮したものが lst にセットされます。

同様にして、ステータスを表現するのに用いるビット数を 2 とし、12 個のトークンのステータスが次の通りだとします。

インデックス ステータス
0 01
1 10
2 00
3 11
4 00
5 01
6 00
7 01
8 01
9 10
10 11
11 11

このステータス群を次の図の要領でパックすると、[0xC9, 0x44, 0xF9] というバイト配列が得られます。

compressed_byte_array_bits2.png

このバイト配列を DEFLATE で圧縮したものが lst にセットされます。

StatusListの実装

Authlete 社がオープンソースで公開している CBOR ライブラリ authlete/cbor (for Java) は、バージョン 1.21 以降、StatusList を表すクラスが StatusList という名前で com.authlete.cbor.tsl パッケージ内に入っています。

この StatusList クラスのコンストラクタは、int bitsbyte[] lstString aggregationUri という引数を取ります。

StatusList クラスのコンストラクタ
public StatusList(int bits, byte[] lst, String aggregationUri)

しかしながら、そもそも lst の値を用意するのが大変なので、このコンストラクタを呼び出すまでの道のりは遠いです。そこで、StatusList クラスのインスタンスを生成するためのユーティリティクラス StatusListBuilder を用意してあります。

StatusListBuilder の使用手順は次のとおりです。

  1. ステータスの表現に使うビット数を 1、2、4、8 の中から決める
  2. ビット数をコンストラクタに渡して StatusListBuilder インスタンスを作成する
  3. 必要な分だけ valueAt メソッドを呼び、ステータスを設定する
  4. aggregation_uri を設定したければ aggregationUri メソッドを呼ぶ
  5. valueAt メソッドに指定したインデックスにより自動拡張されたステータス数を上回る領域を確保したければ、capacity メソッドを呼ぶ
  6. 最後に build メソッドを呼んで StatusList インスタンスを作成する

例えば、TSL 仕様の 4.1. Compressed Byte Array に挙げられている下記のステータス群を持つ StatusList を作成するには、

status[0] = 0b1
status[1] = 0b0
status[2] = 0b0
status[3] = 0b1
status[4] = 0b1
status[5] = 0b1
status[6] = 0b0
status[7] = 0b1
status[8] = 0b1
status[9] = 0b1
status[10] = 0b0
status[11] = 0b0
status[12] = 0b0
status[13] = 0b1
status[14] = 0b0
status[15] = 0b1

次のように書きます。

StatusListBuilder を用いて StatusList を作成する
// ステータスを表現するのに使うビット数
int bits = 1;

// ビット数をコンストラクタに渡して StatusListBuilder のインスタンスを作成する
StatusListBuilder builder = new StatusListBuilder(bits);

// ステータスを設定する
builder.valueAt(StatusTypeValue.INVALID,  0);
builder.valueAt(StatusTypeValue.VALID,    1);
builder.valueAt(StatusTypeValue.VALID,    2);
builder.valueAt(StatusTypeValue.INVALID,  3);
builder.valueAt(StatusTypeValue.INVALID,  4);
builder.valueAt(StatusTypeValue.INVALID,  5);
builder.valueAt(StatusTypeValue.VALID,    6);
builder.valueAt(StatusTypeValue.INVALID,  7);
builder.valueAt(StatusTypeValue.INVALID,  8);
builder.valueAt(StatusTypeValue.INVALID,  9);
builder.valueAt(StatusTypeValue.VALID,   10);
builder.valueAt(StatusTypeValue.VALID,   11);
builder.valueAt(StatusTypeValue.VALID,   12);
builder.valueAt(StatusTypeValue.INVALID, 13);
builder.valueAt(StatusTypeValue.VALID,   14);
builder.valueAt(StatusTypeValue.INVALID, 15);

// StatusList のインスタンスを作成する
StatusList statusList = builder.build();

StatusListCBORItem のサブクラスなので、encodeToHex() メソッドを用いて 16 進数で表現したり、

StatusList の 16 進数表現を出力する
System.out.println(statusList.encodeToHex());
a2646269747301636c73744a78dadbb918000217015d

toString() メソッドや prettify() メソッドを用いて Diagnostic Notation で表現したりできます。

StatusList の Diagnostic Notation 表現を出力する
System.out.println(statusList.prettify());
{
  "bits": 1,
  "lst": h'78dadbb918000217015d'
}

Diagnostic Notation については、RFC 8949 Section 8RFC 8610 Appendix G をご参照ください。

ちなみに、『GSON:バイト配列とbase64url文字列の双方向変換』で紹介している Base64UrlAdapter を用いてバイト配列を base64url 文字列に変換すれば (他の方法でも良いのですがとにかく lst の値をバイト配列から base64url 文字列に変換すれば)、

StatusList の JSON 表現を出力する
// Base64UrlAdapter を有効にして Gson を作成する
Gson gson = new GsonBuilder()
        .registerTypeAdapter(byte[].class, new Base64UrlAdapter())
        .setPrettyPrinting()
        .create();

// parse() メソッドで CBORItem を一般的な Java クラスのオブジェクトに変換
Object statusListObject = statusList.parse();

// JSON に変換する
String json = gson.toJson(statusListObject);

// JSON を出力する
System.out.println(json);

TSL 仕様の 4.2. Status List in JSON Format の規定に従う JSON を生成できます。

{
  "bits": 1,
  "lst": "eNrbuRgAAhcBXQ"
}

おわりに

Java で CBOR を扱う必要が出てきたときは、是非 authlete/cbor ライブラリを使ってみてください。Authlete 社自身も OpenID for Verifiable Credential Issuance 1.0 (OID4VCI) の実装で authlete/cbor ライブラリを使っています。

また、CBOR Zone というウェブサイトも運営しています。CBOR データを下記のフォーマット間で相互変換することができます。便利なので使ってみてください!

  • 16 進数
  • Base64
  • Base64URL
  • Diagnostic Notation

cbor_zone.png

(このスクリーンショットは、StatusList の 16 進数表現から Diagnostic Notation への変換を示しています)

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?