역주: 용어는 glossary.md, 번역 방식은 번역 가이드를 따른다. 핸드셰이크 메시지 이름은 코드 서식(
ClientHello,ServerHello)으로, 원문이 따옴표로 쓴 확장·필드·구조체·경고 이름(“application_layer_protocol_negotiation”, “extension_data”, “ProtocolNameList”, “no_application_protocol”)은 따옴표 그대로 둔다. 구조체 정의와 메시지 흐름 그림은 원문 그대로 둔다.
이 문서는 TLS(Transport Layer Security) 핸드셰이크 안에서 애플리케이션 계층 프로토콜을 협상하기 위한 TLS 확장을 설명한다. 같은 TCP 또는 UDP 포트에서 여러 애플리케이션 프로토콜을 지원하는 경우, 이 확장을 사용하면 애플리케이션 계층이 TLS 연결 안에서 어떤 프로토콜을 사용할지 협상할 수 있다.
이 문서는 인터넷 표준화 트랙(Standards Track) 문서다.
이 문서는 IETF(Internet Engineering Task Force)의 결과물이며 IETF 커뮤니티의 합의를 나타낸다. 이 문서는 공개 검토를 거쳤고 IESG(Internet Engineering Steering Group)의 발행 승인을 받았다. 인터넷 표준에 대한 자세한 정보는 RFC 5741의 2절에 있다.
이 문서의 현재 상태, 정오표, 의견을 보내는 방법은 http://www.rfc-editor.org/info/rfc7301 에서 확인할 수 있다.
Copyright (c) 2014 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 (http://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.
Copyright (c) 2014 IETF Trust 및 문서 저자로 명시된 사람들. 모든 권리 보유.
이 문서에는 BCP 78과, 이 문서의 발행일에 유효한 IETF 문서 관련 IETF Trust 법적 조항(http://trustee.ietf.org/license-info)이 적용된다. 이 문서들은 이 문서에 대한 독자의 권리와 제한을 설명하므로 주의 깊게 검토하기 바란다. 이 문서에서 추출한 코드 구성 요소(Code Components)에는 Trust 법적 조항 4.e절에 설명된 Simplified BSD License 문구를 포함해야 하며, 이 코드 구성 요소는 Simplified BSD License에 설명된 대로 보증 없이 제공된다.
역주: 원문이 따르는 IETF Trust 법적 조항에 따라 원문의 Copyright Notice를 그대로 두고 그 아래에 한국어 번역을 덧붙였으며, 법적 효력은 원문에 있다.
점점 더 많은 애플리케이션 계층 프로토콜이 TLS 프로토콜 [RFC5246]로 캡슐화(encapsulation)되고 있다. 이 캡슐화 덕분에 애플리케이션은 사실상 전 세계 IP 인프라 전체에 걸쳐 443번 포트에 이미 마련되어 있는 안전한 통신 링크를 사용할 수 있다.
443번 포트처럼 서버 쪽 포트 번호 하나에서 여러 애플리케이션 프로토콜을 지원하는 경우, 클라이언트와 서버는 연결마다 사용할 애플리케이션 프로토콜을 협상할 필요가 있다. 왕복(round-trip)이 늘 때마다 최종 사용자의 경험이 나빠지므로, 클라이언트와 서버 사이에 네트워크 왕복을 더하지 않고 이 협상을 해내는 것이 바람직하다. 또한 협상된 애플리케이션 프로토콜에 따라 인증서를 선택할 수 있게 하면 유리하다.
이 문서는 애플리케이션 계층이 TLS 핸드셰이크 안에서 프로토콜 선택을 협상할 수 있게 하는 TLS 확장을 규정한다. 이 작업은 TLS 위의 HTTP/2([HTTP2]) 협상을 다루기 위해 HTTPbis 워킹 그룹(WG)이 요청한 것이지만, ALPN은 임의의 애플리케이션 계층 프로토콜의 협상을 쉽게 해 준다.
ALPN을 사용하면 클라이언트는 지원하는 애플리케이션 프로토콜 목록을 TLS ClientHello 메시지의 일부로 보낸다. 서버는 프로토콜을 하나 고르고, 선택한 프로토콜을 TLS ServerHello 메시지의 일부로 보낸다. 따라서 애플리케이션 프로토콜 협상은 네트워크 왕복을 더하지 않고 TLS 핸드셰이크 안에서 끝낼 수 있으며, 서버는 원하면 애플리케이션 프로토콜마다 다른 인증서를 대응시킬 수 있다.
이 문서의 키워드 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL”은 [RFC2119]에 설명된 대로 해석한다.
이 문서는 새 확장 유형(“application_layer_protocol_negotiation(16)”)을 정의한다. 클라이언트는 이 확장을 ClientHello 메시지에 포함할 수 있다(MAY).
enum {
application_layer_protocol_negotiation(16), (65535)
} ExtensionType;
(“application_layer_protocol_negotiation(16)”) 확장의 “extension_data” 필드에는 반드시 “ProtocolNameList” 값이 들어 있어야 한다(SHALL).
opaque ProtocolName<1..2^8-1>;
struct {
ProtocolName protocol_name_list<2..2^16-1>
} ProtocolNameList;
“ProtocolNameList”에는 클라이언트가 알리는 프로토콜 목록이 선호도가 높은 것부터 차례로 들어 있다. 프로토콜의 이름은 IANA에 등록된, 불투명하고(opaque) 비어 있지 않은 바이트 문자열로 정하며, 자세한 내용은 이 문서의 6장(“IANA 고려 사항”)에서 설명한다. 목록에 빈 문자열을 넣어서는 안 되며(MUST NOT), 바이트 문자열을 잘라서도 안 된다(MUST NOT).
“application_layer_protocol_negotiation” 확장이 들어 있는 ClientHello를 받은 서버는 알맞은 프로토콜 선택 응답을 클라이언트에 돌려줄 수 있다(MAY). 서버는 인식하지 못하는 프로토콜 이름은 무시한다. 서버는 새 ServerHello 확장 유형(“application_layer_protocol_negotiation(16)”)을 확장된(extended) ServerHello 메시지에 담아 클라이언트에 돌려줄 수 있다(MAY). (“application_layer_protocol_negotiation(16)”) 확장의 “extension_data” 필드는 위에서 클라이언트의 “extension_data”에 대해 설명한 것과 같은 구조이며, 다만 “ProtocolNameList”에는 반드시 “ProtocolName”이 정확히 하나 들어 있어야 한다(MUST).
따라서 ClientHello와 ServerHello 메시지에 “application_layer_protocol_negotiation” 확장이 있는 전체 핸드셰이크(full handshake)는 다음 흐름을 따른다([RFC5246]의 7.3절과 비교해 보라).
Client Server
ClientHello --------> ServerHello
(ALPN extension & (ALPN extension &
list of protocols) selected protocol)
Certificate*
ServerKeyExchange*
CertificateRequest*
<-------- ServerHelloDone
Certificate*
ClientKeyExchange
CertificateVerify*
[ChangeCipherSpec]
Finished -------->
[ChangeCipherSpec]
<-------- Finished
Application Data <-------> Application Data
그림 1
* 항상 보내지는 않는, 선택적이거나 상황에 따른 메시지를 나타낸다.
역주: 그림에서 클라이언트의
ClientHello는 ALPN 확장과 프로토콜 목록(ALPN extension & list of protocols)을, 서버의ServerHello는 ALPN 확장과 선택한 프로토콜(ALPN extension & selected protocol)을 담는다.
“application_layer_protocol_negotiation” 확장이 있는 약식 핸드셰이크(abbreviated handshake)는 다음 흐름을 따른다.
Client Server
ClientHello --------> ServerHello
(ALPN extension & (ALPN extension &
list of protocols) selected protocol)
[ChangeCipherSpec]
<-------- Finished
[ChangeCipherSpec]
Finished -------->
Application Data <-------> Application Data
그림 2
다른 많은 TLS 확장과 달리, 이 확장은 세션의 속성이 아니라 연결의 속성만 정한다. 세션 재개(session resumption)나 세션 티켓 [RFC5077]을 사용할 때 이 확장의 이전 내용은 의미가 없으며, 새 핸드셰이크 메시지에 있는 값만 고려한다.
서버는 자신이 지원하는 프로토콜 목록을 선호 순서대로 가지고 있고, 클라이언트가 지원하는 프로토콜만 선택할 것으로 예상된다. 그 경우 서버는 자신이 지원하면서 클라이언트도 알린 프로토콜 가운데 가장 선호하는 것을 선택해야 한다(SHOULD). 클라이언트가 알린 프로토콜을 서버가 하나도 지원하지 않으면, 서버는 반드시 치명적(fatal) “no_application_protocol” 경고로 응답해야 한다(SHALL).
enum {
no_application_protocol(120),
(255)
} AlertDescription;
ServerHello의 “application_layer_protocol_negotiation” 확장 유형에서 식별한 프로토콜은 연결이 재협상(renegotiation)될 때까지 반드시 그 연결의 프로토콜로 확정되어야 한다(SHALL). 서버는 프로토콜을 선택해 응답한 뒤 애플리케이션 데이터 교환에 다른 프로토콜을 사용해서는 안 된다(SHALL NOT).
ALPN 확장은 TLS 프로토콜 확장의 전형적인 설계를 따르도록 만들어졌다. 구체적으로, 협상은 기존 TLS 아키텍처에 맞춰 전적으로 클라이언트/서버 hello 교환 안에서 이루어진다. “application_layer_protocol_negotiation” ServerHello 확장은 (연결이 재협상될 때까지) 그 연결의 프로토콜을 확정하도록 설계되었고, 평문으로 전송된다. 이는 TCP나 UDP 포트 번호만으로는 그 연결에서 쓸 애플리케이션 계층 프로토콜을 확정할 수 없을 때, 네트워크 요소(network element)가 그 연결에 차등 서비스(differentiated service)를 제공할 수 있게 하기 위해서다. 프로토콜 선택의 주도권을 서버에 둠으로써, ALPN은 협상된 프로토콜에 따라 인증서를 선택하거나 연결 경로를 바꾸는 시나리오를 쉽게 한다.
끝으로, 프로토콜 선택을 핸드셰이크 과정에서 평문으로 처리하므로, ALPN은 연결을 수립하기 전에 협상된 프로토콜을 숨길 수 있다는 잘못된 확신을 주지 않는다. 프로토콜을 숨겨야 한다면, 연결을 수립한 뒤 재협상하는 편이 진정한 TLS 보안 보장을 제공하므로 더 나은 방법일 것이다.
ALPN 확장은 TLS 세션 수립이나 애플리케이션 데이터 교환의 보안에 영향을 주지 않는다. ALPN은 TLS 연결에 연관된 애플리케이션 계층 프로토콜을 외부에서 볼 수 있게 표시하는 역할을 한다. 예전에는 연결에 연관된 애플리케이션 계층 프로토콜을 사용 중인 TCP나 UDP 포트 번호로 알아낼 수 있었다.
새 프로토콜 식별자를 추가해 프로토콜 식별자 레지스트리를 넓히려는 구현자와 문서 편집자는, TLS 버전 1.2 이하에서는 클라이언트가 이 식별자를 평문으로 보낸다는 점을 고려해야 한다. 또한 적어도 앞으로 10년 동안은 브라우저가 처음 보내는 ClientHello에 보통 이런 이전 버전의 TLS를 사용할 것으로 예상된다는 점도 고려해야 한다.
그런 식별자가 개인 식별 정보(personally identifiable information)를 유출할 수 있거나, 그런 유출이 프로파일링(profiling)이나 민감한 정보의 유출로 이어질 수 있을 때는 주의해야 한다. 새 프로토콜 식별자에 이 가운데 하나라도 해당하면, 그 식별자가 평문으로 보이게 되는 TLS 구성에서는 그 식별자를 사용하지 않아야 하며(SHOULD NOT), 그런 프로토콜 식별자를 규정하는 문서는 그런 안전하지 않은 사용을 하지 말라고 권해야 한다(SHOULD).
IANA는 “ExtensionType 값(ExtensionType Values)” 레지스트리에 다음 항목을 포함하도록 갱신했다.
16 application_layer_protocol_negotiation
이 문서는 기존 “TLS 확장(Transport Layer Security (TLS) Extensions)” 제목 아래에 “ALPN 프로토콜 ID(Application-Layer Protocol Negotiation (ALPN) Protocol IDs)”라는 이름의 프로토콜 식별자 레지스트리를 만든다.
이 레지스트리의 항목에는 다음 필드가 필요하다.
이 레지스트리는 [RFC5226]에 정의된 “Expert Review” 정책으로 운영된다. 지정 전문가(designated expert)는 식별된 프로토콜의 상호 운용 가능한 구현을 만들 수 있게 하는 영구적이고 쉽게 구할 수 있는 명세에 대한 참조를 포함하도록 권하는 것이 좋다.
이 레지스트리의 초기 등록은 다음과 같다.
Protocol: HTTP/1.1
Identification Sequence:
0x68 0x74 0x74 0x70 0x2f 0x31 0x2e 0x31 ("http/1.1")
Reference: [RFC7230]
Protocol: SPDY/1
Identification Sequence:
0x73 0x70 0x64 0x79 0x2f 0x31 ("spdy/1")
Reference:
http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft1
Protocol: SPDY/2
Identification Sequence:
0x73 0x70 0x64 0x79 0x2f 0x32 ("spdy/2")
Reference:
http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft2
Protocol: SPDY/3
Identification Sequence:
0x73 0x70 0x64 0x79 0x2f 0x33 ("spdy/3")
Reference:
http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3
역주: RFC 8447(2018년 8월)은 이 문서를 갱신해, 이 장의 두 레지스트리 이름 앞에 “TLS”를 붙여 “TLS ALPN 프로토콜 ID(TLS Application-Layer Protocol Negotiation (ALPN) Protocol IDs)”와 “TLS ExtensionType 값(TLS ExtensionType Values)”으로 바꾸었다. 또한 이 문서의 IANA 지시에서 빠져 있던 3.2절의 “no_application_protocol”(120) 경고를 TLS 경고(TLS Alerts) 레지스트리에 추가했다.
이 문서는 특히 Adam Langley가 작성한 NPN(Next Protocol Negotiation) 확장 문서와, Cisco의 Tom Wesselman, Cullen Jennings와 나눈 논의에서 도움을 받았다.
[RFC5246] Dierks, T. and E. Rescorla, “The Transport Layer Security (TLS) Protocol Version 1.2”, RFC 5246, August 2008.
역주: RFC 5246(TLS 1.2)은 2018년 8월 RFC 8446으로, 이어서 2026년 7월 RFC 9846으로 대체되었다(번역). 본문의 [RFC5246] 절 참조는 RFC 5246의 절을 가리킨다.
[RFC7230] Fielding, R. and J. Reschke, “Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing”, RFC 7230, June 2014.
[HTTP2] Belshe, M., Peon, R., and M. Thomson, “Hypertext Transfer Protocol version 2”, Work in Progress, June 2014.
역주: 이 초안은 2015년 5월 RFC 7540으로 발행되었고, RFC 7540은 2022년 6월 RFC 9113으로 대체되었다(번역).
[RFC5077] Salowey, J., Zhou, H., Eronen, P., and H. Tschofenig, “Transport Layer Security (TLS) Session Resumption without Server-Side State”, RFC 5077, January 2008.
역주: RFC 5077은 2018년 8월 RFC 8446으로, 이어서 2026년 7월 RFC 9846으로 대체되었다(번역).
Stephan Friedl
Cisco Systems, Inc.
170 West Tasman Drive
San Jose, CA 95134
USA
Phone: (720)562-6785
EMail: sfriedl@cisco.com
Andrei Popov
Microsoft Corp.
One Microsoft Way
Redmond, WA 98052
USA
EMail: andreipo@microsoft.com
Adam Langley
Google Inc.
USA
EMail: agl@google.com
Emile Stephan
Orange
2 avenue Pierre Marzin
Lannion F-22307
France
EMail: emile.stephan@orange.com
역주: 저자 주소는 2014년 발행 당시의 정보를 원문 그대로 옮긴 것이다.
김마리 (Mariel Kim)
Email: marikim.code@gmail.com
GitHub: https://github.com/marik0de