diff options
author | Hugo Landau <hlandau@openssl.org> | 2023-03-29 07:58:15 +0100 |
---|---|---|
committer | Pauli <pauli@openssl.org> | 2023-06-28 08:05:41 +1000 |
commit | e4c2988dc5f70f15a9cd88e8fa047325c1e41cd2 (patch) | |
tree | f8a0f38af203460f25a7c384e1da938ebd2c1ca7 /doc/designs/quic-design | |
parent | aef249612759a12683c472a1032629ad90f8fd4a (diff) | |
download | openssl-e4c2988dc5f70f15a9cd88e8fa047325c1e41cd2.tar.gz |
Multi-Stream API
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/19769)
Diffstat (limited to 'doc/designs/quic-design')
-rw-r--r-- | doc/designs/quic-design/quic-api-ssl-funcs.md | 381 | ||||
-rw-r--r-- | doc/designs/quic-design/quic-api.md | 534 |
2 files changed, 802 insertions, 113 deletions
diff --git a/doc/designs/quic-design/quic-api-ssl-funcs.md b/doc/designs/quic-design/quic-api-ssl-funcs.md index d43e58684a..c50a6b1cd5 100644 --- a/doc/designs/quic-design/quic-api-ssl-funcs.md +++ b/doc/designs/quic-design/quic-api-ssl-funcs.md @@ -87,6 +87,9 @@ Notes: - †9: QUIC always uses AES-128-GCM initially. We need to determine when and what ciphers we report as being in use. - †10: Not supporting async for now. +- †11: Since these functions only configure cipher suite lists used for TLSv1.2, + which is never used for QUIC, they do not require changes, and we can allow + applications to configure these lists freely, as they will be ignored. | API Item | Cat. | Sema. | Appl. | Impl. Req. | Status | |----------|----------|-----------|---------------|----------------|--------| @@ -140,7 +143,7 @@ Notes: | `SSL_CTX_up_ref` | Object | 🟩U | 🟩A | 🟩NC | 🟢Done | | `SSL_CTX_free` | Object | 🟩U | 🟩A | 🟩NC | 🟢Done | | `SSL_new` | Object | 🟩U | 🟩A | 🟧QSI | 🟢Done | -| `SSL_dup` | Object | 🟩U | 🟩A | 🟧QSI | 🟠Design TBD | +| `SSL_dup` | Object | 🟩U | 🟩A | 🟥FC | 🟢Done | | `SSL_up_ref` | Object | 🟩U | 🟩A | 🟩NC | 🟢Done | | `SSL_free` | Object | 🟩U | 🟩A | 🟧QSI | 🟢Done | | `SSL_is_dtls` | Object | 🟩U | 🟩A | 🟩NC | 🟢Done | @@ -153,28 +156,27 @@ Notes: | **⇒ Method Manipulation** | | | `SSL_CTX_get_ssl_method` | Object | 🟩U | 🟩A | 🟩NC | 🟢Done | | `SSL_get_ssl_method` | Object | 🟩U | 🟩A | 🟩NC | 🟢Done | -| `SSL_CTX_set_ssl_method` | Object | 🟥TBD | 🟩A | 🟧QSI | 🟠Design TBD | -| `SSL_set_ssl_method` | Object | 🟥TBD | 🟩A | 🟧QSI | 🟠Design TBD | +| `SSL_set_ssl_method` | Object | 🟥TBD | 🟩A | 🟧QSI | 🟢Done | | **⇒ SRTP** | | -| `SSL_get_selected_srtp_profile` | HL | 🟩U | 🟥FC | 🟨C\* | 🟡TODO | -| `SSL_get_srtp_profiles` | HL | 🟩U | 🟥FC | 🟨C\* | 🟡TODO | -| `SSL_CTX_set_tlsext_use_srtp` | HL | 🟩U | 🟥FC | 🟨C\* | 🟡TODO | -| `SSL_set_tlsext_use_srtp` | HL | 🟩U | 🟥FC | 🟨C\* | 🟡TODO | +| `SSL_get_selected_srtp_profile` | HL | 🟩U | 🟧NO | 🟨C\* | 🟢Done | +| `SSL_get_srtp_profiles` | HL | 🟩U | 🟧NO | 🟨C\* | 🟢Done | +| `SSL_CTX_set_tlsext_use_srtp` | HL | 🟩U | 🟥FC | 🟨C\* | 🟢Done | +| `SSL_set_tlsext_use_srtp` | HL | 🟩U | 🟥FC | 🟩NC\* | 🟢Done | | **⇒ Ciphersuite Configuration** | | -| `SSL_CTX_set_cipher_list` | HL | 🟩U | 🟩A | 🟨C\* †1 | 🟡TODO | -| `SSL_CTX_set_ciphersuites` | HL | 🟩U | 🟩A | 🟨C\* †1 | 🟡TODO | -| `SSL_CTX_get_ciphers` | HL | 🟩U | 🟩A | 🟨C\* †1 | 🟡TODO | -| `SSL_set_ciphersuites` | HL | 🟩U | 🟩A | 🟨C\* †1 | 🟡TODO | -| `SSL_get1_supported_ciphers` | HL | 🟩U | 🟩A | 🟨C\* †1 | 🟡TODO | -| `SSL_bytes_to_cipher_list` | HL | 🟩U | 🟩A | 🟨C\* †1 | 🟡TODO | -| `SSL_get_ciphers` | HL | 🟩U | 🟩A | 🟨C\* †1 | 🟡TODO | -| `SSL_get_cipher_list` | HL | 🟩U | 🟩A | 🟨C\* †1 | 🟡TODO | -| `SSL_set_cipher_list` | HL | 🟩U | 🟩A | 🟨C\* †1 | 🟡TODO | +| `SSL_CTX_set_cipher_list` | HL | 🟩U | 🟩A | 🟩NC\* †11 | 🟢Done | +| `SSL_CTX_set_ciphersuites` | HL | 🟩U | 🟩A | 🟨C\* †1 | 🟢Done | +| `SSL_CTX_get_ciphers` | HL | 🟩U | 🟩A |🟩NC\* | 🟢Done | +| `SSL_set_ciphersuites` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | +| `SSL_get1_supported_ciphers` | HL | 🟩U | 🟩A | 🟨C\* †1 | 🟢Done | +| `SSL_bytes_to_cipher_list` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | +| `SSL_get_ciphers` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | +| `SSL_get_cipher_list` | HL | 🟩U | 🟩A | 🟩NC\* †11 | 🟢Done | +| `SSL_set_cipher_list` | HL | 🟩U | 🟩A | 🟩NC\* †11 | 🟢Done | | **⇒ Negotiated Ciphersuite Queries** | | -| `SSL_get_current_cipher` | HL | 🟩U | 🟩A | 🟨C\* †9 | 🟠Design TBD | -| `SSL_get_pending_cipher` | HL | 🟩U | 🟩A | 🟨C\* †9 | 🟠Design TBD | -| `SSL_get_shared_ciphers` | HL | 🟩U | 🟩A | 🟨C\* †9 | 🟠Design TBD | -| `SSL_get_client_ciphers` | HL | 🟩U | 🟩A | 🟨C\* †9 | 🟠Design TBD | +| `SSL_get_current_cipher` | HL | 🟩U | 🟩A |🟩NC\* †9 | 🟢Done | +| `SSL_get_pending_cipher` | HL | 🟩U | 🟩A | 🟩NC\* †9 | 🟢Done | +| `SSL_get_shared_ciphers` | HL | 🟩U | 🟩A | 🟩NC\* †9 | 🟢Done | +| `SSL_get_client_ciphers` | HL | 🟩U | 🟩A | 🟩NC\* †9 | 🟢Done | | `SSL_get_current_compression` | HL | 🟩U | 🟩A | 🟩HLNC | 🟢Done | | `SSL_get_current_expansion` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | | `SSL_get_shared_sigalgs` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | @@ -191,9 +193,9 @@ Notes: | `SSL_get0_alpn_selected` | HL | 🟩U | 🟩A | 🟨C\* †2 | 🟡TODO | | `SSL_CTX_set_alpn_protos` | HL | 🟩U | 🟩A | 🟨C\* †2 | 🟡TODO | | **⇒ NPN** | †3 | -| `SSL_CTX_set_next_proto_select_cb` | HL | 🟩U | 🟥FC | 🟨C\* †3 | 🟡TODO | -| `SSL_CTX_set_next_protos_advertised_cb` | HL | 🟩U | 🟥FC | 🟨C\* †3 | 🟡TODO | -| `SSL_get0_next_proto_negotiated` | HL | 🟩U | 🟥FC | 🟨C\* †3 | 🟡TODO | +| `SSL_CTX_set_next_proto_select_cb` | HL | 🟩U | 🟥FC | 🟨C\* †3 | 🟢Done | +| `SSL_CTX_set_next_protos_advertised_cb` | HL | 🟩U | 🟥FC | 🟨C\* †3 | 🟢Done | +| `SSL_get0_next_proto_negotiated` | HL | 🟩U | 🟥FC | 🟩NC\* †3 | 🟢Done | | **⇒ Narrow Waist Interface** | †4 | | `SSL_CTX_ctrl` | Object | 🟩U | 🟩A | 🟩NC\* †4 | 🟢Done | | `SSL_ctrl` | Object | 🟩U | 🟩A | 🟩NC\* †4 | 🟢Done | @@ -394,11 +396,11 @@ Notes: | `SSL_renegotiate_abbreviated` | HL | 🟩U | 🟥FC | 🟩NC\* †5 | 🟢Done | | `SSL_renegotiate_pending` | HL | 🟩U | 🟧NO | 🟩NC\* †5 | 🟢Done | | **⇒ Options** | | -| `SSL_CTX_clear_options` | HL | 🟩U | 🟩A | 🟨C\* | 🟠Design TBD | -| `SSL_CTX_set_options` | HL | 🟩U | 🟩A | 🟨C\* | 🟠Design TBD | +| `SSL_CTX_clear_options` | HL | 🟩U | 🟩A | 🟨C\* | 🟢Done | +| `SSL_CTX_set_options` | HL | 🟩U | 🟩A | 🟨C\* | 🟢Done | | `SSL_CTX_get_options` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | -| `SSL_clear_options` | HL | 🟩U | 🟩A | 🟨C\* | 🟠Design TBD | -| `SSL_set_options` | HL | 🟩U | 🟩A | 🟨C\* | 🟠Design TBD | +| `SSL_clear_options` | HL | 🟩U | 🟩A | 🟨C\* | 🟢Done | +| `SSL_set_options` | HL | 🟩U | 🟩A | 🟨C\* | 🟢Done | | `SSL_get_options` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | | **⇒ Configuration** | | | `SSL_CONF_CTX_new` | Global | 🟩U | 🟩A | 🟩NC\* | 🟢Done | @@ -519,7 +521,7 @@ Notes: | `SSL_set_num_tickets` | HL | 🟩U | 🟩A | 🟩NC\* †7 | 🟢Done | | `SSL_CTX_get_num_tickets` | HL | 🟩U | 🟩A | 🟩NC\* †7 | 🟢Done | | `SSL_CTX_set_num_tickets` | HL | 🟩U | 🟩A | 🟩NC\* †7 | 🟢Done | -| `SSL_new_session_ticket` | HL | 🟩U | 🟩A | 🟨C\* | 🟡TODO | +| `SSL_new_session_ticket` | HL | 🟩U | 🟩A | 🟩NC\* †7 | 🟢Done | | `SSL_set_session_ticket_ext` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | | `SSL_set_session_ticket_ext_cb` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | | `SSL_CTX_set_tlsext_ticket_key_evp_cb` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | @@ -559,9 +561,9 @@ Notes: | `SSL_CTX_use_serverinfo_ex` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | | `SSL_CTX_use_serverinfo_file` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | | **⇒ Post-Handshake Authentication** | | -| `SSL_verify_client_post_handshake` | HL | 🟩U | 🟥FC | 🟨C* †8 | 🟡TODO | -| `SSL_CTX_set_post_handshake_auth` | HL | 🟩U | 🟥FC | 🟨C* †8 | 🟡TODO | -| `SSL_set_post_handshake_auth` | HL | 🟩U | 🟥FC | 🟨C* †8 | 🟡TODO | +| `SSL_verify_client_post_handshake` | HL | 🟩U | 🟥FC | 🟨C* †8 | 🟢Done | +| `SSL_CTX_set_post_handshake_auth` | HL | 🟩U | 🟥FC | 🟨C* †8 | 🟢Done | +| `SSL_set_post_handshake_auth` | HL | 🟩U | 🟥FC | 🟨C* †8 | 🟢Done | | **⇒ DH Parameters** | | | `SSL_CTX_set_dh_auto` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | | `SSL_set_dh_auto` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | @@ -576,23 +578,23 @@ Notes: | `SSL_in_before` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | | `SSL_is_init_finished` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | | `SSL_get_state` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | -| `SSL_rstate_string` | HL | 🟩U | 🟩A | 🟧QSI | 🟠Design TBD | -| `SSL_rstate_string_long` | HL | 🟩U | 🟩A | 🟧QSI | 🟠Design TBD | -| `SSL_state_string` | HL | 🟩U | 🟩A | 🟧QSI | 🟠Design TBD | -| `SSL_state_string_long` | HL | 🟩U | 🟩A | 🟧QSI | 🟠Design TBD | +| `SSL_rstate_string` | HL | 🟩U | 🟩A | 🟧QSI | 🟢Done | +| `SSL_rstate_string_long` | HL | 🟩U | 🟩A | 🟧QSI | 🟢Done | +| `SSL_state_string` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | +| `SSL_state_string_long` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | | **⇒ Data Path and CSSM** | | | `SSL_set_connect_state` | CSSM | 🟩U | 🟩A | 🟧QSI | 🟢Done | | `SSL_set_accept_state` | CSSM | 🟩U | 🟩A | 🟧QSI | 🟢Done | -| `SSL_is_server` | CSSM | 🟩U | 🟩A | 🟧QSI | 🟡TODO | +| `SSL_is_server` | CSSM | 🟩U | 🟩A | 🟩NC\* | 🟢Done | | `SSL_peek` | ADP | 🟩U | 🟩A | 🟧QSI | 🟢Done | | `SSL_peek_ex` | ADP | 🟩U | 🟩A | 🟧QSI | 🟢Done | | `SSL_read` | ADP | 🟩U | 🟩A | 🟧QSI | 🟢Done | | `SSL_read_ex` | ADP | 🟩U | 🟩A | 🟧QSI | 🟢Done | | `SSL_write` | ADP | 🟩U | 🟩A | 🟧QSI | 🟢Done | | `SSL_write_ex` | ADP | 🟩U | 🟩A | 🟧QSI | 🟢Done | -| `SSL_sendfile` | ADP | 🟩U | 🟩A | 🟧QSI | 🟠Design TBD | -| `SSL_pending` | ADP | 🟩U | 🟩A | 🟧QSI | 🟠Design TBD | -| `SSL_has_pending` | ADP | TBD | 🟩A | 🟧QSI | 🟠Design TBD | +| `SSL_sendfile` | ADP | 🟩U | 🟥FC | 🟩NC\* | 🟢Done | +| `SSL_pending` | ADP | 🟩U | 🟩A | 🟧QSI | 🟢Done | +| `SSL_has_pending` | ADP | TBD | 🟩A | 🟧QSI | 🟢Done | | `SSL_accept` | CSSM | 🟩U | 🟩A | 🟧QSI | 🟢Done | | `SSL_connect` | CSSM | 🟩U | 🟩A | 🟧QSI | 🟢Done | | `SSL_do_handshake` | CSSM | 🟩U | 🟩A | 🟧QSI | 🟢Done | @@ -605,15 +607,15 @@ Notes: | `SSL_get_rfd` | NDP | 🟩U | 🟩A | 🟩NC | 🟢Done | | `SSL_get_wfd` | NDP | 🟩U | 🟩A | 🟩NC | 🟢Done | | `SSL_get_fd` | NDP | 🟩U | 🟩A | 🟩NC | 🟢Done | -| `SSL_set_rfd` | NDP | 🟧C | 🟩A | 🟧QSI | 🟡TODO | -| `SSL_set_wfd` | NDP | 🟧C | 🟩A | 🟧QSI | 🟡TODO | -| `SSL_set_fd` | NDP | 🟩U | 🟩A | 🟧QSI | 🟡TODO | -| `SSL_key_update` | RL | 🟩U | 🟩A | 🟧QSI | 🟠Design TBD | -| `SSL_get_key_update_type` | RL | 🟩U | 🟩A | 🟧QSI | 🟠Design TBD | -| `SSL_clear` (connection) | CSSM | TBD | 🟩A | 🟧QSI | 🟡TODO | +| `SSL_set_rfd` | NDP | 🟧C | 🟩A | 🟧QSI | 🟢Done | +| `SSL_set_wfd` | NDP | 🟧C | 🟩A | 🟧QSI | 🟢Done | +| `SSL_set_fd` | NDP | 🟩U | 🟩A | 🟧QSI | 🟢Done | +| `SSL_key_update` | RL | 🟩U | 🟩A | 🟧QSI | 🟢Done | +| `SSL_get_key_update_type` | RL | 🟩U | 🟩A | 🟧QSI | 🟢Done | +| `SSL_clear` (connection) | CSSM | TBD | 🟩A | 🟥FC | 🟢Done | | `SSL_clear` (stream) | CSSM | TBD | 🟩A | 🟧QSI | 🟠Design TBD | | `SSL_shutdown` | CSSM | 🟧C | 🟩A | 🟧QSI | 🟡TODO | -| `SSL_want` | ADP | 🟧C | 🟩A | 🟧QSI | 🟡TODO | +| `SSL_want` | ADP | 🟧C | 🟩A | 🟧QSI | 🟢Done | | `BIO_new_ssl_connect` | Global | 🟩U | 🟩A | 🟧QSI | 🟡TODO | | `BIO_new_buffer_ssl_connect` | Global | 🟩U | 🟦U | 🟧QSI | 🟡TODO | | `SSL_get_shutdown` | CSSM | 🟩U | 🟩A | 🟧QSI | 🟠Design TBD | @@ -632,17 +634,31 @@ Notes: | `SSL_shutdown_ex` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | | `SSL_stream_conclude` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | | `SSL_stream_reset` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | -| `SSL_get_stream_state` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | -| `SSL_get_stream_error_code` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | +| `SSL_get_stream_read_state` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | +| `SSL_get_stream_write_state` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | +| `SSL_get_stream_read_error_code` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | +| `SSL_get_stream_write_error_code` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | | `SSL_get_conn_close_info` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | +| **⇒ New APIs for Multi-Stream** | | +| `SSL_get0_connection` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | +| `SSL_is_connection` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | +| `SSL_get_stream_id` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | +| `SSL_get_stream_type` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | +| `SSL_new_stream` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | +| `SSL_accept_stream` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | +| `SSL_get_accept_stream_queue_len` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | +| `SSL_set_default_stream_mode` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | +| `SSL_set_incoming_stream_reject_policy` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | +| `SSL_detach_stream` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | +| `SSL_attach_stream` | CSSM | 🟦N | 🟩A | 🟥QSA | 🟡TODO | | **⇒ Currently Not Supported** | | -| `SSL_copy_session_id` | Special | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `BIO_ssl_copy_session_id` | Special | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_CTX_set_quiet_shutdown` | CSSM | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_CTX_get_quiet_shutdown` | CSSM | 🟩U | 🟧NO | 🟨C* | 🟡TODO | -| `SSL_set_quiet_shutdown` | CSSM | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_get_quiet_shutdown` | CSSM | 🟩U | 🟧NO | 🟨C* | 🟡TODO | -| `SSL_CTX_set_ssl_version` | HL | 🟩U | 🟥FC | 🟨C* | 🟡TODO | +| `SSL_copy_session_id` | Special | 🟩U | 🟥FC | 🟨C* | 🟢Done | +| `BIO_ssl_copy_session_id` | Special | 🟩U | 🟥FC | 🟨C* | 🟢Done | +| `SSL_CTX_set_quiet_shutdown` | CSSM | 🟩U | 🟦U | 🟩NC | 🟢Done | +| `SSL_CTX_get_quiet_shutdown` | CSSM | 🟩U | 🟦U | 🟩NC | 🟢Done | +| `SSL_set_quiet_shutdown` | CSSM | 🟩U | 🟥FC | 🟨C | 🟢Done | +| `SSL_get_quiet_shutdown` | CSSM | 🟩U | 🟧NO | 🟨C | 🟢Done | +| `SSL_CTX_set_ssl_version` | HL | 🟩U | 🟥FC | 🟨C | 🟢Done | | **⇒ Async** | | | `SSL_CTX_set_async_callback` | Async | 🟩U | 🟧NO | 🟩NC* †10 | 🟢Done | | `SSL_set_async_callback` | Async | 🟩U | 🟧NO | 🟩NC* †10 | 🟢Done | @@ -653,67 +669,67 @@ Notes: | `SSL_get_all_async_fds` | Async | 🟩U | 🟧NO | 🟩NC* †10 | 🟢Done | | `SSL_get_changed_async_fds` | Async | 🟩U | 🟧NO | 🟩NC* †10 | 🟢Done | | **⇒ Readahead** | | -| `SSL_CTX_get_default_read_ahead` | RL | 🟩U | 🟧NO | 🟨C* | 🟡TODO | -| `SSL_CTX_get_read_ahead` | RL | 🟩U | 🟧NO | 🟨C* | 🟡TODO | -| `SSL_CTX_set_read_ahead` | RL | 🟩U | 🟧NO | 🟨C* | 🟡TODO | -| `SSL_get_read_ahead` | RL | 🟩U | 🟧NO | 🟨C* | 🟡TODO | -| `SSL_set_read_ahead` | RL | 🟩U | 🟧NO | 🟨C* | 🟡TODO | -| `SSL_CTX_set_default_read_buffer_len` | RL | 🟩U | 🟧NO | 🟨C* | 🟡TODO | -| `SSL_set_default_read_buffer_len` | RL | 🟩U | 🟧NO | 🟨C* | 🟡TODO | +| `SSL_CTX_get_default_read_ahead` | RL | 🟩U | 🟧NO | 🟩NC* | 🟢Done | +| `SSL_CTX_get_read_ahead` | RL | 🟩U | 🟧NO | 🟩NC* |🟢Done | +| `SSL_CTX_set_read_ahead` | RL | 🟩U | 🟧NO | 🟨C* |🟢Done | +| `SSL_get_read_ahead` | RL | 🟩U | 🟧NO | 🟨C* |🟢Done | +| `SSL_set_read_ahead` | RL | 🟩U | 🟧NO | 🟨C* | 🟢Done | +| `SSL_CTX_set_default_read_buffer_len` | RL | 🟩U | 🟧NO | 🟩NC* | 🟢Done | +| `SSL_set_default_read_buffer_len` | RL | 🟩U | 🟧NO | 🟨C* | 🟢Done | | **⇒ Record Padding and Fragmentation** | | -| `SSL_CTX_set_record_padding_callback` | RL | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_set_record_padding_callback` | RL | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_CTX_get_record_padding_callback_arg` | RL | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_CTX_set_record_padding_callback_arg` | RL | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_get_record_padding_callback_arg` | RL | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_set_record_padding_callback_arg` | RL | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_CTX_set_block_padding` | RL | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_set_block_padding` | RL | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_CTX_set_tlsext_max_fragment_length` | RL | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_set_tlsext_max_fragment_length` | RL | 🟩U | 🟥FC | 🟨C* | 🟡TODO | +| `SSL_CTX_set_record_padding_callback` | RL | 🟩U | 🟥FC | 🟩NC* | 🟢Done | +| `SSL_set_record_padding_callback` | RL | 🟩U | 🟥FC | 🟨C* | 🟢Done | +| `SSL_CTX_get_record_padding_callback_arg` | RL | 🟩U | 🟥FC | 🟩NC* | 🟢Done | +| `SSL_CTX_set_record_padding_callback_arg` | RL | 🟩U | 🟥FC | 🟩NC* | 🟢Done | +| `SSL_get_record_padding_callback_arg` | RL | 🟩U | 🟥FC | 🟩NC* | 🟢Done | +| `SSL_set_record_padding_callback_arg` | RL | 🟩U | 🟥FC |🟩NC* | 🟢Done | +| `SSL_CTX_set_block_padding` | RL | 🟩U | 🟥FC | 🟩NC* | 🟢Done | +| `SSL_set_block_padding` | RL | 🟩U | 🟥FC | 🟨C* | 🟢Done | +| `SSL_CTX_set_tlsext_max_fragment_length` | RL | 🟩U | 🟥FC | 🟩NC* | 🟢Done | +| `SSL_set_tlsext_max_fragment_length` | RL | 🟩U | 🟥FC | 🟨C* | 🟢Done | | **⇒ Stateless/HelloRetryRequest** | | -| `SSL_stateless` | RL | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_CTX_set_stateless_cookie_generate_cb` | RL | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_CTX_set_stateless_cookie_verify_cb` | RL | 🟩U | 🟥FC | 🟨C* | 🟡TODO | +| `SSL_stateless` | RL | 🟩U | 🟥FC | 🟨C* | 🟢Done | +| `SSL_CTX_set_stateless_cookie_generate_cb` | RL | 🟩U | 🟥FC | 🟩NC* | 🟢Done | +| `SSL_CTX_set_stateless_cookie_verify_cb` | RL | 🟩U | 🟥FC | 🟩NC* | 🟢Done | | **⇒ Early Data/0-RTT** | | -| `SSL_CTX_set_allow_early_data_cb` | 0-RTT | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_set_allow_early_data_cb` | 0-RTT | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_CTX_get_recv_max_early_data` | 0-RTT | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_CTX_set_recv_max_early_data` | 0-RTT | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_get_recv_max_early_data` | 0-RTT | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_set_recv_max_early_data` | 0-RTT | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_CTX_get_max_early_data` | 0-RTT | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_CTX_set_max_early_data` | 0-RTT | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_get_max_early_data` | 0-RTT | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_set_max_early_data` | 0-RTT | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_read_early_data` | 0-RTT | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_write_early_data` | 0-RTT | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_get_early_data_status` | 0-RTT | 🟩U | 🟥FC | 🟨C* | 🟡TODO | +| `SSL_CTX_set_allow_early_data_cb` | 0-RTT | 🟩U | 🟥FC | 🟩NC* | 🟢Done | +| `SSL_set_allow_early_data_cb` | 0-RTT | 🟩U | 🟥FC | 🟨C* |🟢Done | +| `SSL_CTX_get_recv_max_early_data` | 0-RTT | 🟩U | 🟥FC | 🟩NC* | 🟢Done | +| `SSL_CTX_set_recv_max_early_data` | 0-RTT | 🟩U | 🟥FC | 🟩NC* | 🟢Done | +| `SSL_get_recv_max_early_data` | 0-RTT | 🟩U | 🟥FC | 🟩NC* | 🟢Done | +| `SSL_set_recv_max_early_data` | 0-RTT | 🟩U | 🟥FC | 🟨C* | 🟢Done | +| `SSL_CTX_get_max_early_data` | 0-RTT | 🟩U | 🟥FC | 🟩NC* | 🟢Done | +| `SSL_CTX_set_max_early_data` | 0-RTT | 🟩U | 🟥FC | 🟩NC* | 🟢Done | +| `SSL_get_max_early_data` | 0-RTT | 🟩U | 🟥FC | 🟩NC* | 🟢Done | +| `SSL_set_max_early_data` | 0-RTT | 🟩U | 🟥FC | 🟨C* | 🟢Done | +| `SSL_read_early_data` | 0-RTT | 🟩U | 🟥FC | 🟨C* | 🟢Done | +| `SSL_write_early_data` | 0-RTT | 🟩U | 🟥FC | 🟨C* | 🟢Done | +| `SSL_get_early_data_status` | 0-RTT | 🟩U | 🟥FC | 🟩NC* | 🟢Done | | **⇒ Miscellaneous** | | | `DTLSv1_listen` | RL | 🟩U | 🟦U | 🟩NC | 🟢Done | | `DTLS_set_timer_cb` | NDP | 🟩U | 🟦U | 🟩NC | 🟢Done | | `DTLS_get_data_mtu` | NDP | 🟩U | 🟦U | 🟩NC | 🟢Done | | `SSL_get_ex_data_X509_STORE_CTX_idx` | Global | 🟩U | 🟦U | 🟩NC | 🟢Done | | `BIO_ssl_shutdown` | Global | 🟩U | 🟩A | 🟩NC | 🟢Done | -| `SSL_alloc_buffers` | HL | 🟩U | 🟩A | 🟨C\* | 🟠Design TBD | -| `SSL_free_buffers` | HL | 🟩U | 🟩A | 🟨C\* | 🟠Design TBD | +| `SSL_alloc_buffers` | HL | 🟩U | 🟩A | 🟨C\* | 🟢Done | +| `SSL_free_buffers` | HL | 🟩U | 🟩A | 🟨C\* | 🟢Done | | `SSL_trace` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | | `SSL_set_debug` | HL | 🟩U | 🟩A | 🟩NC\* | 🟢Done | | **⇒ Controls** | | -| `SSL_CTRL_MODE` | Special | 🟩U | 🟩A | 🟧QSI | 🟡TODO | -| `SSL_CTRL_CLEAR_MODE` | Special | 🟩U | 🟩A | 🟧QSI | 🟡TODO | +| `SSL_CTRL_MODE` | Special | 🟩U | 🟩A | 🟧QSI | 🟢Done | +| `SSL_CTRL_CLEAR_MODE` | Special | 🟩U | 🟩A | 🟧QSI | 🟢Done | | `SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS` | HL | 🟩U | 🟧NO | 🟩NC* | 🟢Done | | `SSL_CTRL_GET_NUM_RENEGOTIATIONS` | HL | 🟩U | 🟧NO | 🟩NC* | 🟢Done | | `SSL_CTRL_GET_TOTAL_RENEGOTIATIONS` | HL | 🟩U | 🟧NO | 🟩NC* | 🟢Done | | `SSL_CTRL_GET_RI_SUPPORT` | HL | 🟩U | 🟧NO | 🟩NC* | 🟢Done | | `SSL_CTRL_GET_READ_AHEAD` | HL | 🟩U | 🟧NO | 🟩NC* | 🟢Done | -| `SSL_CTRL_SET_READ_AHEAD` | HL | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_CTRL_SET_MAX_PIPELINES` | RL | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_CTRL_SET_MAX_SEND_FRAGMENT` | RL | 🟩U | 🟥FC | 🟨C* | 🟡TODO | -| `SSL_CTRL_SET_SPLIT_SEND_FRAGMENT` | RL | 🟩U | 🟥FC | 🟨C* | 🟡TODO | +| `SSL_CTRL_SET_READ_AHEAD` | HL | 🟩U | 🟥FC | 🟨C* |🟢Done | +| `SSL_CTRL_SET_MAX_PIPELINES` | RL | 🟩U | 🟥FC | 🟨C* | 🟢Done | +| `SSL_CTRL_SET_MAX_SEND_FRAGMENT` | RL | 🟩U | 🟥FC | 🟨C* | 🟢Done | +| `SSL_CTRL_SET_SPLIT_SEND_FRAGMENT` | RL | 🟩U | 🟥FC | 🟨C* | 🟢Done | | `SSL_CTRL_SET_MTU` | RL | 🟩U | 🟥FC | 🟩NC* | 🟢Done | -| `SSL_CTRL_SET_MAX_PROTO_VERSION` | HL | 🟩U | 🟩A | 🟨C* | 🟡TODO | -| `SSL_CTRL_SET_MIN_PROTO_VERSION` | HL | 🟩U | 🟩A | 🟨C* | 🟡TODO | +| `SSL_CTRL_SET_MAX_PROTO_VERSION` | HL | 🟩U | 🟩A | 🟨C* | 🟢Done | +| `SSL_CTRL_SET_MIN_PROTO_VERSION` | HL | 🟩U | 🟩A | 🟩NC* | 🟢Done | | `SSL_CTRL_GET_MAX_PROTO_VERSION` | HL | 🟩U | 🟩A | 🟩NC* | 🟢Done | | `SSL_CTRL_GET_MIN_PROTO_VERSION` | HL | 🟩U | 🟩A | 🟩NC* | 🟢Done | | `SSL_CTRL_BUILD_CERT_CHAIN` | HL | 🟩U | 🟩A | 🟩NC* | 🟢Done | @@ -810,5 +826,170 @@ Notes: | `SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER` | ADP | 🟩U | 🟩A | 🟧QSI | 🟢Done | | `SSL_MODE_RELEASE_BUFFERS` | ADP | 🟩U | 🟧NO | 🟩NC | 🟢Done | | `SSL_MODE_ASYNC` | ADP | 🟩U | 🟧NO | 🟩NC | 🟢Done | -| `SSL_MODE_AUTO_RETRY` | ADP | TBD | TBD | TBD | 🔴Pending Triage | -| `SSL_MODE_SEND_FALLBACK_SCSV` | HL | 🟩U | 🟩A | 🟨C\* | 🟡TODO | +| `SSL_MODE_AUTO_RETRY` | ADP | 🟩U | 🟧NO | 🟩NC | 🟢Done | +| `SSL_MODE_SEND_FALLBACK_SCSV` | HL | 🟩U | 🟩U | 🟩NC | 🟢Done | + +Q&A For TLS-Related Calls +------------------------- + +### What should `SSL_get_current_cipher`, `SSL_get_pending_cipher`, etc. do? + +QUIC always uses AES-128-GCM for Initial packets. At this time the handshake +layer has not negotiated a ciphersuite so it has no “current” cipher. We could +return AES-128-GCM here, but it seems reasonable to just return NULL as the +encryption is mostly for protection against accidential modification and not +“real” encryption. From the perspective of the Handshake layer encryption is not +active yet. An application using QUIC can always interpret NULL as meaning +AES-128-GCM is being used if needed as this is implied by using QUIC. + +### What should `SSL_CTX_set_cipher_list` do? + +Since this function configures the cipher list for TLSv1.2 and below only, there +is no need to restrict it as TLSv1.3 is required for QUIC. For the sake of +application compatibility, applications can still configure the TLSv1.2 cipher +list; it will always be ignored. + +### What should `SSL_get_current_cipher` and similar do? + +QUIC always uses AES-128-GCM encryption initially, so we could either return +AES-128-GCM where the handshake has not yet negotiated another algorithm or +return NULL here. + +A. We return NULL here, because it allows applications to detect if a +ciphersuite has been negotiated and NULL can be used to infer that Initial +encryption is still being used. This also minimises the changes needed to the +implementation. + +### What SSL options should be supported? + +Options we explicitly want to support: + +- `SSL_OP_CIPHER_SERVER_PREFERENCE` +- `SSL_OP_DISABLE_TLSEXT_CA_NAMES` +- `SSL_OP_NO_TX_CERTIFICATE_COMPRESSION` +- `SSL_OP_NO_RX_CERTIFICATE_COMPRESSION` +- `SSL_OP_PRIORITIZE_CHACHA` +- `SSL_OP_NO_TICKET` + +Options we do not yet support but could support in the future, currently no-ops: + +- `SSL_OP_CLEANSE_PLAINTEXT` +- `SSL_OP_NO_QUERY_MTU` +- `SSL_OP_NO_ANTI_REPLAY` + +The following options must be explicitly forbidden: + +- `SSL_OP_NO_TLSv1_3` — TLSv1.3 is required for QUIC +- `SSL_OP_ENABLE_MIDDLEBOX_COMPAT` — forbidden by QUIC RFCs +- `SSL_OP_ENABLE_KTLS` — not currently supported for QUIC +- `SSL_OP_SAFARI_ECDHE_ECDSA_BUG` +- `SSL_OP_TLSEXT_PADDING` +- `SSL_OP_TLS_ROLLBACK_BUG` +- `SSL_OP_IGNORE_UNEXPECTED_EOF` +- `SSL_OP_ALLOW_NO_DHE_KEX` + +The following options are ignored for TLSv1.3 or otherwise not applicable and +may therefore be settable but ignored. We take this approach on the grounds +that it is harmless and applications might want to see that options have been +correctly set for protocols unrelated to QUIC. + +- `SSL_OP_CRYPTOPRO_TLSEXT_BUG` +- `SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS` +- `SSL_OP_ALLOW_CLIENT_RENEGOTIATION` +- `SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION` +- `SSL_OP_CISCO_ANYCONNECT` +- `SSL_OP_COOKIE_EXCHANGE` +- `SSL_OP_LEGACY_SERVER_CONNECT` +- `SSL_OP_NO_COMPRESSION` +- `SSL_OP_NO_ENCRYPT_THEN_MAC` +- `SSL_OP_NO_EXTENDED_MASTER_SECRET` +- `SSL_OP_NO_RENEGOTIATION` +- `SSL_OP_NO_RESSION_RESUMPTION_ON_NEGOTIATION` +- `SSL_OP_NO_SSLv3` +- `SSL_OP_NO_TLSv1` +- `SSL_OP_NO_TLSv1_1` +- `SSL_OP_NO_TLSv1_2` +- `SSL_OP_NO_DTLSv1` +- `SSL_OP_NO_DTLSv1_2` + +### What should `SSL_rstate_string` and `SSL_state_string` do? + +SSL_state_string is highly handshake layer specific, so it makes sense to just +forward to the handshake layer. + +SSL_rstate_string is record layer specific. A cursory evaluation of usage via +GitHub code search did not appear to identify much usage of this function other +than for debug output; i.e., there seems to be little usage of this in a way +that depends on the output for the purposes of control flow. Since there is not +really any direct correspondence to the QUIC record layer, we conservatively +define the output of this function as "unknown". + +TODO: forbid NPN +TODO: enforce TLSv1.3 +TODO: forbid PHA - DONE +TODO: forbid middlebox compat mode in a deeper way? +TODO: new_session_ticket doesn't need modifying as such, but ticket machinery + will + +### What should `SSL_pending` and `SSL_has_pending` do? + +`SSL_pending` traditionally yields the number of bytes buffered inside a SSL +object available for immediate reading. For QUIC, we can just make this report +the current size of the receive stream buffer. + +`SSL_has_pending` returns a boolean value indicating whether there is processed +or unprocessed incoming data pending. There is no direct correspondence to +QUIC, so there are various implementation options: + +- `SSL_pending() > 0` +- `SSL_pending() > 0 || pending URXEs or RXEs exist` + +The latter can probably be viewed as more of a direct correspondence to the +design intent of the API, so we go with this. + +### What should `SSL_alloc_buffers` and `SSL_free_buffers` do? + +These do not really correspond to our internal architecture for QUIC. Since +internal buffers are always available, `SSL_alloc_buffers` can simply always +return 1. `SSL_free_buffers` can always return 0, as though the buffers are in +use, which they generally will be. + +### What should `SSL_key_update` and `SSL_get_key_update_type`? + +`SSL_key_update` can trigger a TX record layer key update, which will cause the +peer to respond with a key update in turn. The update occurs asynchronously +at next transmission, not immediately. + +`SSL_get_key_update_type` returns an enumerated value which is only relevant to +the TLSv1.3 protocol; for QUIC, it will always return `SSL_KEY_UPDATE_NONE`. + +### What should `SSL_MODE_AUTO_RETRY` do? + +The absence of `SSL_MODE_AUTO_RETRY` causes `SSL_read`/`SSL_write` on a normal +TLS connection to potentially return due to internal handshake message +processing. This does not really make sense for our QUIC implementation, +therefore we always act as though `SSL_MODE_AUTO_RETRY` is on, and this mode is +ignored. + +### What should `SSL_MODE_SEND_FALLBACK_SCSV` do? + +This is not relevant to QUIC because this functionality relates to protocol +version downgrade attack protection and QUIC only supports TLSv1.3. Thus, +it is ignored. + +### What should `SSL_CTX_set_ssl_version` do? + +This is a deprecated function, so it needn't be supported for QUIC. Fail closed. + +### What should `SSL_set_ssl_method` do? + +For now we can avoid supporting this for QUIC. Supporting this would be rather +hairy. + +### What should `SSL_set_shutdown` do? + +TBD. + +### What should `SSL_dup` and `SSL_clear` do? + +These may be tricky to support. Currently they are blocked. diff --git a/doc/designs/quic-design/quic-api.md b/doc/designs/quic-design/quic-api.md index bb7bc28154..b5a81de87a 100644 --- a/doc/designs/quic-design/quic-api.md +++ b/doc/designs/quic-design/quic-api.md @@ -29,7 +29,7 @@ designs and the relevant design decisions. - [`SSL_get_[rw]fd`](#-ssl-get--rw-fd-) - [`SSL_CTRL_MODE`, `SSL_CTRL_CLEAR_MODE`](#-ssl-ctrl-mode----ssl-ctrl-clear-mode-) - [SSL Modes](#ssl-modes) - + [New APIs](#new-apis) + + [New APIs for Single-Stream Operation](#new-apis-for-single-stream-operation) - [`SSL_tick`](#-ssl-tick-) - [`SSL_get_tick_timeout`](#-ssl-get-tick-timeout-) - [`SSL_set_blocking_mode`, `SSL_get_blocking_mode`](#-ssl-set-blocking-mode----ssl-get-blocking-mode-) @@ -41,8 +41,23 @@ designs and the relevant design decisions. - [`SSL_stream_conclude`](#-ssl-stream-conclude-) - [`SSL_stream_reset`](#-ssl-stream-reset-) - [`SSL_get_stream_state`](#-ssl-get-stream-state-) - - [`SSL_get_stream_error_code`](#-ssl-get-stream-error-code-) + - [`SSL_get_stream_read_error_code`, `SSL_get_stream_write_error_code`](#-ssl-get-stream-read-error-code----ssl-get-stream-write-error-code-) - [`SSL_get_conn_close_info`](#-ssl-get-conn-close-info-) + + [New APIs for Multi-Stream Operation](#new-apis-for-multi-stream-operation) + - [Notes on Multi-Threaded Operation](#notes-on-multi-threaded-operation) + - [Notes on Blocking](#notes-on-blocking) + - [Notes on Application-Level Polling](#notes-on-application-level-polling) + - [`SSL_get0_connection`](#-ssl-get0-connection-) + - [`SSL_is_connection`](#-ssl-is-connection-) + - [`SSL_get_stream_type`](#-ssl-get-stream-type-) + - [`SSL_get_stream_id`](#-ssl-get-stream-id-) + - [`SSL_new_stream`](#-ssl-new-stream-) + - [`SSL_accept_stream`](#-ssl-accept-stream-) + - [`SSL_get_accept_stream_queue_len`](#-ssl-get-accept-stream-queue-len-) + - [`SSL_set_incoming_stream_reject_policy`](#-ssl-set-incoming-stream-reject-policy-) + - [`SSL_set_default_stream_mode`](#-ssl-set-default-stream-mode-) + - [`SSL_detach_stream`](#-ssl-detach-stream-) + - [`SSL_attach_stream`](#-ssl-attach-stream-) + [Future APIs](#future-apis) * [BIO Objects](#bio-objects) + [Existing APIs](#existing-apis-1) @@ -50,7 +65,7 @@ designs and the relevant design decisions. - [`BIO_new_bio_pair`](#-bio-new-bio-pair-) - [Interactions with `BIO_f_buffer`](#interactions-with--bio-f-buffer-) - [MTU Signalling](#mtu-signalling) - + [New APIs](#new-apis-1) + + [New APIs](#new-apis) - [`BIO_sendmmsg` and `BIO_recvmmsg`](#-bio-sendmmsg--and--bio-recvmmsg-) - [Truncation Mode](#truncation-mode) - [Capability Negotiation](#capability-negotiation) @@ -60,7 +75,6 @@ designs and the relevant design decisions. - [`BIO_s_dgram_mem`](#-bio-s-dgram-mem-) - [`BIO_err_is_non_fatal`](#-bio-err-is-non-fatal-) * [Q & A](#q---a) - * [Implementation Status](#implementation-status) Overview and Implementation Status ---------------------------------- @@ -150,6 +164,9 @@ Each API listed below has an information table with the following fields: - **CS:** Not handshake-layer related. Can be used on any QUIC SSL object. + - **S**: Requires a QUIC stream SSL object or a QUIC connection SSL object + with a default stream attached. + ### Existing APIs #### `SSL_set_connect_state` @@ -411,7 +428,7 @@ Should not require any changes. - `SSL_MODE_ASYNC`: TBD. -### New APIs +### New APIs for Single-Stream Operation TBD: Should any of these be implemented as ctrls rather than actual functions? @@ -721,6 +738,22 @@ no-ops. This is considered a success case. * stream. */ #define SSL_STREAM_STATE_NONE 0 + +/* + * The read or write part of the stream is still available and has not been + * terminated in a normal or non-normal manner. + */ +#define SSL_STREAM_STATE_OK 1 + +/* + * The stream is a unidirectional stream and this direction cannot be used; for + * example, a remotely initiated unidirectional stream where + * SSL_get_stream_write_state is called, or a locally initiated unidirectional + * stream where SSL_get_stream_read_state is + called. + */ +#define SSL_STREAM_STATE_WRONG_DIR 2 + /* * The read or write part of the stream has been finished in a normal manner. * @@ -732,17 +765,32 @@ no-ops. This is considered a success case. * already indicated the end of the stream by calling SSL_stream_conclude, * and that future calls to SSL_write will fail. */ -#define SSL_STREAM_STATE_FINISHED 1 +#define SSL_STREAM_STATE_FINISHED 3 /* * The stream was reset by the local party. + * + * For SSL_get_stream_read_state, this means that the stream was aborted using a + * locally transmitted STOP_SENDING frame. Attempts to read from the stream via + * SSL_read will fail, though SSL_read may allow any residual data waiting to + * be read to be read first. + * + * For SSL_get_stream_write_state, this means that the stream was aborted + * using a locally transmitted RESET_STREAM frame. Attempts to write to + * the stream will fail. */ -#define SSL_STREAM_STATE_RESET_LOCAL 2 +#define SSL_STREAM_STATE_RESET_LOCAL 4 /* * The stream was reset by the remote party. + * + * For SSL_get_stream_read_state, this means the peer sent a STREAM_RESET + * frame for the stream. + * + * For SSL_get_stream_write_state, this means the peer sent a STOP_SENDING + * frame for the stream. */ -#define SSL_STREAM_STATE_RESET_REMOTE 3 +#define SSL_STREAM_STATE_RESET_REMOTE 5 /* * The underlying connection supporting the stream has closed or otherwise @@ -755,7 +803,7 @@ no-ops. This is considered a success case. * For SSL_get_stream_write_state, this means that attempts to write to the * stream will fail. */ -#define SSL_STREAM_STATE_CONN_CLOSED 4 +#define SSL_STREAM_STATE_CONN_CLOSED 6 int SSL_get_stream_read_state(SSL *ssl); int SSL_get_stream_write_state(SSL *ssl); @@ -765,22 +813,31 @@ This API allows the current state of a stream to be queried. This allows an application to determine whether a stream is still usable and why a stream has reached an error state. -#### `SSL_get_stream_error_code` +#### `SSL_get_stream_read_error_code`, `SSL_get_stream_write_error_code` | Semantics | `SSL_get_error` | Can Tick? | CSHL | | --------- | ------------- | --------- | ------------- | | New | Never | No | S | ```c -int SSL_get_stream_error_code(SSL *ssl, uint64_t *app_error_code); +int SSL_get_stream_read_error_code(SSL *ssl, uint64_t *app_error_code); +int SSL_get_stream_write_error_code(SSL *ssl, uint64_t *app_error_code); ``` +`SSL_get_stream_read_error_code` gets the error code for the read part of the +stream. + +`SSL_get_stream_write_error_code` gets the error code for the write part of +the stream. + If a stream has been terminated normally, returns 0. If a stream has been terminated non-normally, returns 1 and writes the applicable application error code to `*app_error_code`. -If a stream is still healthy, returns -1. +If a stream is still healthy, or was healthy at the time the connection was +closed, or the respective part of the stream does not exist (e.g. for a +unidirectional stream), returns -1. #### `SSL_get_conn_close_info` @@ -804,7 +861,8 @@ int SSL_get_conn_close_info(SSL *ssl, If a connection is still healthy, returns 0. Otherwise, fills `*info` with information about the error causing connection termination and returns 1. -`info_len` must be set to `sizeof(*info)`. +`info_len` must be set to `sizeof(*info)`. Returns -1 if called on a non-QUIC +SSL object or if the connection status cannot be determined. `info->reason` is set to point to a buffer containing a reason string. The buffer is valid for the lifetime of the SSL object. The reason string will @@ -818,6 +876,340 @@ reason string in bytes. if it was initiated by the application. The namespace of `info->error_code` is determined by this parameter. +### New APIs for Multi-Stream Operation + +The above new APIs are built on constructively to facilitate multi-stream +operation. + +The concept of a QUIC stream SSL object is introduced. A QUIC SSL object is +either a QUIC connection SSL object or a QUIC stream SSL object. A QUIC stream +SSL object belongs to a QUIC connection SSL object. A QUIC connection SSL object +may or may not have an associated default stream. There may only be at most one +default stream for a QUIC connection SSL object. Reading or writing application +data to a QUIC connection SSL object with a default stream is equivalent to +reading or writing to that stream. It is an error to attempt to read or write +application data, or perform other stream-specific operations, on a QUIC +connection SSL object without a default stream associated. + +#### Notes on Multi-Threaded Operation + +Initially these APIs will not be thread safe over the same connection, but in +the longer term we intend to support multiple threads using different QUIC +stream SSL objects on different threads over the same connection without the +application having to do any locking. This is referred to as multi-stream +multi-thread (MSMT) operation. Only APIs explicitly denoted below will +eventually be MSMT-safe. + +#### Notes on Blocking + +The blocking mode can be configured on each SSL object individually. When a QUIC +stream SSL object is created it inherits its blocking state from the currently +configured blocking state of the QUIC connection SSL object at the time the +stream is created. This can be changed independently. For example, a QUIC +connection SSL object can be in blocking mode to allow for blocking +`SSL_accept_stream` calls, yet have some or all QUIC stream SSL objects be in +non-blocking mode concurrently. + +#### Notes on Application-Level Polling + +An API may be added in the future to allow applications to poll multiple QUIC +connection SSL objects efficiently for new stream and stream readability events. +This is not yet urgent but will be more relevant for concurrent server +applications. + +#### `SSL_get0_connection` + +| Semantics | `SSL_get_error` | Can Tick? | CSHL | +| --------- | ------------- | --------- | ------------- | +| New | Never | No | CS | + +```c +/* + * Get the SSL object representing the connection associated with this object. + * + * If the SSL object represents a non-QUIC method or a QUIC connection, this + * returns the same object passed. + * + * If the SSL object represents a QUIC stream returns the QUIC connection + * object. + */ +SSL *SSL_get0_connection(SSL *ssl); +``` + +#### `SSL_is_connection` + +| Semantics | `SSL_get_error` | Can Tick? | CSHL | +| --------- | ------------- | --------- | ------------- | +| New | Never | No | CS | + +```c +/* + * Returns 1 if the object represents a connection. This always returns 1 for + * non-QUIC methods, but returns 0 for SSL objects for QUIC streams which are + * not also the QUIC connection object. + * + * This is exactly equivalent to (SSL_get0_connection(ssl) == ssl). + */ +int SSL_is_connection(SSL *ssl); +``` + +#### `SSL_get_stream_type` + +| Semantics | `SSL_get_error` | Can Tick? | CSHL | +| --------- | ------------- | --------- | ------------- | +| New | Never | No | S | + +```c +/* + * If the object represents a stream, returns a SSL_STREAM_TYPE value + * designating whether the stream can be used for transmission, reception, + * or both. + * + * This always returns SSL_STREAM_TYPE_BIDI for non-QUIC methods. + * + * It returns SSL_STREAM_TYPE_NONE for a QUIC connection object if it + * does not have a default stream. + */ +#define SSL_STREAM_TYPE_NONE 0 +#define SSL_STREAM_TYPE_READ 1 +#define SSL_STREAM_TYPE_WRITE 2 +#define SSL_STREAM_TYPE_BIDI (SSL_STREAM_TYPE_READ | SSL_STREAM_TYPE_WRITE) +__owur int SSL_get_stream_type(SSL *ssl); +``` + +#### `SSL_get_stream_id` + +| Semantics | `SSL_get_error` | Can Tick? | CSHL | +| --------- | ------------- | --------- | ------------- | +| New | Never | No | S | + +```c +/* + * QUIC: Returns the unique stream ID for the stream, an integer in range [0, 2**62-1], + * or UINT64_MAX if the stream ID is not available. If called on a QUIC + * connection, returns the unique stream ID for the default stream if there is + * one, and otherwise returns UINT64_MAX. + * + * TLS, DTLS: Returns UINT64_MAX. + */ +__owur uint64_t SSL_get_stream_id(SSL *ssl); +``` + +#### `SSL_new_stream` + +| Semantics | `SSL_get_error` | Can Tick? | CSHL | +| --------- | ------------- | --------- | ------------- | +| New | Never | No | C | + +```c +/* + * Create a new SSL object representing a single additional stream. + * + * There is no need to call SSL_connect on the resulting object, and + * any such call is a no-op. + * + * For QUIC: + * Creates a new stream. Must be called only on a QUIC connection SSL object. + * Can be used on client or server. If the SSL_STREAM_FLAG_UNI flag is set, + * the created stream is unidirectional, otherwise it is bidirectional. + * + * To be MSMT-safe. + * + * For TLS and DTLS SSL objects: + * Always fails. + */ +#define SSL_STREAM_FLAG_UNI 1 + +SSL *SSL_new_stream(SSL *ssl, uint64_t flags); +``` + +#### `SSL_accept_stream` + +| Semantics | `SSL_get_error` | Can Tick? | CSHL | +| --------- | ------------- | --------- | ------------- | +| New | Never | Yes | C | + +```c +/* + * Create a new SSL object representing an additional stream which was created + * by the peer. + * + * There is no need to call SSL_accept on the resulting object, and + * any such call is a no-op. + * + * For QUIC: + * Must be called only on a QUIC connection SSL object. Fails if called on a + * stream object. Checks if a new stream has been created by the peer. If it + * has, creates a new SSL object to represent it and returns it. Otherwise, + * returns NULL. If multiple streams are available to be accepted, the oldest + * stream (that is, the stream with the lowest stream ID) is accepted. + * + * For all other methods: + * Returns NULL. + * + * The flags argument is unused and should be set to zero. + * + * To be MSMT-safe (i.e., can be called from multiple threads). + * + * If the QUIC connection SSL object is configured in blocking mode, this + * function will block unless the SSL_ACCEPT_STREAM_NO_BLOCK flag is passed. + * + * This function returns NULL if the effective incoming stream reject policy is + * `REJECT`. + */ +#define SSL_ACCEPT_STREAM_NO_BLOCK 1 + +SSL *SSL_accept_stream(SSL *ssl, uint64_t flags); +``` + +#### `SSL_get_accept_stream_queue_len` + +| Semantics | `SSL_get_error` | Can Tick? | CSHL | +| --------- | ------------- | --------- | ------------- | +| New | Never | No | C | + +```c +/* + * Determine the number of streams waiting to be returned on a subsequent call + * to SSL_accept_stream. If this returns a non-zero value, the next call to + * SSL_accept_stream (on any thread) is guaranteed to work. Returns 0 for + * non-QUIC objects, or for QUIC stream objects. + * + * To be MSMT-safe. + */ +size_t SSL_get_accept_stream_queue_len(SSL *ssl); +``` + +#### `SSL_set_incoming_stream_reject_policy` + +| Semantics | `SSL_get_error` | Can Tick? | CSHL | +| --------- | ------------- | --------- | ------------- | +| New | Never | No | C | + +```c +/* + * Sets the policy for incoming streams. If `policy` is `AUTO` (the default): + * + * - if `SSL_detach_stream` has been used, this is equivalent to `ACCEPT`; + * + * - otherwise, if the default stream mode is + * `SSL_DEFAULT_STREAM_MODE_AUTO_BIDI` or + * `SSL_DEFAULT_STREAM_MODE_AUTO_UNI`, this is equivalent to `REJECT`; + * + * - otherwise, this is equivalent to `ACCEPT`. + * + * If configured to `ACCEPT`, incoming streams are placed on the accept queue + * for application consumption. `aec` is ignored in this case. + * + * If configured to `REJECT`, incoming streams automatically have both their + * receiving and sending parts handled via non-normal termination. `aec` is an + * application error code used for the `STOP_SENDING` and `RESET_STREAM` frames + * used for the purposes of this termination. The default AEC value used if this + * function is never called is 0. + */ +#define SSL_INCOMING_STREAM_REJECT_POLICY_AUTO 0 +#define SSL_INCOMING_STREAM_REJECT_POLICY_ACCEPT 1 +#define SSL_INCOMING_STREAM_REJECT_POLICY_REJECT 2 + +int SSL_set_incoming_stream_reject_policy(SSL *ssl, int policy, uint64_t aec); +``` + +#### `SSL_set_default_stream_mode` + +| Semantics | `SSL_get_error` | Can Tick? | CSHL | +| --------- | ------------- | --------- | ------------- | +| New | Never | No | C | + +```c +/* + * Used to control single stream operation. Calling this function determines the + * nature of the default stream which will automatically be created on the QUIC + * connection SSL object. + * + * The default mode is `SSL_DEFAULT_STREAM_MODE_AUTO_BIDI`. + * + * The modes are as follows: + * + * - `SSL_DEFAULT_STREAM_MODE_NONE`: No default stream will ever be created. + * The application is assumed to understand multi-stream operation. + * Remotely-initiated streams are placed in the accept queue for application + * consumption. `SSL_read` and `SSL_write` calls must be made on a QUIC + * stream SSL object, not the QUIC connection SSL object, as no default + * stream will be associated with it. + * + * - `SSL_DEFAULT_STREAM_MODE_AUTO_BIDI`: "First stream wins" mode of + * operation for single-stream usage. If `SSL_write` is called before the + * peer opens a remotely-initiated stream, a locally-initiated bidirectional + * stream is created and bound as the default stream. If the peer opens a + * remotely-initiated stream before the local application calls `SSL_write` + * (with `len > 0`) for the first time, that stream is bound as the default + * stream, which may be bidirectional or unidirectional; if it is + * unidirectional, calls to `SSL_write` will fail. Attempts to create + * additional streams by the peer are automatically rejected unless + * the application opts in (API TBD). + * + * - `SSL_DEFAULT_STREAM_MODE_AUTO_UNI`: "First stream wins" mode of + * operation for single-stream usage, with a unidirectional stream. This + * functions identically to `SSL_DEFAULT_STREAM_MODE_AUTO_BIDI`, but if the + * local application calls `SSL_write` prior to the peer creating a + * remotely-initiated stream, a unidirectional TX-only stream is created and + * bound as the default stream. Thereafter, calls to `SSL_read` will fail. + * If the peer creates a remotely-initiated stream prior to the first call + * to `SSL_write` (with `len > 0`), that stream will be bound as the default + * stream; note that a bidirectional stream may be bound in this case. + * Attempts to create additional streams by the peer are automatically + * rejected unless the application opts in (API TBD). + * + * This function must be called before a default stream object is created, for + * example before initiating a connection. If the function is too late to have + * an effect, this function fails and returns 0. To switch to multi-stream + * operation after a default stream has been created, use `SSL_detach_stream`. + */ +#define SSL_DEFAULT_STREAM_MODE_NONE 0 +#define SSL_DEFAULT_STREAM_MODE_AUTO_BIDI 1 +#define SSL_DEFAULT_STREAM_MODE_AUTO_UNI 2 + +__owur int SSL_set_default_stream_mode(SSL *ssl, uint32_t mode); +``` + +#### `SSL_detach_stream` + +| Semantics | `SSL_get_error` | Can Tick? | CSHL | +| --------- | ------------- | --------- | ------------- | +| New | Never | No | C | + +```c +/* + * Detaches a default stream from a QUIC connection object. If the + * QUIC connection object does not contain a default stream, returns NULL. + * After calling this, calling SSL_get_stream_type on the connection object + * returns SSL_STREAM_TYPE_NONE. Always returns NULL for non-QUIC connections. + * + * Calling this function automatically inhibits default stream creation; + * though, after calling this function, a QUIC connection SSL object will no + * longer have a stream attached to it, calling SSL_read or SSL_write on + * that QUIC connection SSL object will not automatically create a new + * default stream. Default stream creation only occurs at most a single time per + * connection. + */ +SSL *SSL_detach_stream(SSL *ssl); +``` + +#### `SSL_attach_stream` + +| Semantics | `SSL_get_error` | Can Tick? | CSHL | +| --------- | ------------- | --------- | ------------- | +| New | Never | No | C | + +```c +/* + * Attaches a default stream to a QUIC connection object. If the conn object is + * not a QUIC connection object, or already has a default stream, this function + * fails. The stream must belong to the same connection, or this function fails. + */ +__owur int SSL_attach_stream(SSL *conn, SSL *stream); +``` + ### Future APIs A custom poller interface may be provided in the future. For more information, @@ -1192,3 +1584,119 @@ calls. **Q. How should `STOP_SENDING` be supported?** TODO: Determine how `STOP_SENDING` should be supported. + +**Q. Can data be received on a locally initiated bidirectional stream before any +data is sent on that stream?** + +This is an interesting question without a clear answer to be found in the QUIC +RFCs. A close reading of RFC 9000 suggests that the answer is, in principle, +yes; however the RFC also grants explicit permission to make design choices in +implementations which would preclude this: + +>An implementation might choose to defer allocating a stream ID to a stream until +>it sends the first STREAM frame and enters this state, which can allow for +>better stream prioritization. + +If an ID has not been allocated to a stream, obviously incoming data cannot be +addressed to it. However, supposing that an implementation does not do this, +RFC 9000 seems basically clear that it is valid for an application to create a +stream locally, then receive data on it before sending anything: + +>The sending part of a stream that the endpoint initiates (types 0 and 2 for +>clients, 1 and 3 for servers) is opened by the application. The "Ready" +>state represents a newly created stream that is able to accept data from the +>application. +> +>[...] +> +>For a bidirectional stream, the receiving part enters the "Recv" state when +>the sending part initiated by the endpoint (type 0 for a client, type 1 for +>a server) enters the "Ready" state. + +A peer is not generally notified of the creation of a stream which has not sent +any data yet, since the creation of a stream is signalled only implicitly via +the transmission of data in `STREAM` frames. However, a zero-length STREAM frame +could presumably be used to effect such a notification. RFC 9000 contains no +specific discussion of this possibility but does not preclude it. As such, in +order to receive data on a locally-initiated bidirectional stream before sending +any data on that stream, it would be necessary to either + +- Use a QUIC implementation which signals a bidirectional stream which has + not yet sent any data via a zero-length stream frame, or + +- Use an application protocol which can inform the peer of the stream ID + of the created stream in some application protocol-specific way. + This is somewhat less plausible because it would require an API between + the application and its QUIC library to inform the QUIC library + that the peer has in fact created a stream with a given ID and to + take its word for it. This is unlikely to be commonly available, especially as + application errors in usage of such an API would lead to internal + inconsistencies in QUIC connection state. + +Of course this discussion is somewhat esoteric as it is unclear why an +application would want to create a locally-initiated stream and then have the +peer transmit on it first, rather than simply use a remotely-initiated stream. +Thus this discussion of this edge case is more of a curiosity, however for +completeness it needs to be thought about in the API design. + +**Q. How should single-stream operation support locally and remotely-initiated +streams?** + +Note that the ID of a stream depends on whether it is bidirectional and whether +it is initiated by the client or server. Therefore, in single stream operation, +it is necessary to know whether single-stream QUIC is being used with +client-initiated or server-initiated stream initiation, and whether a +bidirectional or unidirectional stream is being used; otherwise, we do not know +which stream ID to bind to. + +The object of single stream operation is to support simple uses cases for simple +applications. There seems no need to support esoteric usage of streams such as +receiving first on a locally initiated stream here, thus we avoid supporting +this to simplify the API. + +As such, an application which calls `SSL_write` on a QUIC connection SSL object +before it calls `SSL_read` by definition is using a locally-initiated stream, +and an application which does the opposite is using a remotely-initiated stream. +We can use the ordering of initial calls to `SSL_read` and `SSL_write` to infer +the desired stream type. + +Supporting locally-initiated streams (`SSL_write` called first) is simple; +we automatically create the stream and queue data for transmission. + +Supporting remotely-initiated streams (`SSL_read` called first) is a little +stranger. We could create the stream with the correct ID when cued to by the +initial call to `SSL_read` implying use of a remotely-initiated stream. However, +this would mean we are creating state tracking a remotely-initiated stream +before the peer has signalled it. This would work in the happy case where the +client is connected to a compatible server but may result in strange +inconsistencies of QUIC internal state if a client is accidentially connected to +an incompatible peer. Since the peer ought to be the authority on the streams it +creates, this seems like an undesirable approach. + +Ergo, creation of a default remotely-initiated stream needs to be deferred +until the *peer* signals such a stream. + +This leads naturally to a "first stream wins" model of implementation: + +- When a QUIC connection SSL object is created, default stream mode is + enabled, meaning that a default stream will be bound to the QUIC connection + SSL object at the earliest available opportunity. However, no default + stream is bound yet. + +- One of the following events happened — whichever happens first wins: + + - The local application calls `SSL_write()` (`len > 0`). A locally-initiated + stream with ordinal 0 is created. The stream is bidirectional by default but + this can be changed. This stream is bound as the default stream. + + - The peer creates a stream. This stream is bound as the default stream. + +If the local application calls `SSL_read()` before either of the above +occur, `SSL_read()` fails as though no data is available until one +of the above events occurs. + +Once one of the above events occurs, any additional stream created by the peer +is automatically terminated using both `STOP_SENDING` and `STREAM_RESET` frames +(to terminate both the receiving and sending parts respectively) and there is no +API-visible effect to the local application (unless the application explicitly +opts into supporting additional streams). |