RFC 4518

Stringprep

[1] stringprep は、 IETF の規格で文字列正規化を行うために定義された枠組み (フレームワーク) です。 IDN などの識別子で使われています。

[177] RFC としては Stringprep廃止されましたが、 まだ互換性のために Stringprep を使い続けなければならないこともあるかもしれません。

仕様書

処理

[3] Stringprep の処理は大きく4段階に分かれます。実装はこの順番に処理しなければなりません >>2 2.。この処理の入力は処理対象の文字列であり、 出力は処理結果の文字列か、または誤りのいずれかです。 (誤りかつ文字列が返されることはありません。 >>2 5.、6.)

  1. [54] 写像 (mapping) : 写像表 (>>59) に基づき、 特定の文字をそれに対応する0文字以上の文字列へと写像します。
  2. [55] 正規化: NFKC により正規化します。 プロファイルによってはこの作業を省略します。
  3. [56] 禁止文字の検査: 禁止表 (>>74) に含まれる文字を検出したら誤りとします。
  4. [57] Bidi に関する検査: Unicode の bidi 算法に基づく表示で問題を起こす可能性があれば誤りとします。 プロファイルによってはこの作業を省略します。

[53] >>54>>55 では文字列の長さが増減することがあり、実装はこれに備えなければなりません >>2 2.

[152] Stringprep では入出力を Unicode 文字列としています。 それ以外の文字コードを使う場合は変換が必要ですが、 Stringprep の仕様の範囲外とされています。
[160] RFC 4518 はこれより前の最初の手順として転符号化 (Transcoding) (>>161) を、これより後の最後の手順として Insignificant Character Handling (>>166) を追加しています。

プロファイルと Unicode の版

[5] RFC 3454Unicode 3.2 に基づいています。 基本的に RFC 3454 とそれに基づくプロファイルは Unicode 3.2 に基づき設計されることになります。 RFC 3454 は新しい版の Unicode で使うことが想定されていないと明確に述べています >>2 1.2

[48] RFC 3454 は新しい版の Unicode に対応した新しい版のプロファイルを作ってもプロファイルを使うプロトコルを全面改訂したりしなくて済むように、 写像表などの非互換変更を禁じたり、 未定義符号位置の処理に関する規定 (>>4) を設けたりしています。

[11] IDNA2003 でも、新しい版を使って正規化してはならないと明確に規定されています。

文字レパートリ

[49] Stringprepプロファイルは、利用する文字レパートリを選択しなければなりません >>2 1.2。 ただし、現在規定されているのは Unicode 3.2 レパートリ >>2 A. のみで、他の選択肢はありません。

[50] 文字レパートリは固定されたものではなく、将来の改訂で文字が追加されることがあります >>2 1.2

[51] といっても唯一定義されている「Unicode 3.2レパートリが拡張されることは流石にないでしょう・・・。

[52] Unicode 3.2 文字レパートリにおける未定義符号位置の一覧も RFC で定義されています >>2 A.。実装は Unicode 3.2 の仕様ではなく、この RFC の一覧に基づいて処理しなければなりません >>2 A., >>2 7.

符号位置の分類

[118] 特定の Stringprep である符号位置がどう処理されるかにより、 符号位置は次の4つのカテゴリーのいずれかに分類できます >>2 7.1

[123] IDNA2008 もこれと似た導出特性値という概念を規定していますが、 IDNA2008 では Unicode特性から直接的に定義されていて、ここでの分類とは大きく異なります。

写像表

[59] Stringprep で使用する写像表プロファイル毎に規定します。

[60] 基本的には Stringprep 仕様で予め定義された表を使うべきですが、 必要なら独自に定義しても構いません>>2 3.

附属書B.1

[62] B.1 Commonly mapped to nothing http://tools.ietf.org/html/rfc3454#appendix-B.1

[63] このは、SOFT HYPHENZERO WIDTH JOINER異体字選択子など、含まれていてもいなくても同じ識別子とみなされるべき >>2 3.1 文字を零文字に置き換える (削除する) ものです。

附属書B.2

[64] B.2 Mapping for case-folding used with NFKC http://tools.ietf.org/html/rfc3454#appendix-B.2

