| RFC 8949 | CBOR | 2020年12月 |
| Bormann & Hoffman | 標準化過程 | [ページ] |
簡潔なバイナリオブジェクト表現(CBOR)はデータ形式であり、その設計 目標には、 極めて小さなコードサイズ、かなり小さなメッセージサイズ、および バージョンネゴシエーションを 必要としない拡張性の可能性が含まれる。これらの設計目標により、ASN.1 や MessagePack などの以前の バイナリ シリアライゼーションとは異なるものになっている。¶
本文書は RFC 7049 を廃止し、編集上の改善、新たな 詳細、および正誤表の修正を提供しつつ、 RFC 7049 の交換形式との完全な互換性を維持する。これは、この形式の 新しいバージョンを作成するものではない。¶
これはインターネット標準化過程の文書である。¶
本文書はインターネット技術タスクフォース(IETF)の成果物である。 これは IETF コミュニティの総意を表す。公開レビューを 受けており、インターネット技術運営グループ(IESG)により 公開が承認されている。インターネット標準に関する詳細情報は RFC 7841 のセクション 2 で入手できる。¶
本文書の現在の状態、正誤表、および本文書へのフィードバックの 提供方法に関する情報は、 https://www.rfc-editor.org/info/rfc8949 で入手できる。¶
Copyright (c) 2020 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.¶
構造化データのバイナリ表現 (バイナリシリアライゼーション形式としても知られる)には、何百もの標準化された形式がある。 そのうち、特定の情報領域向けのものもあれば、 任意のデータ向けに汎用化されたものもある。IETF では、後者のカテゴリでおそらく最もよく知られている 形式は ASN.1 の BER および DER [ASN.1] である。¶
ここで定義される形式は、現在の形式では十分に満たされていない いくつかの具体的な設計目標に従う。基礎となるデータモデルは、 JSON データモデル [RFC8259] の拡張版である。ここで 注意すべき重要な点は、これは RFC 8259 の文法を一般に 拡張する提案ではないということである。そうすると、すでに配備されている JSON 文書との大きな後方互換性の問題を引き起こすためである。 その代わりに、本文書は JSON から出発する独自のデータモデルを 単に定義する。¶
付録 E は既存のいくつかのバイナリ形式を挙げ、 それらが簡潔なバイナリオブジェクト表現(CBOR)の設計目的に どの程度合うか、または合わないかを論じている。¶
本文書は [RFC7049] を廃止し、 RFC 7049 の交換形式との完全な互換性を保ちながら、 編集上の改善、新たな詳細、および正誤表の修正を提供する。 これはこの形式の新しいバージョンを作成するものではない。¶
CBOR の目的は、おおむね重要度の高い順に、 次のとおりである。¶
表現は、インターネット標準で使われるほとんどの一般的な データ形式を曖昧さなく符号化できなければならない。¶
非常に限られたメモリ、処理能力、および命令セットを持つ システムをサポートするため、エンコーダまたはデコーダのコードは コンパクトにできなければならない。¶
データは、スキーマ記述なしで復号できなければならない。¶
シリアライゼーションは十分にコンパクトでなければならないが、 データのコンパクトさはエンコーダおよびデコーダのコードの コンパクトさに次ぐものである。¶
この形式は、制約ノードと大量処理アプリケーションの 両方に適用可能でなければならない。¶
この形式は、JSON との相互変換のために すべての JSON データ型をサポートしなければならない。¶
この形式は拡張可能でなければならず、拡張されたデータは 以前のデコーダでも復号可能でなければならない。¶
本文書におけるキーワード「MUST」、「MUST NOT」、 「REQUIRED」、「SHALL」、「SHALL NOT」、「SHOULD」、「SHOULD NOT」、 「RECOMMENDED」、「NOT RECOMMENDED」、 「MAY」、および「OPTIONAL」は、 ここに示すようにすべて大文字で現れる場合に限り、 BCP 14 [RFC2119] [RFC8174] に記述されるとおりに 解釈される。¶
用語「byte」は、現在慣用的な意味で「octet」の同義語として 使用される。すべてのマルチバイト値はネットワークバイト順 (すなわち、最上位バイトが先、別名「ビッグエンディアン」)で符号化される。¶
本仕様は、次の用語を使用する。¶
Infinity、NaN(数値ではない)、負のゼロ、および非正規数などの 浮動小数点値に関する用語および概念は、[IEEE754] で定義される。¶
ビット演算またはデータ型を説明する場合、本文書は プログラミング言語 C [C] でなじみのある表記を使用する。ただし、 「..」は与えられた両端を含む範囲を表し、上付き表記は べき乗を表す。たとえば、2 の 64 乗は 264 と表記される。 本仕様のプレーンテキスト版では、上付き表記は利用できないため、 代替表記で表示される。その表記はこの RFC に最適化されておらず、 残念ながら C の排他的論理和(これは付録でのみ使用され、 付録ではべき乗は使用されない)と曖昧であり、 プレーンテキスト版の読者に注意深さを要求する。¶
例および擬似コードは、 符号付き整数が 2 の補数表現を使用し、符号付き整数の右シフトが 符号拡張を行うことを仮定している。これらの仮定は、 C++ の 2020 年版(現在は最終ドラフト [Cplusplus20] として利用可能)の セクション 6.8.1(basic.fundamental)および 7.6.7(expr.shift)にも 規定されている。¶
16 進数の「0x」表記と同様に、 2 進表記の数値には「0b」が接頭される。アンダースコアは 読みやすさのためだけに数値に追加できるため、 0b00100001(0x21)は、バイト中のビットの望ましい解釈を 強調するために 0b001_00001 と書かれることがある。この場合、 3 ビットと 5 ビットに分割される。符号化された CBOR データ 項目は、「0x」または「0b」表記で与えられることがある。 これらの値は最初に C と同様に数値として解釈され、その後、 表記に含まれる先頭のゼロバイトも含めて、ネットワークバイト順の バイト文字列として解釈される。¶
語は強調のために イタリック体 にされることがある。
本仕様のプレーンテキスト形式では、これは単語をアンダースコア文字で
囲むことによって示される。逐語テキスト(例: プログラミング言語由来の名前)は
monospace 体で組まれることがある。プレーンテキストでは、
これは多少曖昧ではあるが、テキストを二重引用符で囲むことによって近似される
(二重引用符は通常の意味も保持する)。¶
CBOR は、その汎用データモデルについて明示的である。 これは、CBOR で表現できるすべてのデータ項目の集合を定義する。 その基本汎用データモデルは、「単純値」およびタグの登録によって 拡張可能である。アプリケーションはその結果得られる拡張汎用 データモデルの部分集合を作成して、それぞれの特定データモデルを 構築できる。¶
汎用データモデル内のデータ項目を表現できる環境では、 汎用 CBOR エンコーダおよびデコーダを実装できる (通常、環境内に自然な表現をまだ持たないデータ項目について、 追加の実装データ型を定義することを伴う)。 汎用エンコーダおよびデコーダを提供できることは、CBOR の明示的な設計目標である。 ただし、多くのアプリケーションは独自のアプリケーション固有の エンコーダまたはデコーダを提供する。¶
セクション 3 で定義される 基本(未拡張)汎用データモデルにおいて、データ項目は次のいずれかである。¶
このモデルでは、同じ数値を持つ場合でも、整数値と浮動小数点値は 異なることに注意する。¶
また、シリアライゼーションの変種は汎用データモデルのレベルでは 可視ではないことにも注意する。この意図的な不可視性には、符号化された 浮動小数点値のバイト数も含まれる。また、整数の符号化、 テキストまたはバイト文字列の長さの符号化、配列中の要素数または マップ中のペア数の符号化、あるいはタグ番号の符号化など、 「引数」(セクション 3 参照)の符号化の選択も含まれる。¶
この基本汎用データモデルは、本文書において、 次のような多数の単純値およびタグ番号の登録によって拡張されている。¶
false、true、null、および undefined
(20..23 によって識別される単純値、セクション 3.3)¶
拡張汎用データモデルの追加要素は、CBOR 用に作成された IANA レジストリを通じて定義できる(かつ実際に定義されている)。 そのような拡張が汎用エンコーダまたはデコーダに知られていない場合でも、 その拡張を使用するデータ項目は、基本汎用データモデル内で、 すなわち汎用単純値または汎用タグとして、アプリケーションインタフェースにおいて 表現することにより、アプリケーションとの間で受け渡しできる。¶
言い換えれば、基本汎用データモデルは本文書で定義されるとおり 安定している一方で、拡張汎用データモデルは新しい単純値または タグ番号の登録によって拡大するが、決して縮小しない。¶
汎用エンコーダおよびデコーダが、false、true、
および null(undefined は意図的に省かれている)を
それぞれのプログラミング環境に適した形式で表現できることには強い期待があるが、
タグによって作成されるデータモデル拡張の実装は真に任意であり、
実装品質の問題である。¶
CBOR ベースのプロトコルの特定データモデルは、通常、 拡張汎用データモデルの部分集合を取り、その部分集合および その構成要素内のデータ項目にアプリケーションセマンティクスを割り当てる。 そのような特定データモデルを文書化し、データ項目の型を指定する場合は、 CBOR 表現の側面(「メジャー型 1」、「メジャー型 4」)を参照するのではなく、 汎用データモデル名(「負の整数」、「配列」)によって型を 識別することが望ましい。¶
特定データモデルは、マップキーおよびエンコーダの自由度のために、
(異なる型の値を含む)値の等価性も指定できる。
たとえば、汎用データモデルでは、妥当なマップは 0 と
0.0 の両方をキーとして持つことが MAY であり、
エンコーダは 0.0 を整数
(メジャー型 0、セクション 3.1)として
符号化してはならない(MUST NOT)。
しかし、ある特定データモデルが、整数値を表す浮動小数点表現と
整数表現を等価であると宣言した場合、単一のマップで
0 と 0.0 の両方をマップキーとして使用することは、
異なるメジャー型で符号化されていても重複とみなされ、
したがって無効となる。また、エンコーダは、符号化バイトを節約するためなどに、
整数値の浮動小数点数を整数として、またはその逆に符号化できる。¶
CBOR データ項目(セクション 2)は、 本セクションで説明される整形式の符号化データ項目を運ぶバイト文字列へ 符号化され、またはそこから復号される。この符号化は、初期バイトによって索引付けされた 付録 B の 表 7 に 要約されている。エンコーダは、整形式の符号化データ項目のみを生成しなければならない (MUST)。デコーダは、整形式の符号化 CBOR データ項目ではない入力に 遭遇した場合、復号データ項目を返してはならない(MUST NOT) (これは、損傷した符号化 CBOR データ項目から何らかの情報を利用可能にする可能性のある 診断ツールおよび回復ツールの有用性を損なうものではない)。¶
各符号化データ項目の初期バイトには、メジャー型に関する情報 (上位 3 ビット、セクション 3.1 で説明)と 追加情報(下位 5 ビット)の両方が含まれる。 いくつかの例外を除き、追加情報の値は、符号なし整数「引数」を どのように読み込むかを記述する。¶
初期バイトおよび引数を構成するために消費される追加バイトは、 まとめてデータ項目の ヘッド と呼ばれる。¶
この引数の意味はメジャー型に依存する。 たとえば、メジャー型 0 では引数はデータ項目そのものの値であり (メジャー型 1 では、データ項目の値は引数から計算される)、 メジャー型 2 および 3 では、後続する文字列データのバイト単位の長さを与え、 メジャー型 4 および 5 では、囲まれるデータ項目の数を決定するために使用される。¶
符号化されたバイトシーケンスがデータ項目の終わりより前で 終了した場合、その項目は整形式ではない。最外側の符号化項目が 復号された後にも、符号化されたバイトシーケンスにまだバイトが残っている場合、 その符号化は単一の整形式 CBOR 項目ではない。 アプリケーションによっては、デコーダはその符号化を整形式ではないものとして扱うか、 あるいは残りのバイトの開始位置をアプリケーションに識別するだけにすることができる。¶
CBOR デコーダ実装は、初期バイトの 256 個すべての定義済み値を持つ ジャンプテーブル(表 7)に基づくことができる。 制約された実装のデコーダは、よりコンパクトなコードのために、 初期バイトおよび後続バイトの構造を代わりに使用できる (これがどのように見えるかの大まかな印象については 付録 C を参照)。¶
以下は、メジャー型と、その型に関連付けられる追加情報および その他のバイトの一覧である。¶
これら 8 つのメジャー型により、データ項目の初期バイトに対して 取り得る 256 個の値のうち、どれが使用されるかを示す単純な表 (表 7)が得られる。¶
メジャー型 6 および 7 では、取り得る値の多くが 将来の仕様のために予約されている。これらの値に関する詳細は セクション 9 を参照。¶
表 1 は、 さしあたり セクション 3.2 を無視して、 CBOR によって定義されるメジャー型を要約する。この表の数値 N は 引数を表す。¶
| メジャー型 | 意味 | 内容 |
|---|---|---|
| 0 | 符号なし整数 N | - |
| 1 | 負の整数 -1-N | - |
| 2 | バイト文字列 | N バイト |
| 3 | テキスト文字列 | N バイト(UTF-8 テキスト) |
| 4 | 配列 | N 個のデータ項目(要素) |
| 5 | マップ | 2N 個のデータ項目(キー/値ペア) |
| 6 | 番号 N のタグ | 1 個のデータ項目 |
| 7 | 単純値/浮動小数点 | - |
4 種類の CBOR 項目(配列、マップ、バイト文字列、および テキスト文字列)は、追加情報値 31 を使用して不定長で符号化できる。 これは、配列またはマップ内の項目数、あるいは文字列の総長が わかる前に、その項目の符号化を開始する必要がある場合に有用である。 (データ項目のすべてが分かる前に送信を開始できる能力は、 そのデータ項目内で「ストリーミング」と呼ばれることが多い。)¶
不定長の配列およびマップは、不定長の文字列 (バイト文字列およびテキスト文字列)とは異なる方法で扱われる。¶
「break」停止コードは、メジャー型 7 および追加情報値 31 (0b111_11111)で符号化される。これはそれ自体データ項目ではなく、 不定長項目を閉じるための構文上の機能にすぎない。¶
不定長の文字列、配列、またはマップの直内以外で、 データ項目が期待される場所に「break」停止コードが現れた場合 -- たとえば、定長配列またはマップの直内に現れた場合 -- その包含項目は整形式ではない。¶
不定長配列およびマップは、それぞれのメジャー型に 追加情報値 31 を用い、その後に配列では 0 個以上の項目の任意長シーケンス、 マップではキー/値ペアの任意長シーケンスが続き、最後に「break」 停止コード(セクション 3.2.1)が続くことで表現される。言い換えれば、不定長の 配列およびマップは、追加情報値 31 で始まり、「break」停止コードで終わる点を除き、 他の配列およびマップと同一に見える。¶
マップ内でキーの後に、そのキーの値の代わりとして 「break」停止コードが現れた場合、そのマップは整形式ではない。¶
不定長の配列またはマップ項目を入れ子にすることに対する 制限はない。「break」は単一の項目だけを終了するため、 入れ子になった不定長項目には、不定長項目を開始する型バイトの数と ちょうど同じ数の「break」停止コードが必要である。¶
たとえば、エンコーダが抽象配列 [1, [2, 3], [4, 5]] を 表現したいとする。定長符号化は 0x8301820203820405 となる。¶
83 -- 長さ 3 の配列
01 -- 1
82 -- 長さ 2 の配列
02 -- 2
03 -- 3
82 -- 長さ 2 の配列
04 -- 4
05 -- 5
¶
不定長符号化は、このデータ項目内で符号化される 3 つの配列それぞれに、必要に応じて独立に適用でき、 次のような表現につながる。¶
0x9f018202039f0405ffff
9F -- 不定長配列の開始
01 -- 1
82 -- 長さ 2 の配列
02 -- 2
03 -- 3
9F -- 不定長配列の開始
04 -- 4
05 -- 5
FF -- 「break」(内側の配列)
FF -- 「break」(外側の配列)
¶
0x9f01820203820405ff
9F -- 不定長配列の開始
01 -- 1
82 -- 長さ 2 の配列
02 -- 2
03 -- 3
82 -- 長さ 2 の配列
04 -- 4
05 -- 5
FF -- 「break」
¶
0x83018202039f0405ff
83 -- 長さ 3 の配列
01 -- 1
82 -- 長さ 2 の配列
02 -- 2
03 -- 3
9F -- 不定長配列の開始
04 -- 4
05 -- 5
FF -- 「break」
¶
0x83019f0203ff820405
83 -- 長さ 3 の配列
01 -- 1
9F -- 不定長配列の開始
02 -- 2
03 -- 3
FF -- 「break」
82 -- 長さ 2 の配列
04 -- 4
05 -- 5
¶
不定長マップの例(たまたま 2 つのキー/値ペアを持つ)は、 次のようになる。¶
0xbf6346756ef563416d7421ff
BF -- 不定長マップの開始
63 -- 最初のキー、長さ 3 の UTF-8 文字列
46756e -- "Fun"
F5 -- 最初の値、true
63 -- 2 番目のキー、長さ 3 の UTF-8 文字列
416d74 -- "Amt"
21 -- 2 番目の値、-2
FF -- 「break」
¶
不定長文字列は、バイト文字列またはテキスト文字列の メジャー型と追加情報値 31 を含むバイトで表現され、その後に 指定された型の定長文字列(「チャンク」)が 0 個以上続き、 最後に「break」停止コード(セクション 3.2.1)で 終了する。不定長文字列によって表現されるデータ項目は、 これらのチャンクの連結である。チャンクが存在しない場合、 そのデータ項目は指定された型の空文字列である。長さゼロのチャンクは、 特に有用ではないが、許可される。¶
不定長文字列インジケータ(0b010_11111 または 0b011_11111)と 「break」停止コードの間にある任意の項目が、同じメジャー型の 定長文字列項目でない場合、その文字列は整形式ではない。¶
この設計では、不定長文字列をチャンクとして 不定長文字列に入れ子にすることは許可していない。 もし許可されるなら、デコーダ実装は入れ子レベルのスタック、 または少なくともカウントを保持する必要がある。エンコーダ側では不要である。 なぜなら、内側の不定長文字列はチャンクから構成されるため、 それらを外側の不定長文字列に直接置くことができるからである。¶
不定長テキスト文字列内のいずれかの定長テキスト文字列が 無効である場合、その不定長テキスト文字列は無効である。 これは、単一の Unicode コードポイント(スカラー値)の UTF-8 バイトを チャンク間に分散できないことを意味する点に注意する。 テキスト文字列の新しいチャンクは、コードポイント境界でのみ開始できる。¶
たとえば、次のバイトからなる符号化データ項目を想定する。¶
0b010_11111 0b010_00100 0xaabbccdd 0b010_00011 0xeeff99 0b111_11111
5F -- 不定長バイト文字列の開始
44 -- 長さ 4 のバイト文字列
aabbccdd -- バイト内容
43 -- 長さ 3 のバイト文字列
eeff99 -- バイト内容
FF -- 「break」
¶
復号後、これは 7 バイトの単一のバイト文字列 0xaabbccddeeff99 となる。¶
表 2 は、 CBOR によって定義されるメジャー型について、 不定長符号化(追加情報を 31 に設定)で使用される場合を要約する。¶
| メジャー型 | 意味 | 「break」停止コードまでに 囲まれるもの |
|---|---|---|
| 0 | (整形式ではない) | - |
| 1 | (整形式ではない) | - |
| 2 | バイト文字列 | 定長バイト文字列 |
| 3 | テキスト文字列 | 定長テキスト文字列 |
| 4 | 配列 | データ項目(要素) |
| 5 | マップ | データ項目(キー/値ペア) |
| 6 | (整形式ではない) | - |
| 7 | 「break」停止コード | - |
メジャー型 7 は、浮動小数点数と、 内容を必要としない「単純値」という 2 種類のデータのためのものである。 初期バイト内の 5 ビットの追加情報の各値は、 表 3 で定義されるように、 それぞれ独自の意味を持つ。整数用のメジャー型と同様に、 このメジャー型の項目は内容データを運ばない。すべての情報は 初期バイト(ヘッド)にある。¶
| 5 ビット値 | セマンティクス |
|---|---|
| 0..23 | 単純値(値 0..23) |
| 24 | 単純値(後続バイト内の値 32..255) |
| 25 | IEEE 754 半精度浮動小数点数(16 ビットが続く) |
| 26 | IEEE 754 単精度浮動小数点数(32 ビットが続く) |
| 27 | IEEE 754 倍精度浮動小数点数(64 ビットが続く) |
| 28-30 | 予約済み、本文書では整形式ではない |
| 31 | 不定長項目のための「break」停止コード (セクション 3.2.1) |
他のすべてのメジャー型と同様に、5 ビット値 24 は 1 バイトの拡張を示す。これは単純値を表すために 追加バイトが後続する。(混乱を最小限にするため、値 32 から 255 のみが使用される。)これにより初期バイトの構造は維持される。 すなわち、他のメジャー型と同様に、これらの長さは常に 最初のバイト内の追加情報に依存する。表 4 は、 単純値に割り当てられている数値および利用可能な数値を示す。¶
| 値 | セマンティクス |
|---|---|
| 0..19 | (未割り当て) |
| 20 | false |
| 21 | true |
| 22 | null |
| 23 | undefined |
| 24..31 | (予約済み) |
| 32..255 | (未割り当て) |
エンコーダは、0xf8(メジャー型 7、追加情報 24)で始まり、
0x20(10 進数 32)未満のバイトが続く 2 バイトシーケンスを
発行してはならない(MUST NOT)。そのようなシーケンスは
整形式ではない。(これは、エンコーダが false、true、
null、または undefined を 2 バイトシーケンスで
符号化できず、これらの 1 バイト変種のみが整形式であることを意味する。
より一般的にいえば、各単純値は単一の表現変種のみを持つ。)¶
5 ビット値 25、26、および 27 は、16 ビット、32 ビット、 および 64 ビットの IEEE 754 バイナリ浮動小数点値 [IEEE754] のためのものである。 これらの浮動小数点値は、適切なサイズの追加バイト内に符号化される。 (16 ビット浮動小数点数に関する情報については 付録 D を参照。)¶
データモデルレベルの一部の値について、CBOR は複数の シリアライゼーションを提供する。 多くのアプリケーションでは、エンコーダが常に 優先シリアライゼーション(優先符号化)を選択することが望ましい。しかし、現在の仕様は、 この選好を強制する負担をエンコーダまたはデコーダのいずれにも課さない。¶
一部の制約されたデコーダは、非優先シリアライゼーションを復号する 能力に制限がある場合がある。たとえば、あるアプリケーションで 1_000_000_000(一十億)未満の整数だけが想定される場合、 デコーダは整数内の 64 ビット引数を復号するために必要となるコードを 省いてもよい。常に優先シリアライゼーションを使用するエンコーダ (「優先エンコーダ」)は、このアプリケーションで出現し得る数値について、 このデコーダと相互運用する。一般に、優先エンコーダは、 たとえば常に 64 ビット整数を使用するものよりも、より普遍的に相互運用可能であり (かつ無駄も少ない)。¶
同様に、制約されたエンコーダは、サポートする表現変種の 種類に制限があるため、優先シリアライゼーションを 出力しない場合がある(「変種エンコーダ」)。たとえば、制約されたエンコーダは、 短い表現が利用可能であっても、符号化する整数について 常に 32 ビット変種を使用するように設計され得る (64 ビット変種でしか表現できない整数をアプリケーションが必要としないと仮定する)。 優先シリアライゼーションのみを受け取ることに依存しない デコーダ(「変種許容デコーダ」)は、したがって、より 普遍的に相互運用可能であると言える(もっとも、優先シリアライゼーションを 受け取る場合に最適化していることは十分あり得る)。 CBOR デコーダの完全な実装は、定義上、変種を許容する。 この区別は、CBOR デコーダの制約された実装が変種エンコーダと 出会う場合にのみ関係する。¶
優先シリアライゼーションは、常に引数 (セクション 3)を表す最短形式を使用する。 また、符号化される値を保持する最短の 浮動小数点符号化も使用する。¶
浮動小数点値の優先シリアライゼーションは、その値を保持する最短の 浮動小数点符号化である。たとえば、数値 5.5 には 0xf94580、 数値 5555.5 には 0xfa45ad9c00 を用いる。NaN 値については、より短い仮数を右側にゼロ埋めすることで 元の NaN 値を再構成できる場合、より短い符号化が優先される (多くのアプリケーションでは、単一の NaN 符号化 0xf97e00 で 十分である)。¶
項目のシリアライゼーションが開始される時点で長さがわかっている場合は、 常に定長符号化が優先される。¶
一部のプロトコルでは、エンコーダが特定の 決定論的形式の CBOR のみを出力することを望む場合がある。また、それらのプロトコルは、 デコーダが入力がその決定論的形式であることを検査するようにしてもよい。 それらのプロトコルは、 「決定論的形式」とは何を意味するのか、またエンコーダおよびデコーダに 何が期待されるのかを自由に定義できる。本セクションは、 そのような決定論的形式の基礎として機能し得る制限の集合を定義する。¶
CBOR 符号化は、次の制限を満たす場合に 「中核となる決定論的符号化要件」を満たす。¶
優先シリアライゼーションを使用しなければならない (MUST)。 特に、これは整数、メジャー型 2 から 5 の長さ、およびタグの 引数(セクション 3 を参照)が 可能な限り短くなければならないことを意味する。 たとえば次のとおりである。¶
浮動小数点値も、その値を保持する最短形式を使用しなければならない (MUST)。たとえば、1.5 は 0xf93e00(binary16)として、 1000000.5 は 0xfa49742408(binary32)として符号化される。 (この一つの実装方法は、すべての浮動小数点数を 64 ビット浮動小数点数として開始し、 32 ビット浮動小数点数への試験変換を行うことである。結果が同じ数値であれば、 より短い形式を使用し、16 ビット浮動小数点数への試験変換でこの過程を繰り返す。 これは正の Infinity および負の Infinity に対して 16 ビット浮動小数点数を 選択する場合にも機能する。)¶
すべてのマップ内のキーは、その決定論的 符号化のバイト単位の辞書順でソートされなければならない (MUST)。たとえば、次のキーは正しくソートされている。¶
CBOR タグは、決定論的符号化に対して追加の考慮事項を提示する。 CBOR ベースのプロトコルが、特定のタグの存在と不在に対して同じセマンティクスを 提供する場合(たとえば、日時位置でタグ 1 データ項目と生の数値の両方を許可し、 後者をタグ付けされているかのように扱う場合)、決定論的形式は 「最短形式」の原則に基づいて、そのタグの存在を許可しない。 たとえば、プロトコルは、URL をテキスト文字列として表現するか、 セクション 3.4.5.3 を用いて テキスト文字列を含むタグ番号 32 として表現するかを、 エンコーダに選択させるかもしれない。このプロトコルの決定論的符号化では、 タグが存在することを要求するか、存在しないことを要求する必要があり、 どちらも許すことはできない。¶
特定の場所で特定のセマンティクスを得るためにタグを要求する プロトコルでは、決定論的形式にもそのタグが現れる必要がある。 決定論的符号化に関する考慮事項は、タグの内容にも適用される。¶
プロトコルが、タグ番号 2 または 3 (セクション 3.4.3)を使用して、 絶対値が 264 以上の整数を表現できるフィールドを含む場合、 そのプロトコルの決定論的符号化は、より小さい整数もこれらのタグを使用して 表現するのか、それともメジャー型 0 および 1 を使用して表現するのかを 指定する必要がある。優先シリアライゼーションは後者の選択を使用するため、 これが推奨される。¶
基本浮動小数点値(セクション 3.3)で表現されるか、 タグで表現されるか(またはその両方)にかかわらず、 浮動小数点値を含むプロトコルは、その決定論的符号化に対して 追加要件を定義する必要がある場合がある。たとえば次のとおりである。¶
プロトコルが、整数値と 浮動小数点値を交換可能であると宣言する特定のデータモデルを持つ 浮動小数点値を表現できるフィールドを含む場合、そのプロトコルの 決定論的符号化は、たとえば整数 1.0 を 0x01(符号なし整数)、 0xf93c00(binary16)、0xfa3f800000(binary32)、 または 0xfb3ff0000000000000(binary64)のいずれとして符号化するかを 指定する必要がある。このための規則例は次のとおりである。¶
規則 1 は整数と浮動小数点値の境界をまたぎ、規則 3 は 優先シリアライゼーションを使用しない。そのため、多くの場合、 規則 2 が良い選択となり得る。¶
中核となる決定論的符号化要件(セクション 4.2.1)は、[RFC7049] のセクション 3.9 で示唆された順序 (そこでは「Canonical CBOR」と呼ばれる)とは異なる順序で マップキーをソートする。[RFC7049] で指定された順序との互換性を 必要とするプロトコルは、代わりに本仕様の 「長さ優先の中核となる決定論的符号化要件」の観点から指定できる。¶
CBOR 符号化は、中核となる決定論的符号化要件を満たすが、 すべてのマップ内のキーが次のようにソートされなければならない (MUST)点だけが異なる場合、 「長さ優先の中核となる決定論的符号化要件」を満たす。¶
たとえば、長さ優先の中核となる決定論的符号化要件の下では、 次のキーは正しくソートされている。¶
CBOR のようなデータ形式は、形式ネゴシエーションが存在しない環境で 使用されることが多い。CBOR の具体的な設計目標の一つは、 含まれる、または仮定されるスキーマを必要としないことである。 デコーダは CBOR 項目を受け取り、他の知識なしにそれを復号できる。¶
もちろん、実世界の実装では、エンコーダとデコーダは CBOR データ項目内に何があるべきかについて共通の見解を持つ。 たとえば、合意された形式は「その項目は配列であり、 最初の値は UTF-8 文字列、2 番目の値は整数、以降の値は 0 個以上の浮動小数点数である」または「その項目は キーにバイト文字列を持ち、キーが 0xab01 であるペアを含む マップである」といったものかもしれない。¶
CBOR ベースのプロトコルは、そのデコーダが無効なデータおよび その他の予期しないデータをどのように扱うかを指定しなければならない (MUST)。CBOR ベースのプロトコルは、 任意の妥当なデータを予期しないものとして扱うと指定してもよい (MAY)。CBOR ベースのプロトコルのエンコーダは、 妥当な項目のみを生成しなければならない(MUST)。 すなわち、プロトコルは無効な項目を利用するように設計できない。 エンコーダは、それが使用されるプロトコルで必要とされるだけ多く、または少ない種類の値を 符号化できればよく、デコーダは、それが使用されるプロトコルで必要とされるだけ多く、 または少ない種類の値を理解できればよい。この制限の欠如により、 CBOR は極めて制約の厳しい環境で使用できる。¶
本セクションの残りでは、CBOR ベースのプロトコルを作成する際の いくつかの考慮事項について論じる。少数の例外を除き、これは助言的なものにすぎず、 BCP 14 [RFC2119] [RFC8174] に由来する用語のうち、 BCP 14 の意味で「MAY」と解釈できる語以外を明示的に除外する。 例外は、汎用およびアプリケーション固有のエンコーダとデコーダの 幅広い種類を利用しながら、CBOR ベースのプロトコルの 相互運用性を促進することを目的とする。¶
ストリーミングアプリケーションでは、データストリームは、 CBOR データ項目を連続して連結したシーケンスで構成される場合がある。 そのような環境では、以前のデータ項目の終端後にデータが見つかると、 デコーダは直ちに新しいデータ項目の復号を開始する。¶
データ項目を構成するすべてのバイトが、デコーダに直ちに 利用可能であるとは限らない。一部のデコーダは、完全なデータ項目を アプリケーションに提示できるようになるまで追加データをバッファする。 他のデコーダは、すでに復号できた入れ子データ項目や、まだ完全には到着していない バイト文字列の一部など、トップレベルデータ項目に関する部分的情報を アプリケーションに提示できる。 そのようなアプリケーションはまた、アプリケーションに提示される増分データに対して 望ましい保護が利用可能な、対応するストリーミングセキュリティ機構を 持たなければならない(MUST)。¶
一部のアプリケーションおよびプロトコルは、不定長符号化を 使用したくない場合があることに注意する。不定長符号化を使用すると、 エンコーダは数を数えるためにすべてのデータをまとめる必要がなくなるが、 デコーダは項目の終端を待つ間、増加するメモリ量を割り当てる必要がある。 これは一部のアプリケーションには適しているかもしれないが、 他のアプリケーションには適さない場合がある。¶
汎用 CBOR デコーダは、すべての整形式の符号化 CBOR データ項目を 復号し、データ項目をアプリケーションに提示できる。付録 C を参照。 (診断表記、セクション 8 は、 整形式の CBOR 値を人間に提示するために使用できる。)¶
汎用 CBOR エンコーダは、エンコーダが知らない単純値やタグを 含め、任意の整形式の値を CBOR データ項目として符号化するよう アプリケーションが指定できるアプリケーションインタフェースを提供する。¶
CBOR はこれらのケースを最小限にしようとするが、
すべての整形式 CBOR データが妥当であるとは限らない。
たとえば、符号化テキスト文字列 0x62c0ae は
妥当な UTF-8 を含まない([RFC3629] が
常に最短形式の使用を要求するため)ため、妥当な CBOR 項目ではない。
また、特定のタグは、たとえば bignum タグが別のタグを囲む場合や、
タグ番号 0 のインスタンスがバイト文字列を含む場合、または
[RFC3339] の
date-time 生成規則に一致しない内容を持つテキスト文字列を含む場合などに、
違反され得るセマンティックな制約を課すことがある。
汎用エンコーダおよびデコーダが、無効なデータの処理を可能にするために
アプリケーションインタフェースについて不自然な選択を行うことは要求されない。
汎用エンコーダおよびデコーダは、単純値およびタグの特定のコードポイントが
エンコーダ/デコーダの作成時に登録されていない場合でも、それらを転送することが期待される
(セクション 5.4)。¶
整形式ではあるが無効な CBOR データ項目 (セクション 1.2)は、 CBOR データモデルにおいて、その中に符号化されたデータを解釈する際の 問題を提示する。CBOR ベースのプロトコルは複数の層で指定され得る。 下位層は、転送する CBOR データの一部のセマンティクスを処理しない。 これらの層は、処理しないデータ内の妥当性エラーに気づくことができず、 そのデータをそのまま転送しなければならない(MUST)。 無効な CBOR 項目のセマンティクスを処理する最初の層は、次の 2 つの選択肢の いずれかを選ばなければならない(MUST)。¶
CBOR ベースのプロトコルは、デコーダが遭遇する可能性のある 無効な項目の各種類について、これらの選択肢のどちらを取るかを 指定しなければならない(MUST)。¶
そのような問題は、CBOR の基本的妥当性レベルまたは タグの文脈(タグ妥当性)で発生する可能性がある。¶
基本汎用データモデルでは、2 種類の妥当性エラーが 発生し得る。¶
基本汎用データモデルにタグを追加することにより、 さらに 2 種類の妥当性エラーが導入される。¶
妥当性検査を行うデコーダは、妥当性エラーを持つデータ項目を 信頼できる形で検出するための労力を費やす。たとえば、そのような デコーダには、前のサブセクションに列挙された妥当性エラーのいずれかを含む CBOR データ項目についてエラーを報告する(かつデータを返さない) API が必要である。¶
「Concise Binary Object Representation (CBOR) Tags」レジストリ(セクション 9.2)で 定義されるタグの集合、および 「Concise Binary Object Representation (CBOR) Simple Values」 レジストリ(セクション 9.1)で定義される 単純値の集合は、汎用デコーダが理解する集合を超えて いつでも増大し得る。妥当性検査を行うデコーダは、 認識できないそのようなケースに遭遇した場合、次の 2 つのいずれかを行える。¶
後者の方法は、妥当性検査をサポートしないデコーダにも適しており、 新たに登録されたタグおよび単純値との前方互換性を、 呼び出し元アプリケーションと同時にエンコーダを更新する必要なしに提供する。 (そのためには、デコーダの API に、未知の項目をマークする能力が必要であり、 それにより呼び出し元アプリケーションはプログラムに適した方法でそれらを扱える。)¶
妥当性検査に必要な処理の一部には、かなりのコストがかかる場合があるため (特にマップの重複検出において)、妥当性検査のサポートは すべての CBOR デコーダに課される要件ではない。¶
一部のエンコーダは、エンコーダの結果として妥当な CBOR が得られるような 入力データをアプリケーションが提供することに依存する。 汎用エンコーダはまた、アプリケーションが実際に API に適合したデータを 提供しているかどうかにかかわらず、その出力を妥当な CBOR に確実に 制限する妥当性検査モードを提供したい場合がある。¶
CBOR ベースのプロトコルは、異なる言語環境が、表現可能な 数値の範囲および精度に対して異なる制約を課すことを考慮すべきである。 たとえば、基本的な JavaScript 数値システムはすべての数値を 浮動小数点値として扱うため、53 個を超える有効ビットを持つ整数を 復号する際に、精度が黙って失われる可能性がある。 別の例として、CBOR は整数表現の符号ビットをメジャー型内に保持するため、 ある長さの符号付き数値について、同じ長さの典型的なプラットフォーム符号付き整数表現 (8 バイト int64_t の -263..263-1)よりも 1 ビット多い範囲(たとえば 1+8 バイト整数の -264..264-1)を持つ。 数値を使用するプロトコルは、デコーダおよび受信アプリケーションにおける 自明でない数値の扱いについて期待事項を定義すべきである。¶
浮動小数点数を含む CBOR ベースのプロトコルは、 3 つの形式(半精度、単精度、および倍精度)のうちどれを サポートすべきかを制限できる。整数専用のアプリケーションでは、 プロトコルは浮動小数点値の使用を完全に除外したい場合がある。¶
コンパクトさのために設計された CBOR ベースのプロトコルは、 64 ビット整数の実装の必要を省くなどの目的で、 アプリケーションに必要な長さより長い特定の整数符号化を 除外したい場合がある。 エンコーダは、与えられた値を表現できる最もコンパクトな 整数表現を使用することが期待される。しかし、決定論的符号化を 必要としないコンパクトなアプリケーションは、アプリケーションが 与えられたサイズの整数を復号できる限り、必要以上に長い符号化 (たとえば「0」を 0b000_11001 の後に 2 バイトの 0x00 が続く形で 符号化すること)を使用する値を受け入れるべきである。 同様の考慮事項は浮動小数点値にも適用される。優先シリアライゼーションと 必要以上に長いものの両方を復号することが推奨される。¶
制約されたアプリケーション向けの CBOR ベースのプロトコルで、 特定の数値を整数として表現するか、十進小数または bigfloat として 表現するかの選択肢を提供するもの(指数が小さく非負である場合など)は、 整数表現が直接使用されるという実装品質上の期待を表明してもよい。¶
符号化および復号アプリケーションは、マップでどの型のキーが 使用されるかについて合意する必要がある。JSON ベースのアプリケーションと 相互運用する必要があるアプリケーションでは、キーをテキスト文字列のみに 制限することで変換が簡素化される。そうでなければ、他の CBOR 型から テキスト文字列への指定されたマッピングが必要となり、これはしばしば 実装エラーにつながる。キーが数値的な性質を持ち、キーの数値順序が アプリケーションにとって重要なアプリケーションでは、キーに数値を直接使用することが 有用である。¶
複数の型のキーを使用する場合、それらの型が使用される予定の 特定のプログラミング環境でどのように表現されるかを考慮すべきである。 たとえば、JavaScript Maps [ECMA262] では、 整数 1 のキーは浮動小数点 1.0 のキーと区別できない。 これは、整数キーが使用される場合、プロトコルは同じマップ内で、 値がたまたま整数である浮動小数点キーの使用を避ける必要があることを意味する。¶
CBOR データ項目内に入れ子になったデータ項目を、復号するとすぐに 配信するデコーダ(「ストリーミングデコーダ」)は、マップ内のキーの一意性を 確認するために必要な状態を保持しないことが多い。 同様に、包含データ項目が完全に利用可能になる前にデータ項目の符号化を 開始できるエンコーダ(「ストリーミングエンコーダ」)は、データソースが 一意性を維持することに依存することで、オーバーヘッドを大幅に減らしたい場合がある。¶
CBOR ベースのプロトコルは、受信アプリケーションがマップ内で 複数の同一キーを見た場合に何をするかを定義しなければならない (MUST)。プロトコル内の結果としての規則は、 CBOR データモデルを尊重しなければならない(MUST)。 すなわち、同一キーを持つエントリの特定の扱いを規定することはできない。 ただし、マップ内の同一キーが不正形式のマップを示し、デコーダがエラーで 停止しなければならないという規則を持つことはできる。 重複キーを持つエントリを示すマップを処理する場合、汎用デコーダは次のいずれかを 行うかもしれない。¶
汎用デコーダは、これら 3 つの方法のうちどれを 実装しているかを文書化する必要がある。¶
マップの CBOR データモデルは、マップ表現内のキー/値ペアの順序に セマンティクスを帰属させることを許可しない。 したがって、CBOR ベースのプロトコルは、マップ内のキー/値ペアの順序を変更することが セマンティクスを変更すると指定してはならない(MUST NOT)。 ただし、たとえば決定論的符号化(セクション 4.2)の 要件を満たさないような順序など、一部の順序が許可されないと指定することはできる。 (マップ順序がタイミング、キャッシュ使用量、その他の潜在的なサイドチャネルに与える 二次的効果はセマンティクスの一部とはみなされないが、それ自体でプロトコルが 決定論的符号化形式を要求する十分な理由となる場合がある。)¶
制約デバイス向けのアプリケーションは、少数の頻繁に使用される キーを持つマップがある場合、小さい整数をキーとして使用することを検討すべきである。 たとえば、24 個以下のキーの集合は符号なし整数として 1 バイトで符号化でき、 負の整数も使用する場合は最大 48 個まで可能である。 あまり頻繁に出現しないキーには、より長い符号化を持つ整数を使用できる。¶
CBOR データ項目に適用される特定データモデルは、 マップ内に現れるキーが重複しているか、それとも別個であるかを判断するために使用される。¶
汎用データモデルレベルでは、数値的に等価な整数値と 浮動小数点値は互いに異なり、また各種の大きな数(タグ 2 から 5)とも 異なる。同様に、テキスト文字列は、同じバイトから構成されていても バイト文字列とは異なる。タグ付き値は、タグなし値や異なるタグ番号で タグ付けされた値とは異なる。¶
これらの各グループ内では、数値は数値的に等しい場合を除き 異なる(具体的には、-0.0 は 0.0 と等しい)。 マップキー等価性の目的では、NaN 値は、両方の仮数を右側で 64 ビットまでゼロ拡張した後に 同じ仮数を持つ場合に等価である。¶
バイト文字列およびテキスト文字列はどちらも バイト単位で比較され、配列は要素単位で比較され、 同じ数のバイト/要素を持ち、同じ位置に同じ値を持つ場合に等しい。 2 つのマップは、その順序にかかわらず同じペア集合を持つ場合に等しい。 ペアは、キーと値の両方が等しい場合に等しい。¶
タグ付き値は、タグ番号とタグ内容の両方が等しい場合に等しい。 (特定のタグに対する処理を提供する汎用デコーダは、 セマンティックに等価な一部の値を区別できない場合がある点に注意する。 たとえば、タグ 2 またはタグ 3 の内容に先頭のゼロが現れる場合である (セクション 3.4.3)。) 単純値は、単純に同じ値を持つ場合に等しい。 汎用データモデルでは、それ以外は何も等しくない。 単純値 2 は整数 2 と等価ではなく、配列がマップと等価になることは決してない。¶
セクション 2.2 で論じたように、特定データモデルは、 汎用データモデルでは異なる値を、マップキーを比較する目的で 等価にすることができる。これは、汎用デコーダが、アプリケーションによって 重複マップキーを検査する必要がある復号済みマップをアプリケーションに 配信する場合があることを意味する点に注意する (あるいは、デコーダがこのサービスをアプリケーションのために実行する プログラミングインタフェースを提供してもよい)。特定データモデルは、 この目的において汎用データモデルレベルで等しいマップキーの値を 区別できない。¶
本セクションは、CBOR と JSON の間で変換することについて 非規範的な助言を与える。変換器の実装は、ここにある助言のうち 望むものを使用してもよい(MAY)。¶
JSON テキストは文字のシーケンスであり、 符号化されたバイトシーケンスではない一方、CBOR データ項目は 文字ではなくバイトからなることは注目に値する。¶
CBOR のほとんどの型には、JSON に直接の類似物がある。 しかし、一部にはそれがなく、CBOR から JSON への変換器を実装する者は、 そのような場合に何をすべきかを考慮しなければならない。 次の非規範的な助言は、それらを JSON null などの 単一の代替値に変換することで扱う。¶
CBOR から JSON への変換器は、相互運用性を最大化し、 JSON 出力が予測可能な結果で処理できるという信頼性を高めるために、 JSON プロファイル I-JSON [RFC7493] に 従いたい場合がある。たとえば、これは確実に表現できる整数の範囲や、 古い JSON 実装がサポートし得るトップレベル項目に影響する。¶
すべての JSON 値は、いったん復号されると、1 つ以上の CBOR 値へ直接対応付けられる。他のあらゆる CBOR 生成と同様に、 数値表現に関して判断を行う必要がある。提案される 変換では、次のとおりである。¶
CBOR は一般に JSON よりもコンパクトな符号化を提供するよう 設計されている。思い浮かぶ可能性のある一つの実装戦略は、 単一のバッファ内で JSON から CBOR への符号化をインプレースで行うことである。 この戦略では、いくつかの病的なケースを慎重に考慮する必要がある。 たとえば、エスケープがないか非常に少ない状態で表現され、255 バイトより長い (またははるかに長い)一部の文字列は、CBOR で UTF-8 文字列として 符号化されると拡大する可能性がある。同様に、一部の短い JSON の十進表現(1.1、1e9)から、いくつかの二進浮動小数点表現が 拡大を引き起こす可能性がある。これを正しく行うことは難しい場合があり、 結果として生じる脆弱性は攻撃者に悪用され得る。¶
成功したプロトコルは時間とともに発展する。新しいアイデアが現れ、 実装プラットフォームが改善され、関連プロトコルが開発されて 発展し、アプリケーションおよびプロトコルからの新しい要件が 追加される。したがって、プロトコルの発展を促進することは、 どのようなプロトコル開発においても重要な設計上の考慮事項である。¶
CBOR を使用するプロトコルに対して、CBOR はその発展を促進するための いくつかの有用な機構を提供する。このためのベストプラクティスは、 特に JSON ベースのプロトコルの JSON 形式開発からよく知られている。 したがって、そのようなベストプラクティスは本仕様の範囲外である。¶
しかし、CBOR 自体の発展を促進することは、その範囲内に十分にある。 CBOR は、CBOR ベースのプロトコル開発のための安定した基盤を提供し、 かつ発展できるように設計されている。成功したプロトコルは何十年も存続し得るため、 CBOR は何十年にもわたる使用と発展に備えて設計される必要がある。 本セクションは、CBOR の発展に関するいくつかの指針を提供する。 それは、本文書の他の部分よりも必然的に主観的である。 また、プロトコル開発の教科書になってしまわないよう、必然的に不完全でもある。¶
プロトコル設計では、発展の機会が拡張ポイントの形で 含まれることが多い。たとえば、最初から完全には割り当てられていない コードポイント空間が存在し、プロトコルが、当初割り当てられた数よりも多くの コードポイントを使用し始める実装を許容し、受け入れるように設計されることがある。¶
必要な範囲を予測することが難しい場合があるため、 コードポイント空間のサイズ決定は難しい場合がある。プロトコル設計は、 プロトコルの意図された寿命の間にゆっくり埋められるよう、 コードポイント空間を十分に大きくすることを試みるべきである。¶
CBOR には 3 つの主要な拡張ポイントがある。¶
人間の心は、何かを整然とさせるために、認識された小さな隙間を 埋めようと引き寄せられることがある。追加情報値のコードポイント空間に残された隙間は、 そこにあるというだけで、新しいアイデアを引き寄せるものになると予想される。¶
現在の仕様は、追加情報コードポイント空間を IANA レジストリで 管理しない。その代わり、この空間からの割り当ては、 本仕様を更新することによってのみ行える。¶
n >= 24 の追加情報値については、追加データのサイズは通常 2n-24 バイトである。したがって、追加情報値 28 および 29 は、 それらをプロトコルに追加する必要が生じた場合に備えて、 128 ビットおよび 256 ビット量の候補と見なすべきである。 追加情報値 30 は、一般割り当てに利用可能な唯一の追加情報値となるため、 現在の仕様の更新を通じて割り当てる前に、それを割り当てる非常に正当な理由が あるべきである。¶
CBOR はバイナリ交換形式である。文書化およびデバッグを容易にし、 特にデバッグで協力するエンティティ間の通信を容易にするため、 本セクションは単純で人間が読める診断表記を定義する。 実際の交換は常にバイナリ形式で行われる。¶
これは本当に診断形式であり、解析されることを意図していない点に 注意する。したがって、本書では(ABNF のような)形式的定義は与えない。 (設定ファイル内で CBOR データ項目を表現するためのテキストベース形式を探している 実装者は、YAML [YAML] も 検討したい場合がある。)¶
診断表記は、RFC 8259 で定義される JSON に大まかに基づき、 必要に応じてそれを拡張している。¶
この表記は、数値(整数および浮動小数点)、True(>true<)、 False(>false<)、Null(>null<)、UTF-8 文字列、配列、 およびマップについて JSON 構文を借用する (マップは JSON ではオブジェクトと呼ばれる。診断表記はここで、 キー位置に任意のデータ項目を許可することにより JSON を拡張する)。 Undefined は JavaScript と同様に >undefined< と書かれる。 非有限浮動小数点数 Infinity、-Infinity、および NaN は、 この文中とまったく同じように書かれる(これは JavaScript で書くことができる方法でもあるが、 JSON はそれらを許可しない)。タグは、タグ番号の整数値として書かれ、 その後に括弧内のタグ内容が続く。たとえば、RFC 3339(ISO 8601)で指定される形式の日付は、 次のように表記できる。¶
0("2013-03-21T20:04:00Z")¶
または、等価な相対時刻は次のようになる。¶
1(1363896240)¶
バイト文字列は、いずれかの base 符号化で、パディングなしで、 単一引用符で囲まれ、base16 には >h<、base32 には >b32<、 base32hex には >h32<、base64 または base64url には >b64< を 接頭する形で表記される(実際の符号化は重ならないため、 文字列は曖昧でないままである)。たとえば、バイト文字列 0x12345678 は、 h'12345678'、b32'CI2FM6A'、または b64'EjRWeA' と書くことができる。¶
未割り当ての単純値は、括弧内に適切な整数を入れた "simple()" として与えられる。たとえば、"simple(42)" は メジャー型 7、値 42 を示す。¶
ここで定義された診断表記への有用な拡張の多くは、 [RFC8610] の付録 G「Extended Diagnostic Notation」 (EDN)で提供されている。 同様に、本書で扱われていない NaN ペイロードに関する文書化を提供するために、 この表記は別文書で拡張され得る。¶
複数の代替表現のうちどれが実際に使用されたかを 診断表記で示すことが有用な場合がある。たとえば、 診断デコーダによって >1.5< と書かれたデータ項目は、 半精度、単精度、または倍精度浮動小数点数として符号化されていた可能性がある。¶
符号化インジケータの規約は、アンダースコアで始まり、
それに続く英数字またはアンダースコアであるすべての文字からなるものは
符号化インジケータであり、この情報に関心のない者は無視できる、というものである。
たとえば、_ または _3 である。
符号化インジケータは常に任意である。¶
マップの開始中括弧または配列の開始角括弧の後に単一の アンダースコアを書くことで、そのデータ項目が不定長形式で 表現されたことを示せる。たとえば、[_ 1, 2] は、 データ項目 [1, 2] を表現するために不定長表現が使用されたことを示す インジケータを含む。¶
アンダースコアに十進数字 n が続くものは、 先行する項目(または配列およびマップの場合は、先行する角括弧または 中括弧で始まる項目)が追加情報値 24+n で符号化されたことを示す。 たとえば、1.5_1 は半精度浮動小数点数であり、 1.5_3 は倍精度として符号化されている。この符号化インジケータは 付録 A には示されていない。 (符号化インジケータ "_" は、したがって使用されない完全形 "_7" の 省略形であることに注意する。)¶
不定長のバイト文字列およびテキスト文字列の詳細なチャンク構造は、 (_ h'0123', h'4567') および (_ "foo", "bar") の形で 表記できる。しかし、内部にチャンクを持たない不定長文字列については、 (_ ) はバイト文字列(0x5fff)を意味するのか、テキスト文字列 (0x7fff)を意味するのかが曖昧であるため、使用されない。 代わりに基本形 ''_ および ""_ を使用でき、これらはチャンクがない場合だけのために 予約されている。これは、空チャンクだけを持つ(許可されているが 実際には有用ではない)符号化の短縮形ではない。そのようなものは、 チャンク構造を保持するために (_ '')、(_ "") などとして 表記する必要がある。¶
IANA は新しい CBOR 値のために 2 つのレジストリを作成した。 これらのレジストリは別個であり、すなわち包括的なレジストリの下にはなく、 [RFC8126] の規則に従う。 IANA はまた、新しいメディア型、関連する CoAP Content-Format エントリ、 および構造化構文接尾辞を割り当てた。¶
IANA は [IANA.cbor-simple-values] に "Concise Binary Object Representation (CBOR) Simple Values" レジストリを 作成した。初期値は 表 4 に示されている。¶
範囲 0 から 19 の新しいエントリは Standards Action によって 割り当てられる。 [RFC8126]。 連続したブロック(もしあれば)のために下位番号を予約するため、 IANA が番号 16 から始めて値を割り当てることが提案される。¶
範囲 32 から 255 の新しいエントリは Specification Required によって割り当てられる。¶
単一の符号化 CBOR データ項目に対するインターネットメディア型 [RFC6838](「MIME 型」)は、 "Media Types" レジストリ [IANA.media-types] で 定義される "application/cbor" である。¶
CBOR 用の CoAP Content-Format は、 "Constrained RESTful Environments (CoRE) Parameters" レジストリ [IANA.core-parameters] 内の "CoAP Content-Formats" サブレジストリに登録されている。¶
単一の符号化 CBOR データ項目に基づくメディア型のための 構造化構文接尾辞 [RFC6838] は +cbor であり、IANA はこれを "Structured Syntax Suffixes" レジストリ [IANA.structured-suffix] に登録している。¶
+cbor に対して指定されるフラグメント識別子の構文およびセマンティクスは、 "application/cbor" に対して指定されるものと同じであるべきである (SHOULD)。(RFC 8949 の公開時点で、 "application/cbor" に対して定義されたフラグメント識別構文は存在しない。)¶
特定の "xxx/yyy+cbor" に対するフラグメント識別子の 構文およびセマンティクスは、次のように処理されるべきである (SHOULD)。¶
ネットワークに面したアプリケーションは、受信データに対する 処理ロジックに脆弱性を示す可能性がある。複雑なパーサは、 ノードをリモートからクラッシュさせる能力、さらにはその上で任意のコードを リモートから実行する能力など、そのような脆弱性の発生源となりやすいことが よく知られている。CBOR は、パーサの複雑さを低減し、可能な場合には 符号化可能な値の全範囲に意味を与えることで、そのような脆弱性を 導入する機会を狭めようとする。¶
CBOR デコーダは、検証されていない入力を処理する最初の段階として 使用されることが多いため、CBOR データ項目を復号するシステムを破損させたり、 オーバーランさせたり、制御を奪取したりするように設計され得る、あらゆる種類の 敵対的入力に対して十分に備えておく必要がある。CBOR デコーダは、 入力がファイアウォールによって検査されている場合、TLS などの安全なチャネルを通ってきた場合、 暗号化または署名されている場合、 または信頼されると推定される他の情報源から来た場合であっても、 すべての入力が敵対的であり得ると仮定する必要がある。¶
セクション 4.1 は、 非優先シリアライゼーションを使用する CBOR エンコーダからの入力を、 制約された CBOR デコーダで使用する場合の相互運用性の制限例を示す。 単一のデータ項目が、そのような制約されたデコーダと完全なデコーダの両方によって 消費される場合、コンテンツを注入または操作できる攻撃者に悪用され得る セキュリティ問題につながる可能性がある。¶
本文書全体で論じているように、ある状況では「等価」とみなされ、 別の状況では「等価でない」とみなされ得る値が多数存在する。 一例を挙げるだけでも、数値「one」の数値は整数または bignum として 表現される可能性がある。CBOR 入力を解釈するシステムは、数値「one」について どちらの形式も受け入れるか、一方(または両方)の形式を拒否するかもしれない。 そのような受け入れまたは拒否は、解釈された入力を使用するプログラムに セキュリティ上の影響を及ぼす可能性がある。¶
敵対的入力は、バッファをオーバーランさせたり、 整数演算をオーバーフローまたはアンダーフローさせたり、その他の復号の妨害を 引き起こしたりするように構築される可能性がある。CBOR データ項目には、意図的に極端に大きい、または短すぎる長さやサイズが 含まれることがある。 リソース枯渇攻撃は、デコーダを誘導して非常に大きなデータ項目 (文字列、配列、マップ、さらには任意精度数)を割り当てさせたり、 深く入れ子になった項目を設定してスタック深度を使い果たさせたりしようとする可能性がある。 デコーダは、これらの攻撃を緩和するための適切なリソース管理を持つ必要がある。 (非常に大きなサイズが与えられた項目は、整数オーバーフロー脆弱性を 悪用しようとすることもある。)¶
CBOR デコーダは、定義上、整形式の CBOR だけを受け入れる。 これは堅牢性への第一歩である。整形式の CBOR でない入力は、 整形式性の欠如が検出された時点以降、さらなる処理を引き起こさない。 可能であれば、この時点までに復号されたデータは、CBOR デコーダを使用する アプリケーションに影響を与えるべきではない。¶
整形式性を確認することに加えて、CBOR デコーダは CBOR データに対して 妥当性検査を実行することもある。あるいは、それらの検査を デコーダを使用するアプリケーションに委ねることもできる。この選択は デコーダで明確に文書化される必要がある。CBOR レベルでの妥当性を超えて、 アプリケーションは、入力が CBOR でシリアライズされたアプリケーションプロトコルと 整合していることも確認する必要がある。¶
入力検査自体がリソースを消費する場合がある。これは通常、入力のサイズに 対して線形であり、攻撃者は入力検証で防御側が費やすリソースに見合うリソースを 費やさなければならないことを意味する。 しかし、攻撃者は、標的のデコーダが処理するのに、攻撃者が生成するよりも 長い時間がかかる入力を作成できる可能性がある。 任意精度数の処理は線形の労力を超えることがある。また、デコーダがマップの メモリ内表現を構築するために使用する一部のハッシュテーブル実装は、 秘密鍵([SIPHASH_LNCS] のセクション 7、 および [SIPHASH_OPEN] を参照)または 何らかの他の緩和策が用いられない限り、二次的な労力を費やすよう攻撃され得る。 このような超線形の労力は、攻撃者によって入力検証器の時点またはそれ以前で リソースを枯渇させるために悪用され得る。したがって、CBOR デコーダ実装では これらを避ける必要がある。タグ番号の定義とその実装は、この種の セキュリティに関する考慮事項を追加し得ることに注意する。この場合、それは タグ番号定義のセキュリティに関する考慮事項で論じられるべきである。¶
CBOR エンコーダはネットワークから直接入力を受け取らないため、 CBOR デコーダと同じ方法で直接攻撃されるわけではない。 しかし、CBOR エンコーダは、実装内の別のレベルから入力を受け取る API を 持つことが多く、その API を通じて攻撃され得る。その API の設計および実装は、 その呼び出し元の挙動が敵対的入力またはコーディングミスに基づく可能性があると 仮定すべきである。バッファオーバーラン、整数演算のオーバーフローおよび アンダーフロー、ならびにエンコーダを妨害することを狙ったその他のそのような エラーについて、入力を検査すべきである。¶
プロトコルは、潜在的な複数の解釈が信頼できる形で 単一の解釈へ減らされるように定義されるべきである。たとえば、攻撃者は マップ内の重複キーなどの無効な入力を利用したり、数値処理における 精度の違いを悪用したりして、あるアプリケーションが、2 番目のアプリケーションで 使用される解釈とは異なる解釈に基づいて判断するようにできる可能性がある。 一貫した解釈を容易にするために、エンコーダおよびデコーダ実装は 妥当性検査モードの動作を提供すべきである (セクション 5.4)。 ただし、汎用デコーダは、アプリケーションが入力データに課すすべての要件を 知ることはできないことに注意する。したがって、アプリケーションが独自の 入力検査を実行する責任を免除するものではない。また、定義済みタグ番号の集合は 発展するため、アプリケーションは、使用している汎用デコーダがまだ妥当性検査を サポートしていないタグ番号を用いる場合がある。したがって、汎用デコーダは、 どのタグ番号をサポートし、それらのタグ番号および基本 CBOR (UTF-8 検査、重複マップキー検査)に対してどの妥当性検査を提供するかを 文書化する必要がある。¶
セクション 3.4.3 は、 数値を符号化するために基本整数ではなく bignum 表現という非優先の選択を用いることは、 アプリケーションセマンティクスを持つことを意図していないと述べている。 しかし、CBOR データを受け取るアプリケーションが基本汎用データモデルのデコーダを 使用している場合、それはそのようなセマンティクスを持つことがある。この不一致は、 2 つのセマンティクス集合が異なる場合にセキュリティ問題を引き起こす。 したがって、CBOR を使用するアプリケーションは、CBOR データの各使用に対して 使用するデータモデルを指定する必要がある。¶
CBOR データを他の形式に変換することは一般的である。多くの場合、 CBOR は他の形式よりも表現力のある型を持つ。これは JSON への一般的な変換で 特に当てはまる。型情報の喪失は、表現力の低いデータを処理するシステムに セキュリティ問題を引き起こす可能性がある。¶
セクション 6.2 は、 攻撃者がアプリケーションがその変換を実行していることを知っている場合に 攻撃を可能にし得る、CBOR と JSON の間で変換する一般的であり得る 使用シナリオを説明している。¶
[RFC4648] の base16 および base64 の使用、 ならびに [RFC3629] の UTF-8 の使用に関する セキュリティ上の考慮事項は、CBOR にも関連する。¶
次の表は、これらの値に対する診断表記(左列)とともに、 16 進数での CBOR 符号化値(右列)をいくつか示す。 文字列 "\u00fc" は、単一の Unicode 文字 U+00FC(LATIN SMALL LETTER U WITH DIAERESIS, "ü") を含む UTF-8 文字列に対する診断表記の 一形式であることに注意する。同様に、"\u6c34" は、 単一の文字 U+6C34(CJK UNIFIED IDEOGRAPH-6C34, "水") を持つ診断表記における UTF-8 文字列であり、 しばしば「water」を表す。また、"\ud800\udd51" は、 単一の文字 U+10151(GREEK ACROPHONIC ATTIC FIFTY STATERS, "𐅑") を持つ診断表記における UTF-8 文字列である。 (これらすべての単一文字文字列は、ASCII のみの仕様が必要でないなら、 診断表記でネイティブ UTF-8 として表現することもできる点に注意する。) bignum に対して提供される診断表記では、それらの意図された数値が、 タグ付きバイト文字列(2(h'010000000000000000') など)ではなく、 10 進数(18446744073709551616 など)として示される。¶
| 診断表記 | 符号化 |
|---|---|
| 0 | 0x00 |
| 1 | 0x01 |
| 10 | 0x0a |
| 23 | 0x17 |
| 24 | 0x1818 |
| 25 | 0x1819 |
| 100 | 0x1864 |
| 1000 | 0x1903e8 |
| 1000000 | 0x1a000f4240 |
| 1000000000000 | 0x1b000000e8d4a51000 |
| 18446744073709551615 | 0x1bffffffffffffffff |
| 18446744073709551616 | 0xc249010000000000000000 |
| -18446744073709551616 | 0x3bffffffffffffffff |
| -18446744073709551617 | 0xc349010000000000000000 |
| -1 | 0x20 |
| -10 | 0x29 |
| -100 | 0x3863 |
| -1000 | 0x3903e7 |
| 0.0 | 0xf90000 |
| -0.0 | 0xf98000 |
| 1.0 | 0xf93c00 |
| 1.1 | 0xfb3ff199999999999a |
| 1.5 | 0xf93e00 |
| 65504.0 | 0xf97bff |
| 100000.0 | 0xfa47c35000 |
| 3.4028234663852886e+38 | 0xfa7f7fffff |
| 1.0e+300 | 0xfb7e37e43c8800759c |
| 5.960464477539063e-8 | 0xf90001 |
| 0.00006103515625 | 0xf90400 |
| -4.0 | 0xf9c400 |
| -4.1 | 0xfbc010666666666666 |
| Infinity | 0xf97c00 |
| NaN | 0xf97e00 |
| -Infinity | 0xf9fc00 |
| Infinity | 0xfa7f800000 |
| NaN | 0xfa7fc00000 |
| -Infinity | 0xfaff800000 |
| Infinity | 0xfb7ff0000000000000 |
| NaN | 0xfb7ff8000000000000 |
| -Infinity | 0xfbfff0000000000000 |
| false | 0xf4 |
| true | 0xf5 |
| null | 0xf6 |
| undefined | 0xf7 |
| simple(16) | 0xf0 |
| simple(255) | 0xf8ff |
| 0("2013-03-21T20:04:00Z") | 0xc074323031332d30332d32315432303a 30343a30305a |
| 1(1363896240) | 0xc11a514b67b0 |
| 1(1363896240.5) | 0xc1fb41d452d9ec200000 |
| 23(h'01020304') | 0xd74401020304 |
| 24(h'6449455446') | 0xd818456449455446 |
| 32("http://www.example.com") | 0xd82076687474703a2f2f7777772e6578 616d706c652e636f6d |
| h'' | 0x40 |
| h'01020304' | 0x4401020304 |
| "" | 0x60 |
| "a" | 0x6161 |
| "IETF" | 0x6449455446 |
| "\"\\" | 0x62225c |
| "\u00fc" | 0x62c3bc |
| "\u6c34" | 0x63e6b0b4 |
| "\ud800\udd51" | 0x64f0908591 |
| [] | 0x80 |
| [1, 2, 3] | 0x83010203 |
| [1, [2, 3], [4, 5]] | 0x8301820203820405 |
| [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25] | 0x98190102030405060708090a0b0c0d0e 0f101112131415161718181819 |
| {} | 0xa0 |
| {1: 2, 3: 4} | 0xa201020304 |
| {"a": 1, "b": [2, 3]} | 0xa26161016162820203 |
| ["a", {"b": "c"}] | 0x826161a161626163 |
| {"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"} | 0xa5616161416162614261636143616461 4461656145 |
| (_ h'0102', h'030405') | 0x5f42010243030405ff |
| (_ "strea", "ming") | 0x7f657374726561646d696e67ff |
| [_ ] | 0x9fff |
| [_ 1, [2, 3], [_ 4, 5]] | 0x9f018202039f0405ffff |
| [_ 1, [2, 3], [4, 5]] | 0x9f01820203820405ff |
| [1, [2, 3], [_ 4, 5]] | 0x83018202039f0405ff |
| [1, [_ 2, 3], [4, 5]] | 0x83019f0203ff820405 |
| [_ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25] | 0x9f0102030405060708090a0b0c0d0e0f 101112131415161718181819ff |
| {_ "a": 1, "b": [_ 2, 3]} | 0xbf61610161629f0203ffff |
| ["a", {_ "b": "c"}] | 0x826161bf61626163ff |
| {_ "Fun": true, "Amt": -2} | 0xbf6346756ef563416d7421ff |
簡潔にするため、このジャンプ表は、将来の拡張のために 予約されている初期バイトを示していない。また、任意機能に使用できる 初期バイトについても一部のみを示している。(すべての 符号なし整数はネットワークバイト順である。)¶
| バイト | 構造/セマンティクス |
|---|---|
| 0x00..0x17 | 符号なし整数 0x00..0x17 (0..23) |
| 0x18 | 符号なし整数(1 バイト uint8_t が続く) |
| 0x19 | 符号なし整数(2 バイト uint16_t が続く) |
| 0x1a | 符号なし整数(4 バイト uint32_t が続く) |
| 0x1b | 符号なし整数(8 バイト uint64_t が続く) |
| 0x20..0x37 | 負の整数 -1-0x00..-1-0x17 (-1..-24) |
| 0x38 | 負の整数 -1-n(n 用の 1 バイト uint8_t が続く) |
| 0x39 | 負の整数 -1-n(n 用の 2 バイト uint16_t が続く) |
| 0x3a | 負の整数 -1-n(n 用の 4 バイト uint32_t が続く) |
| 0x3b | 負の整数 -1-n(n 用の 8 バイト uint64_t が続く) |
| 0x40..0x57 | バイト文字列(0x00..0x17 バイトが続く) |
| 0x58 | バイト文字列(n 用の 1 バイト uint8_t、 その後に n バイトが続く) |
| 0x59 | バイト文字列(n 用の 2 バイト uint16_t、 その後に n バイトが続く) |
| 0x5a | バイト文字列(n 用の 4 バイト uint32_t、 その後に n バイトが続く) |
| 0x5b | バイト文字列(n 用の 8 バイト uint64_t、 その後に n バイトが続く) |
| 0x5f | バイト文字列、バイト文字列が続き、 "break" で終了する |
| 0x60..0x77 | UTF-8 文字列(0x00..0x17 バイトが続く) |
| 0x78 | UTF-8 文字列(n 用の 1 バイト uint8_t、 その後に n バイトが続く) |
| 0x79 | UTF-8 文字列(n 用の 2 バイト uint16_t、 その後に n バイトが続く) |
| 0x7a | UTF-8 文字列(n 用の 4 バイト uint32_t、 その後に n バイトが続く) |
| 0x7b | UTF-8 文字列(n 用の 8 バイト uint64_t、 その後に n バイトが続く) |
| 0x7f | UTF-8 文字列、UTF-8 文字列が続き、 "break" で終了する |
| 0x80..0x97 | 配列(0x00..0x17 個のデータ項目が続く) |
| 0x98 | 配列(n 用の 1 バイト uint8_t、その後に n 個のデータ項目が続く) |
| 0x99 | 配列(n 用の 2 バイト uint16_t、その後に n 個のデータ項目が続く) |
| 0x9a | 配列(n 用の 4 バイト uint32_t、その後に n 個のデータ項目が続く) |
| 0x9b | 配列(n 用の 8 バイト uint64_t、その後に n 個のデータ項目が続く) |
| 0x9f | 配列、データ項目が続き、"break" で 終了する |
| 0xa0..0xb7 | マップ(0x00..0x17 対のデータ項目が続く) |
| 0xb8 | マップ(n 用の 1 バイト uint8_t、その後に n 対のデータ項目が続く) |
| 0xb9 | マップ(n 用の 2 バイト uint16_t、その後に n 対のデータ項目が続く) |
| 0xba | マップ(n 用の 4 バイト uint32_t、その後に n 対のデータ項目が続く) |
| 0xbb | マップ(n 用の 8 バイト uint64_t、その後に n 対のデータ項目が続く) |
| 0xbf | マップ、データ項目のペアが続き、 "break" で終了する |
| 0xc0 | テキストベースの日時(データ項目が続く。 セクション 3.4.1 を参照) |
| 0xc1 | エポックベースの日時(データ項目が続く。 セクション 3.4.2 を参照) |
| 0xc2 | 符号なし bignum(データ項目 "byte string" が続く) |
| 0xc3 | 負の bignum(データ項目 "byte string" が続く) |
| 0xc4 | 十進小数(データ項目 "array" が続く。 セクション 3.4.4 を参照) |
| 0xc5 | bigfloat(データ項目 "array" が続く。セクション 3.4.4 を参照) |
| 0xc6..0xd4 | (タグ) |
| 0xd5..0xd7 | 想定変換(データ項目が続く。セクション 3.4.5.2 を参照) |
| 0xd8..0xdb | (追加のタグ。タグ番号の 1/2/4/8 バイトと その後にデータ項目が続く) |
| 0xe0..0xf3 | (単純値) |
| 0xf4 | false |
| 0xf5 | true |
| 0xf6 | null |
| 0xf7 | undefined |
| 0xf8 | (単純値、1 バイトが続く) |
| 0xf9 | 半精度浮動小数点数(2 バイト IEEE 754) |
| 0xfa | 単精度浮動小数点数(4 バイト IEEE 754) |
| 0xfb | 倍精度浮動小数点数(8 バイト IEEE 754) |
| 0xff | "break" 停止コード |
CBOR 項目の整形式性は、 図 1 の擬似コードで検査できる。データが整形式であるための 必要十分条件は次のとおりである。¶
この擬似コードには次の前提条件がある。¶
well_formed は、整形式の定長項目については
メジャー型を返すが、不定長項目については 99 を返す(または、
breakable が設定されている場合に限り、"break" 停止コードについて
-1 を返す)ことに注意する。これは well_formed_indefinite で、
不定長文字列がチャンクとして定長文字列のみを含むことを確認するために使用される。¶
well_formed(breakable = false) {
// 初期バイトを処理する
ib = uint(take(1));
mt = ib >> 5;
val = ai = ib & 0x1f;
switch (ai) {
case 24: val = uint(take(1)); break;
case 25: val = uint(take(2)); break;
case 26: val = uint(take(4)); break;
case 27: val = uint(take(8)); break;
case 28: case 29: case 30: fail();
case 31:
return well_formed_indefinite(mt, breakable);
}
// 内容を処理する
switch (mt) {
// case 0, 1, 7 には内容がない。val だけを使用する
case 2: case 3: take(val); break; // bytes/UTF-8
case 4: for (i = 0; i < val; i++) well_formed(); break;
case 5: for (i = 0; i < val*2; i++) well_formed(); break;
case 6: well_formed(); break; // 1 個の埋め込みデータ項目
case 7: if (ai == 24 && val < 32) fail(); // 不正な simple
}
return mt; // 定長データ項目
}
well_formed_indefinite(mt, breakable) {
switch (mt) {
case 2: case 3:
while ((it = well_formed(true)) != -1)
if (it != mt) // 定長チャンクが必要
fail(); // 同じ型のもの
break;
case 4: while (well_formed(true) != -1); break;
case 5: while (well_formed(true) != -1) well_formed(); break;
case 7:
if (breakable)
return -1; // break out を通知する
else fail(); // 囲む不定長項目がない
default: fail(); // 誤った mt
}
return 99; // 不定長データ項目
}
完全な CBOR デコーダの残りの複雑さは、 復号されたデータを適切な形式でアプリケーションに提示することに関するものである点に 注意する。¶
メジャー型 0 および 1 は、正/負に対して実際に if-then-else を行わなくても、符号付き整数から C で符号化できるように 設計されている(図 2)。これは、 メジャー型 1 の変換である (-1-n) が、C の符号なし算術における ~n(ビット単位の補数)と同じであるという事実を用いる。すると ~n は、 負の場合には (-1)^n として表現でき、非負の場合には 0^n が n を 変更しないままにする。数値の符号は、その数値のビット長より 1 ビット少ない数だけ 算術シフトすることにより、負の場合は -1、非負(0 または正)の場合は 0 に変換できる(たとえば、64 ビット数の場合は 63 だけシフトする)。¶
void encode_sint(int64_t n) {
uint64t ui = n >> 63; // 符号を全長に拡張する
unsigned mt = ui & 0x20; // (シフト済みの)メジャー型を取り出す
ui ^= n; // 負数を補数にする
if (ui < 24)
*p++ = mt + ui;
else if (ui < 256) {
*p++ = mt + 24;
*p++ = ui;
} else
...
これらのコード片で使用される C 言語のプロファイルに関する いくつかの具体的な仮定については、セクション 1.2 を参照。¶
半精度浮動小数点数は 2008 年に IEEE 754 に追加されたばかりであるため [IEEE754]、今日のプログラミングプラットフォームでは それらのサポートがまだ限定的であることが多い。 そのようなサポートがなくても、少なくとも復号サポートを含めることは非常に容易である。 C 言語による半精度浮動小数点数の小さなデコーダの例を 図 3 に示す。Python 用の同様のプログラムは 図 4 にあり、このコードは、その 2 バイト値が すでにネットワークバイト順の(符号なし short)整数として復号されていることを仮定する (付録 C の擬似コードによって行われるのと同様である)。¶
#include <math.h>
double decode_half(unsigned char *halfp) {
unsigned half = (halfp[0] << 8) + halfp[1];
unsigned exp = (half >> 10) & 0x1f;
unsigned mant = half & 0x3ff;
double val;
if (exp == 0) val = ldexp(mant, -24);
else if (exp != 31) val = ldexp(mant + 1024, exp - 25);
else val = mant == 0 ? INFINITY : NAN;
return half & 0x8000 ? -val : val;
}
import struct
from math import ldexp
def decode_single(single):
return struct.unpack("!f", struct.pack("!I", single))[0]
def decode_half(half):
valu = (half & 0x7fff) << 13 | (half & 0x8000) << 16
if ((half & 0x7c00) != 0x7c00):
return ldexp(decode_single(valu), 112)
return decode_single(valu | 0x7f800000)
CBOR の提案は、コンピュータそのものの歴史と同じくらい 長いバイナリ形式の歴史に沿うものである。異なる形式には 異なる目的があった。ほとんどの場合、その形式の目的は 明示されていなかったが、形式が最初に使用された文脈から推測できることもある。 一部の形式は汎用的に使用できることを意図していたが、歴史が示すように、 すべてのプロトコルおよびアプリケーションの需要を満たすバイナリ形式は存在しない。¶
CBOR は、一連の目的から出発し、それらだけを満たそうとする点で、 これらの形式の多くとは異なる。本セクションは、読者が特定のプロトコルまたは アプリケーションに CBOR を使用するか、それとも別の形式を使用するかを判断しやすくするため、 数十ある形式のうちいくつかを CBOR の目的と比較する。¶
ここでの議論は、どの形式に対する批判を意図したものでもない点に注意する。 我々の知る限り、CBOR 以前には、我々が割り当てた優先順位で CBOR の目的を カバーすることを意図した形式はなかった。セクション 1.1 の 目的を簡潔にまとめると次のとおりである。¶
異なる設計目的の集合に関して CBOR と他の形式を論じたものは、 [RFC8618] のセクション 5 および付録 C で提供されている。¶
[ASN.1] には多くの シリアライゼーションがある。IETF では、DER と BER が 最も一般的である。シリアライズされた出力は、多くの項目について 特にコンパクトではなく、数値項目を復号するために必要なコードは、 制約デバイス上では複雑になる場合がある。¶
Packed Encoding Rules(PER)のいくつかの変種のうち一つを 採用した IETF プロトコルは、ほとんど(あるとしても)存在しない。 これには多くの理由があり得るが、よく述べられる理由の一つは、 PER がデータ項目の表面構造の解析にさえスキーマを利用するため、 重要なツールサポートを必要とすることである。使用されている ASN.1 スキーマ言語には異なるバージョンがあり、それも採用を妨げてきた。¶
[MessagePack] は、 簡潔で、広く実装されているカウント付きバイナリ シリアライゼーション形式であり、多くの性質で CBOR に似ているが、 やや規則性が低い。データモデルは JSON データを表現するために使用できる一方で、 MessagePack は多くのリモートプロシージャコール(RPC)アプリケーションや データの長期保存にも使用されてきた。¶
MessagePack は 2011 年ごろに最初に公開されて以来、 本質的に安定している。まだ移行は行われていない。MessagePack の発展は、 既存の保存データとの完全な後方互換性を維持しなければならないという命令と、 拡張に利用できるバイトコードがわずかしか残っていないことによって妨げられている。 MessagePack ユーザーコミュニティから長年にわたり、符号化において バイナリ文字列とテキスト文字列を分離するよう繰り返し要求された結果、 最近では、MessagePack の "raw" データをバイナリデータとテキストデータの 用途の間で曖昧なままにする拡張提案につながった。MessagePack の拡張機構は 依然として不明確である。¶
[BSON] は、 MongoDB データベースにおける JSON 風のマップ(JSON オブジェクト)の 保存のために開発されたデータ形式である。その主な特徴は、 インプレース更新の能力であり、これはコンパクトな表現を妨げる。 BSON はマップキーを除いてカウント付き表現を使用し、マップキーは null バイトで終端される。BSON は JSON 風のオブジェクトをワイヤ上で 表現するために使用できるが、その仕様はデータベースアプリケーションの 要件に支配されており、ややバロック的になっている。BSON 拡張がどのように 実装されるかの状況は依然として不明確である。¶
Message Services Data Transmission(MSDTP)は、 コンパクトなメッセージ形式の非常に初期の例である。これは 1976 年に 書かれた [RFC0713] で説明されている。これは 歴史的価値のためにここに含めているのであり、広く使用されたからではない。¶
CBOR のエンコーダおよびデコーダのコードコンパクト性という 設計目的は、ワイヤ上での簡潔さという目的よりも優先順位が高いが、 多くの人はワイヤサイズに注目する。表 8 は、 単純な入れ子配列 [1, [2, 3]] の符号化例をいくつか示す。 不定長符号化の何らかの形式がその符号化でサポートされている場合は、 [_ 1, [2, 3]](外側の配列が不定長)も示されている。¶
| 形式 | [1, [2, 3]] | [_ 1, [2, 3]] |
|---|---|---|
| RFC 713 | c2 05 81 c2 02 82 83 | |
| ASN.1 BER | 30 0b 02 01 01 30 06 02 01 02 02 01 03 | 30 80 02 01 01 30 06 02 01 02 02 01 03 00 00 |
| MessagePack | 92 01 92 02 03 | |
| BSON | 22 00 00 00 10 30 00 01 00 00 00 04 31 00 13 00 00 00 10 30 00 02 00 00 00 10 31 00 03 00 00 00 00 00 | |
| CBOR | 82 01 82 02 03 | 9f 01 82 02 03 ff |
CBOR データ項目を復号する際に発生し得る整形式性エラーには、 基本的に 3 種類がある。¶
付録 C では、第 1 種のエラーは 最初の段落および箇条書き(「バイトが残っていない」ことを要求する)で扱われ、 第 2 種のエラーは第 2 の段落/箇条書き(「n バイトがもはや利用できない場合」に 失敗する)で扱われる。第 3 種のエラーは、擬似コードにおいて、次の順序で fail() を呼び出す具体的なインスタンスによって識別される。¶
このサブセクションは、整形式ではない CBOR データ項目の例を いくつか示す。各例はバイト列であり、それぞれ 16 進数で示される。 リスト内の複数の例はコンマで区切られる。¶
整形式性エラー第 1 種(データが多すぎる)の例は、 整形式の符号化済み CBOR データ項目にデータを追加することで容易に作成できる。¶
同様に、整形式性エラー第 2 種(データが少なすぎる)の例は、 整形式の符号化済み CBOR データ項目を切り詰めることで作成できる。 テストスイートでは、完了するために大量の追加を必要とする不完全なデータ項目 (たとえば、非常に大きなサイズの文字列の符号化を開始することによるもの)を 具体的にテストすると有益な場合がある。¶
入力の早すぎる終端は、ヘッド内、または囲まれたデータ内で 発生する可能性がある。囲まれたデータは、素の文字列である場合も、 カウント付きまたは "break" 停止コードで終了されるべきであった 囲まれたデータ項目である場合もある。¶
整形式性エラー第 3 種(構文エラー)の 5 つの下位種別について、 いくつかの例を以下に示す。¶
序論で論じたように、 本文書は RFC 7049 の交換形式との完全な互換性を維持しつつ、 RFC 7049 を正式に廃止する。本文書は、編集上の改善、詳細の追加、および 正誤表の修正を提供する。 本文書は、この形式の新しいバージョンを作成するものではない。¶
RFC 7049 に対する 2 つの検証済み正誤表、 [Err3764] および [Err3770] は、 本文中の 2 つの符号化例に関するものであり、修正された (セクション 3.4.3: "29" -> "49", セクション 5.5: "0b000_11101" -> "0b000_11001")。また、RFC 7049 には、単純値に数値 24 を使用する例 [Err5917] が 含まれていたが、これは整形式ではないため、この例は 削除された。正誤表報告 5763 [Err5763] は、 タグの定義の文言における誤りを指摘した。これは セクション 3.4 の書き換え中に解決された。 正誤表報告 5434 [Err5434] は、付録 E の Universal Binary JSON (UBJSON)の例が、正誤表報告提出時点で現行だった UBJSON のバージョンに もはや準拠していないことを指摘した。UBJSON 仕様は 2013 年以降完全に 変化していたことが判明したため、この例は削除された。その他の正誤表報告 [Err4409] [Err4963] [Err4964] は、標準的符号化のためのマップキーソート規則が 煩雑であると述べた。これにより、標準的符号化の提案が再考され、 (後述の)決定論的符号化の提案に置き換えられた。正誤表報告 4294 [Err4294] の編集上の提案も 実装された(セクション 3.2.2 の最後の例のコメントに "Second value" を追加して対称性を改善)。¶
その他の事務的変更には次が含まれる。¶
IANA に関する考慮事項は全般的に更新された(事務的変更、 たとえば現在は仕様の著者として CBOR Working Group を指している)。 それぞれの IANA レジストリへの参照が参考情報としての参考文献に 追加された。¶
"Concise Binary Object Representation (CBOR) Tags" レジストリ [IANA.cbor-tags] では、 256 から 32767("1+2" の下位半分)の空間にあるタグは、 もはや First Come First Served によって割り当てられない。この範囲は 現在 Specification Required である。¶
本文書の改訂中、正誤表報告への対処を超えて、 ワーキンググループは、多様なアプリケーションにおける CBOR の約 7 年間の経験を 活用した。これにより、説明のための表の追加を含む多くの編集上の変更だけでなく、 ある側面の強調と別の側面の弱調にもつながった。¶
重要な追加は セクション 2 であり、CBOR データモデルと、CBOR の処理に関わるその小さな変種を 論じている。これらの変種(基本汎用、拡張汎用、特定)に対する用語の導入は、 文書内の他の箇所でより簡潔な言語を可能にし、また実装および形式の拡張性機能に対する 期待を明確にする助けにもなる。¶
JSON エコシステムから派生した形式として、RFC 7049 は 当時 JavaScript から継承されていた JSON 数値システムの影響を受けていた。 JSON は、整数値と浮動小数点値を区別して提供しない (後者は形式上は十進である)。CBOR は数値のバイナリ表現を提供し、 それは整数値と浮動小数点値の間で異なる。実装および利用の経験から、 これら 2 つの数値領域の分離を本文書でより明確に描くべきであることが示唆された。 整数が浮動小数点値の代わりとしてシームレスに使用できることを示唆する文言は削除された。 また、JSON から CBOR へ変換する際のこれらの型の扱いについて、 (I-JSON [RFC7493] に基づく)提案が追加され、 特定の丸め機構の使用が推奨された。¶
データモデル内の単一の値について、CBOR はしばしば複数の 符号化オプションを提供する。新しいセクション(セクション 4)は、 「優先シリアライゼーション」(セクション 4.1)という用語を導入し、 さまざまな種類のデータ項目についてそれを定義する。この用語に基づいて、 同セクションは、CBOR ベースのプロトコルが "deterministic encoding"(セクション 4.2)をどのように 定義できるかを論じる。これは RFC 7049 の "canonical" および "canonicalization" という用語を避けるものである。 "Core Deterministic Encoding Requirements"(セクション 4.2.1) の提案は、そのようなプロトコル定義の符号化要件に対する汎用サポートを可能にする。 本文書はさらに、RFC 7049 で提案されたマップ順序付けを、符号化キーの単純な 辞書順序に簡素化することで、決定論的符号化の実装を容易にしている。 以前の提案の説明は代替として残され、現在は「長さ優先のマップキー順序付け」 (セクション 4.2.3)と呼ばれている。¶
整形式データおよび妥当なデータに関する用語は鋭くされ、 より厳密に使用されるようになった。例の外では、"syntax error"、 "decoding error"、"strict mode" など、より定義の曖昧な代替用語は避けられた。 また、アプリケーションが入力データに対して持つ、CBOR レベルの妥当性を超える 第 3 の要件レベルが明示的に示された。 整形式(そもそも処理可能)、妥当(妥当性検査を行う汎用デコーダで検査される)、 そして想定される入力(アプリケーションで検査される)は、 受け入れ可能性の階層として扱われる。¶
整形式ではない単純値の扱いは、本文と擬似コードで明確化された。 付録 F が追加され、整形式性エラーを論じ、 それらの例を提供している。擬似コードはより移植性の高いものに更新され、 いくつかの移植性に関する考慮事項が追加された。¶
妥当性の議論は 2 つの領域で鋭くされた。マップ妥当性 (重複キーの扱い)が明確化され、特定の実装選択の適用範囲が説明された。 また、タグ、タグ番号、およびタグ内容に関する用語を整理する中で、 タグ妥当性に関する議論が追加され、タグ内容に対する制限が、 一般的に、また特にタグ 1 について明確化された。¶
シリアライゼーション順序に依存するセマンティクスを持つタグを 定義することについて、実装上の注意(および将来のタグ定義のための注意)が セクション 3.4 に追加された。¶
タグ 35 は本文書によって定義されない。RFC 7049 の定義に基づく 登録はそのまま維持される。¶
セクション 3 では、 "argument" および "head" に関する用語が導入され、 その後の議論が簡素化された。¶
セキュリティに関する考慮事項(セクション 10)はほとんど書き換えられ、大幅に拡張された。その他の複数の箇所でも、 デコーダが整形式性エラーを単純に容認することはできないことが、本文書で より明示的に示されるようになった。¶
CBOR は MessagePack に着想を得た。MessagePack は Sadayuki Furuhashi("frsyuki")によって開発され、 推進された。MessagePack へのこの参照は帰属表示のみを目的としている。CBOR は、 MessagePack のバージョンまたは置換を意図したものではなく、異なる設計目的と 要件を持つ。¶
元の MessagePack 仕様を超える機能の必要性は、 2012 年ごろのほぼ同時期に多くの人々に明らかになった。 BinaryPack は、binaryjs プロジェクトのために Eric Zhang によって 開発された MessagePack の小さな派生である。同様だが異なる拡張が、 Tim Caswell によって彼の msgpack-js および msgpack-js-browser プロジェクトのために作成された。多くの人々が、 テキスト文字列表現とバイト文字列表現を分離するための MessagePack 拡張に関する 議論に貢献してきた。¶
CBOR における追加情報の符号化は、 Klaus Hartke が CoAP のために設計した長さ情報の符号化に 着想を得た。¶
本文書はまた、多くの人々による提案を取り込んでいる。 特に Dan Frost、James Manger、 Jeffrey Yasskin、Joe Hildebrand、 Keith Moore、Laurence Lundblade、 Matthew Lepinski、Michael Richardson、 Nico Williams、Peter Occil、 Phillip Hallam-Baker、Ray Polk、 Stuart Cheshire、Tim Bray、 Tony Finch、Tony Hansen、および Yaron Sheffer である。Benjamin Kaduk は IESG 処理中に広範なレビューを提供した。 Éric Vyncke、Erik Kline、 Robert Wilton、および Roman Danyliw は さらに IESG コメントを提供し、その中には Eve Schooler による IoT directorate レビューも含まれていた。¶