From 4bd185b26c7a68b7909868912f8b5565620f32b6 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 12 Apr 2019 11:13:25 -0400 Subject: [PATCH 01/66] QUIC: Add support for BoringSSL QUIC APIs This adds a compatible API for BoringSSL's QUIC support, based on the current |draft-ietf-quic-tls|. Based on BoringSSL commit 3c034b2cf386b3131f75520705491871a2e0cafe Based on BoringSSL commit c8e0f90f83b9ec38ea833deb86b5a41360b62b6a Based on BoringSSL commit 3cbb0299a28a8bd0136257251a78b91a96c5eec8 Based on BoringSSL commit cc9d935256539af2d3b7f831abf57c0d685ffd81 Based on BoringSSL commit e6eef1ca16a022e476bbaedffef044597cfc8f4b Based on BoringSSL commit 6f733791148cf8a076bf0e95498235aadbe5926d Based on BoringSSL commit 384d0eaf1930af1ebc47eda751f0c78dfcba1c03 Based on BoringSSL commit a0373182eb5cc7b81d49f434596b473c7801c942 Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 --- CHANGES.md | 4 + Configure | 2 + INSTALL.md | 4 + crypto/err/openssl.txt | 2 + doc/man3/SSL_CIPHER_get_name.pod | 13 ++ doc/man3/SSL_CTX_set_quic_method.pod | 232 +++++++++++++++++++++++++ include/openssl/evp.h | 5 + include/openssl/ssl.h.in | 45 +++++ include/openssl/sslerr.h | 2 + include/openssl/tls1.h | 3 + include/openssl/types.h | 2 + ssl/build.info | 2 + ssl/s3_msg.c | 10 ++ ssl/ssl_ciph.c | 32 ++++ ssl/ssl_err.c | 3 + ssl/ssl_lib.c | 41 ++++- ssl/ssl_local.h | 37 ++++ ssl/ssl_quic.c | 248 +++++++++++++++++++++++++++ ssl/statem/extensions.c | 29 ++++ ssl/statem/extensions_clnt.c | 48 ++++++ ssl/statem/extensions_srvr.c | 51 ++++++ ssl/statem/statem.c | 20 ++- ssl/statem/statem_lib.c | 19 +- ssl/statem/statem_local.h | 19 ++ ssl/statem/statem_quic.c | 106 ++++++++++++ ssl/tls13_enc.c | 59 +++++++ test/helpers/ssltestlib.c | 5 + test/sslapitest.c | 132 ++++++++++++++ test/tls13secretstest.c | 7 + util/libssl.num | 11 ++ util/other.syms | 2 + 31 files changed, 1189 insertions(+), 6 deletions(-) create mode 100644 doc/man3/SSL_CTX_set_quic_method.pod create mode 100644 ssl/ssl_quic.c create mode 100644 ssl/statem/statem_quic.c diff --git a/CHANGES.md b/CHANGES.md index f464b2320e9c5..40641853dc47c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -27,6 +27,10 @@ The migration guide contains more detailed information related to new features, breaking changes, and mappings for the large list of deprecated functions. [Migration guide]: https://github.com/openssl/openssl/tree/master/doc/man7/migration_guide.pod +### Changes between 3.0.10 and 3.0.10+quic [1 Aug 2023] + * Add QUIC API support from BoringSSL + + *Todd Short* ### Changes between 3.0.11 and 3.0.12 [24 Oct 2023] diff --git a/Configure b/Configure index dd06aa48988f4..69851e1e97fbe 100755 --- a/Configure +++ b/Configure @@ -467,6 +467,7 @@ my @disablables = ( "poly1305", "posix-io", "psk", + "quic", "rc2", "rc4", "rc5", @@ -635,6 +636,7 @@ my @disable_cascades = ( "legacy" => [ "md2" ], "cmp" => [ "crmf" ], + "tls1_3" => [ "quic" ], "fips" => [ "fips-securitychecks", "acvp-tests" ], diff --git a/INSTALL.md b/INSTALL.md index fef408e9d1e32..87b1faef90f71 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -822,6 +822,10 @@ Don't use POSIX IO capabilities. Don't build support for Pre-Shared Key based ciphersuites. +### no-quic + +Don't build support for QUIC API from BoringSSL. + ### no-rdrand Don't use hardware RDRAND capabilities. diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index e51504b7abd5c..e537738c4c6ac 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1249,6 +1249,7 @@ SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE:158:\ SSL_R_BAD_CHANGE_CIPHER_SPEC:103:bad change cipher spec SSL_R_BAD_CIPHER:186:bad cipher SSL_R_BAD_DATA:390:bad data +SSL_R_BAD_DATA_LENGTH:802:bad data length SSL_R_BAD_DATA_RETURNED_BY_CALLBACK:106:bad data returned by callback SSL_R_BAD_DECOMPRESSION:107:bad decompression SSL_R_BAD_DH_VALUE:102:bad dh value @@ -1536,6 +1537,7 @@ SSL_R_VERSION_TOO_LOW:396:version too low SSL_R_WRONG_CERTIFICATE_TYPE:383:wrong certificate type SSL_R_WRONG_CIPHER_RETURNED:261:wrong cipher returned SSL_R_WRONG_CURVE:378:wrong curve +SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED:800:wrong encryption level received SSL_R_WRONG_SIGNATURE_LENGTH:264:wrong signature length SSL_R_WRONG_SIGNATURE_SIZE:265:wrong signature size SSL_R_WRONG_SIGNATURE_TYPE:370:wrong signature type diff --git a/doc/man3/SSL_CIPHER_get_name.pod b/doc/man3/SSL_CIPHER_get_name.pod index e22a85a063706..7f00f09d67f8f 100644 --- a/doc/man3/SSL_CIPHER_get_name.pod +++ b/doc/man3/SSL_CIPHER_get_name.pod @@ -13,6 +13,7 @@ SSL_CIPHER_get_digest_nid, SSL_CIPHER_get_handshake_digest, SSL_CIPHER_get_kx_nid, SSL_CIPHER_get_auth_nid, +SSL_CIPHER_get_prf_nid, SSL_CIPHER_is_aead, SSL_CIPHER_find, SSL_CIPHER_get_id, @@ -34,6 +35,7 @@ SSL_CIPHER_get_protocol_id const EVP_MD *SSL_CIPHER_get_handshake_digest(const SSL_CIPHER *c); int SSL_CIPHER_get_kx_nid(const SSL_CIPHER *c); int SSL_CIPHER_get_auth_nid(const SSL_CIPHER *c); + int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c); int SSL_CIPHER_is_aead(const SSL_CIPHER *c); const SSL_CIPHER *SSL_CIPHER_find(SSL *ssl, const unsigned char *ptr); uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *c); @@ -91,6 +93,15 @@ TLS 1.3 cipher suites) B is returned. Examples (not comprehensive) NID_auth_ecdsa NID_auth_psk +SSL_CIPHER_get_prf_nid() retuns the pseudo-random function NID for B. If B is +a pre-TLS-1.2 cipher, it returns B but note these ciphers use +SHA-256 in TLS 1.2. Other return values may be treated uniformly in all +applicable versions. Examples (not comprehensive): + + NID_md5_sha1 + NID_sha256 + NID_sha384 + SSL_CIPHER_is_aead() returns 1 if the cipher B is AEAD (e.g. GCM or ChaCha20/Poly1305), and 0 if it is not AEAD. @@ -201,6 +212,8 @@ required to enable this function. The OPENSSL_cipher_name() function was added in OpenSSL 1.1.1. +The SSL_CIPHER_get_prf_nid() function was added in OpenSSL 3.0.0. + =head1 COPYRIGHT Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved. diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod new file mode 100644 index 0000000000000..d938eb4e309ca --- /dev/null +++ b/doc/man3/SSL_CTX_set_quic_method.pod @@ -0,0 +1,232 @@ +=pod + +=head1 NAME + +SSL_QUIC_METHOD, +OSSL_ENCRYPTION_LEVEL, +SSL_CTX_set_quic_method, +SSL_set_quic_method, +SSL_set_quic_transport_params, +SSL_get_peer_quic_transport_params, +SSL_quic_max_handshake_flight_len, +SSL_quic_read_level, +SSL_quic_write_level, +SSL_provide_quic_data, +SSL_process_quic_post_handshake, +SSL_is_quic +- QUIC support + +=head1 SYNOPSIS + + #include + + typedef struct ssl_quic_method_st SSL_QUIC_METHOD; + typedef enum ssl_encryption_level_t OSSL_ENCRYPTION_LEVEL; + + int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method); + int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method); + int SSL_set_quic_transport_params(SSL *ssl, + const uint8_t *params, + size_t params_len); + void SSL_get_peer_quic_transport_params(const SSL *ssl, + const uint8_t **out_params, + size_t *out_params_len); + size_t SSL_quic_max_handshake_flight_len(const SSL *ssl, OSSL_ENCRYPTION_LEVEL level); + OSSL_ENCRYPTION_LEVEL SSL_quic_read_level(const SSL *ssl); + OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl); + int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *data, size_t len); + int SSL_process_quic_post_handshake(SSL *ssl); + int SSL_is_quic(SSL *ssl); + +=head1 DESCRIPTION + +SSL_CTX_set_quic_method() and SSL_set_quic_method() configures the QUIC methods. +This should only be configured with a minimum version of TLS 1.3. B +must remain valid for the lifetime of B or B. Calling this disables +the SSL_OP_ENABLE_MIDDLEBOX_COMPAT option, which is not required for QUIC. + +SSL_set_quic_transport_params() configures B to send B (of length +B) in the quic_transport_parameters extension in either the +ClientHello or EncryptedExtensions handshake message. This extension will +only be sent if the TLS version is at least 1.3, and for a server, only if +the client sent the extension. The buffer pointed to by B only need be +valid for the duration of the call to this function. + +SSL_get_peer_quic_transport_params() provides the caller with the value of the +quic_transport_parameters extension sent by the peer. A pointer to the buffer +containing the TransportParameters will be put in B<*out_params>, and its +length in B<*out_params_len>. This buffer will be valid for the lifetime of the +B. If no params were received from the peer, B<*out_params_len> will be 0. + +SSL_quic_max_handshake_flight_len() returns returns the maximum number of bytes +that may be received at the given encryption level. This function should be +used to limit buffering in the QUIC implementation. + +See https://tools.ietf.org/html/draft-ietf-quic-transport-16#section-4.4. + +SSL_quic_read_level() returns the current read encryption level. + +SSL_quic_write_level() returns the current write encryption level. + +SSL_provide_quic_data() provides data from QUIC at a particular encryption +level B. It is an error to call this function outside of the handshake +or with an encryption level other than the current read level. It returns one +on success and zero on error. + +SSL_process_quic_post_handshake() processes any data that QUIC has provided +after the handshake has completed. This includes NewSessionTicket messages +sent by the server. + +SSL_is_quic() indicates whether a connection uses QUIC. + +=head1 NOTES + +These APIs are implementations of BoringSSL's QUIC APIs. + +QUIC acts as an underlying transport for the TLS 1.3 handshake. The following +functions allow a QUIC implementation to serve as the underlying transport as +described in draft-ietf-quic-tls. + +When configured for QUIC, SSL_do_handshake() will drive the handshake as +before, but it will not use the configured B. It will call functions on +B to configure secrets and send data. If data is needed from +the peer, it will return B. When received, the caller +should call SSL_provide_quic_data() and then SSL_do_handshake() to continue +the handshake. After the handshake is complete, the caller should call +SSL_provide_quic_data() for any post-handshake data, followed by +SSL_process_quic_post_handshake() to process it. It is an error to call +SSL_read()/SSL_read_ex() and SSL_write()/SSL_write_ex() in QUIC. + +Note that secrets for an encryption level may be available to QUIC before the +level is active in TLS. Callers should use SSL_quic_read_level() to determine +the active read level for SSL_provide_quic_data(). SSL_do_handshake() will +pass the active write level to add_handshake_data() when writing data. Callers +can use SSL_quic_write_level() to query the active write level when +generating their own errors. + +See https://tools.ietf.org/html/draft-ietf-quic-tls-15#section-4.1 for more +details. + +To avoid DoS attacks, the QUIC implementation must limit the amount of data +being queued up. The implementation can call +SSL_quic_max_handshake_flight_len() to get the maximum buffer length at each +encryption level. + +draft-ietf-quic-tls defines a new TLS extension quic_transport_parameters +used by QUIC for each endpoint to unilaterally declare its supported +transport parameters. draft-ietf-quic-transport (section 7.4) defines the +contents of that extension (a TransportParameters struct) and describes how +to handle it and its semantic meaning. + +OpenSSL handles this extension as an opaque byte string. The caller is +responsible for serializing and parsing it. + +=head2 OSSL_ENCRYPTION_LEVEL + +B (B) represents the +encryption levels: + +=over 4 + +=item ssl_encryption_initial + +The initial encryption level that is used for client and server hellos. + +=item ssl_encryption_early_data + +The encryption level for early data. This is a write-level for the client +and a read-level for the server. + +=item ssl_encryption_handshake + +The encryption level for the remainder of the handshake. + +=item ssl_encryption_application + +The encryption level for the application data. + +=back + +=head2 SSL_QUIC_METHOD + +The B (B) describes the +QUIC methods. + + struct ssl_quic_method_st { + int (*set_encryption_secrets)(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *read_secret, + const uint8_t *write_secret, size_t secret_len); + int (*add_handshake_data)(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *data, size_t len); + int (*flush_flight)(SSL *ssl); + int (*send_alert)(SSL *ssl, enum ssl_encryption_level_t level, uint8_t alert); + }; + typedef struct ssl_quic_method_st SSL_QUIC_METHOD; + +set_encryption_secrets() configures the read and write secrets for the given +encryption level. This function will always be called before an encryption +level other than B is used. Note, however, that +secrets for a level may be configured before TLS is ready to send or accept +data at that level. + +When reading packets at a given level, the QUIC implementation must send +ACKs at the same level, so this function provides read and write secrets +together. The exception is B, where secrets are +only available in the client to server direction. The other secret will be +NULL. The server acknowledges such data at B, +which will be configured in the same SSL_do_handshake() call. + +This function should use SSL_get_current_cipher() to determine the TLS +cipher suite. + +add_handshake_data() adds handshake data to the current flight at the given +encryption level. It returns one on success and zero on error. + +OpenSSL will pack data from a single encryption level together, but a +single handshake flight may include multiple encryption levels. Callers +should defer writing data to the network until flush_flight() to better +pack QUIC packets into transport datagrams. + +flush_flight() is called when the current flight is complete and should be +written to the transport. Note a flight may contain data at several +encryption levels. + +send_alert() sends a fatal alert at the specified encryption level. + +All QUIC methods return 1 on success and 0 on error. + +=head1 RETURN VALUES + +SSL_CTX_set_quic_method(), +SSL_set_quic_method(), +SSL_set_quic_transport_params(), and +SSL_process_quic_post_handshake() +return 1 on success, and 0 on error. + +SSL_quic_read_level() and SSL_quic_write_level() return the current +encryption level as B (B). + +SSL_quic_max_handshake_flight_len() returns the maximum length of a flight +for a given encryption level. + +SSL_is_quic() returns 1 if QUIC is being used, 0 if not. + +=head1 SEE ALSO + +L, L, L + +=head1 HISTORY + +These functions were added in OpenSSL 3.0.0. + +=head1 COPYRIGHT + +Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the Apache License 2.0 (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L. + +=cut diff --git a/include/openssl/evp.h b/include/openssl/evp.h index e64072f965626..d7c3f7b7630aa 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1741,6 +1741,11 @@ int EVP_PKEY_CTX_set_mac_key(EVP_PKEY_CTX *ctx, const unsigned char *key, * Method handles all operations: don't assume any digest related defaults. */ # define EVP_PKEY_FLAG_SIGCTX_CUSTOM 4 + +/* Used by Chromium/QUIC */ +# define X25519_PRIVATE_KEY_LEN 32 +# define X25519_PUBLIC_VALUE_LEN 32 + # ifndef OPENSSL_NO_DEPRECATED_3_0 OSSL_DEPRECATEDIN_3_0 const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type); OSSL_DEPRECATEDIN_3_0 EVP_PKEY_METHOD *EVP_PKEY_meth_new(int id, int flags); diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in index 105b4a4a3c8bd..e8f49714c5353 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2521,6 +2521,51 @@ void SSL_set_allow_early_data_cb(SSL *s, const char *OSSL_default_cipher_list(void); const char *OSSL_default_ciphersuites(void); +# ifndef OPENSSL_NO_QUIC +/* + * QUIC integration - The QUIC interface matches BoringSSL + * + * ssl_encryption_level_t represents a specific QUIC encryption level used to + * transmit handshake messages. BoringSSL has this as an 'enum'. + */ +typedef enum ssl_encryption_level_t { + ssl_encryption_initial = 0, + ssl_encryption_early_data, + ssl_encryption_handshake, + ssl_encryption_application +} OSSL_ENCRYPTION_LEVEL; + +struct ssl_quic_method_st { + int (*set_encryption_secrets)(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *read_secret, + const uint8_t *write_secret, size_t secret_len); + int (*add_handshake_data)(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *data, size_t len); + int (*flush_flight)(SSL *ssl); + int (*send_alert)(SSL *ssl, enum ssl_encryption_level_t level, uint8_t alert); +}; + +__owur int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method); +__owur int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method); +__owur int SSL_set_quic_transport_params(SSL *ssl, + const uint8_t *params, + size_t params_len); +void SSL_get_peer_quic_transport_params(const SSL *ssl, + const uint8_t **out_params, + size_t *out_params_len); +__owur size_t SSL_quic_max_handshake_flight_len(const SSL *ssl, OSSL_ENCRYPTION_LEVEL level); +__owur OSSL_ENCRYPTION_LEVEL SSL_quic_read_level(const SSL *ssl); +__owur OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl); +__owur int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *data, size_t len); +__owur int SSL_process_quic_post_handshake(SSL *ssl); + +__owur int SSL_is_quic(SSL *ssl); + +# endif + +int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c); + # ifdef __cplusplus } # endif diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h index b156fc2ffd7b8..a60076ee93ea0 100644 --- a/include/openssl/sslerr.h +++ b/include/openssl/sslerr.h @@ -28,6 +28,7 @@ # define SSL_R_BAD_CHANGE_CIPHER_SPEC 103 # define SSL_R_BAD_CIPHER 186 # define SSL_R_BAD_DATA 390 +# define SSL_R_BAD_DATA_LENGTH 802 # define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK 106 # define SSL_R_BAD_DECOMPRESSION 107 # define SSL_R_BAD_DH_VALUE 102 @@ -333,6 +334,7 @@ # define SSL_R_WRONG_CERTIFICATE_TYPE 383 # define SSL_R_WRONG_CIPHER_RETURNED 261 # define SSL_R_WRONG_CURVE 378 +# define SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED 800 # define SSL_R_WRONG_SIGNATURE_LENGTH 264 # define SSL_R_WRONG_SIGNATURE_SIZE 265 # define SSL_R_WRONG_SIGNATURE_TYPE 370 diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h index d6e9331fa1e94..9edb5453ca38f 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -151,6 +151,9 @@ extern "C" { /* Temporary extension type */ # define TLSEXT_TYPE_renegotiate 0xff01 +/* ExtensionType value from draft-ietf-quic-tls-13 */ +# define TLSEXT_TYPE_quic_transport_parameters 0xffa5 + # ifndef OPENSSL_NO_NEXTPROTONEG /* This is not an IANA defined extension number */ # define TLSEXT_TYPE_next_proto_neg 13172 diff --git a/include/openssl/types.h b/include/openssl/types.h index de9f1665249f5..bae9d2f0146bd 100644 --- a/include/openssl/types.h +++ b/include/openssl/types.h @@ -229,6 +229,8 @@ typedef struct ossl_decoder_ctx_st OSSL_DECODER_CTX; typedef struct ossl_self_test_st OSSL_SELF_TEST; +typedef struct ssl_quic_method_st SSL_QUIC_METHOD; + #ifdef __cplusplus } #endif diff --git a/ssl/build.info b/ssl/build.info index 0851357f81eba..ac87437906127 100644 --- a/ssl/build.info +++ b/ssl/build.info @@ -38,6 +38,8 @@ IF[{- !$disabled{'deprecated-3.0'} -}] SOURCE[../libssl]=ssl_rsa_legacy.c ENDIF +SOURCE[../libssl]=ssl_quic.c statem/statem_quic.c + DEFINE[../libssl]=$AESDEF SOURCE[../providers/libcommon.a]=record/tls_pad.c diff --git a/ssl/s3_msg.c b/ssl/s3_msg.c index c0f0dbc17dcc2..667c5385e8f49 100644 --- a/ssl/s3_msg.c +++ b/ssl/s3_msg.c @@ -81,6 +81,16 @@ int ssl3_dispatch_alert(SSL *s) s->s3.alert_dispatch = 0; alertlen = 2; +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + if (!s->quic_method->send_alert(s, s->quic_write_level, + s->s3.send_alert[1])) { + SSLerr(SSL_F_SSL3_DISPATCH_ALERT, ERR_R_INTERNAL_ERROR); + return 0; + } + i = 1; + } else +#endif i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3.send_alert[0], &alertlen, 1, 0, &written); if (i <= 0) { diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c index 73a821289d43a..a73cb532944b9 100644 --- a/ssl/ssl_ciph.c +++ b/ssl/ssl_ciph.c @@ -2239,3 +2239,35 @@ const char *OSSL_default_ciphersuites(void) "TLS_CHACHA20_POLY1305_SHA256:" "TLS_AES_128_GCM_SHA256"; } + +int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c) +{ + switch (c->algorithm2 & (0xFF << TLS1_PRF_DGST_SHIFT)) { + default: + break; + case TLS1_PRF_SHA1_MD5: /* TLS1_PRF */ + return NID_md5_sha1; + case TLS1_PRF_SHA256: + return NID_sha256; + case TLS1_PRF_SHA384: + return NID_sha384; + case TLS1_PRF_GOST94: + return NID_id_GostR3411_94_prf; + case TLS1_PRF_GOST12_256: + return NID_id_GostR3411_2012_256; + case TLS1_PRF_GOST12_512: + return NID_id_GostR3411_2012_512; + } + /* TLSv1.3 ciphers don't specify separate PRF */ + switch (c->algorithm2 & SSL_HANDSHAKE_MAC_MASK) { + default: + break; + case SSL_HANDSHAKE_MAC_MD5_SHA1: /* SSL_HANDSHAKE_MAC_DEFAULT */ + return NID_md5_sha1; + case SSL_HANDSHAKE_MAC_SHA256: + return NID_sha256; + case SSL_HANDSHAKE_MAC_SHA384: + return NID_sha384; + } + return NID_undef; +} diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 41898844ff97e..0210a73ad54a9 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -27,6 +27,7 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { "bad change cipher spec"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CIPHER), "bad cipher"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA), "bad data"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_LENGTH), "bad data length"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK), "bad data returned by callback"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DECOMPRESSION), "bad decompression"}, @@ -544,6 +545,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CIPHER_RETURNED), "wrong cipher returned"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CURVE), "wrong curve"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED), + "wrong encryption level received"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_LENGTH), "wrong signature length"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_SIZE), diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 81a9f0728dbf7..6d2ab0e3283b8 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -841,6 +841,10 @@ SSL *SSL_new(SSL_CTX *ctx) s->job = NULL; +#ifndef OPENSSL_NO_QUIC + s->quic_method = ctx->quic_method; +#endif + #ifndef OPENSSL_NO_CT if (!SSL_set_ct_validation_callback(s, ctx->ct_validation_callback, ctx->ct_validation_callback_arg)) @@ -1240,6 +1244,18 @@ void SSL_free(SSL *s) OPENSSL_free(s->pha_context); EVP_MD_CTX_free(s->pha_dgst); +#ifndef OPENSSL_NO_QUIC + OPENSSL_free(s->ext.quic_transport_params); + OPENSSL_free(s->ext.peer_quic_transport_params); + while (s->quic_input_data_head != NULL) { + QUIC_DATA *qd; + + qd = s->quic_input_data_head; + s->quic_input_data_head = qd->next; + OPENSSL_free(qd); + } +#endif + sk_X509_NAME_pop_free(s->ca_names, X509_NAME_free); sk_X509_NAME_pop_free(s->client_ca_names, X509_NAME_free); @@ -1833,6 +1849,12 @@ static int ssl_io_intern(void *vargs) int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes) { +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + SSLerr(SSL_F_SSL_READ_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return -1; + } +#endif if (s->handshake_func == NULL) { ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED); return -1; @@ -1964,6 +1986,12 @@ int SSL_get_early_data_status(const SSL *s) static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes) { +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + SSLerr(SSL_F_SSL_PEEK_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return -1; + } +#endif if (s->handshake_func == NULL) { ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED); return -1; @@ -2024,6 +2052,12 @@ int SSL_peek_ex(SSL *s, void *buf, size_t num, size_t *readbytes) int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written) { +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + SSLerr(SSL_F_SSL_WRITE_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return -1; + } +#endif if (s->handshake_func == NULL) { ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED); return -1; @@ -3838,6 +3872,11 @@ int SSL_get_error(const SSL *s, int i) } if (SSL_want_read(s)) { +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + return SSL_ERROR_WANT_READ; + } +#endif bio = SSL_get_rbio(s); if (BIO_should_read(bio)) return SSL_ERROR_WANT_READ; @@ -4205,7 +4244,7 @@ EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx) const SSL_CIPHER *SSL_get_current_cipher(const SSL *s) { - if ((s->session != NULL) && (s->session->cipher != NULL)) + if (s->session != NULL) return s->session->cipher; return NULL; } diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 5fb1feb801635..f6b062934ebe6 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -337,6 +337,13 @@ /* Flag used on OpenSSL ciphersuite ids to indicate they are for SSLv3+ */ # define SSL3_CK_CIPHERSUITE_FLAG 0x03000000 +/* Check if an SSL structure is using QUIC (which uses TLSv1.3) */ +# ifndef OPENSSL_NO_QUIC +# define SSL_IS_QUIC(s) (s->quic_method != NULL) +# else +# define SSL_IS_QUIC(s) 0 +# endif + /* Check if an SSL structure is using DTLS */ # define SSL_IS_DTLS(s) (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS) @@ -766,6 +773,7 @@ typedef enum tlsext_index_en { TLSEXT_IDX_cryptopro_bug, TLSEXT_IDX_early_data, TLSEXT_IDX_certificate_authorities, + TLSEXT_IDX_quic_transport_params, TLSEXT_IDX_padding, TLSEXT_IDX_psk, /* Dummy index - must always be the last entry */ @@ -1205,10 +1213,24 @@ struct ssl_ctx_st { uint32_t disabled_mac_mask; uint32_t disabled_mkey_mask; uint32_t disabled_auth_mask; + +#ifndef OPENSSL_NO_QUIC + const SSL_QUIC_METHOD *quic_method; +#endif }; typedef struct cert_pkey_st CERT_PKEY; +#ifndef OPENSSL_NO_QUIC +struct quic_data_st { + struct quic_data_st *next; + OSSL_ENCRYPTION_LEVEL level; + size_t length; +}; +typedef struct quic_data_st QUIC_DATA; +int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level); +#endif + struct ssl_st { /* * protocol version (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION, @@ -1680,8 +1702,23 @@ struct ssl_st { * selected. */ int tick_identity; + +#ifndef OPENSSL_NO_QUIC + uint8_t *quic_transport_params; + size_t quic_transport_params_len; + uint8_t *peer_quic_transport_params; + size_t peer_quic_transport_params_len; +#endif } ext; +#ifndef OPENSSL_NO_QUIC + OSSL_ENCRYPTION_LEVEL quic_read_level; + OSSL_ENCRYPTION_LEVEL quic_write_level; + QUIC_DATA *quic_input_data_head; + QUIC_DATA *quic_input_data_tail; + const SSL_QUIC_METHOD *quic_method; + size_t quic_len; +#endif /* * Parsed form of the ClientHello, kept around across client_hello_cb * calls. diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c new file mode 100644 index 0000000000000..a39e4419c91a9 --- /dev/null +++ b/ssl/ssl_quic.c @@ -0,0 +1,248 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "ssl_local.h" +#include "internal/cryptlib.h" +#include "internal/refcount.h" + +#ifdef OPENSSL_NO_QUIC +NON_EMPTY_TRANSLATION_UNIT +#else + +int SSL_set_quic_transport_params(SSL *ssl, const uint8_t *params, + size_t params_len) +{ + uint8_t *tmp; + + if (params == NULL || params_len == 0) { + tmp = NULL; + params_len = 0; + } else { + tmp = OPENSSL_memdup(params, params_len); + if (tmp == NULL) + return 0; + } + + OPENSSL_free(ssl->ext.quic_transport_params); + ssl->ext.quic_transport_params = tmp; + ssl->ext.quic_transport_params_len = params_len; + return 1; +} + +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; +} + +size_t SSL_quic_max_handshake_flight_len(const SSL *ssl, OSSL_ENCRYPTION_LEVEL level) +{ + /* + * Limits flights to 16K by default when there are no large + * (certificate-carrying) messages. + */ + static const size_t DEFAULT_FLIGHT_LIMIT = 16384; + + switch (level) { + case ssl_encryption_initial: + return DEFAULT_FLIGHT_LIMIT; + case ssl_encryption_early_data: + /* QUIC does not send EndOfEarlyData. */ + return 0; + case ssl_encryption_handshake: + if (ssl->server) { + /* + * Servers may receive Certificate message if configured to request + * client certificates. + */ + if ((ssl->verify_mode & SSL_VERIFY_PEER) + && ssl->max_cert_list > DEFAULT_FLIGHT_LIMIT) + return ssl->max_cert_list; + } else { + /* + * Clients may receive both Certificate message and a CertificateRequest + * message. + */ + if (2*ssl->max_cert_list > DEFAULT_FLIGHT_LIMIT) + return 2 * ssl->max_cert_list; + } + return DEFAULT_FLIGHT_LIMIT; + case ssl_encryption_application: + return DEFAULT_FLIGHT_LIMIT; + } + + return 0; +} + +OSSL_ENCRYPTION_LEVEL SSL_quic_read_level(const SSL *ssl) +{ + return ssl->quic_read_level; +} + +OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl) +{ + return ssl->quic_write_level; +} + +int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *data, size_t len) +{ + size_t l; + + if (!SSL_IS_QUIC(ssl)) { + SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + /* Level can be different than the current read, but not less */ + if (level < ssl->quic_read_level + || (ssl->quic_input_data_tail != NULL && level < ssl->quic_input_data_tail->level)) { + SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); + return 0; + } + + /* Split the QUIC messages up, if necessary */ + while (len > 0) { + QUIC_DATA *qd; + const uint8_t *p = data + 1; + + n2l3(p, l); + l += SSL3_HM_HEADER_LENGTH; + + if (l > len) { + SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_BAD_DATA_LENGTH); + return 0; + } + + qd = OPENSSL_malloc(sizeof(QUIC_DATA) + l); + if (qd == NULL) { + SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); + return 0; + } + + qd->next = NULL; + qd->length = l; + qd->level = level; + memcpy((void*)(qd + 1), data, l); + if (ssl->quic_input_data_tail != NULL) + ssl->quic_input_data_tail->next = qd; + else + ssl->quic_input_data_head = qd; + ssl->quic_input_data_tail = qd; + + data += l; + len -= l; + } + + return 1; +} + +int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method) +{ + switch (ctx->method->version) { + case DTLS1_VERSION: + case DTLS1_2_VERSION: + case DTLS_ANY_VERSION: + case DTLS1_BAD_VER: + return 0; + default: + break; + } + ctx->quic_method = quic_method; + ctx->options &= SSL_OP_ENABLE_MIDDLEBOX_COMPAT; + return 1; +} + +int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method) +{ + switch (ssl->method->version) { + case DTLS1_VERSION: + case DTLS1_2_VERSION: + case DTLS_ANY_VERSION: + case DTLS1_BAD_VER: + return 0; + default: + break; + } + ssl->quic_method = quic_method; + ssl->options &= SSL_OP_ENABLE_MIDDLEBOX_COMPAT; + return 1; +} + +int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) +{ + uint8_t *read_secret = NULL; + uint8_t *write_secret = NULL; + static const unsigned char zeros[EVP_MAX_MD_SIZE]; + + if (!SSL_IS_QUIC(ssl)) + return 1; + + /* secrets from the POV of the client */ + switch (level) { + case ssl_encryption_early_data: + write_secret = ssl->early_secret; + break; + case ssl_encryption_handshake: + read_secret = ssl->client_finished_secret; + write_secret = ssl->server_finished_secret; + break; + case ssl_encryption_application: + read_secret = ssl->client_app_traffic_secret; + write_secret = ssl->server_app_traffic_secret; + break; + default: + return 1; + } + /* In some cases, we want to set the secret only when BOTH are non-zero */ + if (read_secret != NULL && write_secret != NULL + && !memcmp(read_secret, zeros, ssl->quic_len) + && !memcmp(write_secret, zeros, ssl->quic_len)) + return 1; + + if (ssl->server) { + if (!ssl->quic_method->set_encryption_secrets(ssl, level, read_secret, + write_secret, ssl->quic_len)) { + SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + } else { + if (!ssl->quic_method->set_encryption_secrets(ssl, level, write_secret, + read_secret, ssl->quic_len)) { + SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + } + + return 1; +} + +int SSL_process_quic_post_handshake(SSL *ssl) +{ + if (SSL_in_init(ssl) || !SSL_IS_QUIC(ssl)) { + SSLerr(SSL_F_SSL_PROCESS_QUIC_POST_HANDSHAKE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + ossl_statem_set_in_init(ssl, 1); + + if (ssl->handshake_func(ssl) <= 0) + return 0; + + return 1; +} + +int SSL_is_quic(SSL* ssl) +{ + return SSL_IS_QUIC(ssl); +} + +#endif diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index 1518ca7f4e72b..ee8263b76fe6e 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -59,6 +59,10 @@ static int final_early_data(SSL *s, unsigned int context, int sent); static int final_maxfragmentlen(SSL *s, unsigned int context, int sent); 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(SSL *s, unsigned int context, int sent); +#endif /* Structure to define a built-in extension */ typedef struct extensions_definition_st { @@ -370,6 +374,19 @@ static const EXTENSION_DEFINITION ext_defs[] = { tls_construct_certificate_authorities, tls_construct_certificate_authorities, NULL, }, +#ifndef OPENSSL_NO_QUIC + { + TLSEXT_TYPE_quic_transport_parameters, + SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_SERVER_HELLO + | SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY, + init_quic_transport_params, + tls_parse_ctos_quic_transport_params, tls_parse_stoc_quic_transport_params, + tls_construct_stoc_quic_transport_params, tls_construct_ctos_quic_transport_params, + final_quic_transport_params, + }, +#else + INVALID_EXTENSION, +#endif { /* Must be immediately before pre_shared_key */ TLSEXT_TYPE_padding, @@ -1728,3 +1745,15 @@ static int final_psk(SSL *s, unsigned int context, int sent) return 1; } + +#ifndef OPENSSL_NO_QUIC +static int init_quic_transport_params(SSL *s, unsigned int context) +{ + return 1; +} + +static int final_quic_transport_params(SSL *s, unsigned int context, int sent) +{ + return 1; +} +#endif diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index 842be0722bd03..52742dc36a8c1 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1196,7 +1196,29 @@ EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt, #endif } +#ifndef OPENSSL_NO_QUIC +/* SAME AS tls_construct_stoc_quic_transport_params() */ +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) { + return EXT_RETURN_NOT_SENT; + } + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters) + || !WPACKET_start_sub_packet_u16(pkt) + || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params, + s->ext.quic_transport_params_len) + || !WPACKET_close(pkt)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + + return EXT_RETURN_SENT; +} +#endif /* * Parse the server's renegotiation binding and abort if it's not right */ @@ -1981,3 +2003,29 @@ 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(SSL *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx) +{ + PACKET trans_param; + + if (!PACKET_as_length_prefixed_2(pkt, &trans_param) + || PACKET_remaining(&trans_param) == 0) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); + return 0; + } + + OPENSSL_free(s->ext.peer_quic_transport_params); + s->ext.peer_quic_transport_params = NULL; + s->ext.peer_quic_transport_params_len = 0; + + if (!PACKET_memdup(&trans_param, + &s->ext.peer_quic_transport_params, + &s->ext.peer_quic_transport_params_len)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + return 1; +} +#endif diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 1fab5a3d12954..0ca8f154f2b4c 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1232,6 +1232,33 @@ int tls_parse_ctos_post_handshake_auth(SSL *s, PACKET *pkt, return 1; } +#ifndef OPENSSL_NO_QUIC +/* SAME AS tls_parse_stoc_quic_transport_params() */ +int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx) +{ + PACKET trans_param; + + if (!PACKET_as_length_prefixed_2(pkt, &trans_param) + || PACKET_remaining(&trans_param) == 0) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); + return 0; + } + + OPENSSL_free(s->ext.peer_quic_transport_params); + s->ext.peer_quic_transport_params = NULL; + s->ext.peer_quic_transport_params_len = 0; + + if (!PACKET_memdup(&trans_param, + &s->ext.peer_quic_transport_params, + &s->ext.peer_quic_transport_params_len)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + return 1; +} +#endif + /* * Add the server's renegotiation binding */ @@ -1914,3 +1941,27 @@ EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context, return EXT_RETURN_SENT; } + +#ifndef OPENSSL_NO_QUIC +/* SAME AS tls_construct_ctos_quic_transport_params() */ +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) { + return EXT_RETURN_NOT_SENT; + } + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters) + || !WPACKET_start_sub_packet_u16(pkt) + || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params, + s->ext.quic_transport_params_len) + || !WPACKET_close(pkt)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + + return EXT_RETURN_SENT; +} +#endif diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c index 553546d93a411..f6caa64e4ce5b 100644 --- a/ssl/statem/statem.c +++ b/ssl/statem/statem.c @@ -583,6 +583,10 @@ static SUB_STATE_RETURN read_state_machine(SSL *s) * In DTLS we get the whole message in one go - header and body */ ret = dtls_get_message(s, &mt); +#ifndef OPENSSL_NO_QUIC + } else if (SSL_IS_QUIC(s)) { + ret = quic_get_message(s, &mt, &len); +#endif } else { ret = tls_get_message_header(s, &mt); } @@ -612,8 +616,8 @@ static SUB_STATE_RETURN read_state_machine(SSL *s) return SUB_STATE_ERROR; } - /* dtls_get_message already did this */ - if (!SSL_IS_DTLS(s) + /* dtls_get_message/quic_get_message already did this */ + if (!SSL_IS_DTLS(s) && !SSL_IS_QUIC(s) && s->s3.tmp.message_size > 0 && !grow_init_buf(s, s->s3.tmp.message_size + SSL3_HM_HEADER_LENGTH)) { @@ -631,7 +635,8 @@ static SUB_STATE_RETURN read_state_machine(SSL *s) * opportunity to do any further processing. */ ret = dtls_get_message_body(s, &len); - } else { + } else if (!SSL_IS_QUIC(s)) { + /* We already got this above for QUIC */ ret = tls_get_message_body(s, &len); } if (ret == 0) { @@ -921,6 +926,15 @@ static SUB_STATE_RETURN write_state_machine(SSL *s) int statem_flush(SSL *s) { s->rwstate = SSL_WRITING; +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + if (!s->quic_method->flush_flight(s)) { + /* NOTE: BIO_flush() does not generate an error */ + SSLerr(SSL_F_STATEM_FLUSH, ERR_R_INTERNAL_ERROR); + return 0; + } + } else +#endif if (BIO_flush(s->wbio) <= 0) { return 0; } diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index b1ee38b9e5bc4..1afe26be88b9b 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -44,9 +44,23 @@ int ssl3_do_write(SSL *s, int type) { int ret; size_t written = 0; +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s) && type == SSL3_RT_HANDSHAKE) { + ret = s->quic_method->add_handshake_data(s, s->quic_write_level, + (const uint8_t*)&s->init_buf->data[s->init_off], + s->init_num); + if (!ret) { + ret = -1; + /* QUIC can't sent anything out sice the above failed */ + SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_INTERNAL_ERROR); + } else { + written = s->init_num; + } + } else +#endif + ret = ssl3_write_bytes(s, type, &s->init_buf->data[s->init_off], + s->init_num, &written); - ret = ssl3_write_bytes(s, type, &s->init_buf->data[s->init_off], - s->init_num, &written); if (ret <= 0) return -1; if (type == SSL3_RT_HANDSHAKE) @@ -1169,6 +1183,7 @@ int tls_get_message_header(SSL *s, int *mt) do { while (s->init_num < SSL3_HM_HEADER_LENGTH) { + /* QUIC: either create a special ssl_read_bytes... or if/else this */ i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type, &p[s->init_num], SSL3_HM_HEADER_LENGTH - s->init_num, diff --git a/ssl/statem/statem_local.h b/ssl/statem/statem_local.h index ad4d93b1e2798..57e314512bdbd 100644 --- a/ssl/statem/statem_local.h +++ b/ssl/statem/statem_local.h @@ -104,6 +104,7 @@ __owur int tls_get_message_header(SSL *s, int *mt); __owur int tls_get_message_body(SSL *s, size_t *len); __owur int dtls_get_message(SSL *s, int *mt); __owur int dtls_get_message_body(SSL *s, size_t *len); +__owur int quic_get_message(SSL *s, int *mt, size_t *len); /* Message construction and processing functions */ __owur int tls_process_initial_server_flight(SSL *s); @@ -251,6 +252,10 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); 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(SSL *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx); +#endif EXT_RETURN tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, @@ -311,6 +316,11 @@ EXT_RETURN tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, size_t chainidx); 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(SSL *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx); +#endif /* Client Extension processing */ EXT_RETURN tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt, unsigned int context, @@ -380,6 +390,11 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx); 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(SSL *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx); +#endif int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); @@ -423,6 +438,10 @@ int tls_parse_stoc_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); 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(SSL *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx); +#endif int tls_handle_alpn(SSL *s); diff --git a/ssl/statem/statem_quic.c b/ssl/statem/statem_quic.c new file mode 100644 index 0000000000000..66acc30d6d96b --- /dev/null +++ b/ssl/statem/statem_quic.c @@ -0,0 +1,106 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "../ssl_local.h" +#include "statem_local.h" +#include "internal/cryptlib.h" + +#ifdef OPENSSL_NO_QUIC +NON_EMPTY_TRANSLATION_UNIT +#else + +int quic_get_message(SSL *s, int *mt, size_t *len) +{ + size_t l; + QUIC_DATA *qd; + uint8_t *p; + + if (s->quic_input_data_head == NULL) { + s->rwstate = SSL_READING; + *len = 0; + return 0; + } + + /* This is where we check for the proper level, not when data is given */ + if (s->quic_input_data_head->level != s->quic_read_level) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); + *len = 0; + return 0; + } + + if (!BUF_MEM_grow_clean(s->init_buf, (int)s->quic_input_data_head->length)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_BUF_LIB); + *len = 0; + return 0; + } + + /* Copy buffered data */ + qd = s->quic_input_data_head; + memcpy(s->init_buf->data, (void*)(qd + 1), qd->length); + s->init_buf->length = qd->length; + s->quic_input_data_head = qd->next; + if (s->quic_input_data_head == NULL) + s->quic_input_data_tail = NULL; + OPENSSL_free(qd); + + s->s3.tmp.message_type = *mt = *(s->init_buf->data); + p = (uint8_t*)s->init_buf->data + 1; + n2l3(p, l); + s->init_num = s->s3.tmp.message_size = *len = l; + s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH; + + /* No CCS in QUIC/TLSv1.3? */ + if (*mt == SSL3_MT_CHANGE_CIPHER_SPEC) { + SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_CCS_RECEIVED_EARLY); + *len = 0; + return 0; + } + + /* + * If receiving Finished, record MAC of prior handshake messages for + * Finished verification. + */ + if (*mt == SSL3_MT_FINISHED && !ssl3_take_mac(s)) { + /* SSLfatal() already called */ + *len = 0; + return 0; + } + + /* + * We defer feeding in the HRR until later. We'll do it as part of + * processing the message + * The TLsv1.3 handshake transcript stops at the ClientFinished + * message. + */ +#define SERVER_HELLO_RANDOM_OFFSET (SSL3_HM_HEADER_LENGTH + 2) + /* KeyUpdate and NewSessionTicket do not need to be added */ + if (!SSL_IS_TLS13(s) || (s->s3.tmp.message_type != SSL3_MT_NEWSESSION_TICKET + && s->s3.tmp.message_type != SSL3_MT_KEY_UPDATE)) { + if (s->s3.tmp.message_type != SSL3_MT_SERVER_HELLO + || s->init_num < SERVER_HELLO_RANDOM_OFFSET + SSL3_RANDOM_SIZE + || memcmp(hrrrandom, + s->init_buf->data + SERVER_HELLO_RANDOM_OFFSET, + SSL3_RANDOM_SIZE) != 0) { + if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data, + s->init_num + SSL3_HM_HEADER_LENGTH)) { + /* SSLfatal() already called */ + *len = 0; + return 0; + } + } + } + if (s->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data, + (size_t)s->init_num + SSL3_HM_HEADER_LENGTH, s, + s->msg_callback_arg); + + return 1; +} + +#endif diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c index ddcff5eb89119..459964d946fe1 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -440,6 +440,9 @@ int tls13_change_cipher_state(SSL *s, int which) ktls_crypto_info_t crypto_info; BIO *bio; #endif +#ifndef OPENSSL_NO_QUIC + OSSL_ENCRYPTION_LEVEL level = ssl_encryption_initial; +#endif if (which & SSL3_CC_READ) { if (s->enc_read_ctx != NULL) { @@ -485,6 +488,9 @@ int tls13_change_cipher_state(SSL *s, int which) label = client_early_traffic; labellen = sizeof(client_early_traffic) - 1; log_label = CLIENT_EARLY_LABEL; +#ifndef OPENSSL_NO_QUIC + level = ssl_encryption_early_data; +#endif handlen = BIO_get_mem_data(s->s3.handshake_buffer, &hdata); if (handlen <= 0) { @@ -544,6 +550,9 @@ int tls13_change_cipher_state(SSL *s, int which) goto err; } hashlen = hashlenui; +#ifndef OPENSSL_NO_QUIC + s->quic_len = hashlen; +#endif EVP_MD_CTX_free(mdctx); if (!tls13_hkdf_expand(s, md, insecret, @@ -561,6 +570,14 @@ int tls13_change_cipher_state(SSL *s, int which) /* SSLfatal() already called */ goto err; } +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + if (s->server) + s->quic_read_level = ssl_encryption_early_data; + else + s->quic_write_level = ssl_encryption_early_data; + } +#endif } else if (which & SSL3_CC_HANDSHAKE) { insecret = s->handshake_secret; finsecret = s->client_finished_secret; @@ -568,6 +585,15 @@ int tls13_change_cipher_state(SSL *s, int which) label = client_handshake_traffic; labellen = sizeof(client_handshake_traffic) - 1; log_label = CLIENT_HANDSHAKE_LABEL; +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + level = ssl_encryption_handshake; + if (s->server) + s->quic_read_level = ssl_encryption_handshake; + else + s->quic_write_level = ssl_encryption_handshake; + } +#endif /* * The handshake hash used for the server read/client write handshake * traffic secret is the same as the hash for the server @@ -590,6 +616,15 @@ int tls13_change_cipher_state(SSL *s, int which) * previously saved value. */ hash = s->server_finished_hash; +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + level = ssl_encryption_application; /* ??? */ + if (s->server) + s->quic_read_level = ssl_encryption_application; + else + s->quic_write_level = ssl_encryption_application; + } +#endif } } else { /* Early data never applies to client-read/server-write */ @@ -600,11 +635,29 @@ int tls13_change_cipher_state(SSL *s, int which) label = server_handshake_traffic; labellen = sizeof(server_handshake_traffic) - 1; log_label = SERVER_HANDSHAKE_LABEL; +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + level = ssl_encryption_handshake; + if (s->server) + s->quic_write_level = ssl_encryption_handshake; + else + s->quic_read_level = ssl_encryption_handshake; + } +#endif } else { insecret = s->master_secret; label = server_application_traffic; labellen = sizeof(server_application_traffic) - 1; log_label = SERVER_APPLICATION_LABEL; +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + level = ssl_encryption_application; + if (s->server) + s->quic_write_level = ssl_encryption_application; + else + s->quic_read_level = ssl_encryption_application; + } +#endif } } @@ -732,6 +785,12 @@ int tls13_change_cipher_state(SSL *s, int which) skip_ktls: # endif #endif + +#ifndef OPENSSL_NO_QUIC + if (!quic_set_encryption_secrets(s, level)) + goto err; +#endif + ret = 1; err: if ((which & SSL3_CC_EARLY) != 0) { diff --git a/test/helpers/ssltestlib.c b/test/helpers/ssltestlib.c index ef4a6177aa7dd..4812f27a4b532 100644 --- a/test/helpers/ssltestlib.c +++ b/test/helpers/ssltestlib.c @@ -1157,6 +1157,11 @@ int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want) if (!create_bare_ssl_connection(serverssl, clientssl, want, 1)) return 0; +#ifndef OPENSSL_NO_QUIC + /* QUIC does not support SSL_read_ex */ + if (SSL_is_quic(clientssl)) + return 1; +#endif /* * We attempt to read some data on the client side which we expect to fail. * This will ensure we have received the NewSessionTicket in TLSv1.3 where diff --git a/test/sslapitest.c b/test/sslapitest.c index 2191b297d09a6..80ccd20216c0c 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10415,6 +10415,135 @@ static int test_handshake_retry(int idx) return testresult; } +#ifndef OPENSSL_NO_QUIC +static int test_quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *read_secret, + const uint8_t *write_secret, size_t secret_len) +{ + test_printf_stderr("quic_set_encryption_secrets() %s, lvl=%d, len=%zd\n", + ssl->server ? "server" : "client", level, secret_len); + return 1; +} + +static int test_quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *data, size_t len) +{ + SSL *peer = (SSL*)SSL_get_app_data(ssl); + + test_printf_stderr("quic_add_handshake_data() %s, lvl=%d, *data=0x%02X, len=%zd\n", + ssl->server ? "server" : "client", level, (int)*data, len); + if (!TEST_ptr(peer)) + return 0; + + if (!TEST_true(SSL_provide_quic_data(peer, level, data, len))) { + ERR_print_errors_fp(stderr); + return 0; + } + + return 1; +} + +static int test_quic_flush_flight(SSL *ssl) +{ + test_printf_stderr("quic_flush_flight() %s\n", ssl->server ? "server" : "client"); + return 1; +} + +static int test_quic_send_alert(SSL *ssl, enum ssl_encryption_level_t level, uint8_t alert) +{ + test_printf_stderr("quic_send_alert() %s, lvl=%d, alert=%d\n", + ssl->server ? "server" : "client", level, alert); + return 1; +} + +static SSL_QUIC_METHOD quic_method = { + test_quic_set_encryption_secrets, + test_quic_add_handshake_data, + test_quic_flush_flight, + test_quic_send_alert, +}; + +static int test_quic_api(void) +{ + SSL_CTX *cctx = NULL, *sctx = NULL; + SSL *clientssl = NULL, *serverssl = NULL; + int testresult = 0; + + static const char *server_str = "SERVER"; + static const char *client_str = "CLIENT"; + 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_ex(libctx, NULL, 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; + + if (!TEST_true(create_ssl_ctx_pair(libctx, + TLS_server_method(), + TLS_client_method(), + TLS1_3_VERSION, 0, + &sctx, &cctx, cert, privkey)) + || !TEST_true(SSL_CTX_set_quic_method(sctx, &quic_method)) + || !TEST_true(SSL_CTX_set_quic_method(cctx, &quic_method)) + || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, + &clientssl, NULL, NULL)) + || !TEST_true(SSL_set_quic_transport_params(serverssl, + (unsigned char*)server_str, + sizeof(server_str))) + || !TEST_true(SSL_set_quic_transport_params(clientssl, + (unsigned char*)client_str, + sizeof(client_str))) + || !TEST_true(SSL_set_app_data(serverssl, clientssl)) + || !TEST_true(SSL_set_app_data(clientssl, serverssl)) + || !TEST_true(create_ssl_connection(serverssl, clientssl, + SSL_ERROR_NONE)) + || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION) + || !TEST_true(SSL_version(clientssl) == TLS1_3_VERSION) + || !(TEST_int_eq(SSL_quic_read_level(clientssl), ssl_encryption_application)) + || !(TEST_int_eq(SSL_quic_read_level(serverssl), ssl_encryption_application)) + || !(TEST_int_eq(SSL_quic_write_level(clientssl), ssl_encryption_application)) + || !(TEST_int_eq(SSL_quic_write_level(serverssl), ssl_encryption_application))) + goto end; + + SSL_get_peer_quic_transport_params(serverssl, &peer_str, &peer_str_len); + if (!TEST_mem_eq(peer_str, peer_str_len, client_str, sizeof(client_str))) + goto end; + SSL_get_peer_quic_transport_params(clientssl, &peer_str, &peer_str_len); + if (!TEST_mem_eq(peer_str, peer_str_len, server_str, sizeof(server_str))) + goto end; + + /* Deal with two NewSessionTickets */ + if (!TEST_true(SSL_process_quic_post_handshake(clientssl)) + || !TEST_true(SSL_process_quic_post_handshake(clientssl))) + goto end; + + testresult = 1; + + end: + return testresult; +} +#endif /* OPENSSL_NO_QUIC */ + OPT_TEST_DECLARE_USAGE("certfile privkeyfile srpvfile tmpfile provider config dhfile\n") int setup_tests(void) @@ -10687,6 +10816,9 @@ int setup_tests(void) ADD_ALL_TESTS(test_pipelining, 6); #endif ADD_ALL_TESTS(test_handshake_retry, 16); +#ifndef OPENSSL_NO_QUIC + ADD_TEST(test_quic_api); +#endif return 1; err: diff --git a/test/tls13secretstest.c b/test/tls13secretstest.c index bf214d3d5ba75..8323b23778754 100644 --- a/test/tls13secretstest.c +++ b/test/tls13secretstest.c @@ -224,6 +224,13 @@ void ssl_evp_md_free(const EVP_MD *md) { } +#ifndef OPENSSL_NO_QUIC +int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) +{ + return 1; +} +#endif + /* End of mocked out code */ static int test_secret(SSL *s, unsigned char *prk, diff --git a/util/libssl.num b/util/libssl.num index f055c967bf1c8..72ee0bedc6a2a 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -520,3 +520,14 @@ SSL_load_client_CA_file_ex 520 3_0_0 EXIST::FUNCTION: SSL_set0_tmp_dh_pkey 521 3_0_0 EXIST::FUNCTION: SSL_CTX_set0_tmp_dh_pkey 522 3_0_0 EXIST::FUNCTION: SSL_group_to_name 523 3_0_0 EXIST::FUNCTION: +SSL_quic_read_level 20000 3_0_0 EXIST::FUNCTION:QUIC +SSL_set_quic_transport_params 20001 3_0_0 EXIST::FUNCTION:QUIC +SSL_CIPHER_get_prf_nid 20002 3_0_0 EXIST::FUNCTION: +SSL_is_quic 20003 3_0_0 EXIST::FUNCTION:QUIC +SSL_get_peer_quic_transport_params 20004 3_0_0 EXIST::FUNCTION:QUIC +SSL_quic_write_level 20005 3_0_0 EXIST::FUNCTION:QUIC +SSL_CTX_set_quic_method 20006 3_0_0 EXIST::FUNCTION:QUIC +SSL_set_quic_method 20007 3_0_0 EXIST::FUNCTION:QUIC +SSL_quic_max_handshake_flight_len 20008 3_0_0 EXIST::FUNCTION:QUIC +SSL_process_quic_post_handshake 20009 3_0_0 EXIST::FUNCTION:QUIC +SSL_provide_quic_data 20010 3_0_0 EXIST::FUNCTION:QUIC diff --git a/util/other.syms b/util/other.syms index cdd62e81d07b9..baba363337e30 100644 --- a/util/other.syms +++ b/util/other.syms @@ -142,6 +142,8 @@ custom_ext_free_cb datatype custom_ext_parse_cb datatype pem_password_cb datatype ssl_ct_validation_cb datatype +OSSL_ENCRYPTION_LEVEL datatype +SSL_QUIC_METHOD datatype # ASN1_BIT_STRING_digest define BIO_append_filename define From 5f7c2baf3d5dd78ec474097a037265f40f28387b Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 14 Jun 2019 12:04:14 -0400 Subject: [PATCH 02/66] QUIC: New method to get QUIC secret length --- ssl/ssl_local.h | 1 - ssl/ssl_quic.c | 30 ++++++++++++++++++++++++++---- ssl/tls13_enc.c | 3 --- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index f6b062934ebe6..451e9bd65137a 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -1717,7 +1717,6 @@ struct ssl_st { QUIC_DATA *quic_input_data_head; QUIC_DATA *quic_input_data_tail; const SSL_QUIC_METHOD *quic_method; - size_t quic_len; #endif /* * Parsed form of the ClientHello, kept around across client_hello_cb diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index a39e4419c91a9..46cca0b4db29d 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -181,6 +181,8 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) { uint8_t *read_secret = NULL; uint8_t *write_secret = NULL; + size_t len; + const EVP_MD *md; static const unsigned char zeros[EVP_MAX_MD_SIZE]; if (!SSL_IS_QUIC(ssl)) @@ -202,21 +204,41 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) default: return 1; } + + md = ssl_handshake_md(ssl); + if (md == NULL) { + /* May not have selected cipher, yet */ + const SSL_CIPHER *c = NULL; + + if (ssl->session != NULL) + c = SSL_SESSION_get0_cipher(ssl->session); + else if (ssl->psksession != NULL) + c = SSL_SESSION_get0_cipher(ssl->psksession); + + if (c != NULL) + md = SSL_CIPHER_get_handshake_digest(c); + } + + if ((len = EVP_MD_size(md)) <= 0) { + SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + /* In some cases, we want to set the secret only when BOTH are non-zero */ if (read_secret != NULL && write_secret != NULL - && !memcmp(read_secret, zeros, ssl->quic_len) - && !memcmp(write_secret, zeros, ssl->quic_len)) + && !memcmp(read_secret, zeros, len) + && !memcmp(write_secret, zeros, len)) return 1; if (ssl->server) { if (!ssl->quic_method->set_encryption_secrets(ssl, level, read_secret, - write_secret, ssl->quic_len)) { + write_secret, len)) { SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return 0; } } else { if (!ssl->quic_method->set_encryption_secrets(ssl, level, write_secret, - read_secret, ssl->quic_len)) { + read_secret, len)) { SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return 0; } diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c index 459964d946fe1..acfb71f43e8aa 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -550,9 +550,6 @@ int tls13_change_cipher_state(SSL *s, int which) goto err; } hashlen = hashlenui; -#ifndef OPENSSL_NO_QUIC - s->quic_len = hashlen; -#endif EVP_MD_CTX_free(mdctx); if (!tls13_hkdf_expand(s, md, insecret, From 149884c5c6fe4fd235cc865b0f758dc73ef1820d Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 15 Aug 2019 11:13:15 -0400 Subject: [PATCH 03/66] QUIC: Make temp secret names less confusing --- ssl/ssl_quic.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index 46cca0b4db29d..6ba8f569525c0 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -179,8 +179,8 @@ int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method) int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) { - uint8_t *read_secret = NULL; - uint8_t *write_secret = NULL; + uint8_t *c2s_secret = NULL; + uint8_t *s2c_secret = NULL; size_t len; const EVP_MD *md; static const unsigned char zeros[EVP_MAX_MD_SIZE]; @@ -191,15 +191,15 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) /* secrets from the POV of the client */ switch (level) { case ssl_encryption_early_data: - write_secret = ssl->early_secret; + s2c_secret = ssl->early_secret; break; case ssl_encryption_handshake: - read_secret = ssl->client_finished_secret; - write_secret = ssl->server_finished_secret; + c2s_secret = ssl->client_finished_secret; + s2c_secret = ssl->server_finished_secret; break; case ssl_encryption_application: - read_secret = ssl->client_app_traffic_secret; - write_secret = ssl->server_app_traffic_secret; + c2s_secret = ssl->client_app_traffic_secret; + s2c_secret = ssl->server_app_traffic_secret; break; default: return 1; @@ -225,20 +225,20 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) } /* In some cases, we want to set the secret only when BOTH are non-zero */ - if (read_secret != NULL && write_secret != NULL - && !memcmp(read_secret, zeros, len) - && !memcmp(write_secret, zeros, len)) + if (c2s_secret != NULL && s2c_secret != NULL + && !memcmp(c2s_secret, zeros, len) + && !memcmp(s2c_secret, zeros, len)) return 1; if (ssl->server) { - if (!ssl->quic_method->set_encryption_secrets(ssl, level, read_secret, - write_secret, len)) { + if (!ssl->quic_method->set_encryption_secrets(ssl, level, c2s_secret, + s2c_secret, len)) { SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return 0; } } else { - if (!ssl->quic_method->set_encryption_secrets(ssl, level, write_secret, - read_secret, len)) { + if (!ssl->quic_method->set_encryption_secrets(ssl, level, s2c_secret, + c2s_secret, len)) { SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return 0; } From 5d3ff06e5e58d884c6ddb27357545b5d1941ea69 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 15 Aug 2019 11:35:10 -0400 Subject: [PATCH 04/66] QUIC: Move QUIC transport params to encrypted extensions --- ssl/statem/extensions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index ee8263b76fe6e..81181635c4959 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -377,7 +377,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { #ifndef OPENSSL_NO_QUIC { TLSEXT_TYPE_quic_transport_parameters, - SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_SERVER_HELLO + 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, tls_parse_stoc_quic_transport_params, From b519f22956d83d14a4dc4ce091b5d341b02c862c Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 15 Aug 2019 12:37:03 -0400 Subject: [PATCH 05/66] QUIC: Use proper secrets for handshake --- ssl/ssl_local.h | 2 ++ ssl/ssl_quic.c | 4 ++-- ssl/tls13_enc.c | 6 ++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 451e9bd65137a..2cfbddd8bf22e 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -1490,6 +1490,8 @@ struct ssl_st { unsigned char handshake_traffic_hash[EVP_MAX_MD_SIZE]; unsigned char client_app_traffic_secret[EVP_MAX_MD_SIZE]; unsigned char server_app_traffic_secret[EVP_MAX_MD_SIZE]; + unsigned char client_hand_traffic_secret[EVP_MAX_MD_SIZE]; + unsigned char server_hand_traffic_secret[EVP_MAX_MD_SIZE]; unsigned char exporter_master_secret[EVP_MAX_MD_SIZE]; unsigned char early_exporter_master_secret[EVP_MAX_MD_SIZE]; EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */ diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index 6ba8f569525c0..7ece8af9bb762 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -194,8 +194,8 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) s2c_secret = ssl->early_secret; break; case ssl_encryption_handshake: - c2s_secret = ssl->client_finished_secret; - s2c_secret = ssl->server_finished_secret; + c2s_secret = ssl->client_hand_traffic_secret; + s2c_secret = ssl->server_hand_traffic_secret; break; case ssl_encryption_application: c2s_secret = ssl->client_app_traffic_secret; diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c index acfb71f43e8aa..5cc5b436a6046 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -723,6 +723,12 @@ int tls13_change_cipher_state(SSL *s, int which) } } else if (label == client_application_traffic) memcpy(s->client_app_traffic_secret, secret, hashlen); +#ifndef OPENSSL_NO_QUIC + else if (label == client_handshake_traffic) + memcpy(s->client_hand_traffic_secret, secret, hashlen); + else if (label == server_handshake_traffic) + memcpy(s->server_hand_traffic_secret, secret, hashlen); +#endif if (!ssl_log_secret(s, log_label, secret, hashlen)) { /* SSLfatal() already called */ From 7e0a187cacd3ea69949bc71ace717add18797b28 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 15 Aug 2019 13:26:32 -0400 Subject: [PATCH 06/66] QUIC: Handle partial handshake messages --- ssl/ssl_local.h | 1 + ssl/ssl_quic.c | 28 ++++++++++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 2cfbddd8bf22e..9c176e5c0c214 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -1225,6 +1225,7 @@ typedef struct cert_pkey_st CERT_PKEY; struct quic_data_st { struct quic_data_st *next; OSSL_ENCRYPTION_LEVEL level; + size_t offset; size_t length; }; typedef struct quic_data_st QUIC_DATA; diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index 7ece8af9bb762..0959bcf2cf83b 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -114,15 +114,26 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, QUIC_DATA *qd; const uint8_t *p = data + 1; + /* Check for an incomplete block */ + qd = ssl->quic_input_data_tail; + if (qd != NULL) { + l = qd->length - qd->offset; + if (l != 0) { + /* we still need to copy `l` bytes into the last data block */ + if (l > len) + l = len; + memcpy((char*)(qd+1) + qd->offset, data, l); + qd->offset += l; + len -= l; + data += l; + continue; + } + } + n2l3(p, l); l += SSL3_HM_HEADER_LENGTH; - if (l > len) { - SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_BAD_DATA_LENGTH); - return 0; - } - - qd = OPENSSL_malloc(sizeof(QUIC_DATA) + l); + qd = OPENSSL_zalloc(sizeof(QUIC_DATA) + l); if (qd == NULL) { SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); return 0; @@ -131,6 +142,11 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, qd->next = NULL; qd->length = l; qd->level = level; + /* partial data received? */ + if (l > len) + l = len; + qd->offset = l; + memcpy((void*)(qd + 1), data, l); if (ssl->quic_input_data_tail != NULL) ssl->quic_input_data_tail->next = qd; From 4a2ce1616ec73581935726e58202dd2e616fc08d Mon Sep 17 00:00:00 2001 From: Todd Short Date: Mon, 26 Aug 2019 13:14:19 -0400 Subject: [PATCH 07/66] QUIC: Fix duplicate word in docs --- doc/man3/SSL_CTX_set_quic_method.pod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod index d938eb4e309ca..60bf704944b2e 100644 --- a/doc/man3/SSL_CTX_set_quic_method.pod +++ b/doc/man3/SSL_CTX_set_quic_method.pod @@ -59,7 +59,7 @@ containing the TransportParameters will be put in B<*out_params>, and its length in B<*out_params_len>. This buffer will be valid for the lifetime of the B. If no params were received from the peer, B<*out_params_len> will be 0. -SSL_quic_max_handshake_flight_len() returns returns the maximum number of bytes +SSL_quic_max_handshake_flight_len() returns the maximum number of bytes that may be received at the given encryption level. This function should be used to limit buffering in the QUIC implementation. From 68972bb1fa3b7f7390568d3a6e76926977593c04 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Mon, 26 Aug 2019 13:29:17 -0400 Subject: [PATCH 08/66] QUIC: Fix quic_transport constructors/parsers --- ssl/statem/extensions_clnt.c | 16 +++------------- ssl/statem/extensions_srvr.c | 16 +++------------- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index 52742dc36a8c1..3ae28e68dc3b3 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1208,10 +1208,8 @@ EXT_RETURN tls_construct_ctos_quic_transport_params(SSL *s, WPACKET *pkt, } if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters) - || !WPACKET_start_sub_packet_u16(pkt) - || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params, - s->ext.quic_transport_params_len) - || !WPACKET_close(pkt)) { + || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params, + s->ext.quic_transport_params_len)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return EXT_RETURN_FAIL; } @@ -2008,19 +2006,11 @@ int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, int tls_parse_stoc_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { - PACKET trans_param; - - if (!PACKET_as_length_prefixed_2(pkt, &trans_param) - || PACKET_remaining(&trans_param) == 0) { - SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); - return 0; - } - OPENSSL_free(s->ext.peer_quic_transport_params); s->ext.peer_quic_transport_params = NULL; s->ext.peer_quic_transport_params_len = 0; - if (!PACKET_memdup(&trans_param, + if (!PACKET_memdup(pkt, &s->ext.peer_quic_transport_params, &s->ext.peer_quic_transport_params_len)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 0ca8f154f2b4c..8c6fd9bcd07ec 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1237,19 +1237,11 @@ int tls_parse_ctos_post_handshake_auth(SSL *s, PACKET *pkt, int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { - PACKET trans_param; - - if (!PACKET_as_length_prefixed_2(pkt, &trans_param) - || PACKET_remaining(&trans_param) == 0) { - SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); - return 0; - } - OPENSSL_free(s->ext.peer_quic_transport_params); s->ext.peer_quic_transport_params = NULL; s->ext.peer_quic_transport_params_len = 0; - if (!PACKET_memdup(&trans_param, + if (!PACKET_memdup(pkt, &s->ext.peer_quic_transport_params, &s->ext.peer_quic_transport_params_len)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); @@ -1954,10 +1946,8 @@ EXT_RETURN tls_construct_stoc_quic_transport_params(SSL *s, WPACKET *pkt, } if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters) - || !WPACKET_start_sub_packet_u16(pkt) - || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params, - s->ext.quic_transport_params_len) - || !WPACKET_close(pkt)) { + || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params, + s->ext.quic_transport_params_len)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return EXT_RETURN_FAIL; } From a1f142f98030a2dd1790a46c2add2b01762ebfef Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 29 Aug 2019 11:53:41 -0400 Subject: [PATCH 09/66] QUIC: Reset init state in SSL_process_quic_post_handshake() --- ssl/ssl_quic.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index 0959bcf2cf83b..ad6696d964be4 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -265,16 +265,19 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) int SSL_process_quic_post_handshake(SSL *ssl) { + int ret; + if (SSL_in_init(ssl) || !SSL_IS_QUIC(ssl)) { SSLerr(SSL_F_SSL_PROCESS_QUIC_POST_HANDSHAKE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } ossl_statem_set_in_init(ssl, 1); + ret = ssl->handshake_func(ssl); + ossl_statem_set_in_init(ssl, 0); - if (ssl->handshake_func(ssl) <= 0) + if (ret <= 0) return 0; - return 1; } From 742cd8d9f598dae23c79a22498d0a42949b2d4b6 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 29 Aug 2019 12:03:48 -0400 Subject: [PATCH 10/66] QUIC: Don't process an incomplete message --- ssl/statem/statem_quic.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ssl/statem/statem_quic.c b/ssl/statem/statem_quic.c index 66acc30d6d96b..982a9a62921a6 100644 --- a/ssl/statem/statem_quic.c +++ b/ssl/statem/statem_quic.c @@ -18,30 +18,29 @@ NON_EMPTY_TRANSLATION_UNIT int quic_get_message(SSL *s, int *mt, size_t *len) { size_t l; - QUIC_DATA *qd; + QUIC_DATA *qd = s->quic_input_data_head; uint8_t *p; - if (s->quic_input_data_head == NULL) { + if (qd == NULL || (qd->length - qd->offset) != 0) { s->rwstate = SSL_READING; *len = 0; return 0; } /* This is where we check for the proper level, not when data is given */ - if (s->quic_input_data_head->level != s->quic_read_level) { + if (qd->level != s->quic_read_level) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); *len = 0; return 0; } - if (!BUF_MEM_grow_clean(s->init_buf, (int)s->quic_input_data_head->length)) { + if (!BUF_MEM_grow_clean(s->init_buf, (int)qd->length)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_BUF_LIB); *len = 0; return 0; } /* Copy buffered data */ - qd = s->quic_input_data_head; memcpy(s->init_buf->data, (void*)(qd + 1), qd->length); s->init_buf->length = qd->length; s->quic_input_data_head = qd->next; From aae9f8ee1e25decb9ecb860211a23e94ff8d175b Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 29 Aug 2019 20:21:58 -0400 Subject: [PATCH 11/66] QUIC: Quick fix: s2c to c2s for early secret --- ssl/ssl_quic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index ad6696d964be4..14827da88c43c 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -207,7 +207,7 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) /* secrets from the POV of the client */ switch (level) { case ssl_encryption_early_data: - s2c_secret = ssl->early_secret; + c2s_secret = ssl->early_secret; break; case ssl_encryption_handshake: c2s_secret = ssl->client_hand_traffic_secret; From 413aacbe4bb67cbe46305baca5e17a450e1ecc6d Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 30 Aug 2019 09:09:42 -0400 Subject: [PATCH 12/66] QUIC: Add client early traffic secret storage --- ssl/ssl_local.h | 1 + ssl/ssl_quic.c | 2 +- ssl/tls13_enc.c | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 9c176e5c0c214..91d07ac533329 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -1493,6 +1493,7 @@ struct ssl_st { unsigned char server_app_traffic_secret[EVP_MAX_MD_SIZE]; unsigned char client_hand_traffic_secret[EVP_MAX_MD_SIZE]; unsigned char server_hand_traffic_secret[EVP_MAX_MD_SIZE]; + unsigned char client_early_traffic_secret[EVP_MAX_MD_SIZE]; unsigned char exporter_master_secret[EVP_MAX_MD_SIZE]; unsigned char early_exporter_master_secret[EVP_MAX_MD_SIZE]; EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */ diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index 14827da88c43c..0017d1eba93ba 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -207,7 +207,7 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) /* secrets from the POV of the client */ switch (level) { case ssl_encryption_early_data: - c2s_secret = ssl->early_secret; + c2s_secret = ssl->client_early_traffic_secret; break; case ssl_encryption_handshake: c2s_secret = ssl->client_hand_traffic_secret; diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c index 5cc5b436a6046..ccd8bdd5c19a0 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -728,6 +728,8 @@ int tls13_change_cipher_state(SSL *s, int which) memcpy(s->client_hand_traffic_secret, secret, hashlen); else if (label == server_handshake_traffic) memcpy(s->server_hand_traffic_secret, secret, hashlen); + else if (label == client_early_traffic) + memcpy(s->client_early_traffic_secret, secret, hashlen); #endif if (!ssl_log_secret(s, log_label, secret, hashlen)) { From 0ac36ef18a9bfcd0a004c29f9fd8560831d74028 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 30 Aug 2019 09:15:31 -0400 Subject: [PATCH 13/66] QUIC: Add OPENSSL_NO_QUIC wrapper --- ssl/ssl_local.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 91d07ac533329..c791beb594cae 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -1491,9 +1491,11 @@ struct ssl_st { unsigned char handshake_traffic_hash[EVP_MAX_MD_SIZE]; unsigned char client_app_traffic_secret[EVP_MAX_MD_SIZE]; unsigned char server_app_traffic_secret[EVP_MAX_MD_SIZE]; +# ifndef OPENSSL_NO_QUIC unsigned char client_hand_traffic_secret[EVP_MAX_MD_SIZE]; unsigned char server_hand_traffic_secret[EVP_MAX_MD_SIZE]; unsigned char client_early_traffic_secret[EVP_MAX_MD_SIZE]; +# endif unsigned char exporter_master_secret[EVP_MAX_MD_SIZE]; unsigned char early_exporter_master_secret[EVP_MAX_MD_SIZE]; EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */ From 4f8e04665ca779da15a9d9c159c6531016ce4eaa Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 30 Aug 2019 09:47:48 -0400 Subject: [PATCH 14/66] QUIC: Correctly disable middlebox compat --- ssl/ssl_quic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index 0017d1eba93ba..a76c24eac6b95 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -173,7 +173,7 @@ int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method) break; } ctx->quic_method = quic_method; - ctx->options &= SSL_OP_ENABLE_MIDDLEBOX_COMPAT; + ctx->options &= ~SSL_OP_ENABLE_MIDDLEBOX_COMPAT; return 1; } @@ -189,7 +189,7 @@ int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method) break; } ssl->quic_method = quic_method; - ssl->options &= SSL_OP_ENABLE_MIDDLEBOX_COMPAT; + ssl->options &= ~SSL_OP_ENABLE_MIDDLEBOX_COMPAT; return 1; } From e239f71e1788d850719915f0f7a46fde57fca99f Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 30 Aug 2019 11:17:58 -0400 Subject: [PATCH 15/66] QUIC: Move QUIC code out of tls13_change_cipher_state() Create quic_change_cipher_state() that does the minimal required to generate the QUIC secrets. (e.g. encryption contexts are not initialized). --- ssl/ssl_quic.c | 7 -- ssl/tls13_enc.c | 217 ++++++++++++++++++++++++++++++------------------ 2 files changed, 138 insertions(+), 86 deletions(-) diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index a76c24eac6b95..670deea5ab0dd 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -199,7 +199,6 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) uint8_t *s2c_secret = NULL; size_t len; const EVP_MD *md; - static const unsigned char zeros[EVP_MAX_MD_SIZE]; if (!SSL_IS_QUIC(ssl)) return 1; @@ -240,12 +239,6 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) return 0; } - /* In some cases, we want to set the secret only when BOTH are non-zero */ - if (c2s_secret != NULL && s2c_secret != NULL - && !memcmp(c2s_secret, zeros, len) - && !memcmp(s2c_secret, zeros, len)) - return 1; - if (ssl->server) { if (!ssl->quic_method->set_encryption_secrets(ssl, level, c2s_secret, s2c_secret, len)) { diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c index ccd8bdd5c19a0..3c41e514b6511 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -400,27 +400,144 @@ static int derive_secret_key_and_iv(SSL *s, int sending, const EVP_MD *md, return 1; } -int tls13_change_cipher_state(SSL *s, int which) -{ #ifdef CHARSET_EBCDIC - static const unsigned char client_early_traffic[] = {0x63, 0x20, 0x65, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; - static const unsigned char client_handshake_traffic[] = {0x63, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; - static const unsigned char client_application_traffic[] = {0x63, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; - static const unsigned char server_handshake_traffic[] = {0x73, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; - static const unsigned char server_application_traffic[] = {0x73, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; - static const unsigned char exporter_master_secret[] = {0x65, 0x78, 0x70, 0x20, /* master*/ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00}; - static const unsigned char resumption_master_secret[] = {0x72, 0x65, 0x73, 0x20, /* master*/ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00}; - static const unsigned char early_exporter_master_secret[] = {0x65, 0x20, 0x65, 0x78, 0x70, 0x20, /* master*/ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00}; +static const unsigned char client_early_traffic[] = {0x63, 0x20, 0x65, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; +static const unsigned char client_handshake_traffic[] = {0x63, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; +static const unsigned char client_application_traffic[] = {0x63, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; +static const unsigned char server_handshake_traffic[] = {0x73, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; +static const unsigned char server_application_traffic[] = {0x73, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; +static const unsigned char exporter_master_secret[] = {0x65, 0x78, 0x70, 0x20, /* master*/ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00}; +static const unsigned char resumption_master_secret[] = {0x72, 0x65, 0x73, 0x20, /* master*/ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00}; +static const unsigned char early_exporter_master_secret[] = {0x65, 0x20, 0x65, 0x78, 0x70, 0x20, /* master*/ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00}; #else - static const unsigned char client_early_traffic[] = "c e traffic"; - static const unsigned char client_handshake_traffic[] = "c hs traffic"; - static const unsigned char client_application_traffic[] = "c ap traffic"; - static const unsigned char server_handshake_traffic[] = "s hs traffic"; - static const unsigned char server_application_traffic[] = "s ap traffic"; - static const unsigned char exporter_master_secret[] = "exp master"; - static const unsigned char resumption_master_secret[] = "res master"; - static const unsigned char early_exporter_master_secret[] = "e exp master"; +static const unsigned char client_early_traffic[] = "c e traffic"; +static const unsigned char client_handshake_traffic[] = "c hs traffic"; +static const unsigned char client_application_traffic[] = "c ap traffic"; +static const unsigned char server_handshake_traffic[] = "s hs traffic"; +static const unsigned char server_application_traffic[] = "s ap traffic"; +static const unsigned char exporter_master_secret[] = "exp master"; +static const unsigned char resumption_master_secret[] = "res master"; +static const unsigned char early_exporter_master_secret[] = "e exp master"; #endif +#ifndef OPENSSL_NO_QUIC +static int quic_change_cipher_state(SSL *s, int which) +{ + unsigned char hash[EVP_MAX_MD_SIZE]; + size_t hashlen = 0; + int hashleni; + int ret = 0; + const EVP_MD *md = NULL; + OSSL_ENCRYPTION_LEVEL level = ssl_encryption_initial; + int is_handshake = ((which & SSL3_CC_HANDSHAKE) == SSL3_CC_HANDSHAKE); + int is_client_read = ((which & SSL3_CHANGE_CIPHER_CLIENT_READ) == SSL3_CHANGE_CIPHER_CLIENT_READ); + int is_server_write = ((which & SSL3_CHANGE_CIPHER_SERVER_WRITE) == SSL3_CHANGE_CIPHER_SERVER_WRITE); + int is_early = (which & SSL3_CC_EARLY); + + md = ssl_handshake_md(s); + if (!ssl3_digest_cached_records(s, 1) + || !ssl_handshake_hash(s, hash, sizeof(hash), &hashlen)) { + /* SSLfatal() already called */; + goto err; + } + + /* Ensure cast to size_t is safe */ + hashleni = EVP_MD_size(md); + if (!ossl_assert(hashleni >= 0)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); + goto err; + } + hashlen = (size_t)hashleni; + + if (is_handshake) + level = ssl_encryption_handshake; + else + level = ssl_encryption_application; + + if (is_client_read || is_server_write) { + if (is_handshake) { + level = ssl_encryption_handshake; + + if (!tls13_hkdf_expand(s, md, s->handshake_secret, client_handshake_traffic, + sizeof(client_handshake_traffic)-1, hash, hashlen, + s->client_hand_traffic_secret, hashlen, 1)) { + /* SSLfatal() already called */ + goto err; + } + if (!ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL, s->client_hand_traffic_secret, hashlen)) { + /* SSLfatal() already called */ + goto err; + } + + if (!tls13_hkdf_expand(s, md, s->handshake_secret, server_handshake_traffic, + sizeof(server_handshake_traffic)-1, hash, hashlen, + s->server_hand_traffic_secret, hashlen, 1)) { + /* SSLfatal() already called */ + goto err; + } + if (!ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, s->server_hand_traffic_secret, hashlen)) { + /* SSLfatal() already called */ + goto err; + } + } else { + level = ssl_encryption_application; + + if (!tls13_hkdf_expand(s, md, s->master_secret, client_application_traffic, + sizeof(client_application_traffic)-1, hash, hashlen, + s->client_app_traffic_secret, hashlen, 1)) { + /* SSLfatal() already called */ + goto err; + } + if (!ssl_log_secret(s, CLIENT_APPLICATION_LABEL, s->client_app_traffic_secret, hashlen)) { + /* SSLfatal() already called */ + goto err; + } + + if (!tls13_hkdf_expand(s, md, s->master_secret, server_application_traffic, + sizeof(server_application_traffic)-1, hash, hashlen, + s->server_app_traffic_secret, hashlen, 1)) { + /* SSLfatal() already called */ + goto err; + } + if (!ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)) { + /* SSLfatal() already called */ + goto err; + } + } + if (s->server) + s->quic_write_level = level; + else + s->quic_read_level = level; + } else { + if (is_early) { + level = ssl_encryption_early_data; + + if (!tls13_hkdf_expand(s, md, s->early_secret, client_early_traffic, + sizeof(client_early_traffic)-1, hash, hashlen, + s->client_early_traffic_secret, hashlen, 1)) { + /* SSLfatal() already called */ + goto err; + } + if (!ssl_log_secret(s, CLIENT_EARLY_LABEL, s->client_early_traffic_secret, hashlen)) { + /* SSLfatal() already called */ + goto err; + } + } + if (s->server) + s->quic_read_level = level; + else + s->quic_write_level = level; + } + + if (level != ssl_encryption_initial && !quic_set_encryption_secrets(s, level)) + goto err; + + ret = 1; + err: + return ret; +} +#endif /* OPENSSL_NO_QUIC */ +int tls13_change_cipher_state(SSL *s, int which) +{ unsigned char *iv; unsigned char key[EVP_MAX_KEY_LENGTH]; unsigned char secret[EVP_MAX_MD_SIZE]; @@ -440,8 +557,10 @@ int tls13_change_cipher_state(SSL *s, int which) ktls_crypto_info_t crypto_info; BIO *bio; #endif + #ifndef OPENSSL_NO_QUIC - OSSL_ENCRYPTION_LEVEL level = ssl_encryption_initial; + if (SSL_IS_QUIC(s)) + return quic_change_cipher_state(s, which); #endif if (which & SSL3_CC_READ) { @@ -488,9 +607,6 @@ int tls13_change_cipher_state(SSL *s, int which) label = client_early_traffic; labellen = sizeof(client_early_traffic) - 1; log_label = CLIENT_EARLY_LABEL; -#ifndef OPENSSL_NO_QUIC - level = ssl_encryption_early_data; -#endif handlen = BIO_get_mem_data(s->s3.handshake_buffer, &hdata); if (handlen <= 0) { @@ -567,14 +683,6 @@ int tls13_change_cipher_state(SSL *s, int which) /* SSLfatal() already called */ goto err; } -#ifndef OPENSSL_NO_QUIC - if (SSL_IS_QUIC(s)) { - if (s->server) - s->quic_read_level = ssl_encryption_early_data; - else - s->quic_write_level = ssl_encryption_early_data; - } -#endif } else if (which & SSL3_CC_HANDSHAKE) { insecret = s->handshake_secret; finsecret = s->client_finished_secret; @@ -582,15 +690,6 @@ int tls13_change_cipher_state(SSL *s, int which) label = client_handshake_traffic; labellen = sizeof(client_handshake_traffic) - 1; log_label = CLIENT_HANDSHAKE_LABEL; -#ifndef OPENSSL_NO_QUIC - if (SSL_IS_QUIC(s)) { - level = ssl_encryption_handshake; - if (s->server) - s->quic_read_level = ssl_encryption_handshake; - else - s->quic_write_level = ssl_encryption_handshake; - } -#endif /* * The handshake hash used for the server read/client write handshake * traffic secret is the same as the hash for the server @@ -613,15 +712,6 @@ int tls13_change_cipher_state(SSL *s, int which) * previously saved value. */ hash = s->server_finished_hash; -#ifndef OPENSSL_NO_QUIC - if (SSL_IS_QUIC(s)) { - level = ssl_encryption_application; /* ??? */ - if (s->server) - s->quic_read_level = ssl_encryption_application; - else - s->quic_write_level = ssl_encryption_application; - } -#endif } } else { /* Early data never applies to client-read/server-write */ @@ -632,29 +722,11 @@ int tls13_change_cipher_state(SSL *s, int which) label = server_handshake_traffic; labellen = sizeof(server_handshake_traffic) - 1; log_label = SERVER_HANDSHAKE_LABEL; -#ifndef OPENSSL_NO_QUIC - if (SSL_IS_QUIC(s)) { - level = ssl_encryption_handshake; - if (s->server) - s->quic_write_level = ssl_encryption_handshake; - else - s->quic_read_level = ssl_encryption_handshake; - } -#endif } else { insecret = s->master_secret; label = server_application_traffic; labellen = sizeof(server_application_traffic) - 1; log_label = SERVER_APPLICATION_LABEL; -#ifndef OPENSSL_NO_QUIC - if (SSL_IS_QUIC(s)) { - level = ssl_encryption_application; - if (s->server) - s->quic_write_level = ssl_encryption_application; - else - s->quic_read_level = ssl_encryption_application; - } -#endif } } @@ -723,14 +795,6 @@ int tls13_change_cipher_state(SSL *s, int which) } } else if (label == client_application_traffic) memcpy(s->client_app_traffic_secret, secret, hashlen); -#ifndef OPENSSL_NO_QUIC - else if (label == client_handshake_traffic) - memcpy(s->client_hand_traffic_secret, secret, hashlen); - else if (label == server_handshake_traffic) - memcpy(s->server_hand_traffic_secret, secret, hashlen); - else if (label == client_early_traffic) - memcpy(s->client_early_traffic_secret, secret, hashlen); -#endif if (!ssl_log_secret(s, log_label, secret, hashlen)) { /* SSLfatal() already called */ @@ -791,11 +855,6 @@ int tls13_change_cipher_state(SSL *s, int which) # endif #endif -#ifndef OPENSSL_NO_QUIC - if (!quic_set_encryption_secrets(s, level)) - goto err; -#endif - ret = 1; err: if ((which & SSL3_CC_EARLY) != 0) { From b15ef03f3033402dadb8c9aa313ca08c0ac1a638 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 30 Aug 2019 11:38:56 -0400 Subject: [PATCH 16/66] QUIC: Tweeks to quic_change_cipher_state() --- ssl/tls13_enc.c | 69 +++++++++++++++++-------------------------------- 1 file changed, 24 insertions(+), 45 deletions(-) diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c index 3c41e514b6511..56652e0dffb3e 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -448,33 +448,18 @@ static int quic_change_cipher_state(SSL *s, int which) } hashlen = (size_t)hashleni; - if (is_handshake) - level = ssl_encryption_handshake; - else - level = ssl_encryption_application; - if (is_client_read || is_server_write) { if (is_handshake) { level = ssl_encryption_handshake; if (!tls13_hkdf_expand(s, md, s->handshake_secret, client_handshake_traffic, sizeof(client_handshake_traffic)-1, hash, hashlen, - s->client_hand_traffic_secret, hashlen, 1)) { - /* SSLfatal() already called */ - goto err; - } - if (!ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL, s->client_hand_traffic_secret, hashlen)) { - /* SSLfatal() already called */ - goto err; - } - - if (!tls13_hkdf_expand(s, md, s->handshake_secret, server_handshake_traffic, - sizeof(server_handshake_traffic)-1, hash, hashlen, - s->server_hand_traffic_secret, hashlen, 1)) { - /* SSLfatal() already called */ - goto err; - } - if (!ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, s->server_hand_traffic_secret, hashlen)) { + s->client_hand_traffic_secret, hashlen, 1) + || !ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL, s->client_hand_traffic_secret, hashlen) + || !tls13_hkdf_expand(s, md, s->handshake_secret, server_handshake_traffic, + sizeof(server_handshake_traffic)-1, hash, hashlen, + s->server_hand_traffic_secret, hashlen, 1) + || !ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, s->server_hand_traffic_secret, hashlen)) { /* SSLfatal() already called */ goto err; } @@ -483,26 +468,20 @@ static int quic_change_cipher_state(SSL *s, int which) if (!tls13_hkdf_expand(s, md, s->master_secret, client_application_traffic, sizeof(client_application_traffic)-1, hash, hashlen, - s->client_app_traffic_secret, hashlen, 1)) { - /* SSLfatal() already called */ - goto err; - } - if (!ssl_log_secret(s, CLIENT_APPLICATION_LABEL, s->client_app_traffic_secret, hashlen)) { - /* SSLfatal() already called */ - goto err; - } - - if (!tls13_hkdf_expand(s, md, s->master_secret, server_application_traffic, - sizeof(server_application_traffic)-1, hash, hashlen, - s->server_app_traffic_secret, hashlen, 1)) { - /* SSLfatal() already called */ - goto err; - } - if (!ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)) { + s->client_app_traffic_secret, hashlen, 1) + || !ssl_log_secret(s, CLIENT_APPLICATION_LABEL, s->client_app_traffic_secret, hashlen) + || !tls13_hkdf_expand(s, md, s->master_secret, server_application_traffic, + sizeof(server_application_traffic)-1, hash, hashlen, + s->server_app_traffic_secret, hashlen, 1) + || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)) { /* SSLfatal() already called */ goto err; } } + if (!quic_set_encryption_secrets(s, level)) { + /* SSLfatal() already called */ + goto err; + } if (s->server) s->quic_write_level = level; else @@ -513,24 +492,24 @@ static int quic_change_cipher_state(SSL *s, int which) if (!tls13_hkdf_expand(s, md, s->early_secret, client_early_traffic, sizeof(client_early_traffic)-1, hash, hashlen, - s->client_early_traffic_secret, hashlen, 1)) { - /* SSLfatal() already called */ - goto err; - } - if (!ssl_log_secret(s, CLIENT_EARLY_LABEL, s->client_early_traffic_secret, hashlen)) { + s->client_early_traffic_secret, hashlen, 1) + || !ssl_log_secret(s, CLIENT_EARLY_LABEL, s->client_early_traffic_secret, hashlen) + || !quic_set_encryption_secrets(s, level)) { /* SSLfatal() already called */ goto err; } + } else if (is_handshake) { + level = ssl_encryption_handshake; + } else { + level = ssl_encryption_application; } + if (s->server) s->quic_read_level = level; else s->quic_write_level = level; } - if (level != ssl_encryption_initial && !quic_set_encryption_secrets(s, level)) - goto err; - ret = 1; err: return ret; From 2a4b43cd6a50e714b17ca26055c504cd73c9d682 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 24 Sep 2019 10:26:42 -0400 Subject: [PATCH 17/66] QUIC: Add support for more secrets --- ssl/tls13_enc.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c index 56652e0dffb3e..b7d28559ed208 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -456,10 +456,14 @@ static int quic_change_cipher_state(SSL *s, int which) sizeof(client_handshake_traffic)-1, hash, hashlen, s->client_hand_traffic_secret, hashlen, 1) || !ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL, s->client_hand_traffic_secret, hashlen) + || !tls13_derive_finishedkey(s, md, s->client_hand_traffic_secret, + s->client_finished_secret, hashlen) || !tls13_hkdf_expand(s, md, s->handshake_secret, server_handshake_traffic, sizeof(server_handshake_traffic)-1, hash, hashlen, s->server_hand_traffic_secret, hashlen, 1) - || !ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, s->server_hand_traffic_secret, hashlen)) { + || !ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, s->server_hand_traffic_secret, hashlen) + || !tls13_derive_finishedkey(s, md, s->server_hand_traffic_secret, + s->server_finished_secret, hashlen)) { /* SSLfatal() already called */ goto err; } @@ -473,7 +477,10 @@ static int quic_change_cipher_state(SSL *s, int which) || !tls13_hkdf_expand(s, md, s->master_secret, server_application_traffic, sizeof(server_application_traffic)-1, hash, hashlen, s->server_app_traffic_secret, hashlen, 1) - || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)) { + || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen) + || !tls13_hkdf_expand(s, md, s->master_secret, resumption_master_secret, + sizeof(resumption_master_secret)-1, hash, hashlen, + s->resumption_master_secret, hashlen, 1)) { /* SSLfatal() already called */ goto err; } From d70deae0f87a05c1587a8609f693c25819d31834 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 12 Nov 2019 13:52:35 -0500 Subject: [PATCH 18/66] QUIC: Fix resumption secret --- ssl/tls13_enc.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c index b7d28559ed208..569a17586ebc4 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -477,10 +477,7 @@ static int quic_change_cipher_state(SSL *s, int which) || !tls13_hkdf_expand(s, md, s->master_secret, server_application_traffic, sizeof(server_application_traffic)-1, hash, hashlen, s->server_app_traffic_secret, hashlen, 1) - || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen) - || !tls13_hkdf_expand(s, md, s->master_secret, resumption_master_secret, - sizeof(resumption_master_secret)-1, hash, hashlen, - s->resumption_master_secret, hashlen, 1)) { + || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)) { /* SSLfatal() already called */ goto err; } @@ -494,6 +491,8 @@ static int quic_change_cipher_state(SSL *s, int which) else s->quic_read_level = level; } else { + /* is_client_write || is_server_read */ + if (is_early) { level = ssl_encryption_early_data; @@ -509,6 +508,16 @@ static int quic_change_cipher_state(SSL *s, int which) level = ssl_encryption_handshake; } else { level = ssl_encryption_application; + /* + * We also create the resumption master secret, but this time use the + * hash for the whole handshake including the Client Finished + */ + if (!tls13_hkdf_expand(s, md, s->master_secret, resumption_master_secret, + sizeof(resumption_master_secret)-1, hash, hashlen, + s->resumption_master_secret, hashlen, 1)) { + /* SSLfatal() already called */ + goto err; + } } if (s->server) From 034463f24a105084d140896536da2c4299d4906a Mon Sep 17 00:00:00 2001 From: Todd Short Date: Wed, 13 Nov 2019 12:11:00 -0500 Subject: [PATCH 19/66] QUIC: Handle EndOfEarlyData and MaxEarlyData --- ssl/statem/extensions_clnt.c | 11 +++++++++++ ssl/statem/extensions_srvr.c | 12 ++++++++++-- ssl/statem/statem_clnt.c | 8 ++++++++ ssl/statem/statem_srvr.c | 4 ++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index 3ae28e68dc3b3..3e763611993ec 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1919,6 +1919,17 @@ int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context, return 0; } +#ifndef OPENSSL_NO_QUIC + /* + * QUIC server must send 0xFFFFFFFF or it's a PROTOCOL_VIOLATION + * per draft-ietf-quic-tls-24 S4.5 + */ + if (s->quic_method != NULL && max_early_data != 0xFFFFFFFF) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_INVALID_MAX_EARLY_DATA); + return 0; + } +#endif + s->session->ext.max_early_data = max_early_data; return 1; diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 8c6fd9bcd07ec..198b48ea9cb4f 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1890,12 +1890,20 @@ EXT_RETURN tls_construct_stoc_early_data(SSL *s, WPACKET *pkt, size_t chainidx) { if (context == SSL_EXT_TLS1_3_NEW_SESSION_TICKET) { - if (s->max_early_data == 0) + uint32_t max_early_data = s->max_early_data; + + if (max_early_data == 0) return EXT_RETURN_NOT_SENT; +#ifndef OPENSSL_NO_QUIC + /* QUIC server must always send 0xFFFFFFFF, per draft-ietf-quic-tls-24 S4.5 */ + if (s->quic_method != NULL) + max_early_data = 0xFFFFFFFF; +#endif + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_early_data) || !WPACKET_start_sub_packet_u16(pkt) - || !WPACKET_put_bytes_u32(pkt, s->max_early_data) + || !WPACKET_put_bytes_u32(pkt, max_early_data) || !WPACKET_close(pkt)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return EXT_RETURN_FAIL; diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index 3cd1ee2d3dfe1..36cbba2a50c1c 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -904,6 +904,14 @@ int ossl_statem_client_construct_message(SSL *s, WPACKET *pkt, break; case TLS_ST_CW_END_OF_EARLY_DATA: +#ifndef OPENSSL_NO_QUIC + /* QUIC does not send EndOfEarlyData, draft-ietf-quic-tls-24 S8.3 */ + if (s->quic_method != NULL) { + *confunc = NULL; + *mt = SSL3_MT_DUMMY; + break; + } +#endif *confunc = tls_construct_end_of_early_data; *mt = SSL3_MT_END_OF_EARLY_DATA; break; diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index a9e67f9d32a77..69126bd580351 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -76,6 +76,10 @@ static int ossl_statem_server13_read_transition(SSL *s, int mt) break; } else if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) { if (mt == SSL3_MT_END_OF_EARLY_DATA) { +#ifndef OPENSSL_NO_QUIC + if (s->quic_method != NULL) + return 0; +#endif st->hand_state = TLS_ST_SR_END_OF_EARLY_DATA; return 1; } From 4f497cc331260cbcded427189e954aa9f2f9356c Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 7 Jan 2020 10:59:08 -0500 Subject: [PATCH 20/66] QUIC: Fall-through for 0RTT --- ssl/statem/statem_srvr.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 69126bd580351..391e638c9540d 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -74,12 +74,9 @@ static int ossl_statem_server13_read_transition(SSL *s, int mt) return 1; } break; - } else if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) { + } else if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED + && !SSL_IS_QUIC(s)) { if (mt == SSL3_MT_END_OF_EARLY_DATA) { -#ifndef OPENSSL_NO_QUIC - if (s->quic_method != NULL) - return 0; -#endif st->hand_state = TLS_ST_SR_END_OF_EARLY_DATA; return 1; } From 681ad0775d671a1b2337bbf0368cd711a35f0acf Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Wed, 22 Apr 2020 09:12:36 -0700 Subject: [PATCH 21/66] QUIC: Some cleanup for the main QUIC changes Try to reduce unneeded whitespace changes and wrap new code to 80 columns. Reword documentation to attempt to improve clarity. Add some more sanity checks and clarifying comments to the code. Update referenced I-D versions. --- doc/man3/SSL_CTX_set_quic_method.pod | 43 +++++++------- include/openssl/ssl.h.in | 4 +- include/openssl/tls1.h | 2 +- ssl/build.info | 7 ++- ssl/ssl_ciph.c | 2 + ssl/ssl_lib.c | 2 +- ssl/ssl_local.h | 1 + ssl/ssl_quic.c | 45 +++++++-------- ssl/statem/extensions_clnt.c | 2 +- ssl/statem/extensions_srvr.c | 2 +- ssl/statem/statem.c | 2 +- ssl/statem/statem_lib.c | 26 +++++---- ssl/statem/statem_local.h | 2 + ssl/statem/statem_quic.c | 22 ++++---- ssl/tls13_enc.c | 84 +++++++++++++++++++--------- test/sslapitest.c | 11 ++-- util/libssl.num | 2 +- 17 files changed, 155 insertions(+), 104 deletions(-) diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod index 60bf704944b2e..3d7bf7e682137 100644 --- a/doc/man3/SSL_CTX_set_quic_method.pod +++ b/doc/man3/SSL_CTX_set_quic_method.pod @@ -63,22 +63,25 @@ SSL_quic_max_handshake_flight_len() returns the maximum number of bytes that may be received at the given encryption level. This function should be used to limit buffering in the QUIC implementation. -See https://tools.ietf.org/html/draft-ietf-quic-transport-16#section-4.4. +See https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-4. SSL_quic_read_level() returns the current read encryption level. SSL_quic_write_level() returns the current write encryption level. -SSL_provide_quic_data() provides data from QUIC at a particular encryption -level B. It is an error to call this function outside of the handshake -or with an encryption level other than the current read level. It returns one -on success and zero on error. +SSL_provide_quic_data() is used to provide data from QUIC CRYPTO frames to the +state machine, at a particular encryption level B. It is an error to +call this function outside of the handshake or with an encryption level other +than the current read level. The application must buffer and consolidate any +frames with less than four bytes of content. It returns one on success and +zero on error. SSL_process_quic_post_handshake() processes any data that QUIC has provided after the handshake has completed. This includes NewSessionTicket messages sent by the server. -SSL_is_quic() indicates whether a connection uses QUIC. +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. =head1 NOTES @@ -89,11 +92,11 @@ functions allow a QUIC implementation to serve as the underlying transport as described in draft-ietf-quic-tls. When configured for QUIC, SSL_do_handshake() will drive the handshake as -before, but it will not use the configured B. It will call functions on -B to configure secrets and send data. If data is needed from -the peer, it will return B. When received, the caller -should call SSL_provide_quic_data() and then SSL_do_handshake() to continue -the handshake. After the handshake is complete, the caller should call +before, but it will not use the configured B. It will call functions from +the configured B to configure secrets and send data. If data +is needed from the peer, it will return B. When received, +the caller should call SSL_provide_quic_data() and then SSL_do_handshake() to +continue the handshake. After the handshake is complete, the caller should call SSL_provide_quic_data() for any post-handshake data, followed by SSL_process_quic_post_handshake() to process it. It is an error to call SSL_read()/SSL_read_ex() and SSL_write()/SSL_write_ex() in QUIC. @@ -105,7 +108,7 @@ pass the active write level to add_handshake_data() when writing data. Callers can use SSL_quic_write_level() to query the active write level when generating their own errors. -See https://tools.ietf.org/html/draft-ietf-quic-tls-15#section-4.1 for more +See https://tools.ietf.org/html/draft-ietf-quic-tls-27#section-4.1 for more details. To avoid DoS attacks, the QUIC implementation must limit the amount of data @@ -113,11 +116,12 @@ being queued up. The implementation can call SSL_quic_max_handshake_flight_len() to get the maximum buffer length at each encryption level. -draft-ietf-quic-tls defines a new TLS extension quic_transport_parameters +draft-ietf-quic-tls defines a new TLS extension "quic_transport_parameters" used by QUIC for each endpoint to unilaterally declare its supported -transport parameters. draft-ietf-quic-transport (section 7.4) defines the -contents of that extension (a TransportParameters struct) and describes how -to handle it and its semantic meaning. +transport parameters. The contents of the extension are specified in +https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-18 (as +a sequence of tag/length/value parameters) along with the interpretation of the +various parameters and the rules for their processing. OpenSSL handles this extension as an opaque byte string. The caller is responsible for serializing and parsing it. @@ -205,10 +209,11 @@ SSL_process_quic_post_handshake() return 1 on success, and 0 on error. SSL_quic_read_level() and SSL_quic_write_level() return the current -encryption level as B (B). +encryption level as an B +(B). -SSL_quic_max_handshake_flight_len() returns the maximum length of a flight -for a given encryption level. +SSL_quic_max_handshake_flight_len() returns the maximum length in bytes of a +flight for a given encryption level. SSL_is_quic() returns 1 if QUIC is being used, 0 if not. diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in index e8f49714c5353..582e45f31be73 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2562,10 +2562,10 @@ __owur int SSL_process_quic_post_handshake(SSL *ssl); __owur int SSL_is_quic(SSL *ssl); -# endif - int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c); +# endif + # ifdef __cplusplus } # endif diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h index 9edb5453ca38f..20e39fb571166 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -151,7 +151,7 @@ extern "C" { /* Temporary extension type */ # define TLSEXT_TYPE_renegotiate 0xff01 -/* ExtensionType value from draft-ietf-quic-tls-13 */ +/* ExtensionType value from draft-ietf-quic-tls-27 */ # define TLSEXT_TYPE_quic_transport_parameters 0xffa5 # ifndef OPENSSL_NO_NEXTPROTONEG diff --git a/ssl/build.info b/ssl/build.info index ac87437906127..d99835c9a0dad 100644 --- a/ssl/build.info +++ b/ssl/build.info @@ -37,10 +37,11 @@ IF[{- !$disabled{'deprecated-3.0'} -}] SHARED_SOURCE[../libssl]=s3_cbc.c SOURCE[../libssl]=ssl_rsa_legacy.c ENDIF - -SOURCE[../libssl]=ssl_quic.c statem/statem_quic.c - DEFINE[../libssl]=$AESDEF +IF[{- !$disabled{quic} -}] + SOURCE[../libssl]=ssl_quic.c statem/statem_quic.c +ENDIF + SOURCE[../providers/libcommon.a]=record/tls_pad.c SOURCE[../providers/libdefault.a ../providers/libfips.a]=s3_cbc.c diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c index a73cb532944b9..82c02ef29a6b5 100644 --- a/ssl/ssl_ciph.c +++ b/ssl/ssl_ciph.c @@ -2240,6 +2240,7 @@ const char *OSSL_default_ciphersuites(void) "TLS_AES_128_GCM_SHA256"; } +#ifndef OPENSSL_NO_QUIC int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c) { switch (c->algorithm2 & (0xFF << TLS1_PRF_DGST_SHIFT)) { @@ -2271,3 +2272,4 @@ int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c) } return NID_undef; } +#endif diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 6d2ab0e3283b8..223f6078e10b3 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -4244,7 +4244,7 @@ EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx) const SSL_CIPHER *SSL_get_current_cipher(const SSL *s) { - if (s->session != NULL) + if ((s->session != NULL) && (s->session->cipher != NULL)) return s->session->cipher; return NULL; } diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index c791beb594cae..a5eff6726c205 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -1227,6 +1227,7 @@ struct quic_data_st { OSSL_ENCRYPTION_LEVEL level; size_t offset; size_t length; + /* char data[]; should be here but C90 VLAs not allowed here */ }; typedef struct quic_data_st QUIC_DATA; int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level); diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index 670deea5ab0dd..95b3a8b64e119 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -11,10 +11,6 @@ #include "internal/cryptlib.h" #include "internal/refcount.h" -#ifdef OPENSSL_NO_QUIC -NON_EMPTY_TRANSLATION_UNIT -#else - int SSL_set_quic_transport_params(SSL *ssl, const uint8_t *params, size_t params_len) { @@ -109,10 +105,10 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, return 0; } - /* Split the QUIC messages up, if necessary */ + /* Split on handshake message boundaries, if necessary */ while (len > 0) { QUIC_DATA *qd; - const uint8_t *p = data + 1; + const uint8_t *p; /* Check for an incomplete block */ qd = ssl->quic_input_data_tail; @@ -130,6 +126,12 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, } } + if (len < SSL3_HM_HEADER_LENGTH) { + SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_BAD_LENGTH); + return 0; + } + /* TLS Handshake message header has 1-byte type and 3-byte length */ + p = data + 1; n2l3(p, l); l += SSL3_HM_HEADER_LENGTH; @@ -163,15 +165,8 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method) { - switch (ctx->method->version) { - case DTLS1_VERSION: - case DTLS1_2_VERSION: - case DTLS_ANY_VERSION: - case DTLS1_BAD_VER: + if (ctx->method->version != TLS_ANY_VERSION) return 0; - default: - break; - } ctx->quic_method = quic_method; ctx->options &= ~SSL_OP_ENABLE_MIDDLEBOX_COMPAT; return 1; @@ -179,15 +174,8 @@ int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method) int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method) { - switch (ssl->method->version) { - case DTLS1_VERSION: - case DTLS1_2_VERSION: - case DTLS_ANY_VERSION: - case DTLS1_BAD_VER: + if (ssl->method->version != TLS_ANY_VERSION) return 0; - default: - break; - } ssl->quic_method = quic_method; ssl->options &= ~SSL_OP_ENABLE_MIDDLEBOX_COMPAT; return 1; @@ -225,6 +213,12 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) /* May not have selected cipher, yet */ const SSL_CIPHER *c = NULL; + /* + * It probably doesn't make sense to use an (external) PSK session, + * but in theory some kinds of external session caches could be + * implemented using it, so allow psksession to be used as well as + * the regular session. + */ if (ssl->session != NULL) c = SSL_SESSION_get0_cipher(ssl->session); else if (ssl->psksession != NULL) @@ -265,6 +259,11 @@ int SSL_process_quic_post_handshake(SSL *ssl) return 0; } + /* + * This is always safe (we are sure to be at a record boundary) because + * SSL_read()/SSL_write() are never used for QUIC connections -- the + * application data is handled at the QUIC layer instead. + */ ossl_statem_set_in_init(ssl, 1); ret = ssl->handshake_func(ssl); ossl_statem_set_in_init(ssl, 0); @@ -278,5 +277,3 @@ int SSL_is_quic(SSL* ssl) { return SSL_IS_QUIC(ssl); } - -#endif diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index 3e763611993ec..06ccd855a092c 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1922,7 +1922,7 @@ int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context, #ifndef OPENSSL_NO_QUIC /* * QUIC server must send 0xFFFFFFFF or it's a PROTOCOL_VIOLATION - * per draft-ietf-quic-tls-24 S4.5 + * per draft-ietf-quic-tls-27 S4.5 */ if (s->quic_method != NULL && max_early_data != 0xFFFFFFFF) { SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_INVALID_MAX_EARLY_DATA); diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 198b48ea9cb4f..afe61e56d9d6d 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1896,7 +1896,7 @@ EXT_RETURN tls_construct_stoc_early_data(SSL *s, WPACKET *pkt, return EXT_RETURN_NOT_SENT; #ifndef OPENSSL_NO_QUIC - /* QUIC server must always send 0xFFFFFFFF, per draft-ietf-quic-tls-24 S4.5 */ + /* QUIC server must always send 0xFFFFFFFF, per draft-ietf-quic-tls-27 S4.5 */ if (s->quic_method != NULL) max_early_data = 0xFFFFFFFF; #endif diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c index f6caa64e4ce5b..b040d14cd244d 100644 --- a/ssl/statem/statem.c +++ b/ssl/statem/statem.c @@ -585,6 +585,7 @@ static SUB_STATE_RETURN read_state_machine(SSL *s) ret = dtls_get_message(s, &mt); #ifndef OPENSSL_NO_QUIC } else if (SSL_IS_QUIC(s)) { + /* QUIC behaves like DTLS -- all in one go. */ ret = quic_get_message(s, &mt, &len); #endif } else { @@ -929,7 +930,6 @@ int statem_flush(SSL *s) #ifndef OPENSSL_NO_QUIC if (SSL_IS_QUIC(s)) { if (!s->quic_method->flush_flight(s)) { - /* NOTE: BIO_flush() does not generate an error */ SSLerr(SSL_F_STATEM_FLUSH, ERR_R_INTERNAL_ERROR); return 0; } diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index 1afe26be88b9b..950e66a0be91a 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -44,17 +44,24 @@ int ssl3_do_write(SSL *s, int type) { int ret; size_t written = 0; + #ifndef OPENSSL_NO_QUIC - if (SSL_IS_QUIC(s) && type == SSL3_RT_HANDSHAKE) { - ret = s->quic_method->add_handshake_data(s, s->quic_write_level, - (const uint8_t*)&s->init_buf->data[s->init_off], - s->init_num); - if (!ret) { - ret = -1; - /* QUIC can't sent anything out sice the above failed */ - SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_INTERNAL_ERROR); + if (SSL_IS_QUIC(s)) { + if (type == SSL3_RT_HANDSHAKE) { + ret = s->quic_method->add_handshake_data(s, s->quic_write_level, + (const uint8_t*)&s->init_buf->data[s->init_off], + s->init_num); + if (!ret) { + ret = -1; + /* QUIC can't sent anything out sice the above failed */ + SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_INTERNAL_ERROR); + } else { + written = s->init_num; + } } else { - written = s->init_num; + /* QUIC doesn't use ChangeCipherSpec */ + ret = -1; + SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); } } else #endif @@ -1183,7 +1190,6 @@ int tls_get_message_header(SSL *s, int *mt) do { while (s->init_num < SSL3_HM_HEADER_LENGTH) { - /* QUIC: either create a special ssl_read_bytes... or if/else this */ i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type, &p[s->init_num], SSL3_HM_HEADER_LENGTH - s->init_num, diff --git a/ssl/statem/statem_local.h b/ssl/statem/statem_local.h index 57e314512bdbd..6d5820e2cf225 100644 --- a/ssl/statem/statem_local.h +++ b/ssl/statem/statem_local.h @@ -104,7 +104,9 @@ __owur int tls_get_message_header(SSL *s, int *mt); __owur int tls_get_message_body(SSL *s, size_t *len); __owur int dtls_get_message(SSL *s, int *mt); __owur int dtls_get_message_body(SSL *s, size_t *len); +#ifndef OPENSSL_NO_QUIC __owur int quic_get_message(SSL *s, int *mt, size_t *len); +#endif /* Message construction and processing functions */ __owur int tls_process_initial_server_flight(SSL *s); diff --git a/ssl/statem/statem_quic.c b/ssl/statem/statem_quic.c index 982a9a62921a6..df38afbc795a0 100644 --- a/ssl/statem/statem_quic.c +++ b/ssl/statem/statem_quic.c @@ -11,10 +11,6 @@ #include "statem_local.h" #include "internal/cryptlib.h" -#ifdef OPENSSL_NO_QUIC -NON_EMPTY_TRANSLATION_UNIT -#else - int quic_get_message(SSL *s, int *mt, size_t *len) { size_t l; @@ -23,20 +19,26 @@ int quic_get_message(SSL *s, int *mt, size_t *len) if (qd == NULL || (qd->length - qd->offset) != 0) { s->rwstate = SSL_READING; - *len = 0; + *mt = *len = 0; + return 0; + } + + if (!ossl_assert(qd->length >= SSL3_HM_HEADER_LENGTH)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_LENGTH); + *mt = *len = 0; return 0; } /* This is where we check for the proper level, not when data is given */ if (qd->level != s->quic_read_level) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); - *len = 0; + *mt = *len = 0; return 0; } if (!BUF_MEM_grow_clean(s->init_buf, (int)qd->length)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_BUF_LIB); - *len = 0; + *mt = *len = 0; return 0; } @@ -79,8 +81,8 @@ int quic_get_message(SSL *s, int *mt, size_t *len) */ #define SERVER_HELLO_RANDOM_OFFSET (SSL3_HM_HEADER_LENGTH + 2) /* KeyUpdate and NewSessionTicket do not need to be added */ - if (!SSL_IS_TLS13(s) || (s->s3.tmp.message_type != SSL3_MT_NEWSESSION_TICKET - && s->s3.tmp.message_type != SSL3_MT_KEY_UPDATE)) { + if (s->s3.tmp.message_type != SSL3_MT_NEWSESSION_TICKET + && s->s3.tmp.message_type != SSL3_MT_KEY_UPDATE) { if (s->s3.tmp.message_type != SSL3_MT_SERVER_HELLO || s->init_num < SERVER_HELLO_RANDOM_OFFSET + SSL3_RANDOM_SIZE || memcmp(hrrrandom, @@ -101,5 +103,3 @@ int quic_get_message(SSL *s, int *mt, size_t *len) return 1; } - -#endif diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c index 569a17586ebc4..643d2dbfd7134 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -419,6 +419,7 @@ static const unsigned char exporter_master_secret[] = "exp master"; static const unsigned char resumption_master_secret[] = "res master"; static const unsigned char early_exporter_master_secret[] = "e exp master"; #endif + #ifndef OPENSSL_NO_QUIC static int quic_change_cipher_state(SSL *s, int which) { @@ -427,7 +428,7 @@ static int quic_change_cipher_state(SSL *s, int which) int hashleni; int ret = 0; const EVP_MD *md = NULL; - OSSL_ENCRYPTION_LEVEL level = ssl_encryption_initial; + OSSL_ENCRYPTION_LEVEL level; int is_handshake = ((which & SSL3_CC_HANDSHAKE) == SSL3_CC_HANDSHAKE); int is_client_read = ((which & SSL3_CHANGE_CIPHER_CLIENT_READ) == SSL3_CHANGE_CIPHER_CLIENT_READ); int is_server_write = ((which & SSL3_CHANGE_CIPHER_SERVER_WRITE) == SSL3_CHANGE_CIPHER_SERVER_WRITE); @@ -450,34 +451,62 @@ static int quic_change_cipher_state(SSL *s, int which) if (is_client_read || is_server_write) { if (is_handshake) { + /* + * This looks a bit weird, since the condition is basically "the + * server is writing" but we set both the server *and* client + * handshake traffic keys here. That's because there's only a fixed + * number of change-cipher-state events in the TLS 1.3 handshake, + * and in particular there's not an event in between when the server + * writes encrypted handshake messages and when the client writes + * encrypted handshake messages, so we generate both here. + */ level = ssl_encryption_handshake; - if (!tls13_hkdf_expand(s, md, s->handshake_secret, client_handshake_traffic, - sizeof(client_handshake_traffic)-1, hash, hashlen, - s->client_hand_traffic_secret, hashlen, 1) - || !ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL, s->client_hand_traffic_secret, hashlen) - || !tls13_derive_finishedkey(s, md, s->client_hand_traffic_secret, + if (!tls13_hkdf_expand(s, md, s->handshake_secret, + client_handshake_traffic, + sizeof(client_handshake_traffic)-1, hash, + hashlen, s->client_hand_traffic_secret, + hashlen, 1) + || !ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL, + s->client_hand_traffic_secret, hashlen) + || !tls13_derive_finishedkey(s, md, + s->client_hand_traffic_secret, s->client_finished_secret, hashlen) - || !tls13_hkdf_expand(s, md, s->handshake_secret, server_handshake_traffic, - sizeof(server_handshake_traffic)-1, hash, hashlen, - s->server_hand_traffic_secret, hashlen, 1) - || !ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, s->server_hand_traffic_secret, hashlen) - || !tls13_derive_finishedkey(s, md, s->server_hand_traffic_secret, - s->server_finished_secret, hashlen)) { + || !tls13_hkdf_expand(s, md, s->handshake_secret, + server_handshake_traffic, + sizeof(server_handshake_traffic)-1, hash, + hashlen, s->server_hand_traffic_secret, + hashlen, 1) + || !ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, + s->server_hand_traffic_secret, hashlen) + || !tls13_derive_finishedkey(s, md, + s->server_hand_traffic_secret, + s->server_finished_secret, + hashlen)) { /* SSLfatal() already called */ goto err; } } else { + /* + * As above, we generate both sets of application traffic keys at + * the same time. + */ level = ssl_encryption_application; - if (!tls13_hkdf_expand(s, md, s->master_secret, client_application_traffic, - sizeof(client_application_traffic)-1, hash, hashlen, - s->client_app_traffic_secret, hashlen, 1) - || !ssl_log_secret(s, CLIENT_APPLICATION_LABEL, s->client_app_traffic_secret, hashlen) - || !tls13_hkdf_expand(s, md, s->master_secret, server_application_traffic, - sizeof(server_application_traffic)-1, hash, hashlen, + if (!tls13_hkdf_expand(s, md, s->master_secret, + client_application_traffic, + sizeof(client_application_traffic)-1, hash, + hashlen, s->client_app_traffic_secret, + hashlen, 1) + || !ssl_log_secret(s, CLIENT_APPLICATION_LABEL, + s->client_app_traffic_secret, hashlen) + || !tls13_hkdf_expand(s, md, s->master_secret, + server_application_traffic, + sizeof(server_application_traffic)-1, + hash, hashlen, s->server_app_traffic_secret, hashlen, 1) - || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)) { + || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, + s->server_app_traffic_secret, hashlen)) { /* SSLfatal() already called */ goto err; } @@ -497,9 +526,11 @@ static int quic_change_cipher_state(SSL *s, int which) level = ssl_encryption_early_data; if (!tls13_hkdf_expand(s, md, s->early_secret, client_early_traffic, - sizeof(client_early_traffic)-1, hash, hashlen, - s->client_early_traffic_secret, hashlen, 1) - || !ssl_log_secret(s, CLIENT_EARLY_LABEL, s->client_early_traffic_secret, hashlen) + sizeof(client_early_traffic)-1, hash, + hashlen, s->client_early_traffic_secret, + hashlen, 1) + || !ssl_log_secret(s, CLIENT_EARLY_LABEL, + s->client_early_traffic_secret, hashlen) || !quic_set_encryption_secrets(s, level)) { /* SSLfatal() already called */ goto err; @@ -512,9 +543,11 @@ static int quic_change_cipher_state(SSL *s, int which) * We also create the resumption master secret, but this time use the * hash for the whole handshake including the Client Finished */ - if (!tls13_hkdf_expand(s, md, s->master_secret, resumption_master_secret, - sizeof(resumption_master_secret)-1, hash, hashlen, - s->resumption_master_secret, hashlen, 1)) { + if (!tls13_hkdf_expand(s, md, s->master_secret, + resumption_master_secret, + sizeof(resumption_master_secret)-1, hash, + hashlen, s->resumption_master_secret, + hashlen, 1)) { /* SSLfatal() already called */ goto err; } @@ -531,6 +564,7 @@ static int quic_change_cipher_state(SSL *s, int which) return ret; } #endif /* OPENSSL_NO_QUIC */ + int tls13_change_cipher_state(SSL *s, int which) { unsigned char *iv; diff --git a/test/sslapitest.c b/test/sslapitest.c index 80ccd20216c0c..082081f1b533c 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10416,9 +10416,11 @@ static int test_handshake_retry(int idx) } #ifndef OPENSSL_NO_QUIC -static int test_quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, +static int test_quic_set_encryption_secrets(SSL *ssl, + OSSL_ENCRYPTION_LEVEL level, const uint8_t *read_secret, - const uint8_t *write_secret, size_t secret_len) + const uint8_t *write_secret, + size_t secret_len) { test_printf_stderr("quic_set_encryption_secrets() %s, lvl=%d, len=%zd\n", ssl->server ? "server" : "client", level, secret_len); @@ -10430,11 +10432,12 @@ static int test_quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, { SSL *peer = (SSL*)SSL_get_app_data(ssl); - test_printf_stderr("quic_add_handshake_data() %s, lvl=%d, *data=0x%02X, len=%zd\n", - ssl->server ? "server" : "client", level, (int)*data, len); + TEST_info("quic_add_handshake_data() %s, lvl=%d, *data=0x%02X, len=%zd\n", + ssl->server ? "server" : "client", level, (int)*data, len); if (!TEST_ptr(peer)) return 0; + /* We're called with what is locally written; this gives it to the peer */ if (!TEST_true(SSL_provide_quic_data(peer, level, data, len))) { ERR_print_errors_fp(stderr); return 0; diff --git a/util/libssl.num b/util/libssl.num index 72ee0bedc6a2a..da35cf297088a 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -522,7 +522,7 @@ SSL_CTX_set0_tmp_dh_pkey 522 3_0_0 EXIST::FUNCTION: SSL_group_to_name 523 3_0_0 EXIST::FUNCTION: SSL_quic_read_level 20000 3_0_0 EXIST::FUNCTION:QUIC SSL_set_quic_transport_params 20001 3_0_0 EXIST::FUNCTION:QUIC -SSL_CIPHER_get_prf_nid 20002 3_0_0 EXIST::FUNCTION: +SSL_CIPHER_get_prf_nid 20002 3_0_0 EXIST::FUNCTION:QUIC SSL_is_quic 20003 3_0_0 EXIST::FUNCTION:QUIC SSL_get_peer_quic_transport_params 20004 3_0_0 EXIST::FUNCTION:QUIC SSL_quic_write_level 20005 3_0_0 EXIST::FUNCTION:QUIC From 18fef6a5fae8b14ea83ef019796b74bea0b73a7e Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Mon, 11 May 2020 13:13:01 -0700 Subject: [PATCH 22/66] QUIC: Prevent KeyUpdate for QUIC QUIC does not use the TLS KeyUpdate message/mechanism, and indeed it is an error to generate or receive such a message. Add the necessary checks (noting that the check for receipt should be redundant since SSL_provide_quic_data() is the only way to provide input to the TLS layer for a QUIC connection). --- ssl/ssl_quic.c | 6 ++++++ ssl/statem/statem_lib.c | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index 95b3a8b64e119..7b78b2ec5343b 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -92,6 +92,7 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, const uint8_t *data, size_t len) { size_t l; + uint8_t mt; if (!SSL_IS_QUIC(ssl)) { SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); @@ -131,9 +132,14 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, return 0; } /* TLS Handshake message header has 1-byte type and 3-byte length */ + mt = *data; p = data + 1; n2l3(p, l); l += SSL3_HM_HEADER_LENGTH; + if (mt == SSL3_MT_KEY_UPDATE) { + SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_UNEXPECTED_MESSAGE); + return 0; + } qd = OPENSSL_zalloc(sizeof(QUIC_DATA) + l); if (qd == NULL) { diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index 950e66a0be91a..c3f6465f6aadf 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -662,6 +662,13 @@ int tls_construct_finished(SSL *s, WPACKET *pkt) int tls_construct_key_update(SSL *s, WPACKET *pkt) { +#ifndef OPENSSL_NO_QUIC + if (SSL_is_quic(s)) { + /* TLS KeyUpdate is not used for QUIC, so this is an error. */ + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } +#endif if (!WPACKET_put_bytes_u8(pkt, s->key_update)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return 0; @@ -684,6 +691,13 @@ MSG_PROCESS_RETURN tls_process_key_update(SSL *s, PACKET *pkt) return MSG_PROCESS_ERROR; } +#ifndef OPENSSL_NO_QUIC + if (SSL_is_quic(s)) { + SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE); + return MSG_PROCESS_ERROR; + } +#endif + if (!PACKET_get_1(pkt, &updatetype) || PACKET_remaining(pkt) != 0) { SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_KEY_UPDATE); From d984e205919fd0ee8ee426bccca1b5c0dc4cd016 Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Mon, 11 May 2020 13:26:07 -0700 Subject: [PATCH 23/66] QUIC: Test KeyUpdate rejection For now, just test that we don't generate any, since we don't really expose the mechanics for encrypting one and the QUIC API is not integrated into the TLSProxy setup. --- test/sslapitest.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/sslapitest.c b/test/sslapitest.c index 082081f1b533c..ab12539dfd5ba 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10540,6 +10540,17 @@ static int test_quic_api(void) || !TEST_true(SSL_process_quic_post_handshake(clientssl))) goto end; + /* Dummy handshake call should succeed */ + if (!TEST_true(SSL_do_handshake(clientssl))) + goto end; + /* Test that we (correctly) fail to send KeyUpdate */ + if (!TEST_true(SSL_key_update(clientssl, SSL_KEY_UPDATE_NOT_REQUESTED)) + || !TEST_int_le(SSL_do_handshake(clientssl), 0)) + goto end; + if (!TEST_true(SSL_key_update(serverssl, SSL_KEY_UPDATE_NOT_REQUESTED)) + || !TEST_int_le(SSL_do_handshake(serverssl), 0)) + goto end; + testresult = 1; end: From 7784a86b98b6a896949de0eaf0aab336d196253c Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Mon, 31 Aug 2020 12:27:33 -0700 Subject: [PATCH 24/66] QUIC: Buffer all provided quic data Make all data supplied via SSL_provide_quic_data() pass through an internal buffer, so that we can handle data supplied with arbitrary framing and only parse complete TLS records onto the list of QUIC_DATA managed by quic_input_data_head/quic_input_data_tail. This lets us remove the concept of "incomplete" QUIC_DATA structures, and the 'offset' field needed to support them. However, we've already moved the provided data onto the buffer by the time we can check for KeyUpdate messages, so defer that check to quic_get_message() (where it is adjacent to the preexisting ChangeCipherSpec check). To avoid extra memory copies, we also make the QUIC_DATA structures just store offsets into the consolidated buffer instead of having copies of the TLS handshake messages themselves. --- ssl/ssl_lib.c | 1 + ssl/ssl_local.h | 5 +-- ssl/ssl_quic.c | 75 +++++++++++++++++++--------------------- ssl/statem/statem_quic.c | 11 ++++-- 4 files changed, 49 insertions(+), 43 deletions(-) diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 223f6078e10b3..d5191794f60ec 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1247,6 +1247,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); + BUF_MEM_free(s->quic_buf); while (s->quic_input_data_head != NULL) { QUIC_DATA *qd; diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index a5eff6726c205..a4e546197d318 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -1225,9 +1225,8 @@ typedef struct cert_pkey_st CERT_PKEY; struct quic_data_st { struct quic_data_st *next; OSSL_ENCRYPTION_LEVEL level; - size_t offset; + size_t start; /* offset into quic_buf->data */ size_t length; - /* char data[]; should be here but C90 VLAs not allowed here */ }; typedef struct quic_data_st QUIC_DATA; int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level); @@ -1721,8 +1720,10 @@ struct ssl_st { #ifndef OPENSSL_NO_QUIC OSSL_ENCRYPTION_LEVEL quic_read_level; OSSL_ENCRYPTION_LEVEL quic_write_level; + BUF_MEM *quic_buf; /* buffer incoming handshake messages */ QUIC_DATA *quic_input_data_head; QUIC_DATA *quic_input_data_tail; + size_t quic_next_record_start; const SSL_QUIC_METHOD *quic_method; #endif /* diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index 7b78b2ec5343b..e3967205518e1 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -91,8 +91,7 @@ OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl) int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, const uint8_t *data, size_t len) { - size_t l; - uint8_t mt; + size_t l, offset; if (!SSL_IS_QUIC(ssl)) { SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); @@ -106,42 +105,46 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, return 0; } - /* Split on handshake message boundaries, if necessary */ - while (len > 0) { - QUIC_DATA *qd; - const uint8_t *p; - - /* Check for an incomplete block */ - qd = ssl->quic_input_data_tail; - if (qd != NULL) { - l = qd->length - qd->offset; - if (l != 0) { - /* we still need to copy `l` bytes into the last data block */ - if (l > len) - l = len; - memcpy((char*)(qd+1) + qd->offset, data, l); - qd->offset += l; - len -= l; - data += l; - continue; - } + if (ssl->quic_buf == NULL) { + BUF_MEM *buf; + if ((buf = BUF_MEM_new()) == NULL) { + SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); + return 0; } - - if (len < SSL3_HM_HEADER_LENGTH) { - SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_BAD_LENGTH); + if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { + SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); + BUF_MEM_free(buf); return 0; } + ssl->quic_buf = buf; + /* We preallocated storage, but there's still no *data*. */ + ssl->quic_buf->length = 0; + buf = NULL; + } + + offset = ssl->quic_buf->length; + if (!BUF_MEM_grow(ssl->quic_buf, offset + len)) { + SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); + return 0; + } + memcpy(ssl->quic_buf->data + offset, data, len); + + /* Split on handshake message boundaries */ + while (ssl->quic_buf->length > ssl->quic_next_record_start + + SSL3_HM_HEADER_LENGTH) { + QUIC_DATA *qd; + const uint8_t *p; + /* TLS Handshake message header has 1-byte type and 3-byte length */ - mt = *data; - p = data + 1; + p = (const uint8_t *)ssl->quic_buf->data + + ssl->quic_next_record_start + 1; n2l3(p, l); l += SSL3_HM_HEADER_LENGTH; - if (mt == SSL3_MT_KEY_UPDATE) { - SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_UNEXPECTED_MESSAGE); - return 0; - } + /* Don't allocate a QUIC_DATA if we don't have a full record */ + if (l > ssl->quic_buf->length - ssl->quic_next_record_start) + break; - qd = OPENSSL_zalloc(sizeof(QUIC_DATA) + l); + qd = OPENSSL_zalloc(sizeof(*qd)); if (qd == NULL) { SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); return 0; @@ -149,21 +152,15 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, qd->next = NULL; qd->length = l; + qd->start = ssl->quic_next_record_start; qd->level = level; - /* partial data received? */ - if (l > len) - l = len; - qd->offset = l; - memcpy((void*)(qd + 1), data, l); if (ssl->quic_input_data_tail != NULL) ssl->quic_input_data_tail->next = qd; else ssl->quic_input_data_head = qd; ssl->quic_input_data_tail = qd; - - data += l; - len -= l; + ssl->quic_next_record_start += l; } return 1; diff --git a/ssl/statem/statem_quic.c b/ssl/statem/statem_quic.c index df38afbc795a0..a371eeaedbf81 100644 --- a/ssl/statem/statem_quic.c +++ b/ssl/statem/statem_quic.c @@ -17,7 +17,7 @@ int quic_get_message(SSL *s, int *mt, size_t *len) QUIC_DATA *qd = s->quic_input_data_head; uint8_t *p; - if (qd == NULL || (qd->length - qd->offset) != 0) { + if (qd == NULL) { s->rwstate = SSL_READING; *mt = *len = 0; return 0; @@ -43,7 +43,7 @@ int quic_get_message(SSL *s, int *mt, size_t *len) } /* Copy buffered data */ - memcpy(s->init_buf->data, (void*)(qd + 1), qd->length); + memcpy(s->init_buf->data, s->quic_buf->data + qd->start, qd->length); s->init_buf->length = qd->length; s->quic_input_data_head = qd->next; if (s->quic_input_data_head == NULL) @@ -62,6 +62,13 @@ int quic_get_message(SSL *s, int *mt, size_t *len) *len = 0; return 0; } + /* No KeyUpdate in QUIC */ + if (*mt == SSL3_MT_KEY_UPDATE) { + SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE); + *len = 0; + return 0; + } + /* * If receiving Finished, record MAC of prior handshake messages for From 0d9a92a201d3a346381214d7bc8df32436038678 Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Tue, 1 Sep 2020 15:10:41 -0700 Subject: [PATCH 25/66] QUIC: Enforce consistent encryption level for handshake messages The QUIC-TLS spec requires that TLS handshake messages do not cross encryption level boundaries, but we were not previously enforcing this. --- ssl/ssl_local.h | 1 + ssl/ssl_quic.c | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index a4e546197d318..0e68bbcc2f267 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -1720,6 +1720,7 @@ struct ssl_st { #ifndef OPENSSL_NO_QUIC OSSL_ENCRYPTION_LEVEL quic_read_level; OSSL_ENCRYPTION_LEVEL quic_write_level; + OSSL_ENCRYPTION_LEVEL quic_latest_level_received; 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 e3967205518e1..136d2b84600ef 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -100,7 +100,8 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, /* Level can be different than the current read, but not less */ if (level < ssl->quic_read_level - || (ssl->quic_input_data_tail != NULL && level < ssl->quic_input_data_tail->level)) { + || (ssl->quic_input_data_tail != NULL && level < ssl->quic_input_data_tail->level) + || level < ssl->quic_latest_level_received) { SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); return 0; } @@ -122,6 +123,15 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, buf = NULL; } + /* A TLS message must not cross an encryption level boundary */ + if (ssl->quic_buf->length != ssl->quic_next_record_start + && level != ssl->quic_latest_level_received) { + SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, + SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); + return 0; + } + ssl->quic_latest_level_received = level; + offset = ssl->quic_buf->length; if (!BUF_MEM_grow(ssl->quic_buf, offset + len)) { SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); From 8339434507d932aba39d8bff29f4e8968a2cd719 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Sat, 12 Dec 2020 17:27:46 +0900 Subject: [PATCH 26/66] QUIC: add v1 quic_transport_parameters --- crypto/err/openssl.txt | 2 + doc/man3/SSL_CTX_set_quic_method.pod | 25 +++++- include/openssl/ssl.h.in | 13 ++++ include/openssl/sslerr.h | 1 + include/openssl/tls1.h | 3 +- ssl/ssl_err.c | 2 + ssl/ssl_lib.c | 1 + ssl/ssl_local.h | 11 +++ ssl/ssl_quic.c | 41 +++++++++- ssl/statem/extensions.c | 39 ++++++++++ ssl/statem/extensions_clnt.c | 44 ++++++++++- ssl/statem/extensions_srvr.c | 46 ++++++++++- ssl/statem/statem_local.h | 17 +++++ test/sslapitest.c | 110 +++++++++++++++++++++------ util/libssl.num | 4 + 15 files changed, 322 insertions(+), 37 deletions(-) diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index e537738c4c6ac..e380afc3b2e8c 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1387,6 +1387,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 3d7bf7e682137..39ff3a8da4517 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.in b/include/openssl/ssl.h.in index 582e45f31be73..89d82406c2bef 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2562,6 +2562,19 @@ __owur int SSL_process_quic_post_handshake(SSL *ssl); __owur int SSL_is_quic(SSL *ssl); +/* BoringSSL API */ +__owur 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 a60076ee93ea0..05cb3d5173e99 100644 --- a/include/openssl/sslerr.h +++ b/include/openssl/sslerr.h @@ -162,6 +162,7 @@ # 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 20e39fb571166..2669203a28fed 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -152,7 +152,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 0210a73ad54a9..486cc579931ac 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -242,6 +242,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 d5191794f60ec..3c06fd0f375ee 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1246,6 +1246,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 0e68bbcc2f267..839e7b69a2947 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -773,6 +773,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, @@ -1712,6 +1713,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 @@ -1722,6 +1725,14 @@ struct ssl_st { OSSL_ENCRYPTION_LEVEL quic_write_level; OSSL_ENCRYPTION_LEVEL quic_latest_level_received; BUF_MEM *quic_buf; /* buffer incoming handshake messages */ + /* + * 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; QUIC_DATA *quic_input_data_head; QUIC_DATA *quic_input_data_tail; size_t quic_next_record_start; diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index 136d2b84600ef..971af0f4c5d96 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 81181635c4959..eea187b6bf5bc 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -61,6 +61,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 @@ -375,6 +376,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 @@ -1752,8 +1762,37 @@ 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_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 06ccd855a092c..6da3cc560f070 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1197,13 +1197,33 @@ 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, 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; } @@ -2013,7 +2033,23 @@ 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, 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 afe61e56d9d6d..85f8aa35c2850 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1233,7 +1233,22 @@ int tls_parse_ctos_post_handshake_auth(SSL *s, PACKET *pkt, } #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, 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) { @@ -1943,13 +1958,36 @@ 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, 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 6d5820e2cf225..0065db1744c63 100644 --- a/ssl/statem/statem_local.h +++ b/ssl/statem/statem_local.h @@ -255,6 +255,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 @@ -319,6 +323,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); @@ -393,6 +402,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); @@ -441,6 +454,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 ab12539dfd5ba..bec2edf5ae9f7 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10466,7 +10466,13 @@ static SSL_QUIC_METHOD quic_method = { 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; @@ -10477,29 +10483,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_ex(libctx, NULL, 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(libctx, TLS_server_method(), @@ -10518,6 +10502,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) @@ -10551,11 +10537,85 @@ 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: 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_ex(libctx, NULL, 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 /* OPENSSL_NO_QUIC */ OPT_TEST_DECLARE_USAGE("certfile privkeyfile srpvfile tmpfile provider config dhfile\n") @@ -10831,7 +10891,7 @@ int setup_tests(void) #endif ADD_ALL_TESTS(test_handshake_retry, 16); #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 da35cf297088a..41ebba40b20ed 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -531,3 +531,7 @@ SSL_set_quic_method 20007 3_0_0 EXIST::FUNCTION:QUIC SSL_quic_max_handshake_flight_len 20008 3_0_0 EXIST::FUNCTION:QUIC SSL_process_quic_post_handshake 20009 3_0_0 EXIST::FUNCTION:QUIC SSL_provide_quic_data 20010 3_0_0 EXIST::FUNCTION:QUIC +SSL_set_quic_use_legacy_codepoint 20011 3_0_0 EXIST::FUNCTION:QUIC +SSL_set_quic_transport_version 20012 3_0_0 EXIST::FUNCTION:QUIC +SSL_get_peer_quic_transport_version 20013 3_0_0 EXIST::FUNCTION:QUIC +SSL_get_quic_transport_version 20014 3_0_0 EXIST::FUNCTION:QUIC From c40f07dc7583accd6d1fe64b4cefb156853931f2 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 5 Jan 2021 13:50:21 -0500 Subject: [PATCH 27/66] QUIC: return success when no post-handshake data --- ssl/ssl_quic.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index 971af0f4c5d96..477a386da36f3 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -309,6 +309,10 @@ int SSL_process_quic_post_handshake(SSL *ssl) return 0; } + /* if there is no data, return success as BoringSSL */ + if (ssl->quic_input_data_head == NULL) + return 1; + /* * This is always safe (we are sure to be at a record boundary) because * SSL_read()/SSL_write() are never used for QUIC connections -- the From 31574c05f95da21be039bce8dc01051457fb9efe Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Fri, 15 Jan 2021 15:04:00 -0800 Subject: [PATCH 28/66] QUIC: __owur makes no sense for void return values --- include/openssl/ssl.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in index 89d82406c2bef..010283452059a 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2563,7 +2563,7 @@ __owur int SSL_process_quic_post_handshake(SSL *ssl); __owur int SSL_is_quic(SSL *ssl); /* BoringSSL API */ -__owur void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy); +void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy); /* * Set an explicit value that you want to use From 6efb5bec719f2214bb012876ab3b0b5d8a28b9d0 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 19 Feb 2021 10:12:15 -0500 Subject: [PATCH 29/66] QUIC: remove SSL_R_BAD_DATA_LENGTH (unused) --- crypto/err/openssl.txt | 1 - include/openssl/sslerr.h | 1 - ssl/ssl_err.c | 1 - 3 files changed, 3 deletions(-) diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index e380afc3b2e8c..d62ee33ecc77f 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1249,7 +1249,6 @@ SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE:158:\ SSL_R_BAD_CHANGE_CIPHER_SPEC:103:bad change cipher spec SSL_R_BAD_CIPHER:186:bad cipher SSL_R_BAD_DATA:390:bad data -SSL_R_BAD_DATA_LENGTH:802:bad data length SSL_R_BAD_DATA_RETURNED_BY_CALLBACK:106:bad data returned by callback SSL_R_BAD_DECOMPRESSION:107:bad decompression SSL_R_BAD_DH_VALUE:102:bad dh value diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h index 05cb3d5173e99..3d07ecc813543 100644 --- a/include/openssl/sslerr.h +++ b/include/openssl/sslerr.h @@ -28,7 +28,6 @@ # define SSL_R_BAD_CHANGE_CIPHER_SPEC 103 # define SSL_R_BAD_CIPHER 186 # define SSL_R_BAD_DATA 390 -# define SSL_R_BAD_DATA_LENGTH 802 # define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK 106 # define SSL_R_BAD_DECOMPRESSION 107 # define SSL_R_BAD_DH_VALUE 102 diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 486cc579931ac..79c2ed95c1859 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -27,7 +27,6 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { "bad change cipher spec"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CIPHER), "bad cipher"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA), "bad data"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_LENGTH), "bad data length"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK), "bad data returned by callback"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DECOMPRESSION), "bad decompression"}, From 98b9ee1119f5921fc370a5072f1f19e84a93c79c Mon Sep 17 00:00:00 2001 From: Todd Short Date: Wed, 3 Mar 2021 11:44:27 -0500 Subject: [PATCH 30/66] QUIC: Update shared library version Prefix the shared library version with 17 (for 'Q'), to allow this version to be used alongside a standard OpenSSL distribution Add +quic to the version (i.e. build metadata) --- VERSION.dat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION.dat b/VERSION.dat index 9d9448118e6dc..d416c3662e5dd 100644 --- a/VERSION.dat +++ b/VERSION.dat @@ -2,6 +2,6 @@ MAJOR=3 MINOR=0 PATCH=12 PRE_RELEASE_TAG= -BUILD_METADATA= +BUILD_METADATA=quic RELEASE_DATE="24 Oct 2023" -SHLIB_VERSION=3 +SHLIB_VERSION=81.3 From 212fa40f31d70a9e820ed5ab9ea5872095469661 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Wed, 3 Mar 2021 15:44:11 -0500 Subject: [PATCH 31/66] QUIC: Swap around README files --- README-OpenSSL.md | 224 ++++++++++++++++++++++++++++++++ README.md | 322 ++++++++++++++-------------------------------- 2 files changed, 324 insertions(+), 222 deletions(-) create mode 100644 README-OpenSSL.md diff --git a/README-OpenSSL.md b/README-OpenSSL.md new file mode 100644 index 0000000000000..b848d050132aa --- /dev/null +++ b/README-OpenSSL.md @@ -0,0 +1,224 @@ +Welcome to the OpenSSL Project +============================== + +[![openssl logo]][www.openssl.org] + +[![github actions ci badge]][github actions ci] +[![appveyor badge]][appveyor jobs] + +OpenSSL is a robust, commercial-grade, full-featured Open Source Toolkit +for the Transport Layer Security (TLS) protocol formerly known as the +Secure Sockets Layer (SSL) protocol. The protocol implementation is based +on a full-strength general purpose cryptographic library, which can also +be used stand-alone. + +OpenSSL is descended from the SSLeay library developed by Eric A. Young +and Tim J. Hudson. + +The official Home Page of the OpenSSL Project is [www.openssl.org]. + +Table of Contents +================= + + - [Overview](#overview) + - [Download](#download) + - [Build and Install](#build-and-install) + - [Documentation](#documentation) + - [License](#license) + - [Support](#support) + - [Contributing](#contributing) + - [Legalities](#legalities) + +Overview +======== + +The OpenSSL toolkit includes: + +- **libssl** + an implementation of all TLS protocol versions up to TLSv1.3 ([RFC 8446]). + +- **libcrypto** + a full-strength general purpose cryptographic library. It constitutes the + basis of the TLS implementation, but can also be used independently. + +- **openssl** + the OpenSSL command line tool, a swiss army knife for cryptographic tasks, + testing and analyzing. It can be used for + - creation of key parameters + - creation of X.509 certificates, CSRs and CRLs + - calculation of message digests + - encryption and decryption + - SSL/TLS client and server tests + - handling of S/MIME signed or encrypted mail + - and more... + +Download +======== + +For Production Use +------------------ + +Source code tarballs of the official releases can be downloaded from +[www.openssl.org/source](https://www.openssl.org/source). +The OpenSSL project does not distribute the toolkit in binary form. + +However, for a large variety of operating systems precompiled versions +of the OpenSSL toolkit are available. In particular on Linux and other +Unix operating systems it is normally recommended to link against the +precompiled shared libraries provided by the distributor or vendor. + +For Testing and Development +--------------------------- + +Although testing and development could in theory also be done using +the source tarballs, having a local copy of the git repository with +the entire project history gives you much more insight into the +code base. + +The official OpenSSL Git Repository is located at [git.openssl.org]. +There is a GitHub mirror of the repository at [github.com/openssl/openssl], +which is updated automatically from the former on every commit. + +A local copy of the Git Repository can be obtained by cloning it from +the original OpenSSL repository using + + git clone git://git.openssl.org/openssl.git + +or from the GitHub mirror using + + git clone https://github.com/openssl/openssl.git + +If you intend to contribute to OpenSSL, either to fix bugs or contribute +new features, you need to fork the OpenSSL repository openssl/openssl on +GitHub and clone your public fork instead. + + git clone https://github.com/yourname/openssl.git + +This is necessary, because all development of OpenSSL nowadays is done via +GitHub pull requests. For more details, see [Contributing](#contributing). + +Build and Install +================= + +After obtaining the Source, have a look at the [INSTALL](INSTALL.md) file for +detailed instructions about building and installing OpenSSL. For some +platforms, the installation instructions are amended by a platform specific +document. + + * [Notes for UNIX-like platforms](NOTES-UNIX.md) + * [Notes for Android platforms](NOTES-ANDROID.md) + * [Notes for Windows platforms](NOTES-WINDOWS.md) + * [Notes for the DOS platform with DJGPP](NOTES-DJGPP.md) + * [Notes for the OpenVMS platform](NOTES-VMS.md) + * [Notes on Perl](NOTES-PERL.md) + * [Notes on Valgrind](NOTES-VALGRIND.md) + +Specific notes on upgrading to OpenSSL 3.0 from previous versions can be found +in the [migration_guide(7ossl)] manual page. + +Documentation +============= + +Manual Pages +------------ + +The manual pages for the master branch and all current stable releases are +available online. + +- [OpenSSL master](https://www.openssl.org/docs/manmaster) +- [OpenSSL 3.0](https://www.openssl.org/docs/man3.0) +- [OpenSSL 1.1.1](https://www.openssl.org/docs/man1.1.1) + +Wiki +---- + +There is a Wiki at [wiki.openssl.org] which is currently not very active. +It contains a lot of useful information, not all of which is up to date. + +License +======= + +OpenSSL is licensed under the Apache License 2.0, which means that +you are free to get and use it for commercial and non-commercial +purposes as long as you fulfill its conditions. + +See the [LICENSE.txt](LICENSE.txt) file for more details. + +Support +======= + +There are various ways to get in touch. The correct channel depends on +your requirement. see the [SUPPORT](SUPPORT.md) file for more details. + +Contributing +============ + +If you are interested and willing to contribute to the OpenSSL project, +please take a look at the [CONTRIBUTING](CONTRIBUTING.md) file. + +Legalities +========== + +A number of nations restrict the use or export of cryptography. If you are +potentially subject to such restrictions you should seek legal advice before +attempting to develop or distribute cryptographic code. + +Copyright +========= + +Copyright (c) 1998-2023 The OpenSSL Project + +Copyright (c) 1995-1998 Eric A. Young, Tim J. Hudson + +All rights reserved. + + + +[www.openssl.org]: + + "OpenSSL Homepage" + +[git.openssl.org]: + + "OpenSSL Git Repository" + +[git.openssl.org]: + + "OpenSSL Git Repository" + +[github.com/openssl/openssl]: + + "OpenSSL GitHub Mirror" + +[wiki.openssl.org]: + + "OpenSSL Wiki" + +[migration_guide(7ossl)]: + + "OpenSSL Migration Guide" + +[RFC 8446]: + + + + +[openssl logo]: + doc/images/openssl.svg + "OpenSSL Logo" + +[github actions ci badge]: + + "GitHub Actions CI Status" + +[github actions ci]: + + "GitHub Actions CI" + +[appveyor badge]: + + "AppVeyor Build Status" + +[appveyor jobs]: + + "AppVeyor Jobs" diff --git a/README.md b/README.md index b848d050132aa..ef46c4b393a6c 100644 --- a/README.md +++ b/README.md @@ -1,224 +1,102 @@ -Welcome to the OpenSSL Project -============================== - -[![openssl logo]][www.openssl.org] - -[![github actions ci badge]][github actions ci] -[![appveyor badge]][appveyor jobs] - -OpenSSL is a robust, commercial-grade, full-featured Open Source Toolkit -for the Transport Layer Security (TLS) protocol formerly known as the -Secure Sockets Layer (SSL) protocol. The protocol implementation is based -on a full-strength general purpose cryptographic library, which can also -be used stand-alone. - -OpenSSL is descended from the SSLeay library developed by Eric A. Young -and Tim J. Hudson. - -The official Home Page of the OpenSSL Project is [www.openssl.org]. - -Table of Contents -================= - - - [Overview](#overview) - - [Download](#download) - - [Build and Install](#build-and-install) - - [Documentation](#documentation) - - [License](#license) - - [Support](#support) - - [Contributing](#contributing) - - [Legalities](#legalities) - -Overview -======== - -The OpenSSL toolkit includes: - -- **libssl** - an implementation of all TLS protocol versions up to TLSv1.3 ([RFC 8446]). - -- **libcrypto** - a full-strength general purpose cryptographic library. It constitutes the - basis of the TLS implementation, but can also be used independently. - -- **openssl** - the OpenSSL command line tool, a swiss army knife for cryptographic tasks, - testing and analyzing. It can be used for - - creation of key parameters - - creation of X.509 certificates, CSRs and CRLs - - calculation of message digests - - encryption and decryption - - SSL/TLS client and server tests - - handling of S/MIME signed or encrypted mail - - and more... - -Download -======== - -For Production Use ------------------- - -Source code tarballs of the official releases can be downloaded from -[www.openssl.org/source](https://www.openssl.org/source). -The OpenSSL project does not distribute the toolkit in binary form. - -However, for a large variety of operating systems precompiled versions -of the OpenSSL toolkit are available. In particular on Linux and other -Unix operating systems it is normally recommended to link against the -precompiled shared libraries provided by the distributor or vendor. - -For Testing and Development ---------------------------- - -Although testing and development could in theory also be done using -the source tarballs, having a local copy of the git repository with -the entire project history gives you much more insight into the -code base. - -The official OpenSSL Git Repository is located at [git.openssl.org]. -There is a GitHub mirror of the repository at [github.com/openssl/openssl], -which is updated automatically from the former on every commit. - -A local copy of the Git Repository can be obtained by cloning it from -the original OpenSSL repository using - - git clone git://git.openssl.org/openssl.git - -or from the GitHub mirror using - - git clone https://github.com/openssl/openssl.git - -If you intend to contribute to OpenSSL, either to fix bugs or contribute -new features, you need to fork the OpenSSL repository openssl/openssl on -GitHub and clone your public fork instead. - - git clone https://github.com/yourname/openssl.git - -This is necessary, because all development of OpenSSL nowadays is done via -GitHub pull requests. For more details, see [Contributing](#contributing). - -Build and Install -================= - -After obtaining the Source, have a look at the [INSTALL](INSTALL.md) file for -detailed instructions about building and installing OpenSSL. For some -platforms, the installation instructions are amended by a platform specific -document. - - * [Notes for UNIX-like platforms](NOTES-UNIX.md) - * [Notes for Android platforms](NOTES-ANDROID.md) - * [Notes for Windows platforms](NOTES-WINDOWS.md) - * [Notes for the DOS platform with DJGPP](NOTES-DJGPP.md) - * [Notes for the OpenVMS platform](NOTES-VMS.md) - * [Notes on Perl](NOTES-PERL.md) - * [Notes on Valgrind](NOTES-VALGRIND.md) - -Specific notes on upgrading to OpenSSL 3.0 from previous versions can be found -in the [migration_guide(7ossl)] manual page. - -Documentation -============= - -Manual Pages ------------- - -The manual pages for the master branch and all current stable releases are -available online. - -- [OpenSSL master](https://www.openssl.org/docs/manmaster) -- [OpenSSL 3.0](https://www.openssl.org/docs/man3.0) -- [OpenSSL 1.1.1](https://www.openssl.org/docs/man1.1.1) - -Wiki ----- - -There is a Wiki at [wiki.openssl.org] which is currently not very active. -It contains a lot of useful information, not all of which is up to date. - -License -======= - -OpenSSL is licensed under the Apache License 2.0, which means that -you are free to get and use it for commercial and non-commercial -purposes as long as you fulfill its conditions. - -See the [LICENSE.txt](LICENSE.txt) file for more details. - -Support -======= - -There are various ways to get in touch. The correct channel depends on -your requirement. see the [SUPPORT](SUPPORT.md) file for more details. - -Contributing +What This Is ============ -If you are interested and willing to contribute to the OpenSSL project, -please take a look at the [CONTRIBUTING](CONTRIBUTING.md) file. - -Legalities -========== - -A number of nations restrict the use or export of cryptography. If you are -potentially subject to such restrictions you should seek legal advice before -attempting to develop or distribute cryptographic code. - -Copyright -========= - -Copyright (c) 1998-2023 The OpenSSL Project - -Copyright (c) 1995-1998 Eric A. Young, Tim J. Hudson - -All rights reserved. - - - -[www.openssl.org]: - - "OpenSSL Homepage" - -[git.openssl.org]: - - "OpenSSL Git Repository" - -[git.openssl.org]: - - "OpenSSL Git Repository" - -[github.com/openssl/openssl]: - - "OpenSSL GitHub Mirror" - -[wiki.openssl.org]: - - "OpenSSL Wiki" - -[migration_guide(7ossl)]: - - "OpenSSL Migration Guide" - -[RFC 8446]: - - - - -[openssl logo]: - doc/images/openssl.svg - "OpenSSL Logo" - -[github actions ci badge]: - - "GitHub Actions CI Status" - -[github actions ci]: - - "GitHub Actions CI" - -[appveyor badge]: - - "AppVeyor Build Status" - -[appveyor jobs]: - - "AppVeyor Jobs" +This is a fork of [OpenSSL](https://www.openssl.org) to enable QUIC. In addition to the +website, the official source distribution is at https://github.com/openssl/openssl. +The OpenSSL `README` can be found at [README-OpenSSL.md](README-OpenSSL.md). + +This fork adds API that can be used by QUIC implementations for connection +handshakes. Quoting the IETF Working group +[charter](https://datatracker.ietf.org/wg/quic/about/), QUIC is a "UDP-based, +stream-multiplexing, encrypted transport protocol." If you don't need QUIC, you +should use the official OpenSSL distributions. + +This API's here are used by Microsoft's +[MsQuic](https://github.com/microsoft/msquic) and Google's +[Chromium QUIC](https://chromium.googlesource.com/chromium/src/+/master/net/quic/) + +We are not in competition with OpenSSL project. We informed them of +our plans to fork the code before we went public. We do not speak for the +OpenSSL project, and can only point to a +[blog post](https://www.openssl.org/blog/blog/2020/02/17/QUIC-and-OpenSSL/) that +provides their view of QUIC support. + +As stated in their blog post, the OpenSSL team is focused on their 3.0 release +which is still in alpha, and does not intend to add QUIC functionality to 1.1.x. +There is a community need for a QUIC capable TLS library. This fork is intended +as stopgap solution to enable higher level frameworks and runtimes to use QUIC +with the proven and reliable TLS functionality from OpenSSL. This fork will be +maintained until OpenSSL officially provides reasonable support for QUIC +implementations. + +This fork can be considered a supported version of +[OpenSSL PR 8797](https://github.com/openssl/openssl/pull/8797). +We will endeavor to track OpenSSL releases within a day or so, and there is an +item below about how we'll follow their tagging. + +On to the questions and answers. + +What about branches? +-------------------- +We don't want to conflict with OpenSSL branch names. Our current plan is to append +`+quic`. Release tags are likely to be the QUIC branch with `-releaseX` appended. +For example, the OpenSSL tag `openssl-3.0.0-alpha12` would have a branch named +`openssl-3.0.0-alpha12+quic` and a release tag of `openssl-3.0.0-alpha12+quic-release1` + +How are you keeping current with OpenSSL? +----------------------------------------- +(In other words, "What about rebasing?") + +Our plan it to always rebase on top of an upstream release tag. In particular: +- The changes for QUIC will always be at the tip of the branch -- you will know what +is from the original OpenSSL and what is for QUIC. +- New versions are quickly created once upstream creates a new tag. +- The use of git commands (such as "cherry") can be used to ensure that all changes +have moved forward with minimal or no changes. You will be able to see "QUIC: Add X" +on all branches and the commit itself will be nearly identical on all branches, and +any changes to that can be easily identified. + +What about library names? +------------------------- +Library names will be the same, but will use a different version number. The version +numbers for the current OpenSSL libraries are `1.1` (for the 1.1.0 and 1.1.1 branches) +and `3` (for the to-be-3.0 branch). We will be prefixing 81 (ASCII for 'Q') to +the version numbers to generate a unique version number. + +``` +libcrypto.so.81.3 libcrypto.so.81.1.1 libcrypto.so.1.1 libcrypto.so.3 +libssl.so.81.3 libssl.so.81.1.1 libsslo.so.1.1 libssl.so.3 +``` +The SONAME of these libraries are all different, guaranteeing the correct library +will be used. + +...and the executable? +---------------------- +We currently do not have any plans to change the name, mainly because we +haven't made any changes there. If you see a need, please open an issue. + +The `openssl version` command will report that it is `+quic` enabled. + +...and FIPS? +------------ +We are not doing anything with FIPS. This is actually good news: you should +be able to load the OpenSSL 3.0 FIPS module into an application built against +this fork and everything should Just Work™. + +How can I contribute? +--------------------- +We want any code here to be acceptable to OpenSSL. This means that all contributors +must have signed the appropriate +[contributor license agreements](https://www.openssl.org/policies/cla.html). We +will not ask for copies of any paperwork, you just need to tell us that you've +done so (and we might verify with OpenSSL). We are only interested in making it +easier and better for at least the mentioned QUIC implementations to use a variant +of OpenSSL. If you have a pull request that changes the TLS protocol, or adds +assembly support for a new CPU, or otherwise is not specific to enabling QUIC, +please contribute that to OpenSSL. This fork is intended to be a clean extension +to OpenSSL, with the deltas being specific to QUIC. + +Who are you? +------------ +This is a collaborative effort between [Akamai](https://www.akamai.com) and +[Microsoft](https://www.microsoft.com). We welcome anyone to contribute! From 9b4b32f63f2ad92faec02b8da83c7b61a52f9ccc Mon Sep 17 00:00:00 2001 From: Todd Short Date: Wed, 3 Mar 2021 17:32:31 -0500 Subject: [PATCH 32/66] QUIC: Fix 3.0.0 GitHub CI --- test/sslapitest.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/sslapitest.c b/test/sslapitest.c index bec2edf5ae9f7..3bb8792d971cb 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10496,10 +10496,10 @@ static int test_quic_api_version(int clnt, int srvr) &clientssl, NULL, NULL)) || !TEST_true(SSL_set_quic_transport_params(serverssl, (unsigned char*)server_str, - sizeof(server_str))) + strlen(server_str)+1)) || !TEST_true(SSL_set_quic_transport_params(clientssl, (unsigned char*)client_str, - sizeof(client_str))) + strlen(client_str)+1)) || !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)) @@ -10515,10 +10515,10 @@ static int test_quic_api_version(int clnt, int srvr) goto end; SSL_get_peer_quic_transport_params(serverssl, &peer_str, &peer_str_len); - if (!TEST_mem_eq(peer_str, peer_str_len, client_str, sizeof(client_str))) + if (!TEST_mem_eq(peer_str, peer_str_len, client_str, strlen(client_str)+1)) goto end; SSL_get_peer_quic_transport_params(clientssl, &peer_str, &peer_str_len); - if (!TEST_mem_eq(peer_str, peer_str_len, server_str, sizeof(server_str))) + if (!TEST_mem_eq(peer_str, peer_str_len, server_str, strlen(server_str)+1)) goto end; /* Deal with two NewSessionTickets */ From 09ec773078869ac705138cc3e1f4ba85100b7466 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Wed, 3 Mar 2021 17:43:46 -0500 Subject: [PATCH 33/66] QUIC: SSLerr() -> ERR_raise(ERR_LIB_SSL) --- ssl/s3_msg.c | 2 +- ssl/ssl_lib.c | 6 +++--- ssl/ssl_quic.c | 17 ++++++++--------- ssl/statem/statem.c | 2 +- ssl/statem/statem_lib.c | 4 ++-- 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/ssl/s3_msg.c b/ssl/s3_msg.c index 667c5385e8f49..dd2fe040e041d 100644 --- a/ssl/s3_msg.c +++ b/ssl/s3_msg.c @@ -85,7 +85,7 @@ int ssl3_dispatch_alert(SSL *s) if (SSL_IS_QUIC(s)) { if (!s->quic_method->send_alert(s, s->quic_write_level, s->s3.send_alert[1])) { - SSLerr(SSL_F_SSL3_DISPATCH_ALERT, ERR_R_INTERNAL_ERROR); + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); return 0; } i = 1; diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 3c06fd0f375ee..598f3e8adb21a 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1853,7 +1853,7 @@ int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes) { #ifndef OPENSSL_NO_QUIC if (SSL_IS_QUIC(s)) { - SSLerr(SSL_F_SSL_READ_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return -1; } #endif @@ -1990,7 +1990,7 @@ static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes) { #ifndef OPENSSL_NO_QUIC if (SSL_IS_QUIC(s)) { - SSLerr(SSL_F_SSL_PEEK_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return -1; } #endif @@ -2056,7 +2056,7 @@ int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written) { #ifndef OPENSSL_NO_QUIC if (SSL_IS_QUIC(s)) { - SSLerr(SSL_F_SSL_WRITE_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return -1; } #endif diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index 477a386da36f3..d50b1247a6351 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -131,7 +131,7 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, size_t l, offset; if (!SSL_IS_QUIC(ssl)) { - SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } @@ -139,18 +139,18 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, if (level < ssl->quic_read_level || (ssl->quic_input_data_tail != NULL && level < ssl->quic_input_data_tail->level) || level < ssl->quic_latest_level_received) { - SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); + ERR_raise(ERR_LIB_SSL, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); return 0; } if (ssl->quic_buf == NULL) { BUF_MEM *buf; if ((buf = BUF_MEM_new()) == NULL) { - SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); return 0; } if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { - SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); BUF_MEM_free(buf); return 0; } @@ -163,15 +163,14 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, /* A TLS message must not cross an encryption level boundary */ if (ssl->quic_buf->length != ssl->quic_next_record_start && level != ssl->quic_latest_level_received) { - SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, - SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); + ERR_raise(ERR_LIB_SSL, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); return 0; } ssl->quic_latest_level_received = level; offset = ssl->quic_buf->length; if (!BUF_MEM_grow(ssl->quic_buf, offset + len)) { - SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); return 0; } memcpy(ssl->quic_buf->data + offset, data, len); @@ -193,7 +192,7 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, qd = OPENSSL_zalloc(sizeof(*qd)); if (qd == NULL) { - SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); return 0; } @@ -305,7 +304,7 @@ int SSL_process_quic_post_handshake(SSL *ssl) int ret; if (SSL_in_init(ssl) || !SSL_IS_QUIC(ssl)) { - SSLerr(SSL_F_SSL_PROCESS_QUIC_POST_HANDSHAKE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c index b040d14cd244d..df542579d0b6d 100644 --- a/ssl/statem/statem.c +++ b/ssl/statem/statem.c @@ -930,7 +930,7 @@ int statem_flush(SSL *s) #ifndef OPENSSL_NO_QUIC if (SSL_IS_QUIC(s)) { if (!s->quic_method->flush_flight(s)) { - SSLerr(SSL_F_STATEM_FLUSH, ERR_R_INTERNAL_ERROR); + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); return 0; } } else diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index c3f6465f6aadf..cb31835265ff7 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -54,14 +54,14 @@ int ssl3_do_write(SSL *s, int type) if (!ret) { ret = -1; /* QUIC can't sent anything out sice the above failed */ - SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_INTERNAL_ERROR); + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); } else { written = s->init_num; } } else { /* QUIC doesn't use ChangeCipherSpec */ ret = -1; - SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); } } else #endif From 074c23ebe9f70fa5e7edfa1889e7cb4170751963 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 5 Mar 2021 15:22:18 -0500 Subject: [PATCH 34/66] QUIC: Add compile/run-time checking for QUIC --- apps/info.c | 12 ++++++++++++ crypto/info.c | 4 ++++ doc/man3/OpenSSL_version.pod | 8 ++++++++ include/openssl/crypto.h.in | 4 ++++ 4 files changed, 28 insertions(+) diff --git a/apps/info.c b/apps/info.c index c68603652f218..f0f043b7f2f18 100644 --- a/apps/info.c +++ b/apps/info.c @@ -15,6 +15,9 @@ typedef enum OPTION_choice { OPT_COMMON, OPT_CONFIGDIR, OPT_ENGINESDIR, OPT_MODULESDIR, OPT_DSOEXT, OPT_DIRNAMESEP, OPT_LISTSEP, OPT_SEEDS, OPT_CPUSETTINGS +#ifndef OPENSSL_NO_QUIC + , OPT_QUIC +#endif } OPTION_CHOICE; const OPTIONS info_options[] = { @@ -32,6 +35,9 @@ const OPTIONS info_options[] = { {"listsep", OPT_LISTSEP, '-', "List separator character"}, {"seeds", OPT_SEEDS, '-', "Seed sources"}, {"cpusettings", OPT_CPUSETTINGS, '-', "CPU settings info"}, +#ifndef OPENSSL_NO_QUIC + {"quic", OPT_QUIC, '-', "QUIC info"}, +#endif {NULL} }; @@ -84,6 +90,12 @@ int info_main(int argc, char **argv) type = OPENSSL_INFO_CPU_SETTINGS; dirty++; break; +#ifndef OPENSSL_NO_QUIC + case OPT_QUIC: + type = OPENSSL_INFO_QUIC; + dirty++; + break; +#endif } } if (opt_num_rest() != 0) diff --git a/crypto/info.c b/crypto/info.c index a0dc2e80136f8..480bb7e6afe38 100644 --- a/crypto/info.c +++ b/crypto/info.c @@ -199,6 +199,10 @@ const char *OPENSSL_info(int t) if (ossl_cpu_info_str[0] != '\0') return ossl_cpu_info_str + strlen(CPUINFO_PREFIX); break; +#ifndef OPENSSL_NO_QUIC + case OPENSSL_INFO_QUIC: + return "QUIC"; +#endif default: break; } diff --git a/doc/man3/OpenSSL_version.pod b/doc/man3/OpenSSL_version.pod index e1cf16e2a109b..946bb151bafeb 100644 --- a/doc/man3/OpenSSL_version.pod +++ b/doc/man3/OpenSSL_version.pod @@ -211,6 +211,14 @@ automatically configured but may be set via an environment variable. The value has the same syntax as the environment variable. For x86 the string looks like C. +=item OPENSSL_INFO_QUIC + +This is only defined when compiling with a QUIC-enabled version of +OpenSSL. At run time, this will return "QUIC" if QUIC is supported. + +This can be used as a build time flag to determine if OpenSSL has +QUIC enabled. + =back For an unknown I, NULL is returned. diff --git a/include/openssl/crypto.h.in b/include/openssl/crypto.h.in index 7232f647e8a30..53a3758e896a9 100644 --- a/include/openssl/crypto.h.in +++ b/include/openssl/crypto.h.in @@ -176,6 +176,10 @@ const char *OPENSSL_info(int type); # define OPENSSL_INFO_SEED_SOURCE 1007 # define OPENSSL_INFO_CPU_SETTINGS 1008 +# ifndef OPENSSL_NO_QUIC +# define OPENSSL_INFO_QUIC 2000 +# endif + int OPENSSL_issetugid(void); struct crypto_ex_data_st { From 92e26736fdebcf8997c85ca707084f6b338ccf40 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com> Date: Thu, 11 Mar 2021 23:07:55 +0900 Subject: [PATCH 35/66] QUIC: Add early data support (#11) * QUIC: Add early data support This commit adds SSL_set_quic_early_data_enabled to add early data support to QUIC. --- doc/man3/SSL_CTX_set_quic_method.pod | 10 +- include/openssl/ssl.h.in | 2 + ssl/ssl_lib.c | 15 +++ ssl/ssl_quic.c | 76 ++++++++++--- ssl/statem/statem_srvr.c | 10 ++ ssl/tls13_enc.c | 90 +++++++++++++--- test/sslapitest.c | 156 +++++++++++++++++++++++++++ util/libssl.num | 1 + 8 files changed, 327 insertions(+), 33 deletions(-) diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod index 39ff3a8da4517..86eb257e91d40 100644 --- a/doc/man3/SSL_CTX_set_quic_method.pod +++ b/doc/man3/SSL_CTX_set_quic_method.pod @@ -17,7 +17,8 @@ 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 +SSL_set_quic_use_legacy_codepoint, +SSL_set_quic_early_data_enabled - QUIC support =head1 SYNOPSIS @@ -47,6 +48,7 @@ SSL_set_quic_use_legacy_codepoint 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); + void SSL_set_quic_early_data_enabled(SSL *ssl, int enabled); =head1 DESCRIPTION @@ -106,6 +108,12 @@ SSL_set_quic_transport_version(). SSL_get_peer_quic_transport_version() returns the version the that was negotiated. +SSL_set_quic_early_data_enabled() enables QUIC early data if a nonzero +value is passed. Client must set a resumed session before calling +this function. Server must set 0xffffffffu to +SSL_CTX_set_max_early_data() or SSL_set_max_early_data() so that a +session ticket indicates that server is able to accept early data. + =head1 NOTES These APIs are implementations of BoringSSL's QUIC APIs. diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in index 010283452059a..5f337616e8106 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2577,6 +2577,8 @@ __owur int SSL_get_peer_quic_transport_version(const SSL *ssl); int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c); +void SSL_set_quic_early_data_enabled(SSL *ssl, int enabled); + # endif # ifdef __cplusplus diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 598f3e8adb21a..24d9fb3ca3767 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -3978,6 +3978,21 @@ int SSL_do_handshake(SSL *s) ret = s->handshake_func(s); } } +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s) && ret == 1) { + if (s->server) { + if (s->early_data_state == SSL_EARLY_DATA_ACCEPTING) { + s->early_data_state = SSL_EARLY_DATA_FINISHED_READING; + s->rwstate = SSL_READING; + ret = 0; + } + } else if (s->early_data_state == SSL_EARLY_DATA_CONNECTING) { + s->early_data_state = SSL_EARLY_DATA_WRITE_RETRY; + s->rwstate = SSL_READING; + ret = 0; + } + } +#endif return ret; } diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index d50b1247a6351..9d4c8014113fb 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -257,24 +257,46 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) return 1; } - md = ssl_handshake_md(ssl); - if (md == NULL) { - /* May not have selected cipher, yet */ - const SSL_CIPHER *c = NULL; - - /* - * It probably doesn't make sense to use an (external) PSK session, - * but in theory some kinds of external session caches could be - * implemented using it, so allow psksession to be used as well as - * the regular session. - */ - if (ssl->session != NULL) - c = SSL_SESSION_get0_cipher(ssl->session); - else if (ssl->psksession != NULL) + if (level == ssl_encryption_early_data) { + const SSL_CIPHER *c = SSL_SESSION_get0_cipher(ssl->session); + if (ssl->early_data_state == SSL_EARLY_DATA_CONNECTING + && ssl->max_early_data > 0 + && ssl->session->ext.max_early_data == 0) { + if (!ossl_assert(ssl->psksession != NULL + && ssl->max_early_data == + ssl->psksession->ext.max_early_data)) { + SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } c = SSL_SESSION_get0_cipher(ssl->psksession); + } + + if (c == NULL) { + SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } - if (c != NULL) - md = SSL_CIPHER_get_handshake_digest(c); + md = ssl_md(ssl->ctx, c->algorithm2); + } else { + md = ssl_handshake_md(ssl); + if (md == NULL) { + /* May not have selected cipher, yet */ + const SSL_CIPHER *c = NULL; + + /* + * It probably doesn't make sense to use an (external) PSK session, + * but in theory some kinds of external session caches could be + * implemented using it, so allow psksession to be used as well as + * the regular session. + */ + if (ssl->session != NULL) + c = SSL_SESSION_get0_cipher(ssl->session); + else if (ssl->psksession != NULL) + c = SSL_SESSION_get0_cipher(ssl->psksession); + + if (c != NULL) + md = SSL_CIPHER_get_handshake_digest(c); + } } if ((len = EVP_MD_size(md)) <= 0) { @@ -330,3 +352,25 @@ int SSL_is_quic(SSL* ssl) { return SSL_IS_QUIC(ssl); } + +void SSL_set_quic_early_data_enabled(SSL *ssl, int enabled) +{ + if (!SSL_is_quic(ssl) || !SSL_in_before(ssl)) + return; + + if (!enabled) { + ssl->early_data_state = SSL_EARLY_DATA_NONE; + return; + } + + if (ssl->server) { + ssl->early_data_state = SSL_EARLY_DATA_ACCEPTING; + return; + } + + if ((ssl->session == NULL || ssl->session->ext.max_early_data == 0) + && ssl->psk_use_session_cb == NULL) + return; + + ssl->early_data_state = SSL_EARLY_DATA_CONNECTING; +} diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 391e638c9540d..2d3f05d940f3b 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -964,6 +964,16 @@ WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst) SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_SERVER_WRITE)) /* SSLfatal() already called */ return WORK_ERROR; + +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s) && s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) { + s->early_data_state = SSL_EARLY_DATA_FINISHED_READING; + if (!s->method->ssl3_enc->change_cipher_state( + s, SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_SERVER_READ)) + /* SSLfatal() already called */ + return WORK_ERROR; + } +#endif } break; diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c index 643d2dbfd7134..33cf79199fe79 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -434,20 +434,76 @@ static int quic_change_cipher_state(SSL *s, int which) int is_server_write = ((which & SSL3_CHANGE_CIPHER_SERVER_WRITE) == SSL3_CHANGE_CIPHER_SERVER_WRITE); int is_early = (which & SSL3_CC_EARLY); - md = ssl_handshake_md(s); - if (!ssl3_digest_cached_records(s, 1) - || !ssl_handshake_hash(s, hash, sizeof(hash), &hashlen)) { - /* SSLfatal() already called */; - goto err; - } + if (is_early) { + EVP_MD_CTX *mdctx = NULL; + long handlen; + void *hdata; + unsigned int hashlenui; + const SSL_CIPHER *sslcipher = SSL_SESSION_get0_cipher(s->session); + + handlen = BIO_get_mem_data(s->s3.handshake_buffer, &hdata); + if (handlen <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_HANDSHAKE_LENGTH); + goto err; + } - /* Ensure cast to size_t is safe */ - hashleni = EVP_MD_size(md); - if (!ossl_assert(hashleni >= 0)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); - goto err; + if (s->early_data_state == SSL_EARLY_DATA_CONNECTING + && s->max_early_data > 0 + && s->session->ext.max_early_data == 0) { + /* + * If we are attempting to send early data, and we've decided to + * actually do it but max_early_data in s->session is 0 then we + * must be using an external PSK. + */ + if (!ossl_assert(s->psksession != NULL + && s->max_early_data == + s->psksession->ext.max_early_data)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + goto err; + } + sslcipher = SSL_SESSION_get0_cipher(s->psksession); + } + if (sslcipher == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_PSK); + goto err; + } + + /* + * We need to calculate the handshake digest using the digest from + * the session. We haven't yet selected our ciphersuite so we can't + * use ssl_handshake_md(). + */ + mdctx = EVP_MD_CTX_new(); + if (mdctx == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE); + goto err; + } + md = ssl_md(s->ctx, sslcipher->algorithm2); + if (md == NULL || !EVP_DigestInit_ex(mdctx, md, NULL) + || !EVP_DigestUpdate(mdctx, hdata, handlen) + || !EVP_DigestFinal_ex(mdctx, hash, &hashlenui)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + EVP_MD_CTX_free(mdctx); + goto err; + } + hashlen = hashlenui; + EVP_MD_CTX_free(mdctx); + } else { + md = ssl_handshake_md(s); + if (!ssl3_digest_cached_records(s, 1) + || !ssl_handshake_hash(s, hash, sizeof(hash), &hashlen)) { + /* SSLfatal() already called */; + goto err; + } + + /* Ensure cast to size_t is safe */ + hashleni = EVP_MD_size(md); + if (!ossl_assert(hashleni >= 0)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); + goto err; + } + hashlen = (size_t)hashleni; } - hashlen = (size_t)hashleni; if (is_client_read || is_server_write) { if (is_handshake) { @@ -553,10 +609,12 @@ static int quic_change_cipher_state(SSL *s, int which) } } - if (s->server) - s->quic_read_level = level; - else - s->quic_write_level = level; + if (level != ssl_encryption_early_data) { + if (s->server) + s->quic_read_level = level; + else + s->quic_write_level = level; + } } ret = 1; diff --git a/test/sslapitest.c b/test/sslapitest.c index 3bb8792d971cb..8eb9aa426d947 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10616,6 +10616,159 @@ static int test_quic_api(int tst) serverssl = NULL; return testresult; } + +# ifndef OSSL_NO_USABLE_TLS1_3 +/* + * Helper method to setup objects for QUIC early data test. Caller + * frees objects on error. + */ +static int quic_setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx, + SSL **clientssl, SSL **serverssl, + SSL_SESSION **sess, int idx) +{ + static const char *server_str = "SERVER"; + static const char *client_str = "CLIENT"; + + if (*sctx == NULL + && (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), + TLS_client_method(), + TLS1_3_VERSION, 0, + sctx, cctx, cert, privkey)) + || !TEST_true(SSL_CTX_set_quic_method(*sctx, &quic_method)) + || !TEST_true(SSL_CTX_set_quic_method(*cctx, &quic_method)) + || !TEST_true(SSL_CTX_set_max_early_data(*sctx, 0xffffffffu)))) + return 0; + + if (idx == 1) { + /* When idx == 1 we repeat the tests with read_ahead set */ + SSL_CTX_set_read_ahead(*cctx, 1); + SSL_CTX_set_read_ahead(*sctx, 1); + } else if (idx == 2) { + /* When idx == 2 we are doing early_data with a PSK. Set up callbacks */ + SSL_CTX_set_psk_use_session_callback(*cctx, use_session_cb); + SSL_CTX_set_psk_find_session_callback(*sctx, find_session_cb); + use_session_cb_cnt = 0; + find_session_cb_cnt = 0; + srvid = pskid; + } + + if (!TEST_true(create_ssl_objects(*sctx, *cctx, serverssl, clientssl, + NULL, NULL)) + || !TEST_true(SSL_set_quic_transport_params(*serverssl, + (unsigned char*)server_str, + strlen(server_str)+1)) + || !TEST_true(SSL_set_quic_transport_params(*clientssl, + (unsigned char*)client_str, + strlen(client_str)+1)) + || !TEST_true(SSL_set_app_data(*serverssl, *clientssl)) + || !TEST_true(SSL_set_app_data(*clientssl, *serverssl))) + return 0; + + /* + * For one of the run throughs (doesn't matter which one), we'll try sending + * some SNI data in the initial ClientHello. This will be ignored (because + * there is no SNI cb set up by the server), so it should not impact + * early_data. + */ + if (idx == 1 + && !TEST_true(SSL_set_tlsext_host_name(*clientssl, "localhost"))) + return 0; + + if (idx == 2) { + clientpsk = create_a_psk(*clientssl, SHA256_DIGEST_LENGTH); + if (!TEST_ptr(clientpsk) + || !TEST_true(SSL_SESSION_set_max_early_data(clientpsk, + 0xffffffffu)) + || !TEST_true(SSL_SESSION_up_ref(clientpsk))) { + SSL_SESSION_free(clientpsk); + clientpsk = NULL; + return 0; + } + serverpsk = clientpsk; + + if (sess != NULL) { + if (!TEST_true(SSL_SESSION_up_ref(clientpsk))) { + SSL_SESSION_free(clientpsk); + SSL_SESSION_free(serverpsk); + clientpsk = serverpsk = NULL; + return 0; + } + *sess = clientpsk; + } + + SSL_set_quic_early_data_enabled(*serverssl, 1); + SSL_set_quic_early_data_enabled(*clientssl, 1); + + return 1; + } + + if (sess == NULL) + return 1; + + if (!TEST_true(create_ssl_connection(*serverssl, *clientssl, + SSL_ERROR_NONE))) + return 0; + + /* Deal with two NewSessionTickets */ + if (!TEST_true(SSL_process_quic_post_handshake(*clientssl)) + || !TEST_true(SSL_process_quic_post_handshake(*clientssl))) + return 0; + + *sess = SSL_get1_session(*clientssl); + SSL_shutdown(*clientssl); + SSL_shutdown(*serverssl); + SSL_free(*serverssl); + SSL_free(*clientssl); + *serverssl = *clientssl = NULL; + + if (!TEST_true(create_ssl_objects(*sctx, *cctx, serverssl, + clientssl, NULL, NULL)) + || !TEST_true(SSL_set_session(*clientssl, *sess)) + || !TEST_true(SSL_set_quic_transport_params(*serverssl, + (unsigned char*)server_str, + strlen(server_str)+1)) + || !TEST_true(SSL_set_quic_transport_params(*clientssl, + (unsigned char*)client_str, + strlen(client_str)+1)) + || !TEST_true(SSL_set_app_data(*serverssl, *clientssl)) + || !TEST_true(SSL_set_app_data(*clientssl, *serverssl))) + return 0; + + SSL_set_quic_early_data_enabled(*serverssl, 1); + SSL_set_quic_early_data_enabled(*clientssl, 1); + + return 1; +} + +static int test_quic_early_data(int tst) +{ + SSL_CTX *cctx = NULL, *sctx = NULL; + SSL *clientssl = NULL, *serverssl = NULL; + int testresult = 0; + SSL_SESSION *sess = NULL; + + if (!TEST_true(quic_setupearly_data_test(&cctx, &sctx, &clientssl, + &serverssl, &sess, tst))) + goto end; + + if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)) + || !TEST_true(SSL_get_early_data_status(serverssl))) + goto end; + + testresult = 1; + + end: + SSL_SESSION_free(sess); + SSL_SESSION_free(clientpsk); + SSL_SESSION_free(serverpsk); + clientpsk = serverpsk = NULL; + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + return testresult; +} +# endif /* OSSL_NO_USABLE_TLS1_3 */ #endif /* OPENSSL_NO_QUIC */ OPT_TEST_DECLARE_USAGE("certfile privkeyfile srpvfile tmpfile provider config dhfile\n") @@ -10892,6 +11045,9 @@ int setup_tests(void) ADD_ALL_TESTS(test_handshake_retry, 16); #ifndef OPENSSL_NO_QUIC ADD_ALL_TESTS(test_quic_api, 9); +# ifndef OSSL_NO_USABLE_TLS1_3 + ADD_ALL_TESTS(test_quic_early_data, 3); +# endif #endif return 1; diff --git a/util/libssl.num b/util/libssl.num index 41ebba40b20ed..4a9d5b20074af 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -535,3 +535,4 @@ SSL_set_quic_use_legacy_codepoint 20011 3_0_0 EXIST::FUNCTION:QUIC SSL_set_quic_transport_version 20012 3_0_0 EXIST::FUNCTION:QUIC SSL_get_peer_quic_transport_version 20013 3_0_0 EXIST::FUNCTION:QUIC SSL_get_quic_transport_version 20014 3_0_0 EXIST::FUNCTION:QUIC +SSL_set_quic_early_data_enabled 20015 3_0_0 EXIST::FUNCTION:QUIC From 131f087902ff6c2e97b2415772d75f705e914b82 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com> Date: Fri, 12 Mar 2021 00:39:20 +0900 Subject: [PATCH 36/66] QUIC: Make SSL_provide_quic_data accept 0 length data (#13) This commit makes SSL_provide_quic_data accept 0 length data, which matches BoringSSL behavior. Fixes #9 --- ssl/ssl_quic.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index 9d4c8014113fb..49a4f3ab5c7ed 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -143,6 +143,9 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, return 0; } + if (len == 0) + return 1; + if (ssl->quic_buf == NULL) { BUF_MEM *buf; if ((buf = BUF_MEM_new()) == NULL) { From 31a38f93cc0b4c29424423928e3637fffb6162c6 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com> Date: Sat, 13 Mar 2021 05:37:34 +0900 Subject: [PATCH 37/66] QUIC: Process multiple post-handshake messages in a single call (#16) --- ssl/ssl_quic.c | 27 +++++++++++++-------------- test/sslapitest.c | 6 ++---- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index 49a4f3ab5c7ed..6cbd47ad2d390 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -334,20 +334,19 @@ int SSL_process_quic_post_handshake(SSL *ssl) } /* if there is no data, return success as BoringSSL */ - if (ssl->quic_input_data_head == NULL) - return 1; - - /* - * This is always safe (we are sure to be at a record boundary) because - * SSL_read()/SSL_write() are never used for QUIC connections -- the - * application data is handled at the QUIC layer instead. - */ - ossl_statem_set_in_init(ssl, 1); - ret = ssl->handshake_func(ssl); - ossl_statem_set_in_init(ssl, 0); - - if (ret <= 0) - return 0; + while (ssl->quic_input_data_head != NULL) { + /* + * This is always safe (we are sure to be at a record boundary) because + * SSL_read()/SSL_write() are never used for QUIC connections -- the + * application data is handled at the QUIC layer instead. + */ + ossl_statem_set_in_init(ssl, 1); + ret = ssl->handshake_func(ssl); + ossl_statem_set_in_init(ssl, 0); + + if (ret <= 0) + return 0; + } return 1; } diff --git a/test/sslapitest.c b/test/sslapitest.c index 8eb9aa426d947..7604394fa1cde 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10522,8 +10522,7 @@ static int test_quic_api_version(int clnt, int srvr) goto end; /* Deal with two NewSessionTickets */ - if (!TEST_true(SSL_process_quic_post_handshake(clientssl)) - || !TEST_true(SSL_process_quic_post_handshake(clientssl))) + if (!TEST_true(SSL_process_quic_post_handshake(clientssl))) goto end; /* Dummy handshake call should succeed */ @@ -10710,8 +10709,7 @@ static int quic_setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx, return 0; /* Deal with two NewSessionTickets */ - if (!TEST_true(SSL_process_quic_post_handshake(*clientssl)) - || !TEST_true(SSL_process_quic_post_handshake(*clientssl))) + if (!TEST_true(SSL_process_quic_post_handshake(*clientssl))) return 0; *sess = SSL_get1_session(*clientssl); From 408fbc68469c5937d060e66b76bac20fb49868fa Mon Sep 17 00:00:00 2001 From: kaduk Date: Fri, 12 Mar 2021 13:03:14 -0800 Subject: [PATCH 38/66] QUIC: Tighten up some language in SSL_CTX_set_quic_method.pod (#18) --- doc/man3/SSL_CTX_set_quic_method.pod | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod index 86eb257e91d40..906c7591d9e55 100644 --- a/doc/man3/SSL_CTX_set_quic_method.pod +++ b/doc/man3/SSL_CTX_set_quic_method.pod @@ -109,10 +109,10 @@ SSL_get_peer_quic_transport_version() returns the version the that was negotiated. SSL_set_quic_early_data_enabled() enables QUIC early data if a nonzero -value is passed. Client must set a resumed session before calling -this function. Server must set 0xffffffffu to -SSL_CTX_set_max_early_data() or SSL_set_max_early_data() so that a -session ticket indicates that server is able to accept early data. +value is passed. Clients must set a resumed session before calling this +function. Servers must additionally call SSL_CTX_set_max_early_data() or +SSL_set_max_early_data() with 0xffffffffu as the argument, so that any +issued session tickets indicate that server is able to accept early data. =head1 NOTES From 454be29e12d84c8c8a50af57c99b49b57c9689e4 Mon Sep 17 00:00:00 2001 From: Nan Xiao Date: Mon, 15 Mar 2021 23:54:39 +0800 Subject: [PATCH 39/66] QUIC: Fix typo in README.md (#19) Can be squashed with `QUIC: Swap around README files` --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ef46c4b393a6c..26defbc8cbf2a 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ How are you keeping current with OpenSSL? ----------------------------------------- (In other words, "What about rebasing?") -Our plan it to always rebase on top of an upstream release tag. In particular: +Our plan is to always rebase on top of an upstream release tag. In particular: - The changes for QUIC will always be at the tip of the branch -- you will know what is from the original OpenSSL and what is for QUIC. - New versions are quickly created once upstream creates a new tag. From 02e9ec866c7e5b28fcf04d61a0c24eee8f58bb53 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 18 Mar 2021 12:42:01 -0400 Subject: [PATCH 40/66] QUIC: Fix CI (#20) Fixes #2 and #3 and #22 Updates `Configure` script to disable QUIC with `no-bulk` and `no-ec` Updates build.info doc docs Fixes an issue with extension defintions and `no-quic` --- Configure | 3 ++- doc/build.info | 6 ++++++ ssl/statem/extensions.c | 1 + ssl/statem/extensions_srvr.c | 2 +- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Configure b/Configure index 69851e1e97fbe..63440170287d5 100755 --- a/Configure +++ b/Configure @@ -578,6 +578,7 @@ my @disable_cascades = ( "sm3", "sm4", "srp", "srtp", "ssl3-method", "ssl-trace", "ts", "ui-console", "whirlpool", + "quic", "fips-securitychecks" ], sub { $config{processor} eq "386" } => [ "sse2" ], @@ -585,7 +586,7 @@ my @disable_cascades = ( "ssl3-method" => [ "ssl3" ], "zlib" => [ "zlib-dynamic" ], "des" => [ "mdc2" ], - "ec" => [ "ec2m", "ecdsa", "ecdh", "sm2", "gost" ], + "ec" => [ "ec2m", "ecdsa", "ecdh", "sm2", "gost", "quic" ], "dgram" => [ "dtls", "sctp" ], "sock" => [ "dgram" ], "dtls" => [ @dtls ], diff --git a/doc/build.info b/doc/build.info index 00dc150721ac0..8f7186d89bc1f 100644 --- a/doc/build.info +++ b/doc/build.info @@ -2263,6 +2263,10 @@ DEPEND[html/man3/SSL_CTX_set_psk_client_callback.html]=man3/SSL_CTX_set_psk_clie GENERATE[html/man3/SSL_CTX_set_psk_client_callback.html]=man3/SSL_CTX_set_psk_client_callback.pod DEPEND[man/man3/SSL_CTX_set_psk_client_callback.3]=man3/SSL_CTX_set_psk_client_callback.pod GENERATE[man/man3/SSL_CTX_set_psk_client_callback.3]=man3/SSL_CTX_set_psk_client_callback.pod +DEPEND[html/man3/SSL_CTX_set_quic_method.html]=man3/SSL_CTX_set_quic_method.pod +GENERATE[html/man3/SSL_CTX_set_quic_method.html]=man3/SSL_CTX_set_quic_method.pod +DEPEND[man/man3/SSL_CTX_set_quic_method.3]=man3/SSL_CTX_set_quic_method.pod +GENERATE[man/man3/SSL_CTX_set_quic_method.3]=man3/SSL_CTX_set_quic_method.pod DEPEND[html/man3/SSL_CTX_set_quiet_shutdown.html]=man3/SSL_CTX_set_quiet_shutdown.pod GENERATE[html/man3/SSL_CTX_set_quiet_shutdown.html]=man3/SSL_CTX_set_quiet_shutdown.pod DEPEND[man/man3/SSL_CTX_set_quiet_shutdown.3]=man3/SSL_CTX_set_quiet_shutdown.pod @@ -3329,6 +3333,7 @@ html/man3/SSL_CTX_set_msg_callback.html \ html/man3/SSL_CTX_set_num_tickets.html \ html/man3/SSL_CTX_set_options.html \ html/man3/SSL_CTX_set_psk_client_callback.html \ +html/man3/SSL_CTX_set_quic_method.html \ html/man3/SSL_CTX_set_quiet_shutdown.html \ html/man3/SSL_CTX_set_read_ahead.html \ html/man3/SSL_CTX_set_record_padding_callback.html \ @@ -3932,6 +3937,7 @@ man/man3/SSL_CTX_set_msg_callback.3 \ man/man3/SSL_CTX_set_num_tickets.3 \ man/man3/SSL_CTX_set_options.3 \ man/man3/SSL_CTX_set_psk_client_callback.3 \ +man/man3/SSL_CTX_set_quic_method.3 \ man/man3/SSL_CTX_set_quiet_shutdown.3 \ man/man3/SSL_CTX_set_read_ahead.3 \ man/man3/SSL_CTX_set_record_padding_callback.3 \ diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index eea187b6bf5bc..d686bd6dba8a9 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -396,6 +396,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { }, #else INVALID_EXTENSION, + INVALID_EXTENSION, #endif { /* Must be immediately before pre_shared_key */ diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 85f8aa35c2850..244e711b79ba3 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1912,7 +1912,7 @@ EXT_RETURN tls_construct_stoc_early_data(SSL *s, WPACKET *pkt, #ifndef OPENSSL_NO_QUIC /* QUIC server must always send 0xFFFFFFFF, per draft-ietf-quic-tls-27 S4.5 */ - if (s->quic_method != NULL) + if (SSL_IS_QUIC(s)) max_early_data = 0xFFFFFFFF; #endif From cfa609d3567fd171056fca68fa25883a0e83ffe2 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 6 May 2021 16:24:03 -0400 Subject: [PATCH 41/66] QUIC: Break up header/body processing As DTLS has changed, so too must QUIC. --- ssl/statem/statem.c | 9 ++++++--- ssl/statem/statem_local.h | 3 ++- ssl/statem/statem_quic.c | 25 +++++++++++++++---------- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c index df542579d0b6d..e67ee26e87d55 100644 --- a/ssl/statem/statem.c +++ b/ssl/statem/statem.c @@ -586,7 +586,7 @@ static SUB_STATE_RETURN read_state_machine(SSL *s) #ifndef OPENSSL_NO_QUIC } else if (SSL_IS_QUIC(s)) { /* QUIC behaves like DTLS -- all in one go. */ - ret = quic_get_message(s, &mt, &len); + ret = quic_get_message(s, &mt); #endif } else { ret = tls_get_message_header(s, &mt); @@ -636,8 +636,11 @@ static SUB_STATE_RETURN read_state_machine(SSL *s) * opportunity to do any further processing. */ ret = dtls_get_message_body(s, &len); - } else if (!SSL_IS_QUIC(s)) { - /* We already got this above for QUIC */ +#ifndef OPENSSL_NO_QUIC + } else if (SSL_IS_QUIC(s)) { + ret = quic_get_message_body(s, &len); +#endif + } else { ret = tls_get_message_body(s, &len); } if (ret == 0) { diff --git a/ssl/statem/statem_local.h b/ssl/statem/statem_local.h index 0065db1744c63..4203c084e8749 100644 --- a/ssl/statem/statem_local.h +++ b/ssl/statem/statem_local.h @@ -105,7 +105,8 @@ __owur int tls_get_message_body(SSL *s, size_t *len); __owur int dtls_get_message(SSL *s, int *mt); __owur int dtls_get_message_body(SSL *s, size_t *len); #ifndef OPENSSL_NO_QUIC -__owur int quic_get_message(SSL *s, int *mt, size_t *len); +__owur int quic_get_message(SSL *s, int *mt); +__owur int quic_get_message_body(SSL *s, size_t *len); #endif /* Message construction and processing functions */ diff --git a/ssl/statem/statem_quic.c b/ssl/statem/statem_quic.c index a371eeaedbf81..a51bfd74d8c2f 100644 --- a/ssl/statem/statem_quic.c +++ b/ssl/statem/statem_quic.c @@ -11,7 +11,7 @@ #include "statem_local.h" #include "internal/cryptlib.h" -int quic_get_message(SSL *s, int *mt, size_t *len) +int quic_get_message(SSL *s, int *mt) { size_t l; QUIC_DATA *qd = s->quic_input_data_head; @@ -19,26 +19,26 @@ int quic_get_message(SSL *s, int *mt, size_t *len) if (qd == NULL) { s->rwstate = SSL_READING; - *mt = *len = 0; + *mt = 0; return 0; } if (!ossl_assert(qd->length >= SSL3_HM_HEADER_LENGTH)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_LENGTH); - *mt = *len = 0; + *mt = 0; return 0; } /* This is where we check for the proper level, not when data is given */ if (qd->level != s->quic_read_level) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); - *mt = *len = 0; + *mt = 0; return 0; } if (!BUF_MEM_grow_clean(s->init_buf, (int)qd->length)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_BUF_LIB); - *mt = *len = 0; + *mt = 0; return 0; } @@ -53,28 +53,32 @@ int quic_get_message(SSL *s, int *mt, size_t *len) s->s3.tmp.message_type = *mt = *(s->init_buf->data); p = (uint8_t*)s->init_buf->data + 1; n2l3(p, l); - s->init_num = s->s3.tmp.message_size = *len = l; + s->init_num = s->s3.tmp.message_size = l; s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH; + return 1; +} + +int quic_get_message_body(SSL *s, size_t *len) +{ /* No CCS in QUIC/TLSv1.3? */ - if (*mt == SSL3_MT_CHANGE_CIPHER_SPEC) { + if (s->s3.tmp.message_type == SSL3_MT_CHANGE_CIPHER_SPEC) { SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_CCS_RECEIVED_EARLY); *len = 0; return 0; } /* No KeyUpdate in QUIC */ - if (*mt == SSL3_MT_KEY_UPDATE) { + if (s->s3.tmp.message_type == SSL3_MT_KEY_UPDATE) { SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE); *len = 0; return 0; } - /* * If receiving Finished, record MAC of prior handshake messages for * Finished verification. */ - if (*mt == SSL3_MT_FINISHED && !ssl3_take_mac(s)) { + if (s->s3.tmp.message_type == SSL3_MT_FINISHED && !ssl3_take_mac(s)) { /* SSLfatal() already called */ *len = 0; return 0; @@ -108,5 +112,6 @@ int quic_get_message(SSL *s, int *mt, size_t *len) (size_t)s->init_num + SSL3_HM_HEADER_LENGTH, s, s->msg_callback_arg); + *len = s->init_num; return 1; } From de7dc75668c9581601ab71ca1e70b113e9b69fd5 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 24 Jun 2021 15:11:24 -0400 Subject: [PATCH 42/66] QUIC: Fix make doc-nits --- doc/man1/openssl-info.pod.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/man1/openssl-info.pod.in b/doc/man1/openssl-info.pod.in index 0e91bb28ee10d..fe7abee486767 100644 --- a/doc/man1/openssl-info.pod.in +++ b/doc/man1/openssl-info.pod.in @@ -17,6 +17,7 @@ B [B<-listsep>] [B<-seeds>] [B<-cpusettings>] +[B<-quic>] =head1 DESCRIPTION @@ -73,6 +74,10 @@ Outputs the randomness seed sources. Outputs the OpenSSL CPU settings info. +=item B<-quic> + +Outputs the OpenSSL QUIC info. + =back =head1 HISTORY From 48e2c7a8679d1bfb30a3bf95f9bd50cffb9d6d4a Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 24 Jun 2021 15:24:28 -0400 Subject: [PATCH 43/66] QUIC: Fix make md-nits --- README.md | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 26defbc8cbf2a..53c3960c96126 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ What This Is ============ -This is a fork of [OpenSSL](https://www.openssl.org) to enable QUIC. In addition to the -website, the official source distribution is at https://github.com/openssl/openssl. -The OpenSSL `README` can be found at [README-OpenSSL.md](README-OpenSSL.md). +This is a fork of [OpenSSL](https://www.openssl.org) to enable QUIC. In addition +to the website, the official source distribution is at +. The OpenSSL `README` can be found at +[README-OpenSSL.md](README-OpenSSL.md). This fork adds API that can be used by QUIC implementations for connection handshakes. Quoting the IETF Working group @@ -38,6 +39,7 @@ On to the questions and answers. What about branches? -------------------- + We don't want to conflict with OpenSSL branch names. Our current plan is to append `+quic`. Release tags are likely to be the QUIC branch with `-releaseX` appended. For example, the OpenSSL tag `openssl-3.0.0-alpha12` would have a branch named @@ -45,33 +47,39 @@ For example, the OpenSSL tag `openssl-3.0.0-alpha12` would have a branch named How are you keeping current with OpenSSL? ----------------------------------------- + (In other words, "What about rebasing?") Our plan is to always rebase on top of an upstream release tag. In particular: + - The changes for QUIC will always be at the tip of the branch -- you will know what -is from the original OpenSSL and what is for QUIC. + is from the original OpenSSL and what is for QUIC. - New versions are quickly created once upstream creates a new tag. - The use of git commands (such as "cherry") can be used to ensure that all changes -have moved forward with minimal or no changes. You will be able to see "QUIC: Add X" -on all branches and the commit itself will be nearly identical on all branches, and -any changes to that can be easily identified. + +have moved forward with minimal or no changes. You will be able to see +QUIC: Add X" on all branches and the commit itself will be nearly identical on all +branches, and any changes to that can be easily identified. What about library names? ------------------------- + Library names will be the same, but will use a different version number. The version numbers for the current OpenSSL libraries are `1.1` (for the 1.1.0 and 1.1.1 branches) and `3` (for the to-be-3.0 branch). We will be prefixing 81 (ASCII for 'Q') to the version numbers to generate a unique version number. -``` -libcrypto.so.81.3 libcrypto.so.81.1.1 libcrypto.so.1.1 libcrypto.so.3 -libssl.so.81.3 libssl.so.81.1.1 libsslo.so.1.1 libssl.so.3 -``` +- libcrypto.so.81.3 vs libcrypto.so.3 +- libcrypto.so.81.1.1 vs libcrypto.so.1.1 libcrypto.so.3 +- libssl.so.81.3 vs libssl.so.3 +- libssl.so.81.1.1 vs libsslo.so.1.1 + The SONAME of these libraries are all different, guaranteeing the correct library will be used. ...and the executable? ---------------------- + We currently do not have any plans to change the name, mainly because we haven't made any changes there. If you see a need, please open an issue. @@ -79,12 +87,14 @@ The `openssl version` command will report that it is `+quic` enabled. ...and FIPS? ------------ + We are not doing anything with FIPS. This is actually good news: you should be able to load the OpenSSL 3.0 FIPS module into an application built against this fork and everything should Just Work™. How can I contribute? --------------------- + We want any code here to be acceptable to OpenSSL. This means that all contributors must have signed the appropriate [contributor license agreements](https://www.openssl.org/policies/cla.html). We @@ -98,5 +108,6 @@ to OpenSSL, with the deltas being specific to QUIC. Who are you? ------------ + This is a collaborative effort between [Akamai](https://www.akamai.com) and [Microsoft](https://www.microsoft.com). We welcome anyone to contribute! From 3a08713a69971e0c23fe514a2d63a51da83d303f Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 9 Jul 2021 13:29:23 -0400 Subject: [PATCH 44/66] QUIC: Check for FIPS checksum changes --- .github/workflows/fips-checksums.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/.github/workflows/fips-checksums.yml b/.github/workflows/fips-checksums.yml index 1b56755bfbb17..1fa8f44044b0e 100644 --- a/.github/workflows/fips-checksums.yml +++ b/.github/workflows/fips-checksums.yml @@ -73,3 +73,29 @@ jobs: with: name: fips_checksum path: artifact/ + verify-checksums: + runs-on: ubuntu-latest + steps: + - name: install unifdef + run: | + sudo apt-get update + sudo apt-get -yq --no-install-suggests --no-install-recommends --force-yes install unifdef + - uses: actions/checkout@v2 + - name: create build dirs + run: | + mkdir ./build + - name: config + run: ../config enable-fips && perl configdata.pm --dump + working-directory: ./build + - name: make build_generated + run: make -s build_generated + working-directory: ./build + - name: make fips-checksums + run: make fips-checksums + working-directory: ./build + - name: make fips-checksums + run: make fips-checksums + working-directory: ./build + - name: make diff-fips-checksums + run: make diff-fips-checksums + working-directory: ./build From aa2a2433df26fe74383278827799f36063c419fe Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 9 Jul 2021 13:29:03 -0400 Subject: [PATCH 45/66] QUIC: Don't muck with FIPS checksums --- apps/info.c | 1 + crypto/info.c | 1 + include/openssl/crypto.h.in | 4 ---- include/openssl/evp.h | 4 ---- include/openssl/quic.h | 19 +++++++++++++++++++ include/openssl/ssl.h.in | 9 +++++++++ include/openssl/types.h | 2 -- 7 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 include/openssl/quic.h diff --git a/apps/info.c b/apps/info.c index f0f043b7f2f18..66f3ef2587e2e 100644 --- a/apps/info.c +++ b/apps/info.c @@ -10,6 +10,7 @@ #include #include "apps.h" #include "progs.h" +#include typedef enum OPTION_choice { OPT_COMMON, diff --git a/crypto/info.c b/crypto/info.c index 480bb7e6afe38..f5fa92e1580ad 100644 --- a/crypto/info.c +++ b/crypto/info.c @@ -14,6 +14,7 @@ #include "internal/cryptlib.h" #include "e_os.h" #include "buildinf.h" +#include #if defined(__arm__) || defined(__arm) || defined(__aarch64__) # include "arm_arch.h" diff --git a/include/openssl/crypto.h.in b/include/openssl/crypto.h.in index 53a3758e896a9..7232f647e8a30 100644 --- a/include/openssl/crypto.h.in +++ b/include/openssl/crypto.h.in @@ -176,10 +176,6 @@ const char *OPENSSL_info(int type); # define OPENSSL_INFO_SEED_SOURCE 1007 # define OPENSSL_INFO_CPU_SETTINGS 1008 -# ifndef OPENSSL_NO_QUIC -# define OPENSSL_INFO_QUIC 2000 -# endif - int OPENSSL_issetugid(void); struct crypto_ex_data_st { diff --git a/include/openssl/evp.h b/include/openssl/evp.h index d7c3f7b7630aa..c98d9a21f935d 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1742,10 +1742,6 @@ int EVP_PKEY_CTX_set_mac_key(EVP_PKEY_CTX *ctx, const unsigned char *key, */ # define EVP_PKEY_FLAG_SIGCTX_CUSTOM 4 -/* Used by Chromium/QUIC */ -# define X25519_PRIVATE_KEY_LEN 32 -# define X25519_PUBLIC_VALUE_LEN 32 - # ifndef OPENSSL_NO_DEPRECATED_3_0 OSSL_DEPRECATEDIN_3_0 const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type); OSSL_DEPRECATEDIN_3_0 EVP_PKEY_METHOD *EVP_PKEY_meth_new(int id, int flags); diff --git a/include/openssl/quic.h b/include/openssl/quic.h new file mode 100644 index 0000000000000..f95e9e8819e57 --- /dev/null +++ b/include/openssl/quic.h @@ -0,0 +1,19 @@ +/* + * Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef OPENSSL_QUIC_H +# define OPENSSL_QUIC_H +# pragma once +# ifndef OPENSSL_NO_QUIC + +/* moved from crypto.h.in to avoid breaking FIPS checksums */ +# define OPENSSL_INFO_QUIC 2000 + +# endif /* OPENSSL_NO_QUIC */ +#endif /* OPENSSL_QUIC_H */ diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in index 5f337616e8106..677a20be15d94 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2528,6 +2528,15 @@ const char *OSSL_default_ciphersuites(void); * ssl_encryption_level_t represents a specific QUIC encryption level used to * transmit handshake messages. BoringSSL has this as an 'enum'. */ +#include + +/* Used by Chromium/QUIC - moved from evp.h to avoid breaking FIPS checksums */ +# define X25519_PRIVATE_KEY_LEN 32 +# define X25519_PUBLIC_VALUE_LEN 32 + +/* moved from types.h to avoid breaking FIPS checksums */ +typedef struct ssl_quic_method_st SSL_QUIC_METHOD; + typedef enum ssl_encryption_level_t { ssl_encryption_initial = 0, ssl_encryption_early_data, diff --git a/include/openssl/types.h b/include/openssl/types.h index bae9d2f0146bd..de9f1665249f5 100644 --- a/include/openssl/types.h +++ b/include/openssl/types.h @@ -229,8 +229,6 @@ typedef struct ossl_decoder_ctx_st OSSL_DECODER_CTX; typedef struct ossl_self_test_st OSSL_SELF_TEST; -typedef struct ssl_quic_method_st SSL_QUIC_METHOD; - #ifdef __cplusplus } #endif From 7e709e8efdded12d91466a6960acc8694dda46bd Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 29 Jul 2021 13:58:17 -0400 Subject: [PATCH 46/66] QUIC: README.md fixups --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 53c3960c96126..49650f8d42df3 100644 --- a/README.md +++ b/README.md @@ -55,11 +55,10 @@ Our plan is to always rebase on top of an upstream release tag. In particular: - The changes for QUIC will always be at the tip of the branch -- you will know what is from the original OpenSSL and what is for QUIC. - New versions are quickly created once upstream creates a new tag. -- The use of git commands (such as "cherry") can be used to ensure that all changes - -have moved forward with minimal or no changes. You will be able to see -QUIC: Add X" on all branches and the commit itself will be nearly identical on all -branches, and any changes to that can be easily identified. +- The use of git commands (such as `cherry`) can be used to ensure that all changes + have moved forward with minimal or no changes. You will be able to see + "QUIC: Add X" on all branches and the commit itself will be nearly identical on + all branches, and any changes to that can be easily identified. What about library names? ------------------------- @@ -70,7 +69,7 @@ and `3` (for the to-be-3.0 branch). We will be prefixing 81 (ASCII for 'Q') to the version numbers to generate a unique version number. - libcrypto.so.81.3 vs libcrypto.so.3 -- libcrypto.so.81.1.1 vs libcrypto.so.1.1 libcrypto.so.3 +- libcrypto.so.81.1.1 vs libcrypto.so.1.1 - libssl.so.81.3 vs libssl.so.3 - libssl.so.81.1.1 vs libsslo.so.1.1 From deec27108c0642d271af7a598f18909a34ae9c13 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 7 Sep 2021 12:26:10 -0400 Subject: [PATCH 47/66] QUIC: Update RFC references --- doc/man3/SSL_CTX_set_quic_method.pod | 11 +++++------ include/openssl/tls1.h | 2 +- ssl/statem/extensions_clnt.c | 2 +- ssl/statem/extensions_srvr.c | 2 +- ssl/statem/statem_clnt.c | 2 +- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod index 906c7591d9e55..e38f1d21244ae 100644 --- a/doc/man3/SSL_CTX_set_quic_method.pod +++ b/doc/man3/SSL_CTX_set_quic_method.pod @@ -74,7 +74,7 @@ SSL_quic_max_handshake_flight_len() returns the maximum number of bytes that may be received at the given encryption level. This function should be used to limit buffering in the QUIC implementation. -See https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-4. +See L. SSL_quic_read_level() returns the current read encryption level. @@ -120,7 +120,7 @@ These APIs are implementations of BoringSSL's QUIC APIs. QUIC acts as an underlying transport for the TLS 1.3 handshake. The following functions allow a QUIC implementation to serve as the underlying transport as -described in draft-ietf-quic-tls. +described in RFC9001. When configured for QUIC, SSL_do_handshake() will drive the handshake as before, but it will not use the configured B. It will call functions from @@ -139,18 +139,17 @@ pass the active write level to add_handshake_data() when writing data. Callers can use SSL_quic_write_level() to query the active write level when generating their own errors. -See https://tools.ietf.org/html/draft-ietf-quic-tls-27#section-4.1 for more -details. +See L for more details. To avoid DoS attacks, the QUIC implementation must limit the amount of data being queued up. The implementation can call SSL_quic_max_handshake_flight_len() to get the maximum buffer length at each encryption level. -draft-ietf-quic-tls defines a new TLS extension "quic_transport_parameters" +RFC9001 defines a new TLS extension "quic_transport_parameters" used by QUIC for each endpoint to unilaterally declare its supported transport parameters. The contents of the extension are specified in -https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-18 (as +L (as a sequence of tag/length/value parameters) along with the interpretation of the various parameters and the rules for their processing. diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h index 2669203a28fed..40ac50e9757ce 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -151,7 +151,7 @@ extern "C" { /* Temporary extension type */ # define TLSEXT_TYPE_renegotiate 0xff01 -/* ExtensionType value from draft-ietf-quic-tls-27 */ + /* ExtensionType value from RFC9001 */ # define TLSEXT_TYPE_quic_transport_parameters_draft 0xffa5 # define TLSEXT_TYPE_quic_transport_parameters 0x0039 diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index 6da3cc560f070..e7c54e633ea58 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1942,7 +1942,7 @@ int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context, #ifndef OPENSSL_NO_QUIC /* * QUIC server must send 0xFFFFFFFF or it's a PROTOCOL_VIOLATION - * per draft-ietf-quic-tls-27 S4.5 + * per RFC9001 S4.6.1 */ if (s->quic_method != NULL && max_early_data != 0xFFFFFFFF) { SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_INVALID_MAX_EARLY_DATA); diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 244e711b79ba3..0dfbfed9a4af6 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1911,7 +1911,7 @@ EXT_RETURN tls_construct_stoc_early_data(SSL *s, WPACKET *pkt, return EXT_RETURN_NOT_SENT; #ifndef OPENSSL_NO_QUIC - /* QUIC server must always send 0xFFFFFFFF, per draft-ietf-quic-tls-27 S4.5 */ + /* QUIC server must always send 0xFFFFFFFF, per RFC9001 S4.6.1 */ if (SSL_IS_QUIC(s)) max_early_data = 0xFFFFFFFF; #endif diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index 36cbba2a50c1c..f9235d4160c54 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -905,7 +905,7 @@ int ossl_statem_client_construct_message(SSL *s, WPACKET *pkt, case TLS_ST_CW_END_OF_EARLY_DATA: #ifndef OPENSSL_NO_QUIC - /* QUIC does not send EndOfEarlyData, draft-ietf-quic-tls-24 S8.3 */ + /* QUIC does not send EndOfEarlyData, RFC9001 S8.3 */ if (s->quic_method != NULL) { *confunc = NULL; *mt = SSL3_MT_DUMMY; From 67aca74266172bc09c4fe4638d7efe1927e9c40e Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 7 Sep 2021 12:29:37 -0400 Subject: [PATCH 48/66] QUIC: revert white-space change --- include/openssl/evp.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/openssl/evp.h b/include/openssl/evp.h index c98d9a21f935d..e64072f965626 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1741,7 +1741,6 @@ int EVP_PKEY_CTX_set_mac_key(EVP_PKEY_CTX *ctx, const unsigned char *key, * Method handles all operations: don't assume any digest related defaults. */ # define EVP_PKEY_FLAG_SIGCTX_CUSTOM 4 - # ifndef OPENSSL_NO_DEPRECATED_3_0 OSSL_DEPRECATEDIN_3_0 const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type); OSSL_DEPRECATEDIN_3_0 EVP_PKEY_METHOD *EVP_PKEY_meth_new(int id, int flags); From 3e3250b381bf1d952349143626250fca2e83e163 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 7 Sep 2021 12:32:54 -0400 Subject: [PATCH 49/66] QUIC: update copyrights --- doc/man3/SSL_CTX_set_quic_method.pod | 2 +- ssl/ssl_quic.c | 2 +- ssl/statem/statem_quic.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod index e38f1d21244ae..b9191a0264147 100644 --- a/doc/man3/SSL_CTX_set_quic_method.pod +++ b/doc/man3/SSL_CTX_set_quic_method.pod @@ -257,7 +257,7 @@ These functions were added in OpenSSL 3.0.0. =head1 COPYRIGHT -Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index 6cbd47ad2d390..987c1e740ca71 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -1,5 +1,5 @@ /* - * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy diff --git a/ssl/statem/statem_quic.c b/ssl/statem/statem_quic.c index a51bfd74d8c2f..7bd329c242154 100644 --- a/ssl/statem/statem_quic.c +++ b/ssl/statem/statem_quic.c @@ -1,5 +1,5 @@ /* - * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy From 58d907e9a355f8ee7625a7f1dfc27cee36fa92a0 Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Tue, 7 Sep 2021 09:17:39 -0700 Subject: [PATCH 50/66] QUIC: update SSL_provide_quic_data() documentation We now let you call this function outside of the handshake, to provide post-handshake QUIC data. We also no longer have the limitation that the application must provide the TLS handshake message header in a single call. --- doc/man3/SSL_CTX_set_quic_method.pod | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod index b9191a0264147..b2d78872ca3e5 100644 --- a/doc/man3/SSL_CTX_set_quic_method.pod +++ b/doc/man3/SSL_CTX_set_quic_method.pod @@ -82,10 +82,8 @@ SSL_quic_write_level() returns the current write encryption level. SSL_provide_quic_data() is used to provide data from QUIC CRYPTO frames to the state machine, at a particular encryption level B. It is an error to -call this function outside of the handshake or with an encryption level other -than the current read level. The application must buffer and consolidate any -frames with less than four bytes of content. It returns one on success and -zero on error. +call this function with an encryption level less than the current read level. +It returns one on success and zero on error. SSL_process_quic_post_handshake() processes any data that QUIC has provided after the handshake has completed. This includes NewSessionTicket messages From 46cdcfcc7181c8d70eafd94b7cb62b0cb3cce3ed Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Tue, 7 Sep 2021 09:17:56 -0700 Subject: [PATCH 51/66] QUIC: expound on what DoS attacks QUIC avoids The limit on the amount of queued data is to avoid being an amplification vector, specifically. --- doc/man3/SSL_CTX_set_quic_method.pod | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod index b2d78872ca3e5..1ed076c301a27 100644 --- a/doc/man3/SSL_CTX_set_quic_method.pod +++ b/doc/man3/SSL_CTX_set_quic_method.pod @@ -139,8 +139,8 @@ generating their own errors. See L for more details. -To avoid DoS attacks, the QUIC implementation must limit the amount of data -being queued up. The implementation can call +To avoid amplifying DoS attacks, the QUIC implementation must limit the amount +of data being queued up. The implementation can call SSL_quic_max_handshake_flight_len() to get the maximum buffer length at each encryption level. From 88e9d7c82f1ef25ad14595211f59f5f8d07a0403 Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Tue, 7 Sep 2021 09:20:44 -0700 Subject: [PATCH 52/66] QUIC: remove SSL_get_current_cipher() reference The QUIC APIs have no need to interact with TLS ciphers, since QUIC records use different cryptographic protections than TLS ciphers. --- doc/man3/SSL_CTX_set_quic_method.pod | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod index 1ed076c301a27..f12aa8662bef6 100644 --- a/doc/man3/SSL_CTX_set_quic_method.pod +++ b/doc/man3/SSL_CTX_set_quic_method.pod @@ -209,9 +209,6 @@ only available in the client to server direction. The other secret will be NULL. The server acknowledges such data at B, which will be configured in the same SSL_do_handshake() call. -This function should use SSL_get_current_cipher() to determine the TLS -cipher suite. - add_handshake_data() adds handshake data to the current flight at the given encryption level. It returns one on success and zero on error. From 084145b8852df060e7e0e1659fd9662a290f23bf Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Tue, 7 Sep 2021 14:21:22 -0700 Subject: [PATCH 53/66] QUIC: use SSL_IS_QUIC() in more places --- doc/man3/SSL_CTX_set_quic_method.pod | 2 +- ssl/statem/extensions_clnt.c | 2 +- ssl/statem/statem_clnt.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod index f12aa8662bef6..aab5e38889b04 100644 --- a/doc/man3/SSL_CTX_set_quic_method.pod +++ b/doc/man3/SSL_CTX_set_quic_method.pod @@ -103,7 +103,7 @@ 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 +SSL_get_peer_quic_transport_version() returns the version the that was negotiated. SSL_set_quic_early_data_enabled() enables QUIC early data if a nonzero diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index e7c54e633ea58..caeb818a37ce4 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1944,7 +1944,7 @@ int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context, * QUIC server must send 0xFFFFFFFF or it's a PROTOCOL_VIOLATION * per RFC9001 S4.6.1 */ - if (s->quic_method != NULL && max_early_data != 0xFFFFFFFF) { + if (SSL_IS_QUIC(s) && max_early_data != 0xFFFFFFFF) { SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_INVALID_MAX_EARLY_DATA); return 0; } diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index f9235d4160c54..9d925091b6c61 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -906,7 +906,7 @@ int ossl_statem_client_construct_message(SSL *s, WPACKET *pkt, case TLS_ST_CW_END_OF_EARLY_DATA: #ifndef OPENSSL_NO_QUIC /* QUIC does not send EndOfEarlyData, RFC9001 S8.3 */ - if (s->quic_method != NULL) { + if (SSL_IS_QUIC(s)) { *confunc = NULL; *mt = SSL3_MT_DUMMY; break; From b262517e6321690419d65d794510d07134669f6a Mon Sep 17 00:00:00 2001 From: Todd Short Date: Mon, 18 Oct 2021 16:54:31 -0400 Subject: [PATCH 54/66] QUIC: Error when non-empty session_id in CH (fixes #29) --- ssl/statem/statem_srvr.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 2d3f05d940f3b..ddd85cc38c4a9 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -1566,6 +1566,15 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) goto err; } } +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + /* Any other QUIC checks on ClientHello here */ + if (clienthello->session_id_len > 0) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_LENGTH_MISMATCH); + goto err; + } + } +#endif } if (!PACKET_copy_all(&compression, clienthello->compressions, From 737c607564c4878fabac4597c24c6513def871f4 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 19 Oct 2021 12:13:31 -0400 Subject: [PATCH 55/66] QUIC: Update SSL_clear() to clear quic data Fixes #55 Had to fixup tests because SSL_accept() eventually calls SSL_clear() and it was removing the inital ClientHello sent via SSL_provide_quic_data() from the server SSL. --- ssl/ssl_lib.c | 32 ++++++++++++++++++++++++++++++++ test/helpers/ssltestlib.c | 5 ----- test/sslapitest.c | 19 ++++++++++++++----- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 24d9fb3ca3767..588c48f8db782 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -625,6 +625,38 @@ int SSL_clear(SSL *s) s->shared_sigalgs = NULL; s->shared_sigalgslen = 0; +#if !defined(OPENSSL_NO_QUIC) + 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; + OPENSSL_free(s->ext.peer_quic_transport_params); + s->ext.peer_quic_transport_params = NULL; + s->ext.peer_quic_transport_params_len = 0; + s->quic_read_level = ssl_encryption_initial; + s->quic_write_level = ssl_encryption_initial; + s->quic_latest_level_received = ssl_encryption_initial; + while (s->quic_input_data_head != NULL) { + QUIC_DATA *qd; + + qd = s->quic_input_data_head; + s->quic_input_data_head = qd->next; + OPENSSL_free(qd); + } + s->quic_input_data_tail = NULL; + BUF_MEM_free(s->quic_buf); + s->quic_buf = NULL; + s->quic_next_record_start = 0; + memset(s->client_hand_traffic_secret, 0, EVP_MAX_MD_SIZE); + memset(s->server_hand_traffic_secret, 0, EVP_MAX_MD_SIZE); + memset(s->client_early_traffic_secret, 0, EVP_MAX_MD_SIZE); + /* + * CONFIG - DON'T CLEAR + * s->ext.quic_transport_params + * s->ext.quic_transport_params_len + * s->quic_transport_version + * s->quic_method = NULL; + */ +#endif /* * Check to see if we were changed into a different method, if so, revert * back. diff --git a/test/helpers/ssltestlib.c b/test/helpers/ssltestlib.c index 4812f27a4b532..ef4a6177aa7dd 100644 --- a/test/helpers/ssltestlib.c +++ b/test/helpers/ssltestlib.c @@ -1157,11 +1157,6 @@ int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want) if (!create_bare_ssl_connection(serverssl, clientssl, want, 1)) return 0; -#ifndef OPENSSL_NO_QUIC - /* QUIC does not support SSL_read_ex */ - if (SSL_is_quic(clientssl)) - return 1; -#endif /* * We attempt to read some data on the client side which we expect to fail. * This will ensure we have received the NewSessionTicket in TLSv1.3 where diff --git a/test/sslapitest.c b/test/sslapitest.c index 7604394fa1cde..7839830c5d306 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10482,6 +10482,7 @@ static int test_quic_api_version(int clnt, int srvr) static const char *client_str = "CLIENT"; const uint8_t *peer_str; size_t peer_str_len; + int err; TEST_info("original clnt=0x%X, srvr=0x%X\n", clnt, srvr); @@ -10504,8 +10505,10 @@ static int test_quic_api_version(int clnt, int srvr) || !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_int_eq(err = SSL_accept(serverssl), -1) + || !TEST_int_eq(SSL_get_error(serverssl, err), SSL_ERROR_WANT_READ) + || !TEST_true(create_bare_ssl_connection(serverssl, clientssl, + SSL_ERROR_NONE, 0)) || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION) || !TEST_true(SSL_version(clientssl) == TLS1_3_VERSION) || !(TEST_int_eq(SSL_quic_read_level(clientssl), ssl_encryption_application)) @@ -10627,6 +10630,7 @@ static int quic_setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx, { static const char *server_str = "SERVER"; static const char *client_str = "CLIENT"; + int err; if (*sctx == NULL && (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), @@ -10704,8 +10708,10 @@ static int quic_setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx, if (sess == NULL) return 1; - if (!TEST_true(create_ssl_connection(*serverssl, *clientssl, - SSL_ERROR_NONE))) + if (!TEST_int_eq(err = SSL_accept(*serverssl), -1) + || !TEST_int_eq(SSL_get_error(*serverssl, err), SSL_ERROR_WANT_READ) + || !TEST_true(create_bare_ssl_connection(*serverssl, *clientssl, + SSL_ERROR_NONE, 0))) return 0; /* Deal with two NewSessionTickets */ @@ -10744,12 +10750,15 @@ static int test_quic_early_data(int tst) SSL *clientssl = NULL, *serverssl = NULL; int testresult = 0; SSL_SESSION *sess = NULL; + int err; if (!TEST_true(quic_setupearly_data_test(&cctx, &sctx, &clientssl, &serverssl, &sess, tst))) goto end; - if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)) + if (!TEST_int_eq(err = SSL_accept(serverssl), -1) + || !TEST_int_eq(SSL_get_error(serverssl, err), SSL_ERROR_WANT_READ) + || !TEST_true(create_bare_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE, 0)) || !TEST_true(SSL_get_early_data_status(serverssl))) goto end; From bd9d6ff27bdbc5e7fc31fa0f97b5daa202853007 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 29 Oct 2021 14:15:06 -0400 Subject: [PATCH 56/66] QUIC: Better SSL_clear() Undo SSL_clear() changes in test Break apart SSL_clear() into SSL_clear_quic() and SSL_clear_not_quic() In SSL_clear(), call both functions In SSL_accept(), call SSL_clear_not_quic() Don't make the new functions public. --- ssl/ssl_lib.c | 81 +++++++++++++++++++++++++++------------------ ssl/ssl_local.h | 5 +++ ssl/statem/statem.c | 5 +++ test/sslapitest.c | 17 +++------- 4 files changed, 63 insertions(+), 45 deletions(-) diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 588c48f8db782..b0ab5c6ef8004 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -566,7 +566,56 @@ static void clear_ciphers(SSL *s) ssl_clear_hash_ctx(&s->write_hash); } +#ifndef OPENSSL_NO_QUIC int SSL_clear(SSL *s) +{ + if (!SSL_clear_not_quic(s)) + return 0; + return SSL_clear_quic(s); +} + +int SSL_clear_quic(SSL *s) +{ + 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; + OPENSSL_free(s->ext.peer_quic_transport_params); + s->ext.peer_quic_transport_params = NULL; + s->ext.peer_quic_transport_params_len = 0; + s->quic_read_level = ssl_encryption_initial; + s->quic_write_level = ssl_encryption_initial; + s->quic_latest_level_received = ssl_encryption_initial; + while (s->quic_input_data_head != NULL) { + QUIC_DATA *qd; + + qd = s->quic_input_data_head; + s->quic_input_data_head = qd->next; + OPENSSL_free(qd); + } + s->quic_input_data_tail = NULL; + BUF_MEM_free(s->quic_buf); + s->quic_buf = NULL; + s->quic_next_record_start = 0; + memset(s->client_hand_traffic_secret, 0, EVP_MAX_MD_SIZE); + memset(s->server_hand_traffic_secret, 0, EVP_MAX_MD_SIZE); + memset(s->client_early_traffic_secret, 0, EVP_MAX_MD_SIZE); + /* + * CONFIG - DON'T CLEAR + * s->ext.quic_transport_params + * s->ext.quic_transport_params_len + * s->quic_transport_version + * s->quic_method = NULL; + */ + return 1; +} +#endif + +/* Keep this conditional very local */ +#ifndef OPENSSL_NO_QUIC +int SSL_clear_not_quic(SSL *s) +#else +int SSL_clear(SSL *s) +#endif { if (s->method == NULL) { ERR_raise(ERR_LIB_SSL, SSL_R_NO_METHOD_SPECIFIED); @@ -625,38 +674,6 @@ int SSL_clear(SSL *s) s->shared_sigalgs = NULL; s->shared_sigalgslen = 0; -#if !defined(OPENSSL_NO_QUIC) - 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; - OPENSSL_free(s->ext.peer_quic_transport_params); - s->ext.peer_quic_transport_params = NULL; - s->ext.peer_quic_transport_params_len = 0; - s->quic_read_level = ssl_encryption_initial; - s->quic_write_level = ssl_encryption_initial; - s->quic_latest_level_received = ssl_encryption_initial; - while (s->quic_input_data_head != NULL) { - QUIC_DATA *qd; - - qd = s->quic_input_data_head; - s->quic_input_data_head = qd->next; - OPENSSL_free(qd); - } - s->quic_input_data_tail = NULL; - BUF_MEM_free(s->quic_buf); - s->quic_buf = NULL; - s->quic_next_record_start = 0; - memset(s->client_hand_traffic_secret, 0, EVP_MAX_MD_SIZE); - memset(s->server_hand_traffic_secret, 0, EVP_MAX_MD_SIZE); - memset(s->client_early_traffic_secret, 0, EVP_MAX_MD_SIZE); - /* - * CONFIG - DON'T CLEAR - * s->ext.quic_transport_params - * s->ext.quic_transport_params_len - * s->quic_transport_version - * s->quic_method = NULL; - */ -#endif /* * Check to see if we were changed into a different method, if so, revert * back. diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 839e7b69a2947..74b4319df4b21 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -2867,6 +2867,11 @@ void custom_exts_free(custom_ext_methods *exts); void ssl_comp_free_compression_methods_int(void); +#ifndef OPENSSL_NO_QUIC +__owur int SSL_clear_not_quic(SSL *s); +__owur int SSL_clear_quic(SSL *s); +#endif + /* ssl_mcnf.c */ void ssl_ctx_system_config(SSL_CTX *ctx); diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c index e67ee26e87d55..d80d4da2038d1 100644 --- a/ssl/statem/statem.c +++ b/ssl/statem/statem.c @@ -334,8 +334,13 @@ static int state_machine(SSL *s, int server) * If we are stateless then we already called SSL_clear() - don't do * it again and clear the STATELESS flag itself. */ +#ifndef OPENSSL_NO_QUIC + if ((s->s3.flags & TLS1_FLAGS_STATELESS) == 0 && !SSL_clear_not_quic(s)) + return -1; +#else if ((s->s3.flags & TLS1_FLAGS_STATELESS) == 0 && !SSL_clear(s)) return -1; +#endif } #ifndef OPENSSL_NO_SCTP if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))) { diff --git a/test/sslapitest.c b/test/sslapitest.c index 7839830c5d306..3da790b5d2526 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10482,7 +10482,6 @@ static int test_quic_api_version(int clnt, int srvr) static const char *client_str = "CLIENT"; const uint8_t *peer_str; size_t peer_str_len; - int err; TEST_info("original clnt=0x%X, srvr=0x%X\n", clnt, srvr); @@ -10505,10 +10504,8 @@ static int test_quic_api_version(int clnt, int srvr) || !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_int_eq(err = SSL_accept(serverssl), -1) - || !TEST_int_eq(SSL_get_error(serverssl, err), SSL_ERROR_WANT_READ) || !TEST_true(create_bare_ssl_connection(serverssl, clientssl, - SSL_ERROR_NONE, 0)) + SSL_ERROR_NONE, 0)) || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION) || !TEST_true(SSL_version(clientssl) == TLS1_3_VERSION) || !(TEST_int_eq(SSL_quic_read_level(clientssl), ssl_encryption_application)) @@ -10630,7 +10627,6 @@ static int quic_setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx, { static const char *server_str = "SERVER"; static const char *client_str = "CLIENT"; - int err; if (*sctx == NULL && (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), @@ -10708,10 +10704,8 @@ static int quic_setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx, if (sess == NULL) return 1; - if (!TEST_int_eq(err = SSL_accept(*serverssl), -1) - || !TEST_int_eq(SSL_get_error(*serverssl, err), SSL_ERROR_WANT_READ) - || !TEST_true(create_bare_ssl_connection(*serverssl, *clientssl, - SSL_ERROR_NONE, 0))) + if (!TEST_true(create_bare_ssl_connection(*serverssl, *clientssl, + SSL_ERROR_NONE, 0))) return 0; /* Deal with two NewSessionTickets */ @@ -10750,15 +10744,12 @@ static int test_quic_early_data(int tst) SSL *clientssl = NULL, *serverssl = NULL; int testresult = 0; SSL_SESSION *sess = NULL; - int err; if (!TEST_true(quic_setupearly_data_test(&cctx, &sctx, &clientssl, &serverssl, &sess, tst))) goto end; - if (!TEST_int_eq(err = SSL_accept(serverssl), -1) - || !TEST_int_eq(SSL_get_error(serverssl, err), SSL_ERROR_WANT_READ) - || !TEST_true(create_bare_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE, 0)) + if (!TEST_true(create_bare_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE, 0)) || !TEST_true(SSL_get_early_data_status(serverssl))) goto end; From b9e543be9e6cc212260151cb9fcf6125fc43ab90 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 2 Nov 2021 12:16:57 -0400 Subject: [PATCH 57/66] QUIC: Update README Add link to OMCs plans. OpenSSL 3.0 is released, update tense. Fix some typos. Make relative URLs absolute. --- README.md | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 49650f8d42df3..f960fd8e67542 100644 --- a/README.md +++ b/README.md @@ -4,27 +4,28 @@ What This Is This is a fork of [OpenSSL](https://www.openssl.org) to enable QUIC. In addition to the website, the official source distribution is at . The OpenSSL `README` can be found at -[README-OpenSSL.md](README-OpenSSL.md). +[README-OpenSSL.md](https://github.com/quictls/openssl/blob/openssl-3.0.1%2Bquic/README-OpenSSL.md) -This fork adds API that can be used by QUIC implementations for connection +This fork adds APIs that can be used by QUIC implementations for connection handshakes. Quoting the IETF Working group [charter](https://datatracker.ietf.org/wg/quic/about/), QUIC is a "UDP-based, stream-multiplexing, encrypted transport protocol." If you don't need QUIC, you should use the official OpenSSL distributions. -This API's here are used by Microsoft's +The APIs here are used by Microsoft's [MsQuic](https://github.com/microsoft/msquic) and Google's [Chromium QUIC](https://chromium.googlesource.com/chromium/src/+/master/net/quic/) We are not in competition with OpenSSL project. We informed them of our plans to fork the code before we went public. We do not speak for the OpenSSL project, and can only point to a -[blog post](https://www.openssl.org/blog/blog/2020/02/17/QUIC-and-OpenSSL/) that -provides their view of QUIC support. +[blog post](https://www.openssl.org/blog/blog/2020/02/17/QUIC-and-OpenSSL/) and +[openssl-project email](https://github.com/quictls/openssl/discussions/54) +that provides their view of QUIC support. As stated in their blog post, the OpenSSL team is focused on their 3.0 release -which is still in alpha, and does not intend to add QUIC functionality to 1.1.x. -There is a community need for a QUIC capable TLS library. This fork is intended +(released 2021-09-07), and does not intend to add QUIC functionality to 1.1.x. +There is a community need for a QUIC-capable TLS library. This fork is intended as stopgap solution to enable higher level frameworks and runtimes to use QUIC with the proven and reliable TLS functionality from OpenSSL. This fork will be maintained until OpenSSL officially provides reasonable support for QUIC @@ -42,8 +43,8 @@ What about branches? We don't want to conflict with OpenSSL branch names. Our current plan is to append `+quic`. Release tags are likely to be the QUIC branch with `-releaseX` appended. -For example, the OpenSSL tag `openssl-3.0.0-alpha12` would have a branch named -`openssl-3.0.0-alpha12+quic` and a release tag of `openssl-3.0.0-alpha12+quic-release1` +For example, the OpenSSL tag `openssl-3.0.0` would have a branch named +`openssl-3.0.0+quic` and a release tag of `openssl-3.0.0+quic-release1`. How are you keeping current with OpenSSL? ----------------------------------------- @@ -65,13 +66,13 @@ What about library names? Library names will be the same, but will use a different version number. The version numbers for the current OpenSSL libraries are `1.1` (for the 1.1.0 and 1.1.1 branches) -and `3` (for the to-be-3.0 branch). We will be prefixing 81 (ASCII for 'Q') to +and `3` (for the 3.0 branch). We will be prefixing `81` (ASCII for 'Q') to the version numbers to generate a unique version number. -- libcrypto.so.81.3 vs libcrypto.so.3 -- libcrypto.so.81.1.1 vs libcrypto.so.1.1 -- libssl.so.81.3 vs libssl.so.3 -- libssl.so.81.1.1 vs libsslo.so.1.1 +- `libcrypto.so.81.3` vs `libcrypto.so.3` +- `libcrypto.so.81.1.1` vs `libcrypto.so.1.1` +- `libssl.so.81.3` vs `libssl.so.3` +- `libssl.so.81.1.1` vs `libssl.so.1.1` The SONAME of these libraries are all different, guaranteeing the correct library will be used. From 26aa6b8a12c8a4e4937d13fd6b373b65775e7280 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 15 Mar 2022 12:26:00 -0400 Subject: [PATCH 58/66] QUIC: Update README.md for 3.0.7 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f960fd8e67542..899a0f194b600 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ What This Is This is a fork of [OpenSSL](https://www.openssl.org) to enable QUIC. In addition to the website, the official source distribution is at . The OpenSSL `README` can be found at -[README-OpenSSL.md](https://github.com/quictls/openssl/blob/openssl-3.0.1%2Bquic/README-OpenSSL.md) +[README-OpenSSL.md](https://github.com/quictls/openssl/blob/openssl-3.0.7%2Bquic/README-OpenSSL.md) This fork adds APIs that can be used by QUIC implementations for connection handshakes. Quoting the IETF Working group From 06ed1f893cceffcc9ad2ba133be7cd497f1e1490 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 1 Nov 2022 12:55:46 -0400 Subject: [PATCH 59/66] QUIC: Fix extension test --- ssl/ssl_local.h | 4 ++-- test/ext_internal_test.c | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 74b4319df4b21..51c4a77a9ed7c 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -773,8 +773,8 @@ 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_quic_transport_parameters_draft, + TLSEXT_IDX_quic_transport_parameters, TLSEXT_IDX_padding, TLSEXT_IDX_psk, /* Dummy index - must always be the last entry */ diff --git a/test/ext_internal_test.c b/test/ext_internal_test.c index dec6ee61efb35..769b25391d577 100644 --- a/test/ext_internal_test.c +++ b/test/ext_internal_test.c @@ -69,6 +69,13 @@ static EXT_LIST ext_list[] = { EXT_ENTRY(cryptopro_bug), EXT_ENTRY(early_data), EXT_ENTRY(certificate_authorities), +#ifndef OPENSSL_NO_QUIC + EXT_ENTRY(quic_transport_parameters_draft), + EXT_ENTRY(quic_transport_parameters), +#else + EXT_EXCEPTION(quic_transport_parameters_draft), + EXT_EXCEPTION(quic_transport_parameters), +#endif EXT_ENTRY(padding), EXT_ENTRY(psk), EXT_END(num_builtins) From dad1437ef78ce115386a810903186e234c14869c Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 7 Feb 2023 12:40:55 -0500 Subject: [PATCH 60/66] QUIC: Update README.md for 3.0.8 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 899a0f194b600..ef1d8fcf48198 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ What This Is This is a fork of [OpenSSL](https://www.openssl.org) to enable QUIC. In addition to the website, the official source distribution is at . The OpenSSL `README` can be found at -[README-OpenSSL.md](https://github.com/quictls/openssl/blob/openssl-3.0.7%2Bquic/README-OpenSSL.md) +[README-OpenSSL.md](https://github.com/quictls/openssl/blob/openssl-3.0.8%2Bquic/README-OpenSSL.md) This fork adds APIs that can be used by QUIC implementations for connection handshakes. Quoting the IETF Working group From 63bdb717b45d827409e0077ec9bf1b28dec10d5a Mon Sep 17 00:00:00 2001 From: Watson Ladd Date: Tue, 30 May 2023 09:30:31 -0700 Subject: [PATCH 61/66] QUIC: Update README.md for OpenSSL 3.0.9 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ef1d8fcf48198..0a76794507312 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ What This Is This is a fork of [OpenSSL](https://www.openssl.org) to enable QUIC. In addition to the website, the official source distribution is at . The OpenSSL `README` can be found at -[README-OpenSSL.md](https://github.com/quictls/openssl/blob/openssl-3.0.8%2Bquic/README-OpenSSL.md) +[README-OpenSSL.md](https://github.com/quictls/openssl/blob/openssl-3.0.9%2Bquic/README-OpenSSL.md) This fork adds APIs that can be used by QUIC implementations for connection handshakes. Quoting the IETF Working group From f29897cbb838309673eced3825a864dfcb3d67fc Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 1 Aug 2023 13:27:14 -0400 Subject: [PATCH 62/66] QUIC: Update README.md for 3.0.10 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a76794507312..80090a262c050 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ What This Is This is a fork of [OpenSSL](https://www.openssl.org) to enable QUIC. In addition to the website, the official source distribution is at . The OpenSSL `README` can be found at -[README-OpenSSL.md](https://github.com/quictls/openssl/blob/openssl-3.0.9%2Bquic/README-OpenSSL.md) +[README-OpenSSL.md](https://github.com/quictls/openssl/blob/openssl-3.0.10%2Bquic/README-OpenSSL.md) This fork adds APIs that can be used by QUIC implementations for connection handshakes. Quoting the IETF Working group From 292a1a337098282a6dcaf73985b0ebd7e4996e13 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Wed, 2 Aug 2023 10:43:22 -0400 Subject: [PATCH 63/66] QUIC: Fix md-nits --- CHANGES.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 40641853dc47c..3c899c559aebb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -27,8 +27,10 @@ The migration guide contains more detailed information related to new features, breaking changes, and mappings for the large list of deprecated functions. [Migration guide]: https://github.com/openssl/openssl/tree/master/doc/man7/migration_guide.pod + ### Changes between 3.0.10 and 3.0.10+quic [1 Aug 2023] - * Add QUIC API support from BoringSSL + +* Add QUIC API support from BoringSSL *Todd Short* From 9497a4a2feb53f152fcde95177f94d365285b610 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Wed, 2 Aug 2023 10:52:53 -0400 Subject: [PATCH 64/66] QUIC: Cleanup quic tests --- test/sslapitest.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/sslapitest.c b/test/sslapitest.c index 3da790b5d2526..a7df6552eb16b 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10552,6 +10552,11 @@ static int test_quic_api_version(int clnt, int srvr) testresult = 1; end: + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + return testresult; } From 0f3bce9c4cb8bb6a88b99a4ee98cda93c1609490 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 6 Oct 2023 11:48:37 -0400 Subject: [PATCH 65/66] QUIC: Update MD files for 3.0.11 --- CHANGES.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 3c899c559aebb..93f51942cb7dc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -28,7 +28,7 @@ breaking changes, and mappings for the large list of deprecated functions. [Migration guide]: https://github.com/openssl/openssl/tree/master/doc/man7/migration_guide.pod -### Changes between 3.0.10 and 3.0.10+quic [1 Aug 2023] +### Changes between 3.0.11 and 3.0.11+quic [6 Oct 2023] * Add QUIC API support from BoringSSL diff --git a/README.md b/README.md index 80090a262c050..27c7b8f12e410 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ What This Is This is a fork of [OpenSSL](https://www.openssl.org) to enable QUIC. In addition to the website, the official source distribution is at . The OpenSSL `README` can be found at -[README-OpenSSL.md](https://github.com/quictls/openssl/blob/openssl-3.0.10%2Bquic/README-OpenSSL.md) +[README-OpenSSL.md](https://github.com/quictls/openssl/blob/openssl-3.0.11%2Bquic/README-OpenSSL.md) This fork adds APIs that can be used by QUIC implementations for connection handshakes. Quoting the IETF Working group From f1757dfc696348d15cb01a35ce5099c1efdeffea Mon Sep 17 00:00:00 2001 From: Watson Ladd Date: Tue, 24 Oct 2023 09:40:24 -0700 Subject: [PATCH 66/66] QUIC: Update MD files for 3.0.12 --- CHANGES.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 93f51942cb7dc..7d892d57ac091 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -28,7 +28,7 @@ breaking changes, and mappings for the large list of deprecated functions. [Migration guide]: https://github.com/openssl/openssl/tree/master/doc/man7/migration_guide.pod -### Changes between 3.0.11 and 3.0.11+quic [6 Oct 2023] +### Changes between 3.0.12 and 3.0.12+quic [24 Oct 2023] * Add QUIC API support from BoringSSL diff --git a/README.md b/README.md index 27c7b8f12e410..e73b04b378e32 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ What This Is This is a fork of [OpenSSL](https://www.openssl.org) to enable QUIC. In addition to the website, the official source distribution is at . The OpenSSL `README` can be found at -[README-OpenSSL.md](https://github.com/quictls/openssl/blob/openssl-3.0.11%2Bquic/README-OpenSSL.md) +[README-OpenSSL.md](https://github.com/quictls/openssl/blob/openssl-3.0.12%2Bquic/README-OpenSSL.md) This fork adds APIs that can be used by QUIC implementations for connection handshakes. Quoting the IETF Working group