2012-12-18

TLVパーサがほしい

最近仕事でAPDUをいじる必要があるのだが(正確には眺めてるだけなんだけど・・・)、中に入ってるデータとかSIMが返すデータとかがTLV形式であることが多い。っで、TLV自体は別に何か特別な仕様というわけでもないのでこのパーサがあってもいいかなぁと思っていたりする。

問題は、現在既にあるASN.1パーサは基本的にはTLVパーサの上にASN.1のオブジェクトを被せるという形になっている点だろう。TLVだけに特化したのを別に作るのは馬鹿らしいのでこれを分離する方向にしたい。ということでちょっと実装方針を考えることにする。

現状のASN.1パーサはDERとBERに特化した形になっているので不定長のバイト列を処理することができるのだが、TLV形式だけならこれは不要になる。っが、これを外すことは当然だができない。また、DER、BERだとタグ部分が1バイトを超えることがあるが、他の形式だとたいてい1バイトである。(この辺ちょっと自信ない。現状の実装が一般的な気もする。)

となると、タグを読む、長さを読む、値を読む手続きとそれらから得られたデータから最終的なオブジェクトを構築する手続きを渡して、TLVパーサを作るような形にするといいだろうか? でも、そこまでやるなら分離する必要ないよな?オブジェクトの構築だけを外出しにすると、今度は不定長データの処理に困るし、どうしようかな。

一晩寝たらなんかいいアイデアが出た気がする。たぶん寝る前に読んだWikipediaも関係しているだろうが。
結局BERが要求しているTLV形式をもう少し一般化してやればいいだけの話なんだ。タグ、長さ、値に追加で不定長時の区切りを読んでやるようにすればいい。そうすると最終的に必要になるのはオブジェクトを構築する手続きだけになる。
また、TLVの形式はどうやら複数個あるらしく、EMV形式(これがBERを含むたぶん最も一般的なもの)、DGI形式、L16形式があるっぽい。
TLV - Reference Documentation
リンク先はJavaかC#辺りの実装のドキュメントだが、サポートしている形式が3種類ある。ということは、将来的に他の形式をサポートすることも考えると、以下のような手続きでパーサを作成するようにした方がいいかもしれない。
;; タグ長最大4、長さ長最大4、不定長時セパレータ0x0000のTLVパーサを作成する
(make-tlv-parser EMV :tag 4 :length 4
                     :separetor #vu8(0 0) :object-builder asn.1-builder)
;;実際の定義イメージ
(define (make-tlv-parser format . opts)
  (case format
    ((EMV) (apply make-emv-tlv-parser opts))
    (else (implementation-restriction-violation 'make-tlv-parser
            "not supported" format))))
他形式はまだ考えていないが、とりあえずこうしておけばそこそこ一般化できそうだろうか?(たぶん、タグ長と長さ長はEMV形式なら要らんはずだが。)
あとは、ASN.1内で定義されているパーサは結構BERべったりになっているのでうまいこと切り離す必要があるが、そこはなんとかなるだろう。

No comments:

Post a Comment