[7] [DFN[[[ALPN]]]] は、[[アプリケーション層プロトコル]]の[[折衝]]を行う 
[[TLS拡張]]です。 [[TLS]] 上で利用する[[アプリケーション層プロトコル]]を選択するために使うことができます。

[9] [[サーバー]]が同じ [[TCP]] [[ポート]]上で [[TLS]] を介して複数の[[アプリケーション層プロトコル]]の通信を受け付けている場合に、
そのいずれを用いるかを決定するために使います。

[EG[
[70] [[HTTP/2]] に対応した[[クライアント]]や[[サーバー]]は、 [[HTTP/1.1]] と [[HTTP/2]]
のどちらを使うか決定するために [[ALPN]] を使っています。
]EG]

* 仕様書

[REFS[
- [4] '''[CITE@en[RFC 7301 - Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension]] ( ([TIME[2014-07-12 02:05:37 +09:00]] 版)) <http://tools.ietf.org/html/rfc7301>'''
- [5] [CITE[Transport Layer Security (TLS) Extensions]] ([TIME[2014-12-12 17:25:31 +09:00]] 版) <http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids>
- [53] [CITE@en[RFC 7639 - The ALPN HTTP Header Field]] ([TIME[2015-08-27 14:11:50 +09:00]] 版) <https://tools.ietf.org/html/rfc7639>
- [81] [CITE@en[RFC 7838 - HTTP Alternative Services]] ([TIME[2016-04-17 23:25:39 +09:00]] 版) <https://tools.ietf.org/html/rfc7838#section-2>
]REFS]

* 意味

[71] [[ALPN]] は、 [[TLS]] 上で使う[[プロトコル]]について[[クライアント]]が候補を提示し、
[[サーバー]]がその中のいずれかを選ぶことにより、[[折衝]]するものです。

[72] [[ALPN]] は、対応が必須ではない[[TLS拡張]]です。 [[TLS]]
の実装は必ずしも [[ALPN]] に対応する必要はありません。しかし [[HTTP/2]]
のように [[TLS]] 上で使う[[プロトコル]]によっては [[ALPN]] 
への対応が必要となることがあります。従って実用上汎用的な [[TLS]]
の実装は [[ALPN]] にも対応する必要があります。

* 構文

[18] [[TLS]] の[[拡張型]]は、 
[DFN[[CODE[[[application_layer_protocol_negotiation]]]]]] ([CODE[[[16]]]])
です [SRC[>>4]]。

[20] [CODE(TLS)@en[[[ClientHello]]]] および [CODE[[[ServerHello]]]] における[[拡張データ]]は、
[CODE[[[ProtocolNameList]]]] でなければ[['''なりません''']] [SRC[>>4]]。

[21] [DFN[[CODE[[[ProtocolNameList]]]]]] は、 2[[バイト]][[以上]]2[SUP[16]]-1[[バイト]][[以下]]で構成される欄
[DFN[[CODE[[[protocol_name_list]]]]]] であり、 [CODE[[[ProtocolName]]]]
のリストです。 [SRC[>>4]]

[FIG(packet)[
:width:16

=2 長さ
=14... [CODE[[[ProtocolName]]]] の列
]FIG]

[23] [[クライアント]]の [CODE[[[ProtocolNameList]]]] は、[[クライアント]]が[[広告]]する[[プロトコル]]のリストを、
優先度の[[降順]]で示したものです。 [SRC[>>4]]

[29] [[サーバー]]の [CODE[[[ProtocolNameList]]]] は、[[プロトコル]]を1つだけ含まなければ[['''なりません''']] [SRC[>>4]]。

[22] [DFN[[CODE[[[ProtocolName]]]]]] は、1[[バイト]][[以上]]2[SUP[8]]-1[[バイト]][[以下]]の[[バイト列]]です [SRC[>>4]]。

[FIG(packet)[
:width:16

= 1 長さ
= 15... プロトコル名
]FIG]

[24] [CODE[[[ProtocolName]]]] は、 [[IANA]] に登録された不透明の[[バイト列]]です [SRC[>>4]]。

;; [45] 現実には登録されていない値も使われています。

* 文脈

[19] [[TLS]] の[[クライアント]]は、 [CODE(TLS)@en[[[ClientHello]]]]
で本 [[TLS拡張]]を使うことができます [SRC[>>4]]。

[35] [[TLS]] の[[サーバー]]は、 [CODE(TLS)@en[[[ClientHello]]]] での指定に対して
[CODE(TLS)@en[[[ServerHello]]]] で本 [[TLS拡張]]を使うことができます [SRC[>>4]]。