[65] このは、NFKC を使う場合のための大文字から小文字に変換するものです >>2 3.2

[73] この写像表は附属書B.3 (>>66) を >>71 により補強したものです >>2 3.2

附属書B.3

[66] B.3 Mapping for case-folding used with no normalization http://tools.ietf.org/html/rfc3454#appendix-B.3

[67] この写像表は、正規化しない場合のための大文字から小文字に変換するものです >>2 3.2

[72] この写像表Unicode 3.2CaseFolding-3.txt に基づいています >>2 3.2

case folding の写像表

[68] 大文字・小文字不区別としたい場合には、附属書B.2 (>>62) または附属書B.3 (>>64) を使って写像するべきです >>2 3.2

[69] 現在のインターネットプロトコル応用では小文字が一般的なので、 大文字小文字に変換しています >>2 3.2

[70] しかし独自の写像表を使いたいのなら、 UTR #21 に基づくべきであり、 大文字から小文字に変換するべきです。 CaseFolding.txt に基づいて写像表を作るべきであり、完全な大文字・小文字の写像 (full case mapping) を使う (状態 C, F, I を使う) べきです。 >>2 3.2

[71] NFKC を使うなら、 UTR #21 では写像されてなくても処理が必要な文字があるため、 注意が必要です。 (一部のギリシャ文字と多くのラテン文字を含む記号が該当します。) これは、

  1. a を入力とする
  2. b を、 acase folding し、 NFKC正規化したものとする
  3. c を、 bcase folding し、 NFKC正規化したものとする
  4. cb と同じでなければ、 a から c への写像を追加する

... という方法で求められます。 >>2 3.2

正規化

[142] Unicode正規化形には冪等性に関する不具合がありました。この不具合は訂正 #5 で修正されていますが、それまでは正規化形の実装に2通りの可能性がありました。

[143] Perlモジュール Unicode::Stringprep は、 Stringprep正規化によってこの2通りの実装方法での差異が生じる列を検出した場合、 失敗として扱います。 >>14

[156] RFC に従った実装とは言えませんが、やむを得ないのかもしれません。

禁止表

[74] Stringprep で使用する禁止文字プロファイル毎に規定します。

附属書C.1.1

[75] C.1.1 ASCII space characters http://tools.ietf.org/html/rfc3454#appendix-C.1.1

[76] ASCII に含まれる間隔文字の表で、 SPACE だけが含まれています。

附属書C.1.2

[77] C.1.2 Non-ASCII space characters http://tools.ietf.org/html/rfc3454#appendix-C.1.2

[78] 非ASCII文字間隔文字の表です。

附属書C.2.1

[79] C.2.1 ASCII control characters http://tools.ietf.org/html/rfc3454#appendix-C.2.1

[81] ASCII に含まれる制御文字の表です。

附属書C.2.2

[80] C.2.2 Non-ASCII control characters http://tools.ietf.org/html/rfc3454#appendix-C.2.2

[82] 非ASCII文字制御文字の表です。

附属書C.3

[83] C.3 Private use http://tools.ietf.org/html/rfc3454#appendix-C.3

[84] 私用域符号位置の表です。

附属書C.4

[85] C.4 Non-character code points http://tools.ietf.org/html/rfc3454#appendix-C.4

[86] 非文字符号位置の表です。

[93] PropList.txt >>2 5.4 に基づいているとみられます。

附属書C.5

[87] C.5 Surrogate codes http://tools.ietf.org/html/rfc3454#appendix-C.5

[88] サロゲート符号位置の表です。

附属書C.6

[89] C.6 Inappropriate for plain text http://tools.ietf.org/html/rfc3454#appendix-C.6

[94] 普通の文章には登場しない文字 >>2 5.6 が含まれています。

附属書C.7

[90] C.7 Inappropriate for canonical representation http://tools.ietf.org/html/rfc3454#appendix-C.7

[95] IDC が含まれています。同じ文字が複数の方法で表現できてしまうので禁止するとされています。 >>2 5.7

[96] それは誤解なような気がしますが。 IDS文字そのものの表現方法ではないのでは。

附属書C.8

[91] C.8 Change display properties or are deprecated http://tools.ietf.org/html/rfc3454#appendix-C.8

[97] レンダリングを操作するものや Unicode非推奨とされているものが含まれています。 >>2 5.8

附属書C.9

[92] C.9 Tagging characters http://tools.ietf.org/html/rfc3454#appendix-C.9

[98] 不可視なタグ文字が含まれています >>2 5.9

Bidi 文字チェック

[99] bidi 処理によって ltrrtl が混在することによる混乱を避けるため、 bidi 的に文字が適当に並べられていることをチェックします。 このチェックはプロファイルにより省略して構いません >>2 6.

[100] チェックを行う場合、文字列は次の条件をすべて満たさなければなりません >>2 6.

[108] RFC には附属書に RandALCat文字LCat文字の一覧が含まれていますが、 他の表とは違って、 Unicode 3.2 の元のデータでなくこの表を使わなければならないとは明記されていません。 単なるミスなのか何か意図があるのかは不明です。

[109] IDNA2008 は、この条件だと最後の文字結合文字となる場合をカバーしきれておらず、 本来認められるべき文字列であっても排除されてしまうと指摘しています。 そのため代わりに bidi規則を規定しています。

[105] >>104 より、

  • [106] <U+0627><U+0031> (aleph 1)

... は禁止されますが、

  • [107] <U+0627><U+0031><U+0628> (aleph 1 beh)

... は認められます >>2 6.

未定義符号位置の扱い

[4] まだ文字が割当てられておらず、将来割当てられるかもしれない符号位置についての規定もあります。

[12] Stringprep のプロファイルを適用する文字列は大別して 蓄積文字列 (stored string) 照会 (query) の2種類があります >>2 7.。 蓄積文字列はデータベースに登録する項目名のようなもので、 照会はデータベースから項目を取出すために指定する項目名のようなものです。

[113] より新しい版の Unicode文字が割り当てられると、 それに伴い未定義だった時と正規化の結果が変わってしまうことがあります。 また、写像表や禁止文字も拡充されることがあるでしょう。その時に、 古い版でもし蓄積文字列未定義符号位置が含まれていると、 新しい版で Stringprep を適用した結果アクセスできなくなってしまう危険性があります。

[13] IDNA2003 には AllowUnassigned フラグが規定されています。 Nameprep において未定義の符号位置をどう扱うかはこのフラグに依存します。基本的に登録では (蓄積文字列)、lookup では (照会) とします。

プロファイルの定義

[36] プロファイルは、次のものを含んでいなければなりません >>2 1.2

[32] 関係する2つのプロファイルがそれぞれ別々のプロファイルを使っていると、 文字列をどう正規化するか、何が認められるかが違っているため、 相互運用が難しくなります。ですから、新しいプロファイルを無闇に作らず、 既存のプロファイルを流用するよう、強く求められています >>2 1.2

[35] Stringprepプロファイル間でできるだけ表を共有することを意図しており、 従ってプロファイルが独自にを作ることもできるとはいえ、 極力 Stringprep 仕様で定義されているの組み合わせに依ることが望ましいです >>2 1.2

[33] プロファイルにおいてできるだけ多くの文字を利用可能としたい場合、 可能な限り、文字の利用を禁止するのではなく他の文字に変換することを選ぶべきです。 >>2 1.2

[34] Stringprep によって文字関係の規格の逝かれているところを「修正」 することもあるいはできるかもしれませんが、それは行うべきではありません >>2 1.2

登録

[6] Stringprepプロファイルには IETF合意必要 >>2 10. であり、 IESG評価必要 >>2 10. であり、 RFC 化されて IANA に登録されなければなりません >>2 1.2

安定性

[114] 新しい版の文字レパートリに対応した新しい版のプロファイルでは U カテゴリーだった符号位置DMNAO に変更して構いません。 しかし、 AOMND だった符号位置を他のカテゴリーに変更してはなりません >>2 7.1

プロファイルの一覧

[47] 次のようなプロファイルがありました。

name
名前
ver
iana
IANA 状態
ietf
IETF 状態
rep
文字レパートリ
map1
写像 B.1
map2
写像 B.2
map3
写像 B.3
mapo
その他写像
norm
正規化
f11
禁止 C.1.1
f12
禁止 C.1.2
f21
禁止 C.2.1
f22
禁止 C.2.2
f3
禁止 C.3
f4
禁止 C.4
f5
禁止 C.5
f6
禁止 C.6
f7
禁止 C.7
f8
禁止 C.8
f9
禁止 C.9
fo
その他禁止
bidi
bidi
context
利用される場面
note
備考
name
iSCSI
rep
Unicode 3.2
map1
map2
map3
mapo
norm
NFKC
f11
f12
f21
f22
f3
f4
f5
f6
f7
f8
f9
fo
>>8, >>26
bidi
ver
1
ietf
RFC 3722
iana
現行
name
Nameprep
rep
Unicode 3.2
map1
map2
map3
mapo
norm
NFKC
f11
f12
f21
f22
f3
f4
f5
f6
f7
f8
f9
fo
bidi
ietf
RFC 3491 (RFC 5891 により廃止)
iana
現行
ver
1
context
IDNA2003
note
IETF 的には IDNA2008 により廃止、 現実には UTS #46 に移行。
name
Nodeprep
ver
1
iana
非現行
ietf
RFC 3920 >>125 (RFC 6122 により廃止)、 RFC 6122 >>133 (RFC 7622 により廃止)
rep
Unicode 3.2
map1
map2
map3
mapo
norm
NFKC
f11
f12
f21
f22
f3
f4
f5
f6
f7
f8
f9
fo
>>9
bidi
context
[129] XMPP 節点識別子
note
[139] RFC は改訂されていますが、内容は変わっていないので版はどちらも「1」です。
name
Policy MIB Stringprep
ver
1
iana
現行
ietf
RFC 4011
rep
Unicode 3.2
map1
map2
map3
mapo
norm
NFKC
f11
f12
f21
f22
f3
f4
f5
f6
f7
f8
f9
name
Resourceprep
ver
1
iana
非現行
ietf
RFC 3920 >>126 (RFC 6122 により廃止)、 RFC 6122 >>135 (RFC 7622 により廃止)
rep
Unicode 3.2
map1
map2
map3
mapo
norm
NFKC
f11
f12
f21
f22
f3
f4
f5
f6
f7
f8
f9
fo
bidi
context
[132] XMPP 資源部分 (旧称・資源識別子)
note
[140] RFC は改訂されていますが、内容は変わっていないので版はどちらも「1」です。
name
SASLprep
rep
Unicode 3.2
map1
map2
map3
mapo
C.1.2C.1.1
norm
NFKC
f11
f12
f21
f22
f3
f4
f5
f6
f7
f8
f9
bidi
ver
1
iana
非現行
ietf
RFC 4013 (RFC 7613 により廃止)
name
trace
ver
1
iana
現行
ietf
RFC 4505 >>24
rep
Unicode 3.2
map1
map2
map3
mapo
norm
f11
f12
f21
f22
f3
f4
f5
f6
f7
f8
f9
bidi
context
[22] SASL ANONYMOUS
note
[23] 一つ前の RFC 2245非ASCII文字を認めておらず、 Stringprep も使っていませんでした。
name
KRBprep
ietf
I-D >>16 (放棄)
iana
未登録
context
Kerberos
note
[21] 早期の Internet Draft 止まりで RFC 化されていませんが、 GNU Libidn で実装されています >>7。 (この表は libidn の実装状況に従っています。)
map1
map3
norm
NFKC
f12
f22
f3
f4
f5
f6
f7
f8
f9
bidi
name
RFC 4518
iana
未登録
ietf
RFC 4518
rep
Unicode 3.2
map1
map2
map3
mapo
あり
norm
NFKC
f11
f12
f21
f22
f3
f4
f5
f6
f7
f8
f9
fo
U+FFFD
note
なぜかプロファイル扱いにはなっていません。

RFC 4518

[157] RFC 4518LDAP 用のプロファイルを定義しています。 このプロファイルstringprep の前や後の処理を含めて規定しています。

[159] そのためか IANA登録簿にはプロファイルとして登録されていません。
[175] LDAP 自体のみならず、 証明書distinguished name比較でも用いられます。

[161] Map より前に転符号化 (Transcoding) を行います。これは Unicode 文字列へと変換する操作です。

LDAP文字列参照。

[162] Map は、 RFC 3454 の表を使わずに独自の表 (>>163) を使っています。 RFC 3454 の表と若干の出入りがある他、 RFC 3454 で禁止に分類されている文字が除去されたり、 U+0020写像されたりします。

[165] Mapcase folding (RFC 3454 表 B.2) が含まれるか否かは、 比較方法により変わります。

LDAP文字列参照。

[164] Prohibit は、 RFC 3454 の表の他に U+FFFD も含まれています。 また RFC 3454 の表A.1 (Unicode 3.2 時点での未定義符号位置) も含まれています (つまり蓄積文字列 (>>110) に相当します)。 >>167 は禁止される符号位置の一覧です。

[166] 処理の最後に Insignificant Character Handling >>163, >>171 を行います。 これには次の3種類があり、比較方法によりいずれかを選択します。

  1. [172] Insignificant Space Handling
    1. 入力が属性値または非部分文字列 assertion value なら、
      1. 入力に間隔以外の文字が含まれないなら、文字列 SPACE SPACE を返します。
      2. そうでないなら、
        1. 間隔の連続をすべて文字列 SPACE SPACE に置き換えます。
        2. 先頭と末尾に文字列 SPACE SPACE があれば除去します。
        3. 先頭と末尾に SPACE を挿入します。
    2. 入力が部分文字列 assertion value なら、
      1. 入力に間隔以外の文字が含まれないなら、 SPACE を返します。
      2. そうでないなら、
        1. 間隔の連続をすべて文字列 SPACE SPACE に置き換えます。
        2. 入力が initial substring なら、先頭の間隔列を除去し、 SPACE を挿入します。
        3. 入力が initial substring か any substring で間隔で終わるなら、 末尾の間隔列を除去し、 SPACE を挿入します。
        4. 入力が any substring か final substring で間隔で始まるなら、 先頭の間隔列を除去し、 SPACE を挿入します。
        5. 入力が final substring なら、末尾の間隔列を除去し、 SPACE を挿入します。
  2. [173] numericString Insignificant Character Handling
    1. 間隔をすべて削除します。
  3. [174] telephoneNumber Insignificant Character Handling
    1. 間隔をすべて削除します。
    2. ハイフンをすべて削除します。

[168] ここで間隔 (space) とは、 SPACE であって直後に結合文字がないものをいいます。 >>158

[169] ここでハイフン (hyphen) とは、いくつかの文字 (>>170) の直後に結合文字が来ないものをいいます >>158

[155] >>19GNU Libidn で実装されています。 >>19>>153>>154 を経て RFC 4518 となっています。

[150] しかし必要性が不明瞭なのに Stringprep 本家と似て非なるものを制定することになるとは、 この時点で既に技術開発としての Stringprep 族は破綻していたと言わざるを得ませんね。

[151] プロトコルによって細部は違っても全体的な処理の流れは同じだから共通化しようというのが stringprep のはずだったのに、そのフレームワークに合わない改変をするしかなくなって、 しかもそのバリエーションを包含できる stringprep の新版ではなくて、 似て非なる別規格を作ることになったのですから。

[184] 技術的にはそういうほど別物でもなさそうに見えるので、統合できなかったのは政治的理由なんだろうなあ。。。

iSCSI の追加禁止文字

[8] RFC 3722 6.1. の表 (共通入力機構不適切文字):

符号位置文字名称
U+3002IDEOGRAPHIC FULL STOP

[26] RFC 3722 6.2. の表 (禁止済み ASCII 文字):

符号位置
U+0000U+002C
U+002F
U+003BU+0040
U+005BU+0060
U+007BU+007F

Nodeprep の追加禁止文字

[9] RFC 3920 / RFC 6122 A.5. の表:

U+0022QUOTATION MARK
U+0026AMPERSAND
U+0027APOSTROPHE
U+002FSOLIDUS
U+003ACOLON
U+003CLESS-THAN SIGN
U+003EGREATER-THAN SIGN
U+0040COMMERTIAL AT

テストケース

[18] Nameprep and IDNA Test Vectors http://www.gnu.org/software/libidn/draft-josefsson-idn-test-vectors.html

[20] Savannah Git Hosting - libidn.git/tree - tests/ http://git.savannah.gnu.org/gitweb/?p=libidn.git;a=tree;f=tests

歴史

RFC 3454

[180] IETFIDNA と共に Stringprep を開発し、 そのプロファイルである NameprepIDNA で用いることとしました。

[181] StringprepRFC 3454 として出版されました。

IDNA2008 との関係

[28] IDNA2003Stringprepプロファイルである Nameprep を使っていましたが、 IDNA2008Nameprep を使わずにすべて独自に定義しています。 NameprepIDNA2008 にはまったく互換性がありません。

[29] IDNA2008RFC では、他の Stringprep を使う応用であるセキュリティ系プロトコルとは要件が異なり (ドメイン名は分かりやすいことが重要だが合言葉は分かりにくいことが重要)、 共通の仕組みを用いることは必ずしも好ましくないと指摘しています。

PRECIS へ

[145] RFC 6885Stringprepプロファイルとその問題点をまとめたものです。 StringprepUnicode 3.2 に固定されているなど問題があり IDNA2008Stringprep を使わなくなりましたが、 新しいプロトコルは改版可能であるなど DNS とは事情が異なるとして、それとは別の方法で Stringprep を改良する必要があると指摘し、プロファイルの用法を分析しています。

[146] IETF では「Preparation and Comparison of Internationalized Strings」を略して「PRECIS」 と称しており、 Stringprep の改訂のために PRECIS WG を設けています。

[182] RFC 3454PRECISRFC 7564 の出版に伴い廃止されています。

廃止の時点でまだ Stringprep の各プロファイルPRECIS 版は出版されておらず、参照先の RFC廃止状態になっているわけですが、 そんなので IETF の手続き的には良いのでしょうか...
[183] PRECIS も参照。

[141] RFC 7613利用者名合言葉のための PRECIS プロファイルを規定しています。

[147] RFC 7613RFC 4013 SASLprep廃止しています >>112。 ただし従来の SASLprep を用いる応用は、明示的に改訂しない限り、 PRECIS に自動的に移行するわけではない >>112 とされています。

実装

[14] Unicode::Stringprep - search.cpan.org ( ( 版)) http://search.cpan.org/dist/Unicode-Stringprep/lib/Unicode/Stringprep.pm

[17] GNU Libidn>>16>>19 に対応しているらしいです。

メモ

[10] なんか >>7 と同じ表が既に存在しているしorz

Stringprep Profiles http://nameprep.org/stringprep.html

[15] http://search.cpan.org/dist/Unicode-Stringprep/lib/Unicode/Stringprep.pm#CAVEATS

[178] RFC 7542 - The Network Access Identifier ( 版) https://tools.ietf.org/html/rfc7542#section-1.4

* Section 2.4 of [RFC4282] required mappings that are language

specific and that are nearly impossible for intermediate nodes to

perform correctly without information about that language.

* Section 2.4 of [RFC4282] requires normalization of usernames,

which may conflict with local system or administrative

requirements.

* The recommendations in Section 2.4 of [RFC4282] for treatment of

bidirectional characters have proven to be unworkable.

* The prohibition of the use of unassigned code points in

Section 2.4 of [RFC4282] effectively prohibits support for new

scripts.

* No Authentication, Authorization, and Accounting (AAA) client,

proxy, or server has implemented any of the requirements in

Section 2.4 of [RFC4282], among other sections.

[179] NAIRFC 4282 時代に Stringprep を採用していましたが、 RFC 7542>>178 の通り、これが機能しなかったとして、 ただの NFC に変更しています。 PRECIS も使っていません。

[148] RFC 8146 - Adding Support for Salted Password Databases to EAP-pwd () https://tools.ietf.org/html/rfc8146

[149] draft-irtf-cfrg-augpake-08 - Augmented Password-Authenticated Key Exchange (AugPAKE) () https://tools.ietf.org/html/draft-irtf-cfrg-augpake-08