メインコンテンツまでスキップ

4. Presentation Language (表現言語)

本文書は、外部表現におけるデータのフォーマットを扱います。以下の非常に基本的でやや緩く定義された表現構文を使用します。この構文は、その構造において複数のソースから引用しています。構文的にはプログラミング言語「C」に似ており、構文と意図の両方でXDR [XDR] に似ていますが、過度に類似点を見出すことは危険です。この表現言語の目的は、TLSを文書化することのみであり、その特定の目標を超えて一般的な用途はありません。

4.1. Basic Block Size (基本ブロックサイズ)

すべてのデータ項目の表現は明示的に指定されます。基本データブロックサイズは1バイト(つまり8ビット)です。複数バイトのデータ項目は、左から右へ、上から下へとバイトの連結です。バイトストリームから、マルチバイト項目(例では数値)は、次のように形成されます(C表記を使用):

value = (byte[0] << 8*(n-1)) | (byte[1] << 8*(n-2)) |
... | byte[n-1];

このマルチバイト値のバイト順序は、一般的なネットワークバイトオーダーまたはビッグエンディアン形式です。

4.2. Miscellaneous (その他)

コメントは /* で始まり、*/ で終わります。

オプションのコンポーネントは、二重括弧 [[ ]] で囲んで示されます。

解釈されないデータを含む単一バイトエンティティは、opaque型です。

4.3. Vectors (ベクトル)

ベクトル(一次元配列)は、同種のデータ要素のストリームです。ベクトルのサイズは、ドキュメント作成時に指定することも、実行時まで未指定のままにすることもできます。いずれの場合も、長さはベクトル内の要素数ではなく、バイト数を宣言します。型Tの固定長ベクトルである新しい型T'を指定する構文は次のとおりです:

T T'[n];

ここで、T'はデータストリーム内でnバイトを占有し、nはTのサイズの倍数です。ベクトルの長さは、エンコードされたストリームには含まれません。

次の例では、Datumはプロトコルが解釈しない3つの連続したバイトとして定義され、Dataは3つの連続したDatumであり、合計9バイトを消費します。

opaque Datum[3];      /* three uninterpreted bytes */
Datum Data[9]; /* 3 consecutive 3 byte vectors */

可変長ベクトルは、<floor..ceiling> という表記法を使用して、合法的な長さのサブレンジ(境界を含む)を指定することによって定義されます。これらがエンコードされるとき、実際の長さはバイトストリーム内のベクトルの内容の前に配置されます。長さは、ベクトルの指定された最大(ceiling)長を保持するのに必要な数のバイトを消費する数値の形式になります。実際の長さフィールドがゼロの可変長ベクトルは、空のベクトルと呼ばれます。

T T'<floor..ceiling>;

次の例では、mandatoryは、型opaqueの300から400バイトを含む必要があるベクトルです。空にすることはできません。実際の長さフィールドは2バイト、つまりuint16を消費し、値400を表すのに十分です(セクション4.4を参照)。一方、longerは最大800バイトのデータ、または400個のuint16要素を表すことができ、空にすることもできます。そのエンコーディングには、ベクトルの前に付加される2バイトの実際の長さフィールドが含まれます。エンコードされたベクトルの長さは、単一要素の長さの偶数倍でなければなりません(たとえば、17バイトのuint16ベクトルは不正です)。

opaque mandatory<300..400>;
/* length field is 2 bytes, cannot be empty */
uint16 longer<0..800>;
/* zero to 400 16-bit unsigned integers */

4.4. Numbers (数値)

基本的な数値データ型は、符号なしバイト(uint8)です。より大きなすべての数値データ型は、セクション4.1で説明されているように連結された固定長のバイトシリーズから形成され、これらも符号なしです。以下の数値型が事前定義されています。

uint8 uint16[2];
uint8 uint24[3];
uint8 uint32[4];
uint8 uint64[8];

ここおよび仕様の他の場所のすべての値は、ネットワークバイト(ビッグエンディアン)順序で格納されます。16進バイト01 02 03 04で表されるuint32は、10進値16909060に相当します。

場合によっては(DHパラメータなど)、整数をopaqueベクトルとして表現する必要があることに注意してください。そのような場合、それらは符号なし整数として表現されます(つまり、最上位ビットが設定されている場合でも、先頭のゼロオクテットは必要ありません)。

4.5. Enumerateds (列挙型)

enumと呼ばれる追加のスパースデータ型が利用可能です。enum型のフィールドは、定義で宣言された値のみを想定できます。各定義は異なる型です。同じ型の列挙型のみが割り当てまたは比較できます。次の例に示すように、列挙型のすべての要素には値を割り当てる必要があります。列挙型の要素は順序付けられていないため、任意の順序で任意の一意の値を割り当てることができます。

enum { e1(v1), e2(v2), ... , en(vn) [[, (n)]] } Te;

列挙型は、その最大定義序数値がバイトストリームで占めるのと同じスペースを占有します。次の定義では、Color型のフィールドを運ぶために1バイトが使用されます。

enum { red(3), blue(5), white(7) } Color;

余分な要素を定義せずに幅定義を強制するために、関連するタグなしで値を指定することもできます。

次の例では、Tasteはデータストリームで2バイトを消費しますが、値1、2、または4のみを想定できます。

enum { sweet(1), sour(2), bitter(4), (32000) } Taste;

列挙型の要素の名前は、定義された型内でスコープが設定されます。最初の例では、列挙型の2番目の要素への完全修飾参照はColor.blueになります。代入のターゲットが十分に指定されている場合、そのような修飾は必要ありません。

Color color = Color.blue;     /* overspecified, legal */
Color color = blue; /* correct, type implicit */

外部表現に変換されない列挙型の場合、数値情報を省略できます。

enum { low, medium, high } Amount;

4.6. Constructed Types (構造型)

便宜上、プリミティブ型から構造型を構築できます。各仕様は新しい一意の型を宣言します。定義の構文はCに非常に似ています。

struct {
T1 f1;
T2 f2;
...
Tn fn;
} [[T]];

構造内のフィールドは、列挙型で利用可能な構文によく似た構文で、型名を使用して修飾できます。たとえば、T.f2は前の宣言の2番目のフィールドを指します。構造定義は埋め込むことができます。

4.6.1. Variants (バリアント)

定義された構造は、環境内で利用可能ないくつかの知識に基づいてバリアントを持つことがあります。セレクタは、構造が定義する可能なバリアントを定義する列挙型でなければなりません。selectで宣言された列挙型のすべての要素に対してcase分岐が必要です。case分岐には限定的なfall-through機能があります:2つのcase分岐が間にフィールドなしで直接連続している場合、両方とも同じフィールドを含みます。したがって、以下の例では、「orange」と「banana」の両方にV2が含まれます。これはTLS 1.2の新しい構文機能であることに注意してください。

バリアント構造の本体には、参照用のラベルを付けることができます。実行時にバリアントが選択されるメカニズムは、表現言語では規定されていません。

struct {
T1 f1;
T2 f2;
....
Tn fn;
select (E) {
case e1: Te1;
case e2: Te2;
case e3: case e4: Te3;
....
case en: Ten;
} [[fv]];
} [[Tv]];

例:

enum { apple, orange, banana } VariantTag;

struct {
uint16 number;
opaque string<0..10>; /* variable length */
} V1;

struct {
uint32 number;
opaque string[10]; /* fixed length */
} V2;

struct {
select (VariantTag) { /* value of selector is implicit */
case apple:
V1; /* VariantBody, tag = apple */
case orange:
case banana:
V2; /* VariantBody, tag = orange or banana */
} variant_body; /* optional label on variant */
} VariantRecord;

4.7. Cryptographic Attributes (暗号属性)

5つの暗号操作 — デジタル署名 (digital signing)、ストリーム暗号暗号化 (stream cipher encryption)、ブロック暗号暗号化 (block cipher encryption)、追加データ付き認証暗号化 (authenticated encryption with additional data, AEAD)、および公開鍵暗号化 (public key encryption) — は、それぞれdigitally-signed、stream-ciphered、block-ciphered、aead-ciphered、およびpublic-key-encryptedとして指定されます。フィールドの暗号処理は、フィールドの型仕様の前に適切なキーワード指定を追加することによって指定されます。暗号鍵は、現在のセッション状態によって暗黙的に指定されます(セクション6.1を参照)。

デジタル署名要素は、struct DigitallySignedとしてエンコードされます:

struct {
SignatureAndHashAlgorithm algorithm;
opaque signature<0..2^16-1>;
} DigitallySigned;

algorithmフィールドは使用されるアルゴリズムを指定します(このフィールドの定義についてはセクション7.4.1.4.1を参照)。algorithmフィールドの導入は、以前のバージョンからの変更であることに注意してください。signatureは、これらのアルゴリズムを使用した要素の内容のデジタル署名です。内容自体はワイヤー上には現れず、単に計算されます。署名の長さは、署名アルゴリズムと鍵によって指定されます。

RSA署名では、opaqueベクトルには、[PKCS1] で定義されたRSASSA-PKCS1-v1_5署名スキームを使用して生成された署名が含まれます。[PKCS1] で説明されているように、DigestInfoはDERエンコードされなければなりません (MUST) [X680] [X690]。パラメータなしのハッシュアルゴリズム(SHA-1を含む)の場合、DigestInfo.AlgorithmIdentifier.parametersフィールドはNULLでなければなりませんが (MUST)、実装はパラメータなしとNULLパラメータの両方を受け入れなければなりません (MUST)。TLSの以前のバージョンでは、DigestInfoエンコーディングを含まない異なるRSA署名スキームが使用されていたことに注意してください。

DSAでは、SHA-1ハッシュの20バイトが追加のハッシュなしでデジタル署名アルゴリズムを直接通過します。これにより、rとsという2つの値が生成されます。DSA署名は、上記のようにopaqueベクトルであり、その内容は以下のDERエンコーディングです:

Dss-Sig-Value ::= SEQUENCE {
r INTEGER,
s INTEGER
}

注意: 現在の用語では、DSAはデジタル署名アルゴリズム (Digital Signature Algorithm) を指し、DSSはNIST標準を指します。元のSSLおよびTLS仕様では、「DSS」が普遍的に使用されていました。本文書では、「DSA」をアルゴリズムの参照に使用し、「DSS」を標準の参照に使用し、歴史的連続性のためにコードポイント定義で「DSS」を使用します。

ストリーム暗号暗号化では、平文は暗号学的に安全な鍵付き擬似乱数生成器から生成された同量の出力と排他的論理和されます。

ブロック暗号暗号化では、平文のすべてのブロックが暗号文のブロックに暗号化されます。すべてのブロック暗号暗号化はCBC(暗号ブロック連鎖、Cipher Block Chaining)モードで行われ、ブロック暗号化されるすべての項目は暗号ブロック長の正確な倍数になります。

AEAD暗号化では、平文は同時に暗号化および完全性保護されます。入力は任意の長さにでき、aead-ciphered出力は通常、完全性チェック値に対応するために入力よりも大きくなります。

公開鍵暗号化では、公開鍵アルゴリズムを使用してデータを暗号化し、一致する秘密鍵でのみ復号化できるようにします。公開鍵暗号化された要素は、opaqueベクトル <0..2^16-1> としてエンコードされ、長さは暗号化アルゴリズムと鍵によって指定されます。

RSA暗号化は、[PKCS1] で定義されたRSAES-PKCS1-v1_5暗号化スキームを使用して行われます。

次の例では:

stream-ciphered struct {
uint8 field1;
uint8 field2;
digitally-signed opaque {
uint8 field3<0..255>;
uint8 field4;
};
} UserType;

内部構造の内容(field3およびfield4)は、署名/ハッシュアルゴリズムの入力として使用され、その後、構造全体がストリーム暗号で暗号化されます。この構造の長さ(バイト単位)は、field1とfield2の2バイト、署名とハッシュアルゴリズムの2バイト、署名の長さの2バイト、および署名アルゴリズムの出力の長さを加えたものになります。署名に使用されるアルゴリズムと鍵はこの構造をエンコードまたはデコードする前に分かっているため、署名の長さは既知です。

4.8. Constants (定数)

型付き定数は、目的の型のシンボルを宣言し、それに値を割り当てることによって、仕様目的で定義できます。

不十分に指定された型(opaque、可変長ベクトル、およびopaqueを含む構造)には値を割り当てることができません。複数要素の構造またはベクトルのフィールドを省略することはできません。

例:

struct {
uint8 f1;
uint8 f2;
} Example1;

Example1 ex1 = {1, 4}; /* assigns f1 = 1, f2 = 4 */