;; [36] [CODE[[[ClientHello]]]] で [[ALPN]] が使われなかった場合に使って良いのかは謎です。

[38] なお [[ALPN]] は[[折衝]]時に使われるので、[[プロトコル]]は[[平文]]でやりとりされます。
[[プロトコル]]を隠す必要があるなら、[[接続]]確立後に[[再折衝]]するなど対策が必要です [SRC[>>4]]。

[39] [[ALPN]] は、 [[HTTP/2]] を利用する際に使われています。

;; [[HTTPS]] を参照。

[40] [[ALPN]] により[[クライアント]]が指定する[[プロトコル]]のリストは、
[[fingerprinting vector]] です。

* 処理

[25] [[サーバー]]は、 [CODE[[[ClientHello]]]] で [[ALPN]] を受信したら、
適当な[[プロトコル]]を選択して、 [CODE[[[ServerHello]]]] に [[ALPN]]
[[TLS拡張]]によって含めて構いません。 [SRC[>>4]]

;; [30] [[ALPN]] は [[TLSセッション]]ではなく[[接続]]の特性であり、
[[セッション再開]]や[[セッションチケット]]を使う場合でも、
以前の [[ALPN]] 折衝結果は影響しません [SRC[>>4]]。

[31] [[サーバー]]は、対応する[[プロトコル]]の一覧を保持しておき、
その中で[[クライアント]]が対応している[[プロトコル]]のみを選ぶことが期待されています。
その場合には、[[クライアント]]が[[広告]]した[[プロトコル]]の中で[[サーバー]]が最も好ましいと考えるものを選ぶ[['''べき''']]です。 [SRC[>>4]]

[26] [[サーバー]]は、認識しないプロトコル名は無視します。 [SRC[>>4]]

[34] [[サーバー]]が [CODE[[[ServerHello]]]] の [[ALPN]] 拡張で示したプロトコルは
([[再折衝]]まで) 当該[[接続]]で
[[definitive]] なものでなければ[['''なりません''']]。[[サーバー]]は示したプロトコルと異なるものを使っては[['''なりません''']]。 [SRC[>>4]]

[37] [[サーバー]]でプロトコル選択を行うため、[[サーバー]]は[[証明書]]の選択や[[接続]]の
[[rerouting]] を必要に応じて行えます [SRC[>>4]]。

[32] [[サーバー]]は、[[クライアント]]が[[広告]]した[[プロトコル]]のいずれも対応していない場合は、
[DFN[[CODE[[[no_application_protocol]]]]]] [[fatal alert]]
を返す[['''べきです''']] [SRC[>>4]]。

;; [33] [[alert]] の [[IANA登録簿]]にはなぜかこの値は掲載されていません。 [TIME[2015-05-28T09:41:53.400Z]]

[78] [[サーバー]]は、[[クライアント]]が指定した[[プロトコル]]の中から自身が対応しているものを1つ選択することが期待されています。
しかし[[クライアント]]が指定しなかった[[プロトコル]]を指定することも、
できなくはありません。[[クライアント]]はそれをエラーとして扱うべきと思われますが、
実際には対処方法は色々なようです。

[EG[
[79] [[Webブラウザー]]によっては、
[CODE[[[http/1.1]]]] のみを指定したにも関わらず[[サーバー]]が [CODE[[[h2]]]]
を返してきた時、 [[HTTP/2]] を使うことがあります。
]EG]

[73] なお、 [[ALPN]] に対応していない[[サーバー]]は、[[クライアント]]が [[ALPN]]
を指定したとしても無視します。その場合[[クライアント]]がどうするべきかは、
[[プロトコル]]に依存します。

[EG[
[74] 旧来の [[HTTPS]] の[[サーバー]]は [[ALPN]] に対応していませんでした。
[[ALPN]] 対応の [[HTTPS]] [[クライアント]]は常に [CODE[[[http/1.1]]]] と
[CODE[[[http/2]]]] を [[ALPN]] で指定するので、 [[ALPN]] 対応の[[サーバー]]はどちらかを選ぶことになります。
[[ALPN]] 未対応の[[サーバー]]は、 [[ALPN]] の有無に関わらず昔ながらの動作、すなわち 
[CODE[[[http/1.1]]]] 相当の動作をすることになります。
]EG]

* プロトコル名

[10] [[プロトコル名]]としては、通常は名前を [[UTF-8]] で[[符号化]]した[[バイト列]]を使うこととなっています。

[11] [[IANA登録簿]] (>>5) があります。

