| RFC 8949 | CBOR | 2020年12月 |
| Bormann & Hoffman | 標準化過程 | [ページ] |
簡潔なバイナリオブジェクト表現 (CBOR) は、その設計 目標として、 コードサイズを極めて小さくできること、メッセージサイズをかなり小さくできること、および バージョンネゴシエーションを必要としない 拡張性を含むデータ形式です。これらの設計目標により、従来の ASN.1 や MessagePack などのバイナリ シリアライゼーションとは異なっています。¶
この文書は RFC 7049 を廃止し、編集上の改善、新しい 詳細、および正誤表の修正を提供しながら、 RFC 7049 の交換形式との完全な互換性を維持します。この形式の新しいバージョンを 作成するものではありません。¶
これはインターネット標準化過程の文書です。¶
この文書は Internet Engineering Task Force (IETF) の成果物です。これは IETF コミュニティの合意を表しています。これは 公開レビューを受け、Internet Engineering Steering Group (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 (not a number)、負のゼロ、および非正規数などの浮動小数点値に関する用語と概念は、[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 と同様に数値として解釈され、次に、 表記内に明示された先行ゼロバイトを含め、ネットワークバイトオーダーの バイト文字列として解釈されます。¶
強調のために単語をイタリック体にすることがあります。この仕様のプレーンテキスト
形式では、これは単語をアンダースコア文字で
囲むことで示されます。逐語的なテキスト(たとえば、プログラミング言語の
名前)は 等幅 書体で表示されることがあります。プレーン
テキストでは、二重引用符でテキストを囲むことにより、多少曖昧な形で
近似されます(二重引用符は通常の意味も保持します)。¶
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 の両方をキーとして持つことができます。また、エンコーダーは
0.0 を整数
(メジャータイプ 0、セクション 3.1)としてエンコードしてはなりません。しかし、固有データ
モデルが、整数値を持つ浮動小数点表現と整数表現が
等価であると宣言する場合、単一のマップ内でマップキー 0 と 0.0 の両方を使用すると、
異なるメジャータイプとしてエンコードされていても重複と見なされ、
したがって無効となります。また、エンコーダーはエンコードされたバイト数を節約するなどの目的で、
整数値を持つ浮動小数点数を整数として、またはその逆にエンコードできます。¶
CBOR データ項目(セクション 2)は、 このセクションで説明する整形式のエンコード済みデータ項目を保持する バイト文字列へエンコードされ、またはそこからデコードされます。エンコーディングは、 初期バイトによって索引付けされた 付録 B の 表 7 にまとめられています。エンコーダーは 整形式の エンコードされたデータ項目だけを生成しなければなりません。 デコーダーは、整形式のエンコードされた CBOR データ項目ではない入力に 遭遇した場合、デコードされたデータ項目を返してはなりません(これは、 破損したエンコード済み 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)を置いて表現します。 不定長文字列によって表されるデータ項目は、 各チャンクを連結したものです。チャンクが存在しない場合、データ項目は指定された型の空 文字列です。長さ 0 のチャンクは、特に 有用ではありませんが、許可されています。¶
不定長文字列標識 (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 は、 不定長エンコーディング(追加情報を 31 に設定)に使用される CBOR のメジャータイプを まとめたものです。¶
| メジャータイプ | 意味 | 「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 は、 単純値に割り当てられ、また利用可能な数値を 列挙します。¶
エンコーダーは、0xf8(メジャータイプ 7、追加情報 24)で始まり、
0x20(10進数の 32)未満のバイトが続く 2 バイト列を
発行してはなりません。このようなシーケンスは
整形式ではありません。(これは、エンコーダーが false、true、
null、または undefined を 2 バイト列でエンコードできず、これらの 1 バイト
バリアントだけが整形式であることを意味します。より一般的には、各
単純値には単一の表現バリアントしかありません。)¶
5 ビット値 25、26、27 は、それぞれ 16 ビット、32 ビット、64 ビットの IEEE 754 バイナリ浮動小数点値 [IEEE754] のためのものです。これらの浮動小数点値は、 適切なサイズの追加バイトにエンコードされます。(16 ビット 浮動小数点数に関する情報については、 付録 D を参照してください。)¶
データモデルレベルの一部の値について、CBOR は複数の シリアライゼーションを提供します。 多くのアプリケーションでは、エンコーダーが常に 推奨シリアライゼーション(推奨エンコーディング)を選択することが望まれます。ただし、現在の仕様では、 この選択を強制する負担をエンコーダーにもデコーダーにも 課していません。¶
一部の制約付きデコーダーでは、 非推奨のシリアライゼーションをデコードする能力が制限されている場合があります。たとえば、アプリケーションで 1_000_000_000(10 億)未満の整数しか想定されない場合、 デコーダーは整数の 64 ビット 引数をデコードするために必要なコードを省略できます。常に推奨 シリアライゼーションを使用するエンコーダー(「推奨エンコーダー」)は、このアプリケーションで発生し得る 数値について、このデコーダーと相互運用できます。一般的に 言えば、推奨エンコーダーは、たとえば常に 64 ビット 整数を使用するエンコーダーよりも、より広く相互運用可能であり(かつ 無駄も少なくなります)。¶
同様に、制約付きエンコーダーでは、サポートする 表現バリアントの種類が制限されているため、 推奨シリアライゼーションを出力しない場合があります(「バリアントエンコーダー」)。たとえば、制約付きエンコーダーは、 短い表現が利用可能な場合でも、エンコードする整数に対して 常に 32 ビットバリアントを使用するよう設計できます(64 ビットバリアントでしか 表現できない整数をアプリケーションが必要としないものとします)。 推奨シリアライゼーションだけを 受信することに依存しないデコーダー(「バリエーション許容デコーダー」)は、したがって、 より広く 相互運用可能であると言えます(ただし、推奨シリアライゼーションを 受信する場合に最適化することは十分あり得ます)。 CBOR デコーダーの完全な実装は、定義上、 バリエーションを許容します。この区別が重要なのは、CBOR デコーダーの制約付き 実装がバリアントエンコーダーと遭遇する場合だけです。¶
推奨シリアライゼーションでは、常に 引数(セクション 3)を表す最短形式を使用します。また、 エンコードされる値を保持する最短の 浮動小数点エンコーディングも使用します。¶
浮動小数点値の推奨シリアライゼーションは、その値を保持する 最短の浮動小数点エンコーディングです。たとえば、数値 5.5 では 0xf94580、数値 5555.5 では 0xfa45ad9c00 です。NaN 値の場合、短い仮数を右側にゼロパディングすることで元の NaN 値を 再構成できるなら、より短いエンコーディングが推奨されます (多くのアプリケーションでは、単一の NaN エンコーディング 0xf97e00 で 十分です)。¶
項目のシリアライゼーション開始時に長さが既知である場合は常に、 定長エンコーディングが推奨されます。¶
一部のプロトコルでは、エンコーダーが特定の 決定論的形式の CBOR のみを出力することを求める場合があります。また、そのようなプロトコルでは、デコーダーが 入力がその決定論的形式であることを検査する場合もあります。それらのプロトコルは、 「決定論的形式」が何を 意味するのか、またエンコーダーとデコーダーが何を行うことを 期待されるのかを自由に定義できます。このセクションでは、そのような決定論的形式の 基礎として使用できる一連の制限を定義します。¶
CBOR エンコーディングは、次の制限を 満たす場合、「中核となる決定論的エンコーディング 要件」を満たします。¶
推奨シリアライゼーションを使用しなければなりません。 特に、これは、 整数、メジャータイプ 2 から 5 の長さ、およびタグの引数(セクション 3を参照)は 可能な限り短くなければならないことを意味します。 たとえば、次のとおりです。¶
浮動小数点値も、その値を保持する最短形式を 使用しなければなりません。たとえば、1.5 は 0xf93e00 (binary16)、 1000000.5 は 0xfa49742408 (binary32) としてエンコードされます。 (これを実装する 1 つの方法は、すべての浮動小数点数を 64 ビット float として開始し、その後 32 ビット float への試験変換を行うことです。結果が 同じ数値であれば、より短い形式を使用し、 16 ビット float への試験変換でも同じ処理を繰り返します。これは、正と負の Infinity に対して 16 ビット float を選択する場合にも機能します。)¶
各マップのキーは、その決定論的 エンコーディングのバイト単位の辞書順で ソートしなければなりません。たとえば、次のキーは正しくソートされています。¶
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)では、マップキーを セクション 3.9 of [RFC7049] で提案された順序 (そこでは「Canonical CBOR」と呼ばれています)とは異なる順序でソートします。 [RFC7049] で指定された順序との 互換性が必要なプロトコルは、代わりに この仕様の「長さ優先の中核となる決定論的エンコーディング 要件」に基づいて指定できます。¶
CBOR エンコーディングは、中核となる決定論的エンコーディング要件を満たし、 ただし各マップのキーが次のようにソートされなければならない点だけが異なる場合、 「長さ優先の中核となる決定論的 エンコーディング 要件」を満たします。¶
たとえば、長さ優先の中核となる決定論的エンコーディング 要件の下では、次のキーが正しくソートされています。¶
CBOR のようなデータ形式は、形式のネゴシエーションが 存在しない環境で使用されることがよくあります。CBOR の具体的な設計目標の 1 つは、 含まれる、または想定されるスキーマを一切 必要としないことです。デコーダーは CBOR 項目を受け取り、 他の知識なしにデコードできます。¶
もちろん、実際の実装では、エンコーダーとデコーダーは CBOR データ項目に何が含まれるべきかについて共通の認識を持ちます。たとえば、 合意された形式は、「項目は配列であり、 最初の値は UTF-8 文字列、2 番目の値は整数、 その後の値は 0 個以上の浮動小数点数である」、 または「項目はキーとしてバイト文字列を持つマップで、 キーが 0xab01 であるペアを 含む」といったものです。¶
CBOR ベースのプロトコルは、そのデコーダーが 無効なデータやその他の予期しないデータをどのように処理するかを指定しなければなりません。CBOR ベースのプロトコルは、 任意の妥当なデータを予期しないものとして扱うことを 指定できます。 CBOR ベースのプロトコル用のエンコーダーは、妥当な項目だけを生成しなければなりません。つまり、 プロトコルを無効な項目を利用するよう設計することはできません。 エンコーダーは、それが使用されるプロトコルで必要とされるだけの 多くまたは少ない種類の値をエンコードできればよく、デコーダーも、 それが使用されるプロトコルで必要とされるだけの多くまたは少ない種類の値を 理解できればかまいません。この 制限のなさにより、CBOR は極めて制約の厳しい 環境でも使用できます。¶
このセクションの残りでは、CBOR ベースの プロトコルを作成する際の考慮事項について説明します。いくつかの例外を除き、これは助言にすぎず、 BCP 14 [RFC2119] [RFC8174] の意味で「MAY」と解釈できる語以外の BCP 14 の表現を明示的に除外します。 例外は、幅広い種類の 汎用およびアプリケーション固有のエンコーダーとデコーダーを利用しながら、 CBOR ベースのプロトコルの相互運用性を促進することを目的としています。¶
ストリーミングアプリケーションでは、データストリームは CBOR データ項目を連続して連結したシーケンスで構成される場合があります。そのような 環境では、前のデータ項目の終端後にデータが見つかると、 デコーダーは直ちに新しいデータ項目のデコードを開始します。¶
データ項目を構成するすべてのバイトが 直ちにデコーダーから利用可能であるとは限りません。一部のデコーダーは、 完全なデータ項目をアプリケーションに提示できるまで追加データを バッファリングします。他の デコーダーは、すでにデコードできた入れ子のデータ項目や、 まだ完全には到着していないバイト文字列の一部分など、 トップレベルデータ項目に関する部分的な情報をアプリケーションへ提示できます。 このようなアプリケーションは、アプリケーションに提示される増分データに対して 必要な保護を利用できる、対応するストリーミングセキュリティ メカニズムも備えなければなりません。¶
一部のアプリケーションやプロトコルでは、 不定長エンコーディングを使用したくない場合があることに注意してください。不定長エンコーディングを使用すると、 エンコーダーはカウントのためにすべてのデータをマーシャリングする必要がなくなりますが、 デコーダーは項目の終端を待つ間、増え続ける量のメモリを 割り当てる必要があります。これは一部の アプリケーションでは問題ない場合がありますが、他ではそうではありません。¶
汎用 CBOR デコーダーは、すべての整形式のエンコード済み CBOR データ項目をデコードし、 データ項目をアプリケーションへ提示できます。付録 C を参照してください。 (診断表記 セクション 8 は、 整形式の CBOR 値を人間に 提示するために使用できます。)¶
汎用 CBOR エンコーダーは、エンコーダーに未知の単純値やタグを含め、 整形式の任意の値を CBOR データ項目としてエンコードするようアプリケーションが指定できる アプリケーションインターフェイスを提供します。¶
CBOR はこうしたケースを最小化しようとしますが、すべての整形式
CBOR データが妥当であるわけではありません。たとえば、エンコードされたテキスト文字列 0x62c0ae
は妥当な UTF-8 を含まず([RFC3629] では
常に最短形式を使用することを要求しているため)、
したがって妥当な CBOR 項目ではありません。
また、特定のタグでは意味上の制約が
課される場合があり、たとえば多倍長整数タグが
別のタグを囲んでいたり、タグ番号 0 のインスタンスがバイト
文字列を含んでいたり、その内容が [RFC3339] の
date-time 生成規則に一致しないテキスト文字列を含んでいたりすると、
その制約に違反する可能性があります。
無効なデータを処理できるようにするために、汎用エンコーダーやデコーダーが
アプリケーションインターフェイスについて不自然な
選択を行う必要はありません。汎用エンコーダーとデコーダーは、
それらの具体的なコードポイントが
エンコーダー/デコーダー作成時に登録されていなくても、
単純値とタグを転送することが期待されます
(セクション 5.4)。¶
整形式ではあるが無効な CBOR データ項目(セクション 1.2)は、 CBOR データモデルにおいてその中にエンコードされたデータを 解釈する際に問題を引き起こします。 CBOR ベースのプロトコルは複数の層で指定される場合があり、その 下位層では、転送する CBOR データの一部の意味を処理しません。 これらの層は、処理しないデータの妥当性エラーを認識できないため、 そのデータをそのまま転送しなければなりません。無効な CBOR 項目の意味を 初めて処理する層は、次の 2 つの選択肢のいずれかを 選択しなければなりません。¶
CBOR ベースのプロトコルは、デコーダーが遭遇し得る無効項目の各種類について、 これらの選択肢のどちらを採用するかを指定しなければなりません。¶
このような問題は、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 有効ビットを超える整数をデコードすると 精度が暗黙のうちに失われる可能性があります。 もう 1 つの例として、CBOR は整数 表現の符号ビットをメジャータイプに保持するため、特定の長さの符号付き 数値に対して、同じ長さの一般的なプラットフォーム符号付き整数表現より 1 ビット多く使用できます(たとえば、1+8 バイト 整数では -264..264-1、8 バイト int64_t では -263..263-1)。 数値を使用するプロトコルは、 デコーダーおよび受信アプリケーションにおける 単純でない数値の処理について期待事項を定義すべきです。¶
浮動小数点数を含む CBOR ベースのプロトコルでは、 3 つの形式(半精度、単精度、 倍精度)のうち、どれをサポートするかを制限できます。整数のみの アプリケーションでは、プロトコルが 浮動小数点値の使用を完全に除外したい場合があります。¶
コンパクトさを目的として設計された CBOR ベースのプロトコルでは、 64 ビット整数を実装する必要をなくすなどのために、 アプリケーションに必要な長さを超える特定の整数エンコーディングを 除外したい場合があります。 エンコーダーは、与えられた値を表現できる最もコンパクトな 整数表現を使用することが期待されます。ただし、 決定論的エンコーディングを必要としないコンパクトなアプリケーションは、 アプリケーションがそのサイズの整数をデコードできる限り、 必要以上に長いエンコーディングを使用した値 (たとえば、「0」を 0b000_11001 の後に 2 バイトの 0x00 を続けてエンコードすること)も受け入れるべきです。 同様の考慮事項は浮動小数点値にも適用されます。推奨シリアライゼーションと 必要以上に長いものの両方をデコードすることが推奨されます。¶
特定の数値を整数として表現するか、 10進小数または Bigfloat として表現するかを選択できる 制約付きアプリケーション向けの CBOR ベースのプロトコル (たとえば、指数が小さく非負の場合)では、 整数表現を直接使用するという実装品質上の期待を 表明する場合があります。¶
エンコード側とデコード側のアプリケーションは、 マップでどの型のキーを使用するかについて合意する必要があります。 JSON ベースのアプリケーションと相互運用する必要があるアプリケーションでは、 キーをテキスト文字列だけに制限すると変換が簡単になります。そうしない場合、 他の CBOR 型からテキスト文字列への指定された マッピングが必要になり、これは 実装エラーにつながることがよくあります。キーが本質的に 数値であり、キーの数値順序がアプリケーションにとって重要な場合、 数値をキーとして直接使用すると便利です。¶
複数の型のキーを使用する場合、 使用される特定のプログラミング環境で これらの型がどのように表現されるかを考慮すべきです。たとえば、 JavaScript の Map [ECMA262] では、整数 1 のキーと 浮動小数点数 1.0 のキーを 区別できません。これは、整数 キーを使用する場合、プロトコルは同じマップ内で、値がたまたま整数となる 浮動小数点キーの使用を避ける必要があることを意味します。¶
CBOR データ項目内に入れ子になったデータ項目を デコードすると直ちに渡すデコーダー(「ストリーミングデコーダー」)は、 マップ内のキーの一意性を確認するために必要な状態を 保持しないことがよくあります。 同様に、包含データ項目が完全に利用可能になる前に データ項目のエンコードを開始できるエンコーダー(「ストリーミングエンコーダー」)は、 データソースが一意性を維持することに依存することで、 オーバーヘッドを大幅に削減したい場合があります。¶
CBOR ベースのプロトコルは、受信アプリケーションが マップ内に複数の同一キーを見つけた場合に何を行うかを定義しなければなりません。 プロトコル内の結果として得られる規則は CBOR データモデルを尊重しなければなりません。つまり、 マップ内に同一キーが存在することが不正なマップを示し、 デコーダーがエラーで停止しなければならないという規則を設ける場合を除き、 同一キーを持つエントリの特定の処理方法を規定することはできません。 重複キーを持つエントリを含むマップを処理する際、汎用 デコーダーは次のいずれかを行う場合があります。¶
汎用デコーダーは、これら 3 つの方法のどれを 実装するかを文書化する必要があります。¶
マップの CBOR データモデルでは、 マップ表現内のキー/値ペアの順序に意味を帰属させることはできません。したがって、 CBOR ベースのプロトコルは、決定論的 エンコーディング(セクション 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 の間で変換するための非規範的な助言を示します。コンバーターの実装は、 ここにある助言のうち望むものを使用できます。¶
JSON テキストは文字のシーケンスであり、 エンコードされたバイト列ではない一方、CBOR データ項目は 文字ではなくバイトで構成されることに注意する価値があります。¶
CBOR の型の大部分には、JSON に直接対応するものがあります。しかし、 一部には対応するものがなく、CBOR-to-JSON コンバーターの実装者は、 そのような場合に何を行うかを 検討する必要があります。次の非規範的な助言では、 JSON null のような単一の代替値へ変換することで、 これらを処理します。¶
CBOR-to-JSON コンバーターは、相互運用性を最大化し、 JSON 出力を予測可能な結果で処理できるという確信を 高めるため、JSON プロファイル I-JSON [RFC7493] に従いたい場合があります。たとえば、 これは確実に表現できる整数の範囲や、 古い JSON 実装がサポートできる トップレベル項目にも影響します。¶
すべての JSON 値は、デコード後、 1 つ以上の CBOR 値へ直接マッピングされます。他の種類の CBOR 生成と同様に、 数値表現について決定を 行う必要があります。推奨される 変換では、次のようになります。¶
CBOR は一般に JSON よりコンパクトなエンコーディングを 提供するよう設計されています。思い浮かぶ実装戦略の 1 つは、 単一のバッファ内で JSON-to-CBOR エンコーディングをインプレースで行うことです。この 戦略では、エスケープがまったくない、または非常に少なく、 255 バイトより長い(またははるかに長い)一部の文字列が、 CBOR の UTF-8 文字列としてエンコードされると拡大する場合があるなど、 多数の病的な ケースを慎重に検討する必要があります。同様に、一部のバイナリ 浮動小数点表現は、JSON の短い 10進表現(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 は、 この文とまったく同じように記述します(これは JSON では許可されませんが、 JavaScript で記述できる方法でもあります)。タグは、 タグ番号を整数として記述し、その後に括弧内のタグ内容を続けます。たとえば、 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 を示します。¶
ここで定義した診断表記に対する多数の有用な拡張が、 付録 G of [RFC8610] の「Extended Diagnostic Notation」 (EDN) で提供されています。 同様に、この表記は別の文書で拡張して、 この文書では扱わない NaN ペイロードを文書化できるでしょう。¶
複数の代替表現のうちどれが実際に使用されたかを 診断表記で示すと便利な場合があります。たとえば、 診断デコーダーによって >1.5< と記述されたデータ項目は、 半精度、単精度、または倍精度の浮動小数点数として エンコードされていた可能性があります。¶
エンコーディング標識の慣例では、
アンダースコアで始まり、その後に続く英数字または
アンダースコアのすべての文字がエンコーディング標識となり、この情報に
関心がない者は無視できます。たとえば、_ または _3。
エンコーディング標識は常に
任意です。¶
マップの開始中括弧または 配列の開始角括弧の後に単一のアンダースコアを記述して、そのデータ項目が 不定長形式で表現されていたことを示すことができます。たとえば、[_ 1, 2] には、 データ項目 [1, 2] を表現するために 不定長表現が使用されたことを示す標識が含まれます。¶
アンダースコアの後に10進数字 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 type」)は、「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" に指定されるものと同じであるべきです。(RFC 8949 の 公開時点では、"application/cbor" に定義されたフラグメント識別 構文はありません。)¶
特定の "xxx/yyy+cbor" のフラグメント識別子の構文と意味は、次のように処理すべきです。¶
ネットワークに面したアプリケーションは、受信データの 処理ロジックに脆弱性を示す可能性があります。複雑なパーサーは、 ノードをリモートからクラッシュさせたり、さらには任意のコードをリモートから実行したりできるなど、 このような脆弱性の原因になりやすいことがよく知られています。 CBOR は、パーサーの複雑さを減らし、可能な場合にはエンコード可能な値の 全範囲に意味を与えることで、このような 脆弱性が導入される機会を狭めようとしています。¶
CBOR デコーダーは、検証されていない入力を処理する 最初の段階として使用されることが多いため、CBOR データ項目をデコードするシステムを 破損させたり、オーバーランさせたり、制御を奪ったりするよう設計された可能性のある、 あらゆる種類の敵対的入力に十分備える必要があります。CBOR デコーダーは、 すべての入力が敵対的である可能性を想定する必要があります。たとえそれが ファイアウォールによって検査されていたり、TLS のようなセキュアなチャネルを経由していたり、暗号化または 署名されていたり、 その他の信頼できると想定されるソースから来たものであっても同様です。¶
セクション 4.1 では、 非推奨のシリアライゼーションを使用する CBOR エンコーダーからの入力を、 制約付き CBOR デコーダーで使用する場合の相互運用性の制限例を示しています。 単一のデータ項目が、このような 制約付きデコーダーと完全なデコーダーの両方によって消費される場合、 コンテンツを挿入または操作できる攻撃者に悪用され得るセキュリティ上の問題につながる可能性があります。¶
この文書全体で説明しているように、ある状況では 「等価」とみなされ、別の状況では「等価でない」とみなされる値が多数あります。 一例として、数値「1」は 整数または多倍長整数として表現される場合があります。CBOR 入力を解釈するシステムは、 数値「1」についてどちらの形式も受け入れる場合も、一方(または両方)の形式を拒否する場合もあります。このような受け入れ または拒否は、解釈された入力を使用するプログラムに セキュリティ上の影響を及ぼす可能性があります。¶
敵対的入力は、バッファをオーバーランさせたり、整数演算をオーバーフローまたは アンダーフローさせたり、その他のデコード障害を引き起こしたりするよう構成される可能性があります。CBOR データ項目には、意図的に 極端に大きい、または短すぎる長さやサイズが設定される場合があります。 リソース枯渇攻撃では、デコーダーに 非常に大きなデータ項目(文字列、配列、マップ、さらには 任意精度数)を割り当てさせたり、深く入れ子にした項目を構成することで スタック深度を使い果たさせたりしようとする可能性があります。デコーダーには、 これらの攻撃を軽減するための適切なリソース管理が必要です。(非常に 大きなサイズが指定された項目は、整数 オーバーフローの脆弱性を悪用しようとする可能性もあります。)¶
CBOR デコーダーは、定義上、整形式の CBOR のみを受け入れます。これは 堅牢性を得るための第一歩です。整形式の CBOR ではない入力は、 整形式でないことが検出された時点から それ以上処理されません。可能であれば、この時点までに デコードされたデータが、CBOR デコーダーを使用する アプリケーションに影響を与えるべきではありません。¶
CBOR デコーダーは、整形式であることを確認するだけでなく、 CBOR データに対して妥当性検査を実行する場合もあります。あるいは、 その検査をデコーダーを使用するアプリケーションに委ねることもできます。この選択は、 デコーダーで明確に文書化する必要があります。CBOR レベルでの妥当性に加えて、 アプリケーションは、入力が CBOR でシリアライズされた アプリケーションプロトコルに適合していることも確認する必要があります。¶
入力検査自体がリソースを消費する場合があります。通常、これは 入力サイズに対して線形であり、攻撃者は入力検証において防御側が費やす リソースに見合うリソースを 費やさなければならないことを意味します。 しかし、攻撃者が生成するよりも対象デコーダーで処理する方が長い時間を要する入力を、 攻撃者が作成できる可能性があります。 任意精度数の処理は、 線形を超える処理量を必要とする場合があります。また、デコーダーが マップのメモリ内表現を構築するために使用する一部のハッシュテーブル実装は、 秘密鍵 ([SIPHASH_LNCS] のセクション 7 を参照、また [SIPHASH_OPEN] も参照)またはその他の軽減策を 使用しない限り、二次的な処理量を費やすよう攻撃される可能性があります。 このような超線形の処理量は、 入力バリデーター上またはその前でリソースを枯渇させるために攻撃者に 悪用され得ます。そのため、CBOR デコーダー 実装では回避する必要があります。タグ番号の定義とその実装が この種のセキュリティ上の考慮事項を追加する可能性があることに注意してください。その場合、 タグ番号定義のセキュリティに関する考慮事項で 説明すべきです。¶
CBOR エンコーダーはネットワークから直接入力を受け取らないため、 CBOR デコーダーと同じ方法で直接攻撃されることはありません。 しかし、CBOR エンコーダーには、 実装内の別の層から入力を受け取る API があることが多く、 その API を通じて攻撃される可能性があります。その API の設計と実装では、 呼び出し元の動作が敵対的入力または コーディングミスに基づいている可能性を想定すべきです。バッファオーバーラン、 整数演算のオーバーフローとアンダーフロー、およびエンコーダーを妨害することを目的とする その他の同様のエラーについて入力を検査すべきです。¶
プロトコルは、 複数の解釈の可能性が確実に 単一の解釈へ縮減されるよう定義すべきです。たとえば、攻撃者は マップ内の重複キーなどの無効な入力を利用したり、数値処理における異なる 精度を悪用して、あるアプリケーションが、 別のアプリケーションで使用される解釈とは異なる解釈に基づいて 判断するよう仕向けたりする可能性があります。一貫した解釈を促進するため、 エンコーダーとデコーダーの実装は、 妥当性検査を行う動作モード (セクション 5.4)を提供すべきです。ただし、汎用デコーダーは、 アプリケーションが入力 データに課すすべての要件を知ることはできません。そのため、アプリケーション自身が 入力検査を行う必要がなくなるわけではありません。また、定義されたタグ番号の集合は 発展するため、アプリケーションは、使用している汎用デコーダーが 妥当性検査をまだサポートしていないタグ番号を使用する可能性があります。したがって汎用 デコーダーは、どのタグ番号を サポートしているか、およびそれらのタグ番号と基本 CBOR (UTF-8 検査、重複マップキー検査)についてどのような妥当性検査を提供するかを文書化する必要があります。¶
セクション 3.4.3 では、数値をエンコードするために 基本整数ではなく多倍長整数表現を選択する非推奨の選択には、 アプリケーション上の意味を持たせる意図がないと述べていますが、 CBOR データを受信するアプリケーションが基本的な汎用データモデルのデコーダーを使用している場合、 そのような意味を持つ可能性があります。この 相違は、2 つの意味の集合が異なる場合にセキュリティ上の問題を引き起こします。したがって、 CBOR を使用するアプリケーションは、CBOR データを使用する各箇所について、 使用するデータモデルを指定する必要があります。¶
CBOR データを他の形式へ変換することは一般的です。多くの場合、CBOR は 他の形式より表現力の高い型を持っています。これは特に、 一般的な JSON への変換で当てはまります。型情報の損失は、 表現力の低いデータを処理するシステムにセキュリティ上の 問題を引き起こす可能性があります。¶
セクション 6.2 では、 攻撃者がアプリケーションが変換を行っていることを知っている場合に 攻撃を可能にする可能性がある、CBOR と JSON の間の変換という、 おそらく一般的な使用シナリオを説明しています。¶
[RFC4648] の base16 および base64 の使用に関するセキュリティ上の考慮事項と、[RFC3629] の UTF-8 の使用に関するセキュリティ上の考慮事項は、CBOR にも 関係します。¶
次の表では、いくつかの CBOR エンコード済み値を16進数 (右列)で、その値の診断表記(左 列)とともに示します。文字列 "\u00fc" は、単一の Unicode 文字 U+00FC (LATIN SMALL LETTER U WITH DIAERESIS, "ü") を含む UTF-8 文字列の診断 表記の一形式であることに注意してください。同様に、"\u6c34" は、 単一の文字 U+6C34 (CJK UNIFIED IDEOGRAPH-6C34, "水") を含む診断表記の UTF-8 文字列であり、 しばしば「水」を表します。また、"\ud800\udd51" は、 単一の文字 U+10151 (GREEK ACROPHONIC ATTIC FIFTY STATERS, "𐅑") を含む診断表記の UTF-8 文字列です。(これらすべての単一文字 文字列は、ASCII のみの仕様が必要でない限り、 診断表記内でネイティブ UTF-8 によって表現することもできます。) 多倍長整数について示す診断表記では、 その意図された数値を、タグ付きバイト文字列( 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 | 符号なし多倍長整数(データ項目「バイト文字列」が 後続) |
| 0xc3 | 負の多倍長整数(データ項目「バイト文字列」が 後続) |
| 0xc4 | 10進小数(データ項目「配列」が後続。 セクション 3.4.4 を参照) |
| 0xc5 | Bigfloat(データ項目「配列」が後続。セクション 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; // バイト/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(); // 不正な単純値
}
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 を通知
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 を参照してください。¶
半精度浮動小数点数が IEEE 754 に追加されたのは 2008 年になってからであるため [IEEE754]、現在のプログラミングプラットフォームでも それらのサポートは限定的であることがよくあります。このようなサポートがなくても、少なくともデコード サポートを含めることは非常に簡単です。C 言語による半精度浮動小数点数の 小さなデコーダーの例を 図 3 に示します。Python の同様のプログラムは 図 4 にあります。このコードは、2 バイト値がすでに ネットワークバイトオーダーの(unsigned 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 プロトコルは、ほとんど(あるいはまったく)ありません。その理由は多数考えられますが、 よく挙げられる理由の 1 つは、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 は整数と浮動小数点 値を区別していません(また、後者は形式上10進数です)。CBOR は 数値の2進表現を提供し、整数と 浮動小数点値で異なります。実装と使用の経験から、これら 2 つの数値 領域の分離を文書内でより明確にする必要があることが示唆されました。そのため、 整数が浮動小数点 値の代わりにシームレスに使用できることを示唆する表現は削除されました。また、JSON を CBOR に変換するときのこれらの型の扱いについて (I-JSON [RFC7493] に基づく)提案が追加され、 特定の丸め機構の使用が推奨されました。¶
データモデル内の 1 つの値に対して、CBOR は複数の エンコーディングの選択肢を提供することがよくあります。新しいセクション(セクション 4)では、 「推奨シリアライゼーション」(セクション 4.1)という用語を導入し、 さまざまな種類のデータ項目について定義しています。この用語に基づき、このセクションでは CBOR ベースのプロトコルが「決定論的 エンコーディング」(セクション 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 の定義に 基づく登録は引き続き有効です。¶
「argument」と「head」について、 セクション 3 に用語が導入され、 以降の議論が簡潔になりました。¶
セキュリティに関する考慮事項(セクション 10)は 大部分が書き直され、大幅に 拡充されました。また、文書内の複数の箇所で、 デコーダーが整形式性エラーを単純に容認してはならないことが、より明確に示されています。¶
CBOR は MessagePack から着想を得ました。MessagePack は Sadayuki Furuhashi ("frsyuki") によって開発され、普及が進められました。この MessagePack への言及は帰属表示のみを目的としています。CBOR は 設計目標と要件が異なるため、MessagePack の バージョンまたは代替を意図したものではありません。¶
元の MessagePack 仕様を超える機能の必要性は、2012 年頃のほぼ同じ時期に 多くの人々にとって明らかになりました。BinaryPack は MessagePack の小規模な派生であり、 binaryjs プロジェクトのために Eric Zhang によって開発されました。これと似ていますが 異なる拡張が、Tim Caswell によって msgpack-js および msgpack-js-browser プロジェクト向けに作成されました。多くの人々が、 テキスト文字列の 表現とバイト文字列の表現を分離するための MessagePack の拡張についての議論に貢献しました。¶
CBOR の追加情報のエンコーディングは、 CoAP のために Klaus Hartke が設計した長さ情報の エンコーディングから着想を得ました。¶
この文書には、多くの人々による提案も取り入れられています。 特に 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 は、 Eve Schooler による IoT directorate のレビューを含む、 さらなる IESG コメントを提供しました。¶