From 3fdfe6298bbc61e9ec63e89e7ec83a2db707b0fc Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 12 Apr 2019 11:13:25 -0400 Subject: [PATCH 01/67] 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 | 6 + 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 | 140 +++++++++++++++ test/tls13secretstest.c | 7 + util/libssl.num | 11 ++ util/other.syms | 2 + 31 files changed, 1199 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 00229382d4b78..a6acac3b94c91 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -509,6 +509,12 @@ 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.8 and 3.0.8+quic [7 Feb 2023] + + * Add QUIC API support from BoringSSL. + + *Todd Short* + ### Changes between 3.0.7 and 3.0.8 [7 Feb 2023] * Fixed NULL dereference during PKCS7 data verification. diff --git a/Configure b/Configure index b358f86c26ef0..41ddd9d7da392 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 036ac468a9e69..189e1f36225ee 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -830,6 +830,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 2bd54879b1a18..ba0fa2c90a139 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1268,6 +1268,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 @@ -1555,6 +1556,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 09b7280bdd581..a55ad4d980f9b 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-2024 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 d0fce0c5d5b22..02e02d8c9f556 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1744,6 +1744,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 f03f52fbd8823..e2e31bce9be3b 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2524,6 +2524,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 1e36405e32c0b..3a8b9f9e52bfd 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 @@ -335,6 +336,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 03f43744b199f..843aba2b54a37 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 5f9d8c23ea0bf..31d8c18746dae 100644 --- a/include/openssl/types.h +++ b/include/openssl/types.h @@ -232,6 +232,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 e3c2b1c1962a4..e9bd01524d091 100644 --- a/ssl/ssl_ciph.c +++ b/ssl/ssl_ciph.c @@ -2245,3 +2245,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 75be692e0007b..8b020f863eaa8 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"}, @@ -548,6 +549,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 f218dcf1dbcdb..ff0530501702b 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -857,6 +857,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)) @@ -1254,6 +1258,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); @@ -1853,6 +1869,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; @@ -1984,6 +2006,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; @@ -2044,6 +2072,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; @@ -3876,6 +3910,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; @@ -4243,7 +4282,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 845329a809589..3e67b369906ec 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 2ff809bc0fb6b..4f774f9b414f1 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -58,6 +58,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 { @@ -369,6 +373,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, @@ -1718,3 +1735,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 ced88f77ba3c3..7f33e0efc8112 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 */ @@ -2006,3 +2028,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 4816d37c8ab7a..6291ee28736f9 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1237,6 +1237,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 */ @@ -1920,3 +1947,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 c412a77904477..01faf9349e342 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) @@ -1167,6 +1181,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 9ae2126e3cf6f..b828b509f4045 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -422,6 +422,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) { @@ -467,6 +470,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) { @@ -526,6 +532,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, @@ -543,6 +552,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; @@ -550,6 +567,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 @@ -572,6 +598,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 */ @@ -582,11 +617,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 } } @@ -714,6 +767,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 e362585d35f95..b2c1ce3384a21 100644 --- a/test/helpers/ssltestlib.c +++ b/test/helpers/ssltestlib.c @@ -1166,6 +1166,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 f5de24351541d..5d2b83b227aa7 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10270,6 +10270,7 @@ static int test_inherit_verify_param(void) return testresult; } + static int test_load_dhfile(void) { #ifndef OPENSSL_NO_DH @@ -10305,9 +10306,144 @@ static int test_load_dhfile(void) #endif } +#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: + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + + return testresult; +} +#endif /* OPENSSL_NO_QUIC */ + #ifndef OSSL_NO_USABLE_TLS1_3 /* Test that read_ahead works across a key change */ static int test_read_ahead_key_change(void) + { SSL_CTX *cctx = NULL, *sctx = NULL; SSL *clientssl = NULL, *serverssl = NULL; @@ -10367,6 +10503,7 @@ static int test_read_ahead_key_change(void) SSL_free(clientssl); SSL_CTX_free(sctx); SSL_CTX_free(cctx); + return testresult; } @@ -11627,6 +11764,9 @@ int setup_tests(void) ADD_ALL_TESTS(test_npn, 5); #endif ADD_ALL_TESTS(test_alpn, 4); +#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 ea0a8caac4359..839d0d2c08c76 100644 --- a/util/other.syms +++ b/util/other.syms @@ -143,6 +143,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 ef699ffe03f2a5f4848dedb4211f933aa1beb84e Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 14 Jun 2019 12:04:14 -0400 Subject: [PATCH 02/67] 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 3e67b369906ec..725ba1cdc57d7 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 b828b509f4045..d4fafc4339c5a 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -532,9 +532,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 7b9b88d13a20495adac9cdd10d69cf0d5890ec3e Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 15 Aug 2019 11:13:15 -0400 Subject: [PATCH 03/67] 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 323500dd7e214c5d835d4c2dedceadc244ec9a47 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 15 Aug 2019 11:35:10 -0400 Subject: [PATCH 04/67] 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 4f774f9b414f1..f55143415ddd8 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -376,7 +376,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 4407aa7c317ec34820a11c6b9e269e48fe04a7fa Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 15 Aug 2019 12:37:03 -0400 Subject: [PATCH 05/67] 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 725ba1cdc57d7..17f8aed1e3717 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 d4fafc4339c5a..68b6573fd14e3 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -705,6 +705,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 b2666a1bed3a8197f30479be93e7617fb49e2d2b Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 15 Aug 2019 13:26:32 -0400 Subject: [PATCH 06/67] 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 17f8aed1e3717..b3d0046f0915c 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 7fec6bbe30b276eee3cf32bfb30a0aac871a538c Mon Sep 17 00:00:00 2001 From: Todd Short Date: Mon, 26 Aug 2019 13:14:19 -0400 Subject: [PATCH 07/67] 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 6ad64ecd148c3ffeb6873b3c5037f1fa98eb09e9 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Mon, 26 Aug 2019 13:29:17 -0400 Subject: [PATCH 08/67] 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 7f33e0efc8112..ada2610365a6c 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; } @@ -2033,19 +2031,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 6291ee28736f9..8cedf7805d049 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1242,19 +1242,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); @@ -1960,10 +1952,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 14837f985a9751252124b489f3d72a4401ba094a Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 29 Aug 2019 11:53:41 -0400 Subject: [PATCH 09/67] 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 d2753323012f82d4eb0b1cfaa93a0643fb7dc5a0 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 29 Aug 2019 12:03:48 -0400 Subject: [PATCH 10/67] 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 bed28f4d45aa648cc9ab751157b0974626f64605 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 29 Aug 2019 20:21:58 -0400 Subject: [PATCH 11/67] 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 ba834f803e14329bedd21d12a07e9bb08867126e Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 30 Aug 2019 09:09:42 -0400 Subject: [PATCH 12/67] 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 b3d0046f0915c..b3fd00dbfd420 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 68b6573fd14e3..4d89eb314e466 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -710,6 +710,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 d95d74c26d21d1f934e6350bef25280fb173daf4 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 30 Aug 2019 09:15:31 -0400 Subject: [PATCH 13/67] 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 b3fd00dbfd420..049d6448c9356 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 350ac3ce5a3bf56f566dae6030ab6c9fbe0fe182 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 30 Aug 2019 09:47:48 -0400 Subject: [PATCH 14/67] 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 dc7b5a1dcd7b5eb0e1d9a03214005ba0d6f2addd Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 30 Aug 2019 11:17:58 -0400 Subject: [PATCH 15/67] 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 | 216 +++++++++++++++++++++++++++++++----------------- 2 files changed, 139 insertions(+), 84 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 4d89eb314e466..1f7b27d4f4a53 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -385,24 +385,144 @@ static int derive_secret_key_and_iv(SSL *s, int sending, const EVP_MD *md, return 1; } +#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}; +#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"; +#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) { - /* ASCII: "c e traffic", in hex for EBCDIC compatibility */ - static const unsigned char client_early_traffic[] = "\x63\x20\x65\x20\x74\x72\x61\x66\x66\x69\x63"; - /* ASCII: "c hs traffic", in hex for EBCDIC compatibility */ - static const unsigned char client_handshake_traffic[] = "\x63\x20\x68\x73\x20\x74\x72\x61\x66\x66\x69\x63"; - /* ASCII: "c ap traffic", in hex for EBCDIC compatibility */ - static const unsigned char client_application_traffic[] = "\x63\x20\x61\x70\x20\x74\x72\x61\x66\x66\x69\x63"; - /* ASCII: "s hs traffic", in hex for EBCDIC compatibility */ - static const unsigned char server_handshake_traffic[] = "\x73\x20\x68\x73\x20\x74\x72\x61\x66\x66\x69\x63"; - /* ASCII: "s ap traffic", in hex for EBCDIC compatibility */ - static const unsigned char server_application_traffic[] = "\x73\x20\x61\x70\x20\x74\x72\x61\x66\x66\x69\x63"; - /* ASCII: "exp master", in hex for EBCDIC compatibility */ - static const unsigned char exporter_master_secret[] = "\x65\x78\x70\x20\x6D\x61\x73\x74\x65\x72"; - /* ASCII: "res master", in hex for EBCDIC compatibility */ - static const unsigned char resumption_master_secret[] = "\x72\x65\x73\x20\x6D\x61\x73\x74\x65\x72"; - /* ASCII: "e exp master", in hex for EBCDIC compatibility */ - static const unsigned char early_exporter_master_secret[] = "\x65\x20\x65\x78\x70\x20\x6D\x61\x73\x74\x65\x72"; unsigned char *iv; unsigned char key[EVP_MAX_KEY_LENGTH]; unsigned char secret[EVP_MAX_MD_SIZE]; @@ -422,8 +542,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) { @@ -470,9 +592,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) { @@ -549,14 +668,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; @@ -564,15 +675,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 @@ -595,15 +697,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 */ @@ -614,29 +707,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 } } @@ -705,14 +780,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 */ @@ -773,11 +840,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 d04aed502ac1aee5b7542a061d442f4ccb8b9228 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 30 Aug 2019 11:38:56 -0400 Subject: [PATCH 16/67] 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 1f7b27d4f4a53..5e472044b0617 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -433,33 +433,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; } @@ -468,26 +453,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 @@ -498,24 +477,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 7d24771ae6a5fc05cf3d579d889b112708802a1f Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 24 Sep 2019 10:26:42 -0400 Subject: [PATCH 17/67] 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 5e472044b0617..487365627a277 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -441,10 +441,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; } @@ -458,7 +462,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 67c9294177527b956e34ef07ed8ecdc63116c83a Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 12 Nov 2019 13:52:35 -0500 Subject: [PATCH 18/67] 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 487365627a277..a5b674d04b282 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -462,10 +462,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; } @@ -479,6 +476,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; @@ -494,6 +493,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 f0caa58221a11430622dbdc85297ea980aeead08 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Wed, 13 Nov 2019 12:11:00 -0500 Subject: [PATCH 19/67] 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 ada2610365a6c..da70a5b06d026 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1944,6 +1944,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 8cedf7805d049..4efbb036d189c 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1896,12 +1896,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 817c5eeecdf01..2d9d7ee400fe8 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 34cbf28a639b30d0a4b9b6e4ea0a26c61ac703d8 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 7 Jan 2020 10:59:08 -0500 Subject: [PATCH 20/67] 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 2d9d7ee400fe8..e0497947e0a28 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 83cb5bc672843e26e45eb67ebdd3d595c58942de Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Wed, 22 Apr 2020 09:12:36 -0700 Subject: [PATCH 21/67] 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 e2e31bce9be3b..6b5fbfbf02596 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2565,10 +2565,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 843aba2b54a37..fc89768a26c03 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 e9bd01524d091..b594006d86804 100644 --- a/ssl/ssl_ciph.c +++ b/ssl/ssl_ciph.c @@ -2246,6 +2246,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)) { @@ -2277,3 +2278,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 ff0530501702b..9b3338759d1d6 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -4282,7 +4282,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 049d6448c9356..c4033b4688de3 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 da70a5b06d026..b1068ad709402 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1947,7 +1947,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 4efbb036d189c..eee25c26700db 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1902,7 +1902,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 01faf9349e342..e96b654c501d7 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 @@ -1181,7 +1188,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 a5b674d04b282..a63beea2244a0 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -404,6 +404,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) { @@ -412,7 +413,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); @@ -435,34 +436,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; } @@ -482,9 +511,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; @@ -497,9 +528,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; } @@ -516,6 +549,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 5d2b83b227aa7..00d9b1bd2e333 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10307,9 +10307,11 @@ static int test_load_dhfile(void) } #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); @@ -10321,11 +10323,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 fc5c9c80082219a6dd5d1103c6a023892ff42029 Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Mon, 11 May 2020 13:13:01 -0700 Subject: [PATCH 22/67] 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 e96b654c501d7..005c842fbddb7 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -660,6 +660,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; @@ -682,6 +689,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 24d2ce60a350f15f7bdb4942f3ca7cdc6cd89545 Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Mon, 11 May 2020 13:26:07 -0700 Subject: [PATCH 23/67] 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 00d9b1bd2e333..4ce1d0b1bff39 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10431,6 +10431,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 de43120fd8cd0e7073aac0f28d549b8d5282e7ad Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Mon, 31 Aug 2020 12:27:33 -0700 Subject: [PATCH 24/67] 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 9b3338759d1d6..ea5d3c6b9a594 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1261,6 +1261,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 c4033b4688de3..44395fb36563b 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 53834e3e86a0431b87f54c2f007ac89786a68e84 Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Tue, 1 Sep 2020 15:10:41 -0700 Subject: [PATCH 25/67] 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 44395fb36563b..d99b751bfce4a 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 064a96beb62aebc8f89dbce2e3bd78620e88e3a7 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Sat, 12 Dec 2020 17:27:46 +0900 Subject: [PATCH 26/67] 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 ba0fa2c90a139..685cc1fb4a876 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1406,6 +1406,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 6b5fbfbf02596..e221ebbb41bcb 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2565,6 +2565,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 3a8b9f9e52bfd..ce7ce1bb526de 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 fc89768a26c03..258f5fc05ed20 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 8b020f863eaa8..32adc6a932ba7 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 ea5d3c6b9a594..74512c4ce0cd1 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1260,6 +1260,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 d99b751bfce4a..9bbc528dd9577 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 f55143415ddd8..8c6b3ad7ad39b 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -60,6 +60,7 @@ static int init_post_handshake_auth(SSL *s, unsigned int context); static int final_psk(SSL *s, unsigned int context, int sent); #ifndef OPENSSL_NO_QUIC static int init_quic_transport_params(SSL *s, unsigned int context); +static int final_quic_transport_params_draft(SSL *s, unsigned int context, int sent); static int final_quic_transport_params(SSL *s, unsigned int context, int sent); #endif @@ -374,6 +375,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 @@ -1742,8 +1752,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 b1068ad709402..5fb8cb4ed0333 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; } @@ -2038,7 +2058,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 eee25c26700db..6f8dd766372ec 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1238,7 +1238,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) { @@ -1949,13 +1964,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 4ce1d0b1bff39..91d668ad439f6 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10357,7 +10357,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; @@ -10368,29 +10374,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(), @@ -10409,6 +10393,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) @@ -10442,6 +10428,19 @@ static int test_quic_api(void) || !TEST_int_le(SSL_do_handshake(serverssl), 0)) goto end; + TEST_info("original clnt=0x%X, srvr=0x%X\n", clnt, srvr); + if (srvr == 0 && clnt == 0) + srvr = clnt = TLSEXT_TYPE_quic_transport_parameters; + else if (srvr == 0) + srvr = clnt; + else if (clnt == 0) + clnt = srvr; + TEST_info("expected clnt=0x%X, srvr=0x%X\n", clnt, srvr); + if (!TEST_int_eq(SSL_get_peer_quic_transport_version(serverssl), clnt)) + goto end; + if (!TEST_int_eq(SSL_get_peer_quic_transport_version(clientssl), srvr)) + goto end; + testresult = 1; end: @@ -10452,6 +10451,67 @@ static int test_quic_api(void) 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 */ #ifndef OSSL_NO_USABLE_TLS1_3 @@ -11779,7 +11839,7 @@ int setup_tests(void) #endif ADD_ALL_TESTS(test_alpn, 4); #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 34637131fddcbe264a67c5a2cd2497172e79fc66 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 5 Jan 2021 13:50:21 -0500 Subject: [PATCH 27/67] 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 2aea47c22a84c0e4859c9e9916c02f7640a241d3 Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Fri, 15 Jan 2021 15:04:00 -0800 Subject: [PATCH 28/67] 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 e221ebbb41bcb..289f55feb1cb6 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2566,7 +2566,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 04b258aaa4b80dc52579c86686c1273053b41a17 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 19 Feb 2021 10:12:15 -0500 Subject: [PATCH 29/67] 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 685cc1fb4a876..541c2145ef1aa 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1268,7 +1268,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 ce7ce1bb526de..b159ef8127c04 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 32adc6a932ba7..fe0d9c280f7e5 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 342119537ea9beac39e59844994934a59b99d49a Mon Sep 17 00:00:00 2001 From: Todd Short Date: Wed, 3 Mar 2021 11:44:27 -0500 Subject: [PATCH 30/67] 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 9b870f4104f7d..98d892c048732 100644 --- a/VERSION.dat +++ b/VERSION.dat @@ -2,6 +2,6 @@ MAJOR=3 MINOR=1 PATCH=8 PRE_RELEASE_TAG= -BUILD_METADATA= +BUILD_METADATA=quic RELEASE_DATE="11 Feb 2025" -SHLIB_VERSION=3 +SHLIB_VERSION=81.3 From ead4b8c4eb34cf3b909079f991b865e1a2433a6a Mon Sep 17 00:00:00 2001 From: Todd Short Date: Wed, 3 Mar 2021 15:44:11 -0500 Subject: [PATCH 31/67] QUIC: Swap around README files --- README-OpenSSL.md | 212 +++++++++++++++++++++++++++++++ README.md | 310 +++++++++++++++------------------------------- 2 files changed, 312 insertions(+), 210 deletions(-) create mode 100644 README-OpenSSL.md diff --git a/README-OpenSSL.md b/README-OpenSSL.md new file mode 100644 index 0000000000000..4d04514116e80 --- /dev/null +++ b/README-OpenSSL.md @@ -0,0 +1,212 @@ +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 +[openssl-library.org/source/](https://openssl-library.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 main OpenSSL Git repository is private. +There is a public GitHub mirror of it 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 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 GitHub mirror 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-2025 The OpenSSL Project + +Copyright (c) 1995-1998 Eric A. Young, Tim J. Hudson + +All rights reserved. + + + +[www.openssl.org]: + + "OpenSSL Homepage" + +[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 4d04514116e80..ef46c4b393a6c 100644 --- a/README.md +++ b/README.md @@ -1,212 +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 -[openssl-library.org/source/](https://openssl-library.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 main OpenSSL Git repository is private. -There is a public GitHub mirror of it 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 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 GitHub mirror 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-2025 The OpenSSL Project - -Copyright (c) 1995-1998 Eric A. Young, Tim J. Hudson - -All rights reserved. - - - -[www.openssl.org]: - - "OpenSSL Homepage" - -[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 c91737d1866ad1e4cf6e6f62529fa65516ac00e6 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Wed, 3 Mar 2021 17:32:31 -0500 Subject: [PATCH 32/67] 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 91d668ad439f6..a1f0a2895f825 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10387,10 +10387,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)) @@ -10406,10 +10406,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 b930d97284a574f6cf1336925c981459cbf214e8 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Wed, 3 Mar 2021 17:43:46 -0500 Subject: [PATCH 33/67] 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 74512c4ce0cd1..c289555a5fa06 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1873,7 +1873,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 @@ -2010,7 +2010,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 @@ -2076,7 +2076,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 005c842fbddb7..5a83ebeabdff7 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 c73839c0932dd9ef65025db0942dcb8084062a0b Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 5 Mar 2021 15:22:18 -0500 Subject: [PATCH 34/67] 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 9ef9ee4704705..f8a495e098013 100644 --- a/crypto/info.c +++ b/crypto/info.c @@ -203,6 +203,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 fb0c7cbb87178..6eca308b3250d 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 bc09538b1804ebfd84799017ea4461138d2eda6b 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/67] 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 289f55feb1cb6..f1d1ec0ec3812 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2580,6 +2580,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 c289555a5fa06..93efdc12dc736 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -4016,6 +4016,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 e0497947e0a28..8fcbd8b4e79a9 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 a63beea2244a0..a1d4dd04b8a9e 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -419,20 +419,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) { @@ -538,10 +594,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 a1f0a2895f825..02f78f5396f0d 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10512,6 +10512,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); + 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 */ #ifndef OSSL_NO_USABLE_TLS1_3 @@ -11840,6 +11993,9 @@ int setup_tests(void) ADD_ALL_TESTS(test_alpn, 4); #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 9cddd90159542d262dc79a1a344600d2fcd344f3 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/67] 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 e0b76754cde6624a066bbfaa7188c0921359283c 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/67] 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 02f78f5396f0d..5ef3e7679466c 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10413,8 +10413,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 */ @@ -10606,8 +10605,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 4635dc4f951de7dfd96df1e48a535d8bcc09da37 Mon Sep 17 00:00:00 2001 From: kaduk Date: Fri, 12 Mar 2021 13:03:14 -0800 Subject: [PATCH 38/67] 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 7350d977102a036410e8aaaa74d1e83f24dfc904 Mon Sep 17 00:00:00 2001 From: Nan Xiao Date: Mon, 15 Mar 2021 23:54:39 +0800 Subject: [PATCH 39/67] 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 b1e6654ff81eae53d3fc0819dc83cbe271d839ef Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 18 Mar 2021 12:42:01 -0400 Subject: [PATCH 40/67] 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 41ddd9d7da392..ba3e8b0f92d96 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 0279e2390a324..f779146273958 100644 --- a/doc/build.info +++ b/doc/build.info @@ -2271,6 +2271,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 @@ -3351,6 +3355,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 \ @@ -3959,6 +3964,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 8c6b3ad7ad39b..986f4ecc00d20 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -395,6 +395,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 6f8dd766372ec..b559791eb4b4f 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1918,7 +1918,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 23b11bf958e8c2f0784283f33147546885827ca6 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 6 May 2021 16:24:03 -0400 Subject: [PATCH 41/67] 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 2064b7f6ac93179385f63724fefce34cdfbe99e0 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 24 Jun 2021 15:11:24 -0400 Subject: [PATCH 42/67] 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 3c5615040b2f41259b62cf8f628426cd839dc536 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 24 Jun 2021 15:24:28 -0400 Subject: [PATCH 43/67] 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 13c3f74373039fbd53b9d90520830e8f3dabe972 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 9 Jul 2021 13:29:03 -0400 Subject: [PATCH 44/67] 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 f8a495e098013..e7a37e392233a 100644 --- a/crypto/info.c +++ b/crypto/info.c @@ -14,6 +14,7 @@ #include "internal/cryptlib.h" #include "internal/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 6eca308b3250d..fb0c7cbb87178 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 02e02d8c9f556..ed19eefb80653 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1745,10 +1745,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 f1d1ec0ec3812..ce29710a959d8 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2531,6 +2531,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 31d8c18746dae..5f9d8c23ea0bf 100644 --- a/include/openssl/types.h +++ b/include/openssl/types.h @@ -232,8 +232,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 3f827944bd59f50bbbb7af3109ed7d86b623326c Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 29 Jul 2021 13:58:17 -0400 Subject: [PATCH 45/67] 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 4ec178f185a989f6956c285d21b4ab375b5f111d Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 7 Sep 2021 12:26:10 -0400 Subject: [PATCH 46/67] 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 258f5fc05ed20..c721d39f9e3ad 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 5fb8cb4ed0333..26e92383081a4 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1967,7 +1967,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 b559791eb4b4f..351bc1905a559 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1917,7 +1917,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 c1d0456ac20a6ea083be47274e004133a2c81b4b Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 7 Sep 2021 12:29:37 -0400 Subject: [PATCH 47/67] 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 ed19eefb80653..d0fce0c5d5b22 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1744,7 +1744,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 13d39501d1fd29acb27175dd571d5b099a197d37 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 7 Sep 2021 12:32:54 -0400 Subject: [PATCH 48/67] 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 95d9653357b9b660f1604b2be68566517e93b164 Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Tue, 7 Sep 2021 09:17:39 -0700 Subject: [PATCH 49/67] 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 bb1cbd56b8b5dcdab619040b2b38065aa6591202 Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Tue, 7 Sep 2021 09:17:56 -0700 Subject: [PATCH 50/67] 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 eebacb7e9be3281fe5bf9d575f6c058ff440cc18 Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Tue, 7 Sep 2021 09:20:44 -0700 Subject: [PATCH 51/67] 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 736b5400389b7baaee17d9fc8a85ddd4a6bfcab4 Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Tue, 7 Sep 2021 14:21:22 -0700 Subject: [PATCH 52/67] 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 26e92383081a4..3b0781fc71c70 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1969,7 +1969,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 93c257a93aeefc3e68e5509185cfdee6bebda118 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Mon, 18 Oct 2021 16:54:31 -0400 Subject: [PATCH 53/67] 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 8fcbd8b4e79a9..9857c641b56b3 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 aa0a8d944892cc96378aaaa00b736899b9276f8c Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 19 Oct 2021 12:13:31 -0400 Subject: [PATCH 54/67] 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 93efdc12dc736..c69648ad4319e 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -641,6 +641,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 b2c1ce3384a21..e362585d35f95 100644 --- a/test/helpers/ssltestlib.c +++ b/test/helpers/ssltestlib.c @@ -1166,11 +1166,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 5ef3e7679466c..4734841849013 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10373,6 +10373,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); @@ -10395,8 +10396,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)) @@ -10523,6 +10526,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(), @@ -10600,8 +10604,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 */ @@ -10640,12 +10646,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 4bde87b0f3ec9a53224d47b75efdc8709ab81cb7 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 29 Oct 2021 14:15:06 -0400 Subject: [PATCH 55/67] 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 c69648ad4319e..80bfa1408bbd8 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -582,7 +582,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); @@ -641,38 +690,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 9bbc528dd9577..3fb1f0956f5b8 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 4734841849013..8766702e7e022 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10373,7 +10373,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); @@ -10396,10 +10395,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)) @@ -10526,7 +10523,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(), @@ -10604,10 +10600,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 */ @@ -10646,15 +10640,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 fdbc223cfde6874fa3269ee53ddb10e39d92bc5c Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 2 Nov 2021 12:16:57 -0400 Subject: [PATCH 56/67] 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 72add3a57a27b7f09c5c0d2a934f6b1058a85eca Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 15 Mar 2022 12:26:00 -0400 Subject: [PATCH 57/67] 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 87890d19c4ea3dea2181bfbdfb1223f0c6062223 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 1 Nov 2022 12:55:46 -0400 Subject: [PATCH 58/67] 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 3fb1f0956f5b8..93f77f9612a50 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 2130c588c6c1a67e8011355a693588087be291fd Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 7 Feb 2023 12:40:55 -0500 Subject: [PATCH 59/67] 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 b95fb6b92c442d0bd1f112bd569ad9c42e875ab4 Mon Sep 17 00:00:00 2001 From: Watson Ladd Date: Mon, 20 Mar 2023 09:40:15 -0700 Subject: [PATCH 60/67] QUIC: Update README.md for 3.1.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ef1d8fcf48198..1162c55d9d6e8 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.1.0%2Bquic/README-OpenSSL.md) This fork adds APIs that can be used by QUIC implementations for connection handshakes. Quoting the IETF Working group From 1ab22a3e905e7133af01ed1ed7a70af6d427ca6b Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 1 Aug 2023 13:55:55 -0400 Subject: [PATCH 61/67] QUIC: Update README.md for 3.1.2 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1162c55d9d6e8..90570290f1929 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.1.0%2Bquic/README-OpenSSL.md) +[README-OpenSSL.md](https://github.com/quictls/openssl/blob/openssl-3.1.2%2Bquic/README-OpenSSL.md) This fork adds APIs that can be used by QUIC implementations for connection handshakes. Quoting the IETF Working group From 8c807beeb9a8898015b53733bae4d05549724454 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 1 Aug 2023 13:59:55 -0400 Subject: [PATCH 62/67] QUIC: Fix use of create_a_psk --- test/sslapitest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sslapitest.c b/test/sslapitest.c index 8766702e7e022..d55458de1da7e 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10570,7 +10570,7 @@ static int quic_setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx, return 0; if (idx == 2) { - clientpsk = create_a_psk(*clientssl); + clientpsk = create_a_psk(*clientssl, SHA384_DIGEST_LENGTH); if (!TEST_ptr(clientpsk) || !TEST_true(SSL_SESSION_set_max_early_data(clientpsk, 0xffffffffu)) From 544c351c2a4553a5c634f26d506803530b08433b Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 6 Oct 2023 12:05:19 -0400 Subject: [PATCH 63/67] QUIC: Update MD files for 3.1.5 --- CHANGES.md | 6 ------ README.md | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a6acac3b94c91..00229382d4b78 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -509,12 +509,6 @@ 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.8 and 3.0.8+quic [7 Feb 2023] - - * Add QUIC API support from BoringSSL. - - *Todd Short* - ### Changes between 3.0.7 and 3.0.8 [7 Feb 2023] * Fixed NULL dereference during PKCS7 data verification. diff --git a/README.md b/README.md index 90570290f1929..eada105022db7 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.1.2%2Bquic/README-OpenSSL.md) +[README-OpenSSL.md](https://github.com/quictls/openssl/blob/openssl-3.1.5%2Bquic/README-OpenSSL.md) This fork adds APIs that can be used by QUIC implementations for connection handshakes. Quoting the IETF Working group From 63218e783053e598c82c036facd60d7c72ac2f93 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Mon, 12 Aug 2024 11:15:17 -0400 Subject: [PATCH 64/67] QUIC: Update readme for 3.1.6 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eada105022db7..d83f2b2f6580d 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.1.5%2Bquic/README-OpenSSL.md) +[README-OpenSSL.md](https://github.com/quictls/openssl/blob/openssl-3.1.6%2Bquic/README-OpenSSL.md) This fork adds APIs that can be used by QUIC implementations for connection handshakes. Quoting the IETF Working group From 0d143694433b1b2568331e0a3257534a3b7f6a7a Mon Sep 17 00:00:00 2001 From: Watson Ladd Date: Tue, 3 Sep 2024 09:24:53 -0700 Subject: [PATCH 65/67] QUIC: Update README and CHANGES for 3.1.8 --- CHANGES.md | 6 ++++++ README.md | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 00229382d4b78..56c8a321e3a08 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -22,6 +22,12 @@ OpenSSL Releases OpenSSL 3.1 ----------- +### Changes between 3.1.8 and 3.1.8+quic [27 Feb 2024] + +* Added BoringSSL QUIC API support + + *Todd Short* + ### Changes between 3.1.7 and 3.1.8 [11 Feb 2025] * Fixed timing side-channel in ECDSA signature computation. diff --git a/README.md b/README.md index d83f2b2f6580d..d99697eced723 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.1.6%2Bquic/README-OpenSSL.md) +[README-OpenSSL.md](https://github.com/quictls/openssl/blob/openssl-3.1.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 2a1da077e41db2bc943441f88e86e7940253aa16 Mon Sep 17 00:00:00 2001 From: Rich Salz Date: Sun, 16 Feb 2025 10:49:48 -0500 Subject: [PATCH 66/67] Update README.md Explain that this repo is archived and point to quictls/quictls --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index d99697eced723..4fe9bb7564c1d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,14 @@ What This Is ============ +**This repository is now archived. We only tracked up through 3.1.8 and then, because +it became too difficult as OpenSSL added more code to their implementation of +QUIC, we moved to becoming a full fork of OpenSSL. We encourage you to see that +respository's [README](https://github.com/quictls/quictls/blob/main/README.md) If there +features you would like to see from more recent OpenSSL releases, please +[report an issue](https://github.com/quictls/quictls/issues), or -- better yet :) -- +make a [pull request](https://github.com/quictls/quictls/pulls).** + 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 @@ -15,6 +23,7 @@ should use the official OpenSSL distributions. 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/) +among others (ngHTTP, etc). 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 From 99d5964fac56c13eed5879e978ebad011e0a20c1 Mon Sep 17 00:00:00 2001 From: Rich Salz Date: Tue, 25 Feb 2025 14:01:59 -0500 Subject: [PATCH 67/67] Update README.md Explain OldQuicTLS, QuicTLS naming. --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 4fe9bb7564c1d..aeac3a36f4ec1 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,9 @@ features you would like to see from more recent OpenSSL releases, please [report an issue](https://github.com/quictls/quictls/issues), or -- better yet :) -- make a [pull request](https://github.com/quictls/quictls/pulls).** +**We encourage everyone to move to using the new QUICTLS project. If you support +both, we suggest you refer to this as `OldQuicTLS` and the new fork as `QuicTLS`** + 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