[12] 次の値が使われています。
[FIG(short list)[
- [CODE@en[[[http/1.1]]]]
- [CODE@en[[[spdy/1]]]]
- [CODE@en[[[spdy/2]]]]
- [CODE@en[[[spdy/3]]]]
- [CODE@en[[[spdy/3.1]]]]
- [CODE@en[[[stun.turn]]]]
- [CODE@en[[[stun.nat-discovery]]]]
- [CODE@en[[[h2]]]]
- [CODE@en[[[h2c]]]]
- [CODE@en[[[h2-11]]]]
- [CODE@en[[[h2-12]]]]
- [CODE@en[[[h2-13]]]]
- [CODE@en[[[h2-14]]]]
- [CODE@en[[[h2-15]]]]
- [CODE@en[[[h2-16]]]]
- [CODE[quic]]
- [CODE[webrtc]]
- [CODE[c-webrtc]]
- [CODE[ftp]]
- [CODE[imap]]
- [CODE[pop3]]
- [CODE[managesieve]]
- [CODE[hq]]
- [CODE[http/0.9]]
- [CODE[http/1.0]]
]FIG]

;; [28] >>27 に [[JSON]] 形式の一覧データファイルがあります。
[REFS[
- [27] [CITE@en[data-web-defs/tls.txt at master · manakai/data-web-defs]] ([TIME[2015-05-28 13:20:43 +09:00]] 版) <https://github.com/manakai/data-web-defs/blob/master/doc/tls.txt>
]REFS]

[80] [[ALPNプロトコル名]]は、次の場面で使われます。
[FIG(short list)[
- [[TLS]] [[ALPN]]
- [CODE(HTTP)@en[ALPN:]]
- [[代替サービス]]
]FIG]

[82] [[代替サービス]]では、特に規定がない限り、当該[[プロトコル]]を [[TLS]]
上で利用することを意味する [SRC[>>81]] とされています。

