From 4a7d4adee53ce8082210b56c156624c2b1e16eea Mon Sep 17 00:00:00 2001 From: Todd Short Date: Sat, 12 Dec 2020 17:27:46 +0900 Subject: QUIC: add v1 quic_transport_parameters (cherry picked from commit 8f4f7f2b3adebe5f6e23a8c0f5684feae5574ae2) --- crypto/err/openssl.txt | 11 +++ doc/man3/SSL_CTX_set_quic_method.pod | 25 +++++- include/openssl/ssl.h | 13 ++++ include/openssl/sslerr.h | 6 ++ include/openssl/tls1.h | 3 +- ssl/ssl_err.c | 12 +++ ssl/ssl_lib.c | 1 + ssl/ssl_local.h | 11 +++ ssl/ssl_quic.c | 41 +++++++++- ssl/statem/extensions.c | 40 ++++++++++ ssl/statem/extensions_clnt.c | 46 ++++++++++- ssl/statem/extensions_srvr.c | 48 +++++++++++- ssl/statem/statem_local.h | 17 ++++ test/sslapitest.c | 111 +++++++++++++++++++++------ util/libssl.num | 4 + 15 files changed, 352 insertions(+), 37 deletions(-) diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 8af0be60a6..12c8cb8779 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1162,6 +1162,7 @@ SSL_F_FINAL_EMS:486:final_ems SSL_F_FINAL_KEY_SHARE:503:final_key_share SSL_F_FINAL_MAXFRAGMENTLEN:557:final_maxfragmentlen SSL_F_FINAL_PSK:639:final_psk +SSL_F_FINAL_QUIC_TRANSPORT_PARAMS:3012:final_quic_transport_params SSL_F_FINAL_RENEGOTIATE:483:final_renegotiate SSL_F_FINAL_SERVER_NAME:558:final_server_name SSL_F_FINAL_SIG_ALGS:497:final_sig_algs @@ -1434,6 +1435,8 @@ SSL_F_TLS_CONSTRUCT_CTOS_PSK:501:tls_construct_ctos_psk SSL_F_TLS_CONSTRUCT_CTOS_PSK_KEX_MODES:509:tls_construct_ctos_psk_kex_modes SSL_F_TLS_CONSTRUCT_CTOS_QUIC_TRANSPORT_PARAMS:3008:\ tls_construct_ctos_quic_transport_params +SSL_F_TLS_CONSTRUCT_CTOS_QUIC_TRANSPORT_PARAMS_DRAFT:3013:\ + tls_construct_ctos_quic_transport_params_draft SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE:473:tls_construct_ctos_renegotiate SSL_F_TLS_CONSTRUCT_CTOS_SCT:474:tls_construct_ctos_sct SSL_F_TLS_CONSTRUCT_CTOS_SERVER_NAME:475:tls_construct_ctos_server_name @@ -1477,6 +1480,8 @@ SSL_F_TLS_CONSTRUCT_STOC_NEXT_PROTO_NEG:457:tls_construct_stoc_next_proto_neg SSL_F_TLS_CONSTRUCT_STOC_PSK:504:tls_construct_stoc_psk SSL_F_TLS_CONSTRUCT_STOC_QUIC_TRANSPORT_PARAMS:3009:\ tls_construct_stoc_quic_transport_params +SSL_F_TLS_CONSTRUCT_STOC_QUIC_TRANSPORT_PARAMS_DRAFT:3014:\ + tls_construct_stoc_quic_transport_params_draft SSL_F_TLS_CONSTRUCT_STOC_RENEGOTIATE:458:tls_construct_stoc_renegotiate SSL_F_TLS_CONSTRUCT_STOC_SERVER_NAME:459:tls_construct_stoc_server_name SSL_F_TLS_CONSTRUCT_STOC_SESSION_TICKET:460:tls_construct_stoc_session_ticket @@ -1507,6 +1512,8 @@ SSL_F_TLS_PARSE_CTOS_PSK:505:tls_parse_ctos_psk SSL_F_TLS_PARSE_CTOS_PSK_KEX_MODES:572:tls_parse_ctos_psk_kex_modes SSL_F_TLS_PARSE_CTOS_QUIC_TRANSPORT_PARAMS:3010:\ tls_parse_ctos_quic_transport_params +SSL_F_TLS_PARSE_CTOS_QUIC_TRANSPORT_PARAMS_DRAFT:3015:\ + tls_parse_ctos_quic_transport_params_draft SSL_F_TLS_PARSE_CTOS_RENEGOTIATE:464:tls_parse_ctos_renegotiate SSL_F_TLS_PARSE_CTOS_SERVER_NAME:573:tls_parse_ctos_server_name SSL_F_TLS_PARSE_CTOS_SESSION_TICKET:574:tls_parse_ctos_session_ticket @@ -1527,6 +1534,8 @@ SSL_F_TLS_PARSE_STOC_NPN:582:tls_parse_stoc_npn SSL_F_TLS_PARSE_STOC_PSK:502:tls_parse_stoc_psk SSL_F_TLS_PARSE_STOC_QUIC_TRANSPORT_PARAMS:3011:\ tls_parse_stoc_quic_transport_params +SSL_F_TLS_PARSE_STOC_QUIC_TRANSPORT_PARAMS_DRAFT:3016:\ + tls_parse_stoc_quic_transport_params_draft SSL_F_TLS_PARSE_STOC_RENEGOTIATE:448:tls_parse_stoc_renegotiate SSL_F_TLS_PARSE_STOC_SCT:564:tls_parse_stoc_sct SSL_F_TLS_PARSE_STOC_SERVER_NAME:583:tls_parse_stoc_server_name @@ -2764,6 +2773,8 @@ SSL_R_MISSING_ECDSA_SIGNING_CERT:381:missing ecdsa signing cert SSL_R_MISSING_FATAL:256:missing fatal SSL_R_MISSING_PARAMETERS:290:missing parameters SSL_R_MISSING_PSK_KEX_MODES_EXTENSION:310:missing psk kex modes extension +SSL_R_MISSING_QUIC_TRANSPORT_PARAMETERS_EXTENSION:801:\ + missing quic transport parameters extension SSL_R_MISSING_RSA_CERTIFICATE:168:missing rsa certificate SSL_R_MISSING_RSA_ENCRYPTING_CERT:169:missing rsa encrypting cert SSL_R_MISSING_RSA_SIGNING_CERT:170:missing rsa signing cert diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod index 3d7bf7e682..39ff3a8da4 100644 --- a/doc/man3/SSL_CTX_set_quic_method.pod +++ b/doc/man3/SSL_CTX_set_quic_method.pod @@ -13,7 +13,11 @@ SSL_quic_read_level, SSL_quic_write_level, SSL_provide_quic_data, SSL_process_quic_post_handshake, -SSL_is_quic +SSL_is_quic, +SSL_get_peer_quic_transport_version, +SSL_get_quic_transport_version, +SSL_set_quic_transport_version, +SSL_set_quic_use_legacy_codepoint - QUIC support =head1 SYNOPSIS @@ -39,6 +43,11 @@ SSL_is_quic int SSL_process_quic_post_handshake(SSL *ssl); int SSL_is_quic(SSL *ssl); + void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy); + void SSL_set_quic_transport_version(SSL *ssl, int version); + int SSL_get_quic_transport_version(const SSL *ssl); + int SSL_get_peer_quic_transport_version(const SSL *ssl); + =head1 DESCRIPTION SSL_CTX_set_quic_method() and SSL_set_quic_method() configures the QUIC methods. @@ -83,6 +92,20 @@ sent by the server. SSL_is_quic() indicates whether a connection uses QUIC. A given B or B can only be used with QUIC or TLS, but not both. +SSL_set_quic_use_legacy_codepoint() specifies the legacy extension codepoint +in manner compatible with some versions of BoringSSL. + +SSL_set_quic_transport_version() specifies the quic transport version that +allows for backwards and forwards compatibility. If set to 0 (default) the +server will use the highest version the client sent. If set to 0 (default) +the client will send both extensions. + +SSL_get_quic_transport_version() returns the value set by +SSL_set_quic_transport_version(). + +SSL_get_peer_quic_transport_version() returns the version the that was +negotiated. + =head1 NOTES These APIs are implementations of BoringSSL's QUIC APIs. diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index b7cdbfbae4..aaa8b0135b 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -2483,6 +2483,19 @@ __owur int SSL_process_quic_post_handshake(SSL *ssl); __owur int SSL_is_quic(SSL *ssl); +/* BoringSSL API */ +void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy); + +/* + * Set an explicit value that you want to use + * If 0 (default) the server will use the highest extenstion the client sent + * If 0 (default) the client will send both extensions + */ +void SSL_set_quic_transport_version(SSL *ssl, int version); +__owur int SSL_get_quic_transport_version(const SSL *ssl); +/* Returns the negotiated version, or -1 on error */ +__owur int SSL_get_peer_quic_transport_version(const SSL *ssl); + int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c); # endif diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h index e31bf3ccf6..64e152cc51 100644 --- a/include/openssl/sslerr.h +++ b/include/openssl/sslerr.h @@ -71,6 +71,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_FINAL_KEY_SHARE 503 # define SSL_F_FINAL_MAXFRAGMENTLEN 557 # define SSL_F_FINAL_PSK 639 +# define SSL_F_FINAL_QUIC_TRANSPORT_PARAMS 3012 # define SSL_F_FINAL_RENEGOTIATE 483 # define SSL_F_FINAL_SERVER_NAME 558 # define SSL_F_FINAL_SIG_ALGS 497 @@ -329,6 +330,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_CONSTRUCT_CTOS_PSK 501 # define SSL_F_TLS_CONSTRUCT_CTOS_PSK_KEX_MODES 509 # define SSL_F_TLS_CONSTRUCT_CTOS_QUIC_TRANSPORT_PARAMS 3008 +# define SSL_F_TLS_CONSTRUCT_CTOS_QUIC_TRANSPORT_PARAMS_DRAFT 3013 # define SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE 473 # define SSL_F_TLS_CONSTRUCT_CTOS_SCT 474 # define SSL_F_TLS_CONSTRUCT_CTOS_SERVER_NAME 475 @@ -369,6 +371,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_CONSTRUCT_STOC_NEXT_PROTO_NEG 457 # define SSL_F_TLS_CONSTRUCT_STOC_PSK 504 # define SSL_F_TLS_CONSTRUCT_STOC_QUIC_TRANSPORT_PARAMS 3009 +# define SSL_F_TLS_CONSTRUCT_STOC_QUIC_TRANSPORT_PARAMS_DRAFT 3014 # define SSL_F_TLS_CONSTRUCT_STOC_RENEGOTIATE 458 # define SSL_F_TLS_CONSTRUCT_STOC_SERVER_NAME 459 # define SSL_F_TLS_CONSTRUCT_STOC_SESSION_TICKET 460 @@ -395,6 +398,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_PARSE_CTOS_PSK 505 # define SSL_F_TLS_PARSE_CTOS_PSK_KEX_MODES 572 # define SSL_F_TLS_PARSE_CTOS_QUIC_TRANSPORT_PARAMS 3010 +# define SSL_F_TLS_PARSE_CTOS_QUIC_TRANSPORT_PARAMS_DRAFT 3015 # define SSL_F_TLS_PARSE_CTOS_RENEGOTIATE 464 # define SSL_F_TLS_PARSE_CTOS_SERVER_NAME 573 # define SSL_F_TLS_PARSE_CTOS_SESSION_TICKET 574 @@ -414,6 +418,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_PARSE_STOC_NPN 582 # define SSL_F_TLS_PARSE_STOC_PSK 502 # define SSL_F_TLS_PARSE_STOC_QUIC_TRANSPORT_PARAMS 3011 +# define SSL_F_TLS_PARSE_STOC_QUIC_TRANSPORT_PARAMS_DRAFT 3016 # define SSL_F_TLS_PARSE_STOC_RENEGOTIATE 448 # define SSL_F_TLS_PARSE_STOC_SCT 564 # define SSL_F_TLS_PARSE_STOC_SERVER_NAME 583 @@ -606,6 +611,7 @@ int ERR_load_SSL_strings(void); # define SSL_R_MISSING_FATAL 256 # define SSL_R_MISSING_PARAMETERS 290 # define SSL_R_MISSING_PSK_KEX_MODES_EXTENSION 310 +# define SSL_R_MISSING_QUIC_TRANSPORT_PARAMETERS_EXTENSION 801 # define SSL_R_MISSING_RSA_CERTIFICATE 168 # define SSL_R_MISSING_RSA_ENCRYPTING_CERT 169 # define SSL_R_MISSING_RSA_SIGNING_CERT 170 diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h index c11ca1efa3..2cbf53265f 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -149,7 +149,8 @@ extern "C" { # define TLSEXT_TYPE_renegotiate 0xff01 /* ExtensionType value from draft-ietf-quic-tls-27 */ -# define TLSEXT_TYPE_quic_transport_parameters 0xffa5 +# define TLSEXT_TYPE_quic_transport_parameters_draft 0xffa5 +# define TLSEXT_TYPE_quic_transport_parameters 0x0039 # ifndef OPENSSL_NO_NEXTPROTONEG /* This is not an IANA defined extension number */ diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 094c575100..56adfdca42 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -86,6 +86,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = { {ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_MAXFRAGMENTLEN, 0), "final_maxfragmentlen"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_PSK, 0), "final_psk"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_QUIC_TRANSPORT_PARAMS, 0), + "final_quic_transport_params"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_RENEGOTIATE, 0), "final_renegotiate"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_SERVER_NAME, 0), "final_server_name"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_SIG_ALGS, 0), "final_sig_algs"}, @@ -497,6 +499,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = { "tls_construct_ctos_psk_kex_modes"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_QUIC_TRANSPORT_PARAMS, 0), "tls_construct_ctos_quic_transport_params"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_QUIC_TRANSPORT_PARAMS_DRAFT, 0), + "tls_construct_ctos_quic_transport_params_draft"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE, 0), "tls_construct_ctos_renegotiate"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_SCT, 0), @@ -570,6 +574,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = { "tls_construct_stoc_psk"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_QUIC_TRANSPORT_PARAMS, 0), "tls_construct_stoc_quic_transport_params"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_QUIC_TRANSPORT_PARAMS_DRAFT, 0), + "tls_construct_stoc_quic_transport_params_draft"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_RENEGOTIATE, 0), "tls_construct_stoc_renegotiate"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_SERVER_NAME, 0), @@ -618,6 +624,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = { "tls_parse_ctos_psk_kex_modes"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_QUIC_TRANSPORT_PARAMS, 0), "tls_parse_ctos_quic_transport_params"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_QUIC_TRANSPORT_PARAMS_DRAFT, 0), + "tls_parse_ctos_quic_transport_params_draft"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_RENEGOTIATE, 0), "tls_parse_ctos_renegotiate"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_SERVER_NAME, 0), @@ -652,6 +660,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = { {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_PSK, 0), "tls_parse_stoc_psk"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_QUIC_TRANSPORT_PARAMS, 0), "tls_parse_stoc_quic_transport_params"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_QUIC_TRANSPORT_PARAMS_DRAFT, 0), + "tls_parse_stoc_quic_transport_params_draft"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_RENEGOTIATE, 0), "tls_parse_stoc_renegotiate"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_SCT, 0), "tls_parse_stoc_sct"}, @@ -974,6 +984,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_PARAMETERS), "missing parameters"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_PSK_KEX_MODES_EXTENSION), "missing psk kex modes extension"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_QUIC_TRANSPORT_PARAMETERS_EXTENSION), + "missing quic transport parameters extension"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_CERTIFICATE), "missing rsa certificate"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_ENCRYPTING_CERT), diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 7c579307fb..058cbf072c 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1218,6 +1218,7 @@ void SSL_free(SSL *s) #ifndef OPENSSL_NO_QUIC OPENSSL_free(s->ext.quic_transport_params); + OPENSSL_free(s->ext.peer_quic_transport_params_draft); OPENSSL_free(s->ext.peer_quic_transport_params); BUF_MEM_free(s->quic_buf); while (s->quic_input_data_head != NULL) { diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 213c87f77c..f9b6a5cc9d 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -721,6 +721,7 @@ typedef enum tlsext_index_en { TLSEXT_IDX_cryptopro_bug, TLSEXT_IDX_early_data, TLSEXT_IDX_certificate_authorities, + TLSEXT_IDX_quic_transport_params_draft, TLSEXT_IDX_quic_transport_params, TLSEXT_IDX_padding, TLSEXT_IDX_psk, @@ -1398,6 +1399,8 @@ struct ssl_st { #ifndef OPENSSL_NO_QUIC uint8_t *quic_transport_params; size_t quic_transport_params_len; + uint8_t *peer_quic_transport_params_draft; + size_t peer_quic_transport_params_draft_len; uint8_t *peer_quic_transport_params; size_t peer_quic_transport_params_len; #endif @@ -1407,6 +1410,14 @@ struct ssl_st { OSSL_ENCRYPTION_LEVEL quic_read_level; OSSL_ENCRYPTION_LEVEL quic_write_level; OSSL_ENCRYPTION_LEVEL quic_latest_level_received; + /* + * defaults to 0, but can be set to: + * - TLSEXT_TYPE_quic_transport_parameters_draft + * - TLSEXT_TYPE_quic_transport_parameters + * Client: if 0, send both + * Server: if 0, use same version as client sent + */ + int quic_transport_version; BUF_MEM *quic_buf; /* buffer incoming handshake messages */ QUIC_DATA *quic_input_data_head; QUIC_DATA *quic_input_data_tail; diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index b79a40a8b6..f7171be140 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -35,8 +35,45 @@ void SSL_get_peer_quic_transport_params(const SSL *ssl, const uint8_t **out_params, size_t *out_params_len) { - *out_params = ssl->ext.peer_quic_transport_params; - *out_params_len = ssl->ext.peer_quic_transport_params_len; + if (ssl->ext.peer_quic_transport_params_len) { + *out_params = ssl->ext.peer_quic_transport_params; + *out_params_len = ssl->ext.peer_quic_transport_params_len; + } else { + *out_params = ssl->ext.peer_quic_transport_params_draft; + *out_params_len = ssl->ext.peer_quic_transport_params_draft_len; + } +} + +/* Returns the negotiated version, or -1 on error */ +int SSL_get_peer_quic_transport_version(const SSL *ssl) +{ + if (ssl->ext.peer_quic_transport_params_len != 0 + && ssl->ext.peer_quic_transport_params_draft_len != 0) + return -1; + if (ssl->ext.peer_quic_transport_params_len != 0) + return TLSEXT_TYPE_quic_transport_parameters; + if (ssl->ext.peer_quic_transport_params_draft_len != 0) + return TLSEXT_TYPE_quic_transport_parameters_draft; + + return -1; +} + +void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy) +{ + if (use_legacy) + ssl->quic_transport_version = TLSEXT_TYPE_quic_transport_parameters_draft; + else + ssl->quic_transport_version = TLSEXT_TYPE_quic_transport_parameters; +} + +void SSL_set_quic_transport_version(SSL *ssl, int version) +{ + ssl->quic_transport_version = version; +} + +int SSL_get_quic_transport_version(const SSL *ssl) +{ + return ssl->quic_transport_version; } size_t SSL_quic_max_handshake_flight_len(const SSL *ssl, OSSL_ENCRYPTION_LEVEL level) diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index f7a395f4bb..3a6702cd6a 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -60,6 +60,7 @@ static int init_post_handshake_auth(SSL *s, unsigned int context); static int final_psk(SSL *s, unsigned int context, int sent); #ifndef OPENSSL_NO_QUIC static int init_quic_transport_params(SSL *s, unsigned int context); +static int final_quic_transport_params_draft(SSL *s, unsigned int context, int sent); static int final_quic_transport_params(SSL *s, unsigned int context, int sent); #endif @@ -382,6 +383,15 @@ static const EXTENSION_DEFINITION ext_defs[] = { tls_construct_certificate_authorities, NULL, }, #ifndef OPENSSL_NO_QUIC + { + TLSEXT_TYPE_quic_transport_parameters_draft, + SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS + | SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY, + init_quic_transport_params, + tls_parse_ctos_quic_transport_params_draft, tls_parse_stoc_quic_transport_params_draft, + tls_construct_stoc_quic_transport_params_draft, tls_construct_ctos_quic_transport_params_draft, + final_quic_transport_params_draft, + }, { TLSEXT_TYPE_quic_transport_parameters, SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS @@ -1769,8 +1779,38 @@ static int init_quic_transport_params(SSL *s, unsigned int context) return 1; } +static int final_quic_transport_params_draft(SSL *s, unsigned int context, + int sent) +{ + return 1; +} + static int final_quic_transport_params(SSL *s, unsigned int context, int sent) { + /* called after final_quic_transport_params_draft */ + if (SSL_IS_QUIC(s)) { + if (s->ext.peer_quic_transport_params_len == 0 + && s->ext.peer_quic_transport_params_draft_len == 0) { + SSLfatal(s, SSL_AD_MISSING_EXTENSION, + SSL_F_FINAL_QUIC_TRANSPORT_PARAMS, + SSL_R_MISSING_QUIC_TRANSPORT_PARAMETERS_EXTENSION); + return 0; + } + /* if we got both, discard the one we can't use */ + if (s->ext.peer_quic_transport_params_len != 0 + && s->ext.peer_quic_transport_params_draft_len != 0) { + if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters_draft) { + OPENSSL_free(s->ext.peer_quic_transport_params); + s->ext.peer_quic_transport_params = NULL; + s->ext.peer_quic_transport_params_len = 0; + } else { + OPENSSL_free(s->ext.peer_quic_transport_params_draft); + s->ext.peer_quic_transport_params_draft = NULL; + s->ext.peer_quic_transport_params_draft_len = 0; + } + } + } + return 1; } #endif diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index fd76adccdc..28d74aae48 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1229,13 +1229,34 @@ EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt, } #ifndef OPENSSL_NO_QUIC -/* SAME AS tls_construct_stoc_quic_transport_params() */ +EXT_RETURN tls_construct_ctos_quic_transport_params_draft(SSL *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx) +{ + if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters + || s->ext.quic_transport_params == NULL + || s->ext.quic_transport_params_len == 0) { + return EXT_RETURN_NOT_SENT; + } + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters_draft) + || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params, + s->ext.quic_transport_params_len)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_CONSTRUCT_CTOS_QUIC_TRANSPORT_PARAMS_DRAFT, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + + return EXT_RETURN_SENT; +} + EXT_RETURN tls_construct_ctos_quic_transport_params(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { - if (s->ext.quic_transport_params == NULL - || s->ext.quic_transport_params_len == 0) { + if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters_draft + || s->ext.quic_transport_params == NULL + || s->ext.quic_transport_params_len == 0) { return EXT_RETURN_NOT_SENT; } @@ -2059,7 +2080,24 @@ int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, return 1; } #ifndef OPENSSL_NO_QUIC -/* SAME AS tls_parse_ctos_quic_transport_params() */ +int tls_parse_stoc_quic_transport_params_draft(SSL *s, PACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx) +{ + OPENSSL_free(s->ext.peer_quic_transport_params_draft); + s->ext.peer_quic_transport_params_draft = NULL; + s->ext.peer_quic_transport_params_draft_len = 0; + + if (!PACKET_memdup(pkt, + &s->ext.peer_quic_transport_params_draft, + &s->ext.peer_quic_transport_params_draft_len)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_PARSE_STOC_QUIC_TRANSPORT_PARAMS_DRAFT, ERR_R_INTERNAL_ERROR); + return 0; + } + return 1; +} + int tls_parse_stoc_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 3499aa608c..6a4fcdb4f0 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1303,7 +1303,23 @@ int tls_parse_ctos_post_handshake_auth(SSL *s, PACKET *pkt, unsigned int context } #ifndef OPENSSL_NO_QUIC -/* SAME AS tls_parse_stoc_quic_transport_params() */ +int tls_parse_ctos_quic_transport_params_draft(SSL *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx) +{ + OPENSSL_free(s->ext.peer_quic_transport_params_draft); + s->ext.peer_quic_transport_params_draft = NULL; + s->ext.peer_quic_transport_params_draft_len = 0; + + if (!PACKET_memdup(pkt, + &s->ext.peer_quic_transport_params_draft, + &s->ext.peer_quic_transport_params_draft_len)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_PARSE_CTOS_QUIC_TRANSPORT_PARAMS_DRAFT, ERR_R_INTERNAL_ERROR); + return 0; + } + return 1; +} + int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { @@ -2009,13 +2025,37 @@ EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context, } #ifndef OPENSSL_NO_QUIC -/* SAME AS tls_construct_ctos_quic_transport_params() */ +EXT_RETURN tls_construct_stoc_quic_transport_params_draft(SSL *s, WPACKET *pkt, + unsigned int context, + X509 *x, + size_t chainidx) +{ + if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters + || s->ext.peer_quic_transport_params_draft_len == 0 + || s->ext.quic_transport_params == NULL + || s->ext.quic_transport_params_len == 0) { + return EXT_RETURN_NOT_SENT; + } + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters_draft) + || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params, + s->ext.quic_transport_params_len)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_CONSTRUCT_STOC_QUIC_TRANSPORT_PARAMS_DRAFT, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + + return EXT_RETURN_SENT; +} + EXT_RETURN tls_construct_stoc_quic_transport_params(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { - if (s->ext.quic_transport_params == NULL - || s->ext.quic_transport_params_len == 0) { + if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters_draft + || s->ext.peer_quic_transport_params_len == 0 + || s->ext.quic_transport_params == NULL + || s->ext.quic_transport_params_len == 0) { return EXT_RETURN_NOT_SENT; } diff --git a/ssl/statem/statem_local.h b/ssl/statem/statem_local.h index cefbebdd92..7bf905f3df 100644 --- a/ssl/statem/statem_local.h +++ b/ssl/statem/statem_local.h @@ -242,6 +242,10 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, int tls_parse_ctos_post_handshake_auth(SSL *, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); #ifndef OPENSSL_NO_QUIC +int tls_parse_ctos_quic_transport_params_draft(SSL *s, PACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx); + int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); #endif @@ -308,6 +312,11 @@ EXT_RETURN tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx); #ifndef OPENSSL_NO_QUIC +EXT_RETURN tls_construct_stoc_quic_transport_params_draft(SSL *s, WPACKET *pkt, + unsigned int context, + X509 *x, + size_t chainidx); + EXT_RETURN tls_construct_stoc_quic_transport_params(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx); @@ -383,6 +392,10 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx); #ifndef OPENSSL_NO_QUIC +EXT_RETURN tls_construct_ctos_quic_transport_params_draft(SSL *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx); + EXT_RETURN tls_construct_ctos_quic_transport_params(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx); @@ -433,6 +446,10 @@ int tls_parse_stoc_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x, int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); #ifndef OPENSSL_NO_QUIC +int tls_parse_stoc_quic_transport_params_draft(SSL *s, PACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx); + int tls_parse_stoc_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); #endif diff --git a/test/sslapitest.c b/test/sslapitest.c index c82cd73c0a..a200ec82f2 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -7336,7 +7336,14 @@ static SSL_QUIC_METHOD quic_method = { test_quic_flush_flight, test_quic_send_alert, }; -static int test_quic_api(void) + +static int test_quic_api_set_versions(SSL *ssl, int ver) +{ + SSL_set_quic_transport_version(ssl, ver); + return 1; +} + +static int test_quic_api_version(int clnt, int srvr) { SSL_CTX *cctx = NULL, *sctx = NULL; SSL *clientssl = NULL, *serverssl = NULL; @@ -7346,29 +7353,7 @@ static int test_quic_api(void) const uint8_t *peer_str; size_t peer_str_len; - /* Clean up logging space */ - memset(client_log_buffer, 0, sizeof(client_log_buffer)); - memset(server_log_buffer, 0, sizeof(server_log_buffer)); - client_log_buffer_index = 0; - server_log_buffer_index = 0; - error_writing_log = 0; - - - if (!TEST_ptr(sctx = SSL_CTX_new(TLS_server_method())) - || !TEST_true(SSL_CTX_set_quic_method(sctx, &quic_method)) - || !TEST_ptr(sctx->quic_method) - || !TEST_ptr(serverssl = SSL_new(sctx)) - || !TEST_true(SSL_IS_QUIC(serverssl)) - || !TEST_true(SSL_set_quic_method(serverssl, NULL)) - || !TEST_false(SSL_IS_QUIC(serverssl)) - || !TEST_true(SSL_set_quic_method(serverssl, &quic_method)) - || !TEST_true(SSL_IS_QUIC(serverssl))) - goto end; - - SSL_CTX_free(sctx); - sctx = NULL; - SSL_free(serverssl); - serverssl = NULL; + TEST_info("original clnt=0x%X, srvr=0x%X\n", clnt, srvr); if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(), @@ -7386,6 +7371,8 @@ static int test_quic_api(void) sizeof(client_str))) || !TEST_true(SSL_set_app_data(serverssl, clientssl)) || !TEST_true(SSL_set_app_data(clientssl, serverssl)) + || !TEST_true(test_quic_api_set_versions(clientssl, clnt)) + || !TEST_true(test_quic_api_set_versions(serverssl, srvr)) || !TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)) || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION) @@ -7419,6 +7406,19 @@ static int test_quic_api(void) || !TEST_int_le(SSL_do_handshake(serverssl), 0)) goto end; + TEST_info("original clnt=0x%X, srvr=0x%X\n", clnt, srvr); + if (srvr == 0 && clnt == 0) + srvr = clnt = TLSEXT_TYPE_quic_transport_parameters; + else if (srvr == 0) + srvr = clnt; + else if (clnt == 0) + clnt = srvr; + TEST_info("expected clnt=0x%X, srvr=0x%X\n", clnt, srvr); + if (!TEST_int_eq(SSL_get_peer_quic_transport_version(serverssl), clnt)) + goto end; + if (!TEST_int_eq(SSL_get_peer_quic_transport_version(clientssl), srvr)) + goto end; + testresult = 1; end: @@ -7429,6 +7429,67 @@ end: return testresult; } + +static int test_quic_api(int tst) +{ + SSL_CTX *sctx = NULL; + SSL *serverssl = NULL; + int testresult = 0; + static int clnt_params[] = { 0, + TLSEXT_TYPE_quic_transport_parameters_draft, + TLSEXT_TYPE_quic_transport_parameters, + 0, + TLSEXT_TYPE_quic_transport_parameters_draft, + TLSEXT_TYPE_quic_transport_parameters, + 0, + TLSEXT_TYPE_quic_transport_parameters_draft, + TLSEXT_TYPE_quic_transport_parameters }; + static int srvr_params[] = { 0, + 0, + 0, + TLSEXT_TYPE_quic_transport_parameters_draft, + TLSEXT_TYPE_quic_transport_parameters_draft, + TLSEXT_TYPE_quic_transport_parameters_draft, + TLSEXT_TYPE_quic_transport_parameters, + TLSEXT_TYPE_quic_transport_parameters, + TLSEXT_TYPE_quic_transport_parameters }; + static int results[] = { 1, 1, 1, 1, 1, 0, 1, 0, 1 }; + + /* Failure cases: + * test 6/[5] clnt = parameters, srvr = draft + * test 8/[7] clnt = draft, srvr = parameters + */ + + /* Clean up logging space */ + memset(client_log_buffer, 0, sizeof(client_log_buffer)); + memset(server_log_buffer, 0, sizeof(server_log_buffer)); + client_log_buffer_index = 0; + server_log_buffer_index = 0; + error_writing_log = 0; + + if (!TEST_ptr(sctx = SSL_CTX_new(TLS_server_method())) + || !TEST_true(SSL_CTX_set_quic_method(sctx, &quic_method)) + || !TEST_ptr(sctx->quic_method) + || !TEST_ptr(serverssl = SSL_new(sctx)) + || !TEST_true(SSL_IS_QUIC(serverssl)) + || !TEST_true(SSL_set_quic_method(serverssl, NULL)) + || !TEST_false(SSL_IS_QUIC(serverssl)) + || !TEST_true(SSL_set_quic_method(serverssl, &quic_method)) + || !TEST_true(SSL_IS_QUIC(serverssl))) + goto end; + + if (!TEST_int_eq(test_quic_api_version(clnt_params[tst], srvr_params[tst]), results[tst])) + goto end; + + testresult = 1; + +end: + SSL_CTX_free(sctx); + sctx = NULL; + SSL_free(serverssl); + serverssl = NULL; + return testresult; +} #endif int setup_tests(void) @@ -7566,7 +7627,7 @@ int setup_tests(void) ADD_ALL_TESTS(test_serverinfo_custom, 4); #endif #ifndef OPENSSL_NO_QUIC - ADD_TEST(test_quic_api); + ADD_ALL_TESTS(test_quic_api, 9); #endif return 1; } diff --git a/util/libssl.num b/util/libssl.num index 9a19d1757d..d27011d83f 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -509,3 +509,7 @@ SSL_set_quic_method 20007 1_1_1i EXIST::FUNCTION:QUIC SSL_quic_max_handshake_flight_len 20008 1_1_1i EXIST::FUNCTION:QUIC SSL_process_quic_post_handshake 20009 1_1_1i EXIST::FUNCTION:QUIC SSL_provide_quic_data 20010 1_1_1i EXIST::FUNCTION:QUIC +SSL_set_quic_use_legacy_codepoint 20011 1_1_1i EXIST::FUNCTION:QUIC +SSL_set_quic_transport_version 20012 1_1_1i EXIST::FUNCTION:QUIC +SSL_get_peer_quic_transport_version 20013 1_1_1i EXIST::FUNCTION:QUIC +SSL_get_quic_transport_version 20014 1_1_1i EXIST::FUNCTION:QUIC -- 2.35.3