[REFS[
- [87] [CITE@en[NextHopProtocol Values · Issue #122 · w3c/resource-timing]] ([TIME[2018-05-18 15:42:18 +09:00]]) <https://github.com/w3c/resource-timing/issues/122>
]REFS]

* [CODE(HTTP)@en[ALPN:]] ヘッダー (HTTP)

[54] [[HTTP]] の [DFN[[CODE(HTTP)@en[[[ALPN:]]]]]] [[ヘッダー]]は、
[CODE(HTTP)@en[[[CONNECT]]]] [[トンネル]]内の[[プロトコル]]の[[ヒント]]を示すものです。

** 意味

[55] [[クライアント]]が [CODE(HTTP)@en[[[CONNECT]]]] [[要求]]により確立する[[トンネル]]内で使う[[プロトコル]](群)を示すものです
[SRC[>>53]]。

[57] 複数あり得る時は、すべてを示します [SRC[>>53]]。

[58] この[[ヘッダー]]は[[クライアント]]の意思を示すためだけのものであり、
[[折衝]]に使うことを目的とはしていません [SRC[>>53]]。

[75] ヘッダー名から分かる通り [[TLS拡張]]の [[ALPN]] の強い影響下にあり、
併用するものとして設計されてはいますが、両者が連動するわけではありません。

** 構文

[61] [CODE(HTTP)@en[[[ALPN:]]]] [[ヘッダー]]の値は、
1つ以上の値の[[リスト]] ([CODE(HTTP)[#]]) です [SRC[>>53]]。

[FIG(railroad)[
= 値
= *
== [[OWS]]
== [CODE(HTTP)[[[,]]]]
== [[OWS]]
== 値
]FIG]

[60] 値は、 [[ALPN]] の[[プロトコル]]識別子を使います [SRC[>>53]]。
ただし [[HTTP]] の[[字句]]で表せない[[オクテット]]および [CODE(HTTP)[[[%]]]]
は、 [[RFC 3986]] [[パーセント符号化]]しなければ[['''なりません''']] [SRC[>>53]]。
それ以外の[[字句]]で表せる[[オクテット]]は、[[パーセント符号化]]しては[['''なりません''']]
[SRC[>>53]]。[[パーセント符号化]]の[[十六進数]]は、[[大文字]]でなければ[['''なりません''']]
[SRC[>>53]]。

;; [62] 値の大文字と小文字は、区別されます。

[56] [[トンネル]]内で [[TLS]] を使う時は、 [[TLS handshake]] の [CODE@en[[[ClientHello]]]]
で [[ALPN]] によって示す[[プロトコル]]のリストと同じものとします [SRC[>>53]]。

[63] [[TLS]] を使わない場合など[[折衝]]しないと思われる場合は、
利用するプロトコルを1つ指定します。その他何らかの方法で折衝できる場合は、
折衝対象のプロトコルを指定します。 [SRC[>>53]]

** 文脈

[66] [CODE(HTTP)@en[[[CONNECT]]]] [[要求]]で指定できます。
この[[ヘッダー]]は必須ではありません [SRC[>>53]]。

[68] この[[ヘッダー]]は、[[fingerprinting vector]] です。
機密や繊細な情報を晒してしまうことになるときは、
送信する[['''べきではありません''']] [SRC[>>53]]。

[76] [CODE[[[CONNECT]]]] 以外での利用について何の規定もありませんが (それが [[IETF]]
クオリティー)、 [CODE(HTTP)@en[[[CONNECT]]]] 以外では意味をなしません。

** 処理

[59] [[プロキシ]]は、示された[[プロトコル]]を見て[[トンネル]]の拒絶や優先度制御、
その他の決定を行うことができます [SRC[>>53]]。

;; [64] しかし [CODE(HTTP)@en[[[ALPN:]]]] [[ヘッダー]]の値が正しいとは限らないので、
アクセス制御に直ちに用いられるわけではありません [SRC[>>53]]。

[65] [[プロキシ]]は、[[トンネル]]のプロトコルを認識できなかったというだけの理由で[[トンネル]]を切断する[['''べきではありません''']]
[SRC[>>53]]。

* 関連

[17] [[HTTPS]] も参照。

* 歴史

** NPN

[42] [DFN[[CODE[[[13172]]]]]] ([DFN[[CODE[[[next_protocol_negotiation]]]]]])

[1] [CITE@en[draft-agl-tls-nextprotoneg-00 - Transport Layer Security (TLS) Next Protocol Negotiation Extension]]
([TIME[2010-07-24 08:19:18 +09:00]] 版)
<http://tools.ietf.org/html/draft-agl-tls-nextprotoneg>

[2] [CITE@en[HTML5 Revision Tracker]]
([TIME[2010-08-13 22:20:59 +09:00]] 版)
<http://html5.org/tools/web-apps-tracker?from=5287&to=5288>

[3] [CITE@en[HTML5 Revision Tracker]]
([TIME[2010-08-14 10:48:51 +09:00]] 版)
<http://html5.org/tools/web-apps-tracker?from=5288&to=5289>

[6] >>2, >>3 この [[Web Socket]] の [[NPN]] 対応、[[IETF]] に移管された後いつの間にか消えてなくなったようですね。。。
[[Web Socket]] は [[HTTP]] から移行するモードで独立したプロトコルではない、
というのが [[IETF]] の主張だからなのでしょうか。

[43] [[Firefox]] も [[Chrome]] も、まだ [CODE[[[ClientHello]]]] に [[NPN]]
を含めています。 [TIME[2015-08-15T03:15:28.100Z]]

[44] 廃案になったためか、実際に使われている値であるにも関わらず、
[[IANA登録簿]]には掲載されていません。 [TIME[2015-08-15T03:16:14.400Z]]

** ALPN

[8] [[ALPN]] は [[HTTP/2]] のために [[IETF]] [[HTTPbis WG]] からの要求で開発されました [SRC[>>4]]。

[13] [CITE[SPDY - OpenSSL の ALPN/NPN API の使い方 - Qiita]]
( ([TIME[2014-12-13 20:30:42 +09:00]] 版))
<http://qiita.com/tatsuhiro-t/items/dea3fb279ad265681049>

[14] [CITE@en[1047698 – ALPN advertisment order may be wrong]] ([TIME[2014-12-13 20:32:49 +09:00]] 版) <https://bugzilla.mozilla.org/show_bug.cgi?id=1047698>

[15] [CITE@en[Chromium Blog: Hello HTTP/2, Goodbye SPDY]]
( ([TIME[2015-02-10 03:03:41 +09:00]] 版))
<http://blog.chromium.org/2015/02/hello-http2-goodbye-spdy-http-is_9.html>

[16] [CITE@en[RFC 7443 - Application-Layer Protocol Negotiation (ALPN) Labels for Session Traversal Utilities for NAT (STUN) Usages]]
([TIME[2015-01-23 14:56:59 +09:00]] 版)
<https://tools.ietf.org/html/rfc7443>

[46] [CITE@en[861266 – Implement TLS 1.2 (RFC 5246) in Gecko (Firefox, Thunderbird), on by default]]
([TIME[2015-08-28 11:49:39 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=861266>

[47] [CITE@en[996238 – ALPN identifiers for WebRTC]]
([TIME[2015-08-28 11:51:56 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=996238>

[48] [CITE@en[959664 – Add ALPN (RFC 7301) support to NSS]]
([TIME[2015-08-28 11:57:54 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=959664>

[49] [CITE@en[1047698 – ALPN advertisment order may be wrong]]
([TIME[2015-08-28 11:58:39 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=1047698>

[51] [CITE[Issue 497770 - chromium - BoringSSL ALPN callback cannot send SSL ALERT 120 (no application protocol found) - An open-source project to help move the web forward. - Google Project Hosting]]
([TIME[2015-09-24 20:45:48 +09:00]] 版)
<https://code.google.com/p/chromium/issues/detail?id=497770>

[FIG(quote)[
[FIGCAPTION[
[52] [CITE@en[ALPN Status · http2/http2-spec Wiki]]
([TIME[2015-09-24 20:58:32 +09:00]] 版)
<https://github.com/http2/http2-spec/wiki/ALPN-Status>
]FIGCAPTION]

> Note that some client implementations deal very poorly if a server sends both ALPN and NPN in the ServerHello. When a server responds negotiating a protocol via ALPN in the ServerHello, it must not also send a list of protocols for NPN negotiation as well.

]FIG]

** [CODE(HTTP)@en[ALPN:]] ヘッダー

[41] [CITE@en[draft-ietf-httpbis-tunnel-protocol-05 - The ALPN HTTP Header Field]]
([TIME[2015-07-09 12:21:49 +09:00]] 版)
<https://tools.ietf.org/html/draft-ietf-httpbis-tunnel-protocol-05>

[50] [CITE@en[1125292 – Support Tunnel-Protocol for WebRTC]]
([TIME[2015-09-24 20:36:41 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=1125292>

* 実装

[67] [[HTTPS]] において [[Chrome]] も [[Firefox]] も [[ALPN]]
を使って [[HTTP/1]] と [[HTTP/2]] を選択しています。

;; [[HTTPS]] も参照。

[69] [[HTTPS]] のための [CODE(HTTP)@en[[[CONNECT]]]] [[要求]]には、
[[Firefox]] も [[Chrome]] も [CODE(HTTP)@en[[[ALPN:]]]]
[[ヘッダー]]を使わないようです。 [TIME[2015-09-24T13:53:06.500Z]]

[77] 古い [[OpenSSL]] では [[ALPN]] が使えません。少し古めの [[OS]]
の標準 [[OpenSSL]] [[パッケージ]]は古い [[OpenSSL]] (にパッチを当てたもの)
しか提供していないことがあるので、しばらくは注意が必要です。 [TIME[2015-10-17T04:46:45.200Z]]

[FIG(quote)[
[FIGCAPTION[
[83] [CITE[API Deprecations and Removals in Chrome 51 | Web Updates - Google Developers]]
( ([TIME[2016-08-03 01:42:01 +09:00]]))
<https://developers.google.com/web/updates/2016/04/chrome-51-deprecations#remove-tls-next-protocol-negotiation-npn>
]FIGCAPTION]

> As part of deprecation of SPDY, NPN is removed, having previously been replaced with ALPN.

]FIG]


[84] [CITE@en[Added a link to the ALPN Protocol IDs registry #122 (#125)]]
([[plehegar]]著, [TIME[2017-10-30 23:12:47 +09:00]])
<https://github.com/w3c/resource-timing/commit/68372fd743899173148227cab10caad3bf762e8c>

[85] [CITE@en[NextHopProtocol Values · Issue #122 · w3c/resource-timing]]
([TIME[2017-10-31 14:40:22 +09:00]])
<https://github.com/w3c/resource-timing/issues/122>

[86] [CITE@en[Added a link to the ALPN Protocol IDs registry by plehegar · Pull Request #125 · w3c/resource-timing]]
([TIME[2017-10-31 14:40:37 +09:00]])
<https://github.com/w3c/resource-timing/pull/125>

[88] [CITE@en[Better registry definition, removed HTTP0.9 and 1.0, made ALPN a MUST]]
([[yoavweiss]]著, [TIME[2018-06-15 18:58:54 +09:00]])
<https://github.com/w3c/resource-timing/commit/de148c01702782055f4d3309c0c879f0d10d22a5>

[89] [CITE@en[Add nextHopProtocol HTTP/0.9 and 1.0. Link to QUIC by yoavweiss · Pull Request #159 · w3c/resource-timing]]
([TIME[2018-06-16 14:36:36 +09:00]])
<https://github.com/w3c/resource-timing/pull/159>