add QUIC support.

This commit is contained in:
Stefan Eissing 2022-08-08 13:24:00 +02:00
parent 7004157869
commit 4431438fb2
25 changed files with 4173 additions and 46 deletions

2
.gitignore vendored
View File

@ -390,3 +390,5 @@ cmake_install.cmake
# GDB Settings
\.gdbinit
# Pycharm and other IDEs
\.idea

View File

@ -44,6 +44,9 @@ function(generate_build_flags)
if(WOLFSSL_DTLS13 OR WOLFSSL_USER_SETTINGS)
set(BUILD_DTLS13 "yes" PARENT_SCOPE)
endif()
if(WOLFSSL_QUIC)
set(BUILD_QUIC "yes" PARENT_SCOPE)
endif()
if(WOLFSSL_RNG OR WOLFSSL_USER_SETTINGS)
set(BUILD_RNG "yes" PARENT_SCOPE)
endif()
@ -818,6 +821,10 @@ function(generate_lib_src_list LIB_SOURCES)
list(APPEND LIB_SOURCES src/dtls13.c)
endif()
if(BUILD_QUIC)
list(APPEND LIB_SOURCES src/quic.c)
endif()
if(BUILD_OCSP)
list(APPEND LIB_SOURCES src/ocsp.c)
endif()

View File

@ -664,6 +664,7 @@ then
test "$enable_tls13" = "" && enable_tls13=yes
test "$enable_rsapss" = "" && enable_rsapss=yes
fi
test "$enable_quic" = "" && enable_quic=yes
# this set is also enabled by enable-all-crypto:
test "$enable_atomicuser" = "" && enable_atomicuser=yes
@ -1037,6 +1038,25 @@ then
ENABLED_TLS13="no"
fi
# QUIC support
AC_ARG_ENABLE([quic],
[AS_HELP_STRING([--enable-quic],[Enable QUIC API with wolfSSL TLS v1.3 (default: disabled)])],
[ ENABLED_QUIC=$enableval ],
[ ENABLED_QUIC=no ]
)
if test "$ENABLED_QUIC" = "yes"
then
if test "x$ENABLED_TLS13" = "xno"
then
AC_MSG_ERROR([TLS 1.3 is disabled - necessary for QUIC])
fi
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_QUIC"
# QUIC proto handlers need app_data at WOLFSSL*
AM_CFLAGS="$AM_CFLAGS -DHAVE_EX_DATA"
fi
# Post-handshake Authentication
AC_ARG_ENABLE([postauth],
[AS_HELP_STRING([--enable-postauth],[Enable wolfSSL Post-handshake Authentication (default: disabled)])],
@ -1477,6 +1497,12 @@ AC_ARG_ENABLE([opensslextra],
[ ENABLED_OPENSSLEXTRA=no ]
)
if test "$ENABLED_QUIC" = "yes"
then
ENABLED_OPENSSLEXTRA="yes"
fi
# One Error Queue per Thread
AC_ARG_ENABLE([error-queue-per-thread],
[AS_HELP_STRING([--enable-error-queue-per-thread],[Enable one error queue per thread. Requires thread local storage. (default: disabled)])],
@ -1943,6 +1969,11 @@ then
ENABLED_AESCTR=yes
fi
if test "$ENABLED_QUIC" = "yes"
then
ENABLED_AESCTR=yes
fi
# AES-OFB
AC_ARG_ENABLE([aesofb],
[AS_HELP_STRING([--enable-aesofb],[Enable wolfSSL AES-OFB support (default: disabled)])],
@ -4550,6 +4581,11 @@ then
ENABLED_SNI="yes"
fi
if test "$ENABLED_QUIC" = "yes"
then
ENABLED_SNI=yes
fi
if test "x$ENABLED_SNI" = "xyes"
then
AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_SNI"
@ -4574,6 +4610,11 @@ then
ENABLED_ALPN=yes
fi
if test "$ENABLED_QUIC" = "yes"
then
ENABLED_ALPN=yes
fi
if test "x$ENABLED_ALPN" = "xyes"
then
AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_ALPN"
@ -4833,7 +4874,6 @@ then
AM_CFLAGS="$AM_CFLAGS -DNO_SESSION_CACHE"
fi
# PKCS7
AC_ARG_ENABLE([pkcs7],
[AS_HELP_STRING([--enable-pkcs7],[Enable PKCS7 (default: disabled)])],
@ -5669,6 +5709,12 @@ then
# FTPS server requires pointer to session cache
AM_CFLAGS="$AM_CFLAGS -DNO_SESSION_CACHE_REF"
if test "x$ENABLED_QUIC" = "xno"
then
ENABLED_QUIC="yes"
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_QUIC"
fi
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DES_ECB"
fi
@ -8033,6 +8079,7 @@ AM_CONDITIONAL([BUILD_ERROR_STRINGS],[test "x$ENABLED_ERROR_STRINGS" = "xyes"])
AM_CONDITIONAL([BUILD_DO178],[test "x$ENABLED_DO178" = "xyes"])
AM_CONDITIONAL([BUILD_PSA],[test "x$ENABLED_PSA" = "xyes"])
AM_CONDITIONAL([BUILD_DTLS13],[test "x$ENABLED_DTLS13" = "xyes"])
AM_CONDITIONAL([BUILD_QUIC],[test "x$ENABLED_QUIC" = "xyes"])
if test "$ENABLED_REPRODUCIBLE_BUILD" != "yes" &&
(test "$ax_enable_debug" = "yes" ||
@ -8381,6 +8428,7 @@ echo " * TLS v1.2: $ENABLED_TLSV12"
echo " * TLS v1.3: $ENABLED_TLS13"
echo " * Post-handshake Auth: $ENABLED_TLS13_POST_AUTH"
echo " * Early Data: $ENABLED_TLS13_EARLY_DATA"
echo " * QUIC: $ENABLED_QUIC"
echo " * Send State in HRR Cookie: $ENABLED_SEND_HRR_COOKIE"
echo " * OCSP: $ENABLED_OCSP"
echo " * OCSP Stapling: $ENABLED_CERTIFICATE_STATUS_REQUEST"

99
doc/QUIC.md Normal file
View File

@ -0,0 +1,99 @@
# QUIC in wolfSSL
This is an intermediate documentation about the added support for the QUIC protocol in wolfSSL.
It is intended as a guide to reviewing the changes and a base for future update of the standard
wolfSSL documentation, once the changes have been reviewed.
## Configuration
QUIC support is enabled in the common autoconf style via:
```
> ./configure --enable-quic
```
this drags in some very basic features. To have everything necessary for a QUIC protocol implementation like ngtcpo2, one would do:
```
./configure --enable-quic --enable-session-ticket --enable-earlydata --enable-psk --enable-sni --enable-alpn
```
CMake support files have been updated as well, but not tested.
## Structure of Changes
The following files carry the main code added:
```
src/quic.c
wolfssl/quic.h
tests/quic.c
```
Additions to other files were necessary, protected by `#ifdef WOLFSSL_QUIC`, those cover:
* additions to `SSL_new()`, `SSL_free()`, `SSL_clear()`
* a new TLSX extension for QUIC transport parameters in QUICv1 and draft-27 versions. A new error code for when this is missing.
* a new `ssl->options` field to en-/disable TLSv1.3 MiddleBox Compat support, since this feature may not be active on a TLS13 session that is used by QUIC.
* handling of EarlyData without `EndOfEarlyData` messages being exchanged, since QUIC does not use those.
## API
The exposed API carries all methods that the [quictls/openssl](https://github.com/quictls/openssl) introduces. This seems to become the standard, since other *SLL libraries have picked those up or are about to. The methods are all in the `wolfSSL_` prefix. There are some additional methods, which are covered below.
### Core Interworking
At the base is the struct `WOLFSSL_QUIC_METHOD` which carries four callbacks:
* `set_encryption_secrets()`: to forward generated secrets.
* `add_handshake_data()`: to forward Handshake messages.
* `flush_flight()`: to tell the QUIC protocol handler to flush any buffered data.
* `send_alert()`: to forward SSL alerts.
A QUIC protocol handler installs these via `wolfSSL_CTX_set_quic_method()` or `wolfSSL_set_quic_method()`. When CRYPTO messages arrive from the peer, those are added via `wolfSSL_provide_quic_data()` to the `WOLFSSL*` instance:
```
DATA ---recv+decrypt---+
v
wolfSSL_provide_quic_data(ssl, ...)
wolfSSL_do_handshake(ssl);
+-> add_handshake_data_callback(REPLY)
|
REPLY <--encrypt+send---+
```
The wolfSSL instance performs the common TLSv1.3 handshake processing with the significant change that it does not encrypt or decrypt messages itself. It computes all the secrets and MACs as usual, however.
Encryption and Decryption is done by the QUIC protocol handler. Which is why it gets access to the secrets
at the different encryption levels: `initial`(no encryption), `handshake`, `application` and `earlydata`.
For sending data, the level to use for encryption is a call parameter in `add_handshake_data()`. For received data, the level to use for decryption can be interrogated via `wolfSSL_quic_read_level()`.
When the handshake is done, any additional CRYPTO messages are received in the same way, only `wolfSSL_process_quic_post_handshake()` is invoked to process them.
### Crypto Support
At the basic level, there are:
* `wolfSSL_quic_get_aead()`: to get the AEAD cipher negotiated
* `wolfSSL_quic_get_md()`: to get the MD negotiated
* `wolfSSL_quic_get_hp()`: to get the EVP_CIPHER for header protection
* `wolfSSL_quic_get_aead_tag_len()`: the get the tag length of the negotiated AEAD cipher
In addition to that, the wolfSSL QUIC API offers the following functions:
* `wolfSSL_quic_crypt_new()`: to setup a `WOLFSSL_EVP_CIPHER_CTX` for en- or decryption with AEAD cipher, key and iv.
* `wolfSSL_quic_aead_encrypt()`: to encrypt with such a context and params
* `wolfSSL_quic_aead_decrypt()`: to decrypt with such a context and params
and for key generation `wolfSSL_quic_hkdf_extract()`, `wolfSSL_quic_hkdf_expand()` and `wolfSSL_quic_hkdf()`.
## Tests
Tests have been added in `tests/quic.c` to run as part of `unit.tests`. Those go from basic checks on providing data and receiving secrets to complete handshakes between SSL client and server instances. These handshakes are done plain, with session resumption and with early data.
These tests exchange the handshake messages between the SSL instances unencrypted, verifying their sequence and contents. They also verify that client and sever did indeed generate identical secrets for the different encryption levels.

View File

@ -0,0 +1,606 @@
/*!
\ingroup QUIC
\brief Callback invoked when secrets are generated during a handshake.
Since QUIC protocol handlers perform the en-/decryption of packets, they
need the negotiated secrets for the levels early_data/handshake/application.
The callback will be invoked several times during a handshake. Either both
or only the read or write secret might be provided. This does not mean the
given encryption level is already in effect.
\return 1 on success, 0 on failure.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\param level - the encryption level the secrets are for
\param read_secret - the secret used in decryption at the given level, may be NULL.
\param write_secret - the secret used in encryption at the given level, may be NULL.
\param secret_len - the length of the secret
\sa wolfSSL_set_quic_method
*/
int (*set_encryption_secrets)(WOLFSSL *ssl, WOLFSSL_ENCRYPTION_LEVEL level,
const uint8_t *read_secret,
const uint8_t *write_secret, size_t secret_len);
/*!
\ingroup QUIC
\brief Callback invoked for forwarding handshake CRYPTO data to peer.
The data forwarded this way is not encrypted. It is the job of the QUIC
protocol implementation to do this. Which secrets are to be used
is determined by the encryption level specified.
This callback may be invoked several times during handshake or post handshake
processing. The data may cover a complete CRYPTO record, but may also
be partial. However, the callback will have received all records data before
using another encryption level.
\return 1 on success, 0 on failure.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\param level - the encryption level to use for encrypting the data
\param data - the data itself
\param len - the length of the data
\sa wolfSSL_set_quic_method
*/
int (*add_handshake_data)(WOLFSSL *ssl, WOLFSSL_ENCRYPTION_LEVEL level,
const uint8_t *data, size_t len);
/*!
\ingroup QUIC
\brief Callback invoked for advisory flushing of the data to send.
\return 1 on success, 0 on failure.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\sa wolfSSL_set_quic_method
*/
int (*flush_flight)(WOLFSSL *ssl);
/*!
\ingroup QUIC
\brief Callback invoked when an SSL alert happened during processing.
\return 1 on success, 0 on failure.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\param level - the encryption level in effect when the alert happened
\param alert - the error
\sa wolfSSL_set_quic_method
*/
int (*send_alert)(WOLFSSL *ssl, WOLFSSL_ENCRYPTION_LEVEL level, uint8_t alert);
/*!
\ingroup QUIC
\brief Activate QUIC protocol for a WOLFSSL_CTX and all derived WOLFSSL instances
by providing the four callbacks required. The CTX needs to be a TLSv1.3 one.
The passed quic_method needs to have a lifetime outlasting the SSL instances.
It is not copied. All callbacks need to be provided.
\return WOLFSSL_SUCCESS If successful.
\param ctx - a pointer to a WOLFSSL_CTX structure, created using wolfSSL_CTX_new().
\param quic_method - the callback structure
\sa wolfSSL_is_quic
\sa wolfSSL_set_quic_method
*/
int wolfSSL_CTX_set_quic_method(WOLFSSL_CTX *ctx, const WOLFSSL_QUIC_METHOD *quic_method);
/*!
\ingroup QUIC
\brief Activate QUIC protocol for a WOLFSSL instance by providing the
four callbacks required. The WOLFSSL needs to be a TLSv1.3 one.
The passed quic_method needs to have a lifetime outlasting the SSL instance.
It is not copied. All callbacks need to be provided.
\return WOLFSSL_SUCCESS If successful.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\param quic_method - the callback structure
\sa wolfSSL_is_quic
\sa wolfSSL_CTX_set_quic_method
*/
int wolfSSL_set_quic_method(WOLFSSL *ssl, const WOLFSSL_QUIC_METHOD *quic_method);
/*!
\ingroup QUIC
\brief Check if QUIC has been activated in a WOLFSSL instance.
\return 1 if WOLFSSL is using QUIC.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\sa wolfSSL_CTX_quic_method
\sa wolfSSL_CTX_set_quic_method
*/
int wolfSSL_is_quic(WOLFSSL *ssl);
/*!
\ingroup QUIC
\brief Determine the encryption level for reads currently in use. Meaningful only when
the WOLFSSL instance is using QUIC.
Note that the effective level is always a parameter when passing data back and
forth. Data from a peer might arrive at other levels than reported via this
function.
\return encryption level.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\sa wolfSSL_quic_write_level
*/
WOLFSSL_ENCRYPTION_LEVEL wolfSSL_quic_read_level(const WOLFSSL *ssl);
/*!
\ingroup QUIC
\brief Determine the encryption level for writes currently in use. Meaningful only when
the WOLFSSL instance is using QUIC.
Note that the effective level is always a parameter when passing data back and
forth. Data from a peer might arrive at other levels than reported via this
function.
\return encryption level.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\sa wolfSSL_quic_read_level
*/
WOLFSSL_ENCRYPTION_LEVEL wolfSSL_quic_write_level(const WOLFSSL *ssl);
/*!
\ingroup QUIC
\brief Configure which QUIC version shall be used. Without calling this,
the WOLFSSL will offer both (draft-27 and v1) to a server, resp. accept
both from a client and negotiate the most recent one.
\return WOLFSSL_SUCCESS If successful.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\param use_legacy - true if draft-27 shall be used, 0 if only QUICv1 is used.
\sa wolfSSL_set_quic_transport_version
*/
void wolfSSL_set_quic_use_legacy_codepoint(WOLFSSL *ssl, int use_legacy);
/*!
\ingroup QUIC
\brief Configure which QUIC version shall be used.
\return WOLFSSL_SUCCESS If successful.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\param version - the TLS Extension defined for the QUIC version.
\sa wolfSSL_set_quic_use_legacy_codepoint
*/
void wolfSSL_set_quic_transport_version(WOLFSSL *ssl, int version);
/*!
\ingroup QUIC
\brief Get the configured QUIC version.
\return TLS Extension of configured version.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\sa wolfSSL_set_quic_use_legacy_codepoint
\sa wolfSSL_set_quic_transport_version
*/
int wolfSSL_get_quic_transport_version(const WOLFSSL *ssl);
/*!
\ingroup QUIC
\brief Set the QUIC transport parameters to use.
\return WOLFSSL_SUCCESS If successful.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\param params - the parameter bytes to use
·param params_len - the length of the parameters
\sa wolfSSL_set_quic_use_legacy_codepoint
\sa wolfSSL_set_quic_transport_version
*/
int wolfSSL_set_quic_transport_params(WOLFSSL *ssl, const uint8_t *params, size_t params_len);
/*!
\ingroup QUIC
\brief Get the negotiated QUIC transport version. This will only give
meaningful results when called after the respective TLS extensions have
been seen from the peer.
\return the negotiated version or -1.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\sa wolfSSL_set_quic_use_legacy_codepoint
\sa wolfSSL_set_quic_transport_version
*/
int wolfSSL_get_peer_quic_transport_version(const WOLFSSL *ssl);
/*!
\ingroup QUIC
\brief Get the negotiated QUIC transport parameters. This will only give
meaningful results when called after the respective TLS extensions have
been seen from the peer.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\param out_params - the parameters sent be the peer, set to NULL if not available.
\param out_params_len - the length of the parameters sent be the peer, set to 0 if not available
\sa wolfSSL_get_peer_quic_transport_version
*/
void wolfSSL_get_peer_quic_transport_params(const WOLFSSL *ssl, const uint8_t **out_params, size_t *out_params_len);
/*!
\ingroup QUIC
\brief Configure if Early Data is enabled. Intended for servers to signal
this to clients.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\param enabled - != 0 iff early data is enabled
*/
void wolfSSL_set_quic_early_data_enabled(WOLFSSL *ssl, int enabled);
/*!
\ingroup QUIC
\brief Get advice on the amount of data that shall be "in flight", e.g. unacknowledged
at the given encryption level. This is the amount of data the WOLFSSL instance
is prepared to buffer.
\return the recommend max data in flight
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\param level - the encryption level to inquire about
*/
size_t wolfSSL_quic_max_handshake_flight_len(const WOLFSSL *ssl, WOLFSSL_ENCRYPTION_LEVEL level);
/*!
\ingroup QUIC
\brief Pass decrypted CRYPTO data to the WOLFSSL instance for further processing.
The encryption level between calls is only every allowed to increase and it is
also checked that data records are complete before a change in encryption
level is accepted.
\return WOLFSSL_SUCCESS If successful.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\param level - the level the data was encrypted at
\param data - the data itself
\param len - the length of the data
\sa wolfSSL_process_quic_post_handshake
\sa wolfSSL_quic_read_write
\sa wolfSSL_accept
\sa wolfSSL_connect
*/
int wolfSSL_provide_quic_data(WOLFSSL *ssl, WOLFSSL_ENCRYPTION_LEVEL level, const uint8_t *data, size_t len);
/*!
\ingroup QUIC
\brief Process any CRYPTO records that have been provided after the handshake
has completed. Will fail if called before that.
\return WOLFSSL_SUCCESS If successful.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\sa wolfSSL_provide_quic_data
\sa wolfSSL_quic_read_write
\sa wolfSSL_accept
\sa wolfSSL_connect
*/
WOLFSSL_API int wolfSSL_process_quic_post_handshake(WOLFSSL *ssl);
/*!
\ingroup QUIC
\brief Process any CRYPTO records that have been provided during or after the handshake.
Will progress the handshake if not already complete and otherwise work like
wolfSSL_process_quic_post_handshake().
\return WOLFSSL_SUCCESS If successful.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\sa wolfSSL_provide_quic_data
\sa wolfSSL_quic_read_write
\sa wolfSSL_accept
\sa wolfSSL_connect
*/
int wolfSSL_quic_read_write(WOLFSSL *ssl);
/*!
\ingroup QUIC
\brief Get the AEAD cipher negotiated in the TLS handshake.
\return negotiated cipher or NULL if not determined.
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\sa wolfSSL_quic_aead_is_gcm
\sa wolfSSL_quic_aead_is_ccm
\sa wolfSSL_quic_aead_is_chacha20
\sa wolfSSL_quic_get_aead_tag_len
\sa wolfSSL_quic_get_md
\sa wolfSSL_quic_get_hp
\sa wolfSSL_quic_crypt_new
\sa wolfSSL_quic_aead_encrypt
\sa wolfSSL_quic_aead_decrypt
*/
const WOLFSSL_EVP_CIPHER *wolfSSL_quic_get_aead(WOLFSSL *ssl);
/*!
\ingroup QUIC
\brief Check if the AEAD cipher is GCM.
\return != 0 iff the AEAD cipher is GCM.
\param cipher - the cipher
\sa wolfSSL_quic_get_aead
\sa wolfSSL_quic_aead_is_ccm
\sa wolfSSL_quic_aead_is_chacha20
\sa wolfSSL_quic_get_aead_tag_len
\sa wolfSSL_quic_get_md
\sa wolfSSL_quic_get_hp
\sa wolfSSL_quic_crypt_new
\sa wolfSSL_quic_aead_encrypt
\sa wolfSSL_quic_aead_decrypt
*/
int wolfSSL_quic_aead_is_gcm(const WOLFSSL_EVP_CIPHER *aead_cipher);
/*!
\ingroup QUIC
\brief Check if the AEAD cipher is CCM.
\return != 0 iff the AEAD cipher is CCM.
\param cipher - the cipher
\sa wolfSSL_quic_get_aead
\sa wolfSSL_quic_aead_is_gcm
\sa wolfSSL_quic_aead_is_chacha20
\sa wolfSSL_quic_get_aead_tag_len
\sa wolfSSL_quic_get_md
\sa wolfSSL_quic_get_hp
\sa wolfSSL_quic_crypt_new
\sa wolfSSL_quic_aead_encrypt
\sa wolfSSL_quic_aead_decrypt
*/
int wolfSSL_quic_aead_is_ccm(const WOLFSSL_EVP_CIPHER *aead_cipher);
/*!
\ingroup QUIC
\brief Check if the AEAD cipher is CHACHA20.
\return != 0 iff the AEAD cipher is CHACHA20.
\param cipher - the cipher
\sa wolfSSL_quic_get_aead
\sa wolfSSL_quic_aead_is_ccm
\sa wolfSSL_quic_aead_is_gcm
\sa wolfSSL_quic_get_aead_tag_len
\sa wolfSSL_quic_get_md
\sa wolfSSL_quic_get_hp
\sa wolfSSL_quic_crypt_new
\sa wolfSSL_quic_aead_encrypt
\sa wolfSSL_quic_aead_decrypt
*/
int wolfSSL_quic_aead_is_chacha20(const WOLFSSL_EVP_CIPHER *aead_cipher);
/*!
\ingroup QUIC
\brief Determine the tag length for the AEAD cipher.
\return tag length of AEAD cipher.
\param cipher - the cipher
\sa wolfSSL_quic_get_aead
*/
WOLFSSL_API size_t wolfSSL_quic_get_aead_tag_len(const WOLFSSL_EVP_CIPHER *aead_cipher);
/*!
\ingroup QUIC
\brief Determine the message digest negotiated in the TLS handshake.
\return the message digest negotiated in the TLS handshake
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\sa wolfSSL_quic_get_aead
\sa wolfSSL_quic_get_hp
*/
WOLFSSL_API const WOLFSSL_EVP_MD *wolfSSL_quic_get_md(WOLFSSL *ssl);
/*!
\ingroup QUIC
\brief Determine the header protection cipher negotiated in the TLS handshake.
\return the header protection cipher negotiated in the TLS handshake
\param ssl - a pointer to a WOLFSSL structure, created using wolfSSL_new().
\sa wolfSSL_quic_get_aead
\sa wolfSSL_quic_get_md
*/
const WOLFSSL_EVP_CIPHER *wolfSSL_quic_get_hp(WOLFSSL *ssl);
/*!
\ingroup QUIC
\brief Create a cipher context for en-/decryption.
\return the created context or NULL in case of errors.
\param cipher - the cipher to use in the context.
\param key - the key to use in the context.
\param iv - the iv to use in the context.
\param encrypt - != 0 if for encryption, otherwise decryption
\sa wolfSSL_quic_get_aead
\sa wolfSSL_quic_get_hp
\sa wolfSSL_quic_aead_encrypt
\sa wolfSSL_quic_aead_decrypt
*/
WOLFSSL_EVP_CIPHER_CTX *wolfSSL_quic_crypt_new(const WOLFSSL_EVP_CIPHER *cipher,
const uint8_t *key, const uint8_t *iv, int encrypt);
/*!
\ingroup QUIC
\brief Encrypt the plain text in the given context.
\return WOLFSSL_SUCCESS If successful.
\param dest - destination where encrypted data is to be written
\param aead_ctx - the cipher context to use
\param plain - the plain data to encrypt
\param plainlen - the length of the plain data
\param iv - the iv to use
\param aad - the add to use
\param aadlen - the length of the aad
\sa wolfSSL_quic_get_aead
\sa wolfSSL_quic_get_hp
\sa wolfSSL_quic_crypt_new
\sa wolfSSL_quic_aead_decrypt
*/
int wolfSSL_quic_aead_encrypt(uint8_t *dest, WOLFSSL_EVP_CIPHER_CTX *aead_ctx,
const uint8_t *plain, size_t plainlen,
const uint8_t *iv, const uint8_t *aad, size_t aadlen);
/*!
\ingroup QUIC
\brief Decrypt the cipher text in the given context.
\return WOLFSSL_SUCCESS If successful.
\param dest - destination where plain text is to be written
\param ctx - the cipher context to use
\param enc - the encrypted data to decrypt
\param envlen - the length of the encrypted data
\param iv - the iv to use
\param aad - the add to use
\param aadlen - the length of the aad
\sa wolfSSL_quic_get_aead
\sa wolfSSL_quic_get_hp
\sa wolfSSL_quic_crypt_new
\sa wolfSSL_quic_aead_encrypt
*/
int wolfSSL_quic_aead_decrypt(uint8_t *dest, WOLFSSL_EVP_CIPHER_CTX *ctx,
const uint8_t *enc, size_t enclen,
const uint8_t *iv, const uint8_t *aad, size_t aadlen);
/*!
\ingroup QUIC
\brief Extract a pseudo random key.
\return WOLFSSL_SUCCESS If successful.
\param dest - destination where key is to be written
\param md - message digest to use
\param secret - the secret to use
\param secretlen - the length of the secret
\param salt - the salt to use
\param saltlen - the length of the salt
\sa wolfSSL_quic_hkdf_expand
\sa wolfSSL_quic_hkdf
*/
int wolfSSL_quic_hkdf_extract(uint8_t *dest, const WOLFSSL_EVP_MD *md,
const uint8_t *secret, size_t secretlen,
const uint8_t *salt, size_t saltlen);
/*!
\ingroup QUIC
\brief Expand a pseudo random key into a new key.
\return WOLFSSL_SUCCESS If successful.
\param dest - destination where key is to be written
\param destlen - length of the key to expand
\param md - message digest to use
\param secret - the secret to use
\param secretlen - the length of the secret
\param info - the info to use
\param infolen - the length of the info
\sa wolfSSL_quic_hkdf_extract
\sa wolfSSL_quic_hkdf
*/
int wolfSSL_quic_hkdf_expand(uint8_t *dest, size_t destlen,
const WOLFSSL_EVP_MD *md,
const uint8_t *secret, size_t secretlen,
const uint8_t *info, size_t infolen);
/*!
\ingroup QUIC
\brief Expand and Extract a pseudo random key.
\return WOLFSSL_SUCCESS If successful.
\param dest - destination where key is to be written
\param destlen - length of the key
\param md - message digest to use
\param secret - the secret to use
\param secretlen - the length of the secret
\param salt - the salt to use
\param saltlen - the length of the salt
\param info - the info to use
\param infolen - the length of the info
\sa wolfSSL_quic_hkdf_extract
\sa wolfSSL_quic_hkdf_expand
*/
int wolfSSL_quic_hkdf(uint8_t *dest, size_t destlen,
const WOLFSSL_EVP_MD *md,
const uint8_t *secret, size_t secretlen,
const uint8_t *salt, size_t saltlen,
const uint8_t *info, size_t infolen);

View File

@ -14332,3 +14332,18 @@ int wolfSSL_RSA_sign_generic_padding(int type, const unsigned char* m,
\param ssl A WOLFSSL object pointer
*/
int wolfSSL_dtls13_has_pending_msg(WOLFSSL *ssl);
/*!
\ingroup SSL
\brief Get the maximum size of Early Data from a session.
\param [in] s the WOLFSSL_SESSION instance.
\return the value of max_early_data that was configured in the WOLFSSL* the session
was derived from.
\sa wolfSSL_set_max_early_data
\sa wolfSSL_write_early_data
\sa wolfSSL_read_early_data
*/
unsigned int wolfSSL_SESSION_get_max_early_data(const WOLFSSL_SESSION *s);

View File

@ -2,7 +2,9 @@
# included from Top Level Makefile.am
# All paths should be given relative to the root
dist_doc_DATA+= doc/README.txt
dist_doc_DATA+= doc/README.txt \
doc/QUIC.md
dox-pdf:
echo "Generating PDF"

View File

@ -234,6 +234,7 @@ mkdir -p $RPM_BUILD_ROOT/
%{_includedir}/wolfssl/openssl/x509_vfy.h
%{_includedir}/wolfssl/openssl/x509v3.h
%{_includedir}/wolfssl/options.h
%{_includedir}/wolfssl/quic.h
%{_includedir}/wolfssl/sniffer.h
%{_includedir}/wolfssl/sniffer_error.h
%{_includedir}/wolfssl/ssl.h

View File

@ -699,6 +699,10 @@ if BUILD_DTLS13
src_libwolfssl_la_SOURCES += src/dtls13.c
endif
if BUILD_QUIC
src_libwolfssl_la_SOURCES += src/quic.c
endif
endif !BUILD_CRYPTONLY

View File

@ -533,7 +533,11 @@ static WC_INLINE int IsEncryptionOn(WOLFSSL* ssl, int isSend)
}
#endif /* WOLFSSL_DTLS */
#ifdef WOLFSSL_QUIC
if (WOLFSSL_IS_QUIC(ssl) && IsAtLeastTLSv1_3(ssl->version)) {
return 0;
}
#endif
return ssl->keys.encryptionOn &&
(isSend ? ssl->encrypt.setup : ssl->decrypt.setup);
}
@ -6871,6 +6875,13 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
ssl->dtls13Rtx.rtxRecordTailPtr = &ssl->dtls13Rtx.rtxRecords;
#endif /* WOLFSSL_DTLS13 */
#ifdef WOLFSSL_QUIC
if (ctx->quic.method) {
ret = wolfSSL_set_quic_method(ssl, ctx->quic.method);
if (ret != WOLFSSL_SUCCESS)
return ret;
}
#endif
return 0;
}
@ -7538,6 +7549,9 @@ void SSL_ResourceFree(WOLFSSL* ssl)
#ifdef WOLFSSL_DTLS13
Dtls13FreeFsmResources(ssl);
#endif /* WOLFSSL_DTLS13 */
#ifdef WOLFSSL_QUIC
wolfSSL_quic_free(ssl);
#endif
}
/* Free any handshake resources no longer needed */
@ -9268,6 +9282,15 @@ static int wolfSSLReceive(WOLFSSL* ssl, byte* buf, word32 sz)
int recvd;
int retryLimit = WOLFSSL_MODE_AUTO_RETRY_ATTEMPTS;
#ifdef WOLFSSL_QUIC
if (WOLFSSL_IS_QUIC(ssl)) {
/* QUIC only "reads" from data provided by the application
* via wolfSSL_provide_quic_data(). Transfer from there
* into the inputBuffer. */
return wolfSSL_quic_receive(ssl, buf, sz);
}
#endif
if (ssl->CBIORecv == NULL) {
WOLFSSL_MSG("Your IO Recv callback is null, please set");
return -1;
@ -9423,7 +9446,7 @@ void ShrinkInputBuffer(WOLFSSL* ssl, int forcedFree)
int SendBuffered(WOLFSSL* ssl)
{
if (ssl->CBIOSend == NULL) {
if (ssl->CBIOSend == NULL && !WOLFSSL_IS_QUIC(ssl)) {
WOLFSSL_MSG("Your IO Send callback is null, please set");
return SOCKET_ERROR_E;
}
@ -9436,6 +9459,12 @@ int SendBuffered(WOLFSSL* ssl)
}
#endif
#ifdef WOLFSSL_QUIC
if (WOLFSSL_IS_QUIC(ssl)) {
return wolfSSL_quic_send(ssl);
}
#endif
while (ssl->buffers.outputBuffer.length > 0) {
int sent = ssl->CBIOSend(ssl,
(char*)ssl->buffers.outputBuffer.buffer +
@ -17644,7 +17673,7 @@ int TimingPadVerify(WOLFSSL* ssl, const byte* input, int padLen, int macSz,
int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx, int sniff)
{
word32 msgSz = ssl->keys.encryptSz;
word32 msgSz = WOLFSSL_IS_QUIC(ssl)? ssl->curSize : ssl->keys.encryptSz;
word32 idx = *inOutIdx;
int dataSz;
int ivExtra = 0;
@ -21876,6 +21905,16 @@ static int SendAlert_ex(WOLFSSL* ssl, int severity, int type)
WOLFSSL_ENTER("SendAlert");
#ifdef WOLFSSL_QUIC
if (WOLFSSL_IS_QUIC(ssl)) {
ret = !ssl->quic.method->send_alert(ssl, ssl->quic.enc_level_write, (uint8_t)type);
if (ret) {
WOLFSSL_MSG("QUIC send_alert callback error");
}
return ret;
}
#endif
#ifdef HAVE_WRITE_DUP
if (ssl->dupWrite && ssl->dupSide == READ_DUP_SIDE) {
int notifyErr = 0;
@ -22522,6 +22561,11 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e)
case FALCON_KEY_SIZE_E:
return "Wrong key size for Falcon.";
#ifdef WOLFSSL_QUIC
case QUIC_TP_MISSING_E:
return "QUIC transport parameter not set";
#endif
default :
return "unknown error number";
}

View File

@ -2988,6 +2988,11 @@ int SetKeysSide(WOLFSSL* ssl, enum encrypt_side side)
if (ret == 0 && ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version))
ret = Dtls13SetRecordNumberKeys(ssl, side);
#endif /* WOLFSSL_DTLS13 */
#ifdef WOLFSSL_QUIC
if (ret == 0 && WOLFSSL_IS_QUIC(ssl)) {
ret = wolfSSL_quic_keys_active(ssl, side);
}
#endif /* WOLFSSL_QUIC */
#ifdef HAVE_SECURE_RENEGOTIATION
#ifdef WOLFSSL_DTLS

1262
src/quic.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2338,6 +2338,12 @@ int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz)
if (ssl == NULL || data == NULL || sz < 0)
return BAD_FUNC_ARG;
#ifdef WOLFSSL_QUIC
if (WOLFSSL_IS_QUIC(ssl)) {
WOLFSSL_MSG("SSL_write() on QUIC not allowed");
return BAD_FUNC_ARG;
}
#endif
#ifdef WOLFSSL_EARLY_DATA
if (ssl->earlyData != no_early_data && (ret = wolfSSL_negotiate(ssl)) < 0) {
ssl->error = ret;
@ -2405,6 +2411,12 @@ static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, int sz, int peek)
if (ssl == NULL || data == NULL || sz < 0)
return BAD_FUNC_ARG;
#ifdef WOLFSSL_QUIC
if (WOLFSSL_IS_QUIC(ssl)) {
WOLFSSL_MSG("SSL_read() on QUIC not allowed");
return BAD_FUNC_ARG;
}
#endif
#if defined(WOLFSSL_ERROR_CODE_OPENSSL) && defined(OPENSSL_EXTRA)
/* This additional logic is meant to simulate following openSSL behavior:
* After bidirectional SSL_shutdown complete, SSL_read returns 0 and
@ -9792,6 +9804,13 @@ int wolfSSL_SESSION_get_master_key_length(const WOLFSSL_SESSION* ses)
return SECRET_LEN;
}
#ifdef WOLFSSL_EARLY_DATA
unsigned int wolfSSL_SESSION_get_max_early_data(const WOLFSSL_SESSION *session)
{
return session->maxEarlyDataSz;
}
#endif /* WOLFSSL_EARLY_DATA */
#endif /* OPENSSL_EXTRA */
typedef struct {
@ -18253,6 +18272,10 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
InitX509(&ssl->peerCert, 0, ssl->heap);
#endif
#ifdef WOLFSSL_QUIC
wolfSSL_quic_clear(ssl);
#endif
return WOLFSSL_SUCCESS;
}
@ -33310,7 +33333,8 @@ int wolfSSL_sk_WOLFSSL_STRING_num(WOLF_STACK_OF(WOLFSSL_STRING)* strings)
#endif /* WOLFSSL_NGINX || WOLFSSL_HAPROXY || OPENSSL_EXTRA || OPENSSL_ALL */
#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \
defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY)
defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY) || \
defined(WOLFSSL_QUIC)
#ifdef HAVE_ALPN
void wolfSSL_get0_alpn_selected(const WOLFSSL *ssl, const unsigned char **data,
unsigned int *len)

151
src/tls.c
View File

@ -1226,8 +1226,8 @@ int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, int padSz,
* from one peer to another.
*/
/** Supports up to 64 flags. Increase as needed. */
#define SEMAPHORE_SIZE 8
/** Supports up to 72 flags. Increase as needed. */
#define SEMAPHORE_SIZE 9
/**
* Converts the extension type (id) to an index in the semaphore.
@ -1254,7 +1254,10 @@ static WC_INLINE word16 TLSX_ToSemaphore(word16 type)
case TLSX_RENEGOTIATION_INFO: /* 0xFF01 */
return 63;
#ifdef WOLFSSL_QUIC
case TLSX_KEY_QUIC_TP_PARAMS_DRAFT: /* 0xffa5 */
return 64;
#endif
default:
if (type > 62) {
/* This message SHOULD only happens during the adding of
@ -10394,6 +10397,95 @@ int TLSX_EarlyData_Use(WOLFSSL* ssl, word32 maxSz)
#endif
/******************************************************************************/
/* QUIC transport parameter extension */
/******************************************************************************/
#ifdef WOLFSSL_QUIC
static word16 TLSX_QuicTP_GetSize(TLSX* extension)
{
const QuicTransportParam *tp = (QuicTransportParam*)extension->data;
return tp ? tp->len : 0;
}
int TLSX_QuicTP_Use(WOLFSSL* ssl, TLSX_Type ext_type, int is_response)
{
int ret = 0;
TLSX* extension;
WOLFSSL_ENTER("TLSX_QuicTP_Use");
if (ssl->quic.transport_local == NULL) {
/* RFC9000, ch 7.3: "An endpoint MUST treat the absence of [...]
* from either endpoint [...] as a connection error of type
* TRANSPORT_PARAMETER_ERROR."
*/
ret = QUIC_TP_MISSING_E;
goto cleanup;
}
extension = TLSX_Find(ssl->extensions, ext_type);
if (extension == NULL) {
ret = TLSX_Push(&ssl->extensions, ext_type, NULL, ssl->heap);
if (ret != 0)
goto cleanup;
extension = TLSX_Find(ssl->extensions, ext_type);
if (extension == NULL) {
ret = MEMORY_E;
goto cleanup;
}
}
extension->resp = is_response;
extension->data = (void*)QuicTransportParam_dup(ssl->quic.transport_local, ssl->heap);
if (!extension->data) {
ret = MEMORY_E;
goto cleanup;
}
cleanup:
WOLFSSL_LEAVE("TLSX_QuicTP_Use", ret);
return ret;
}
static word16 TLSX_QuicTP_Write(QuicTransportParam *tp, byte* output)
{
word16 len = 0;
WOLFSSL_ENTER("TLSX_QuicTP_Write");
if (tp && tp->len) {
XMEMCPY(output, tp->data, tp->len);
len = tp->len;
}
WOLFSSL_LEAVE("TLSX_QuicTP_Write", len);
return len;
}
static int TLSX_QuicTP_Parse(WOLFSSL *ssl, const byte *input, size_t len, int ext_type, int msgType)
{
const QuicTransportParam *tp, **ptp;
(void)msgType;
tp = QuicTransportParam_new(input, len, ssl->heap);
if (!tp) {
return MEMORY_E;
}
ptp = (ext_type == TLSX_KEY_QUIC_TP_PARAMS_DRAFT) ?
&ssl->quic.transport_peer_draft : &ssl->quic.transport_peer;
if (*ptp) {
QTP_FREE(*ptp, ssl->heap);
}
*ptp = tp;
return 0;
}
#define QTP_GET_SIZE TLSX_QuicTP_GetSize
#define QTP_USE TLSX_QuicTP_Use
#define QTP_WRITE TLSX_QuicTP_Write
#define QTP_PARSE TLSX_QuicTP_Parse
#endif /* WOLFSSL_QUIC */
/******************************************************************************/
/* TLS Extensions Framework */
/******************************************************************************/
@ -10536,6 +10628,14 @@ void TLSX_FreeAll(TLSX* list, void* heap)
break;
#endif
#ifdef WOLFSSL_QUIC
case TLSX_KEY_QUIC_TP_PARAMS:
FALL_THROUGH;
case TLSX_KEY_QUIC_TP_PARAMS_DRAFT:
QTP_FREE((QuicTransportParam*)extension->data, heap);
break;
#endif
default:
break;
}
@ -10691,6 +10791,14 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
length += SRTP_GET_SIZE((TlsxSrtp*)extension->data);
break;
#endif
#ifdef WOLFSSL_QUIC
case TLSX_KEY_QUIC_TP_PARAMS:
FALL_THROUGH; /* followed by */
case TLSX_KEY_QUIC_TP_PARAMS_DRAFT:
length += QTP_GET_SIZE(extension);
break;
#endif
default:
break;
}
@ -10878,6 +10986,15 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore,
case TLSX_USE_SRTP:
offset += SRTP_WRITE((TlsxSrtp*)extension->data, output+offset);
break;
#endif
#ifdef WOLFSSL_QUIC
case TLSX_KEY_QUIC_TP_PARAMS:
FALL_THROUGH;
case TLSX_KEY_QUIC_TP_PARAMS_DRAFT:
WOLFSSL_MSG("QUIC transport parameter to write");
offset += QTP_WRITE((QuicTransportParam*)extension->data,
output + offset);
break;
#endif
default:
break;
@ -12536,6 +12653,34 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
ret = SRTP_PARSE(ssl, input + offset, size, isRequest);
break;
#endif
#ifdef WOLFSSL_QUIC
case TLSX_KEY_QUIC_TP_PARAMS:
FALL_THROUGH;
case TLSX_KEY_QUIC_TP_PARAMS_DRAFT:
WOLFSSL_MSG("QUIC transport parameter received");
#ifdef WOLFSSL_DEBUG_TLS
WOLFSSL_BUFFER(input + offset, size);
#endif
if (IsAtLeastTLSv1_3(ssl->version) &&
msgType != client_hello &&
msgType != server_hello &&
msgType != encrypted_extensions) {
return EXT_NOT_ALLOWED;
}
else if (!IsAtLeastTLSv1_3(ssl->version) &&
msgType == encrypted_extensions) {
return EXT_NOT_ALLOWED;
}
else if (WOLFSSL_IS_QUIC(ssl)) {
ret = QTP_PARSE(ssl, input + offset, size, type, msgType);
}
else {
WOLFSSL_MSG("QUIC transport param TLS extension type, but no QUIC");
return EXT_NOT_ALLOWED; /* be safe, this should not happen */
}
break;
#endif /* WOLFSSL_QUIC */
default:
WOLFSSL_MSG("Unknown TLS extension type");
}

View File

@ -1280,6 +1280,14 @@ int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store)
break;
}
#ifdef WOLFSSL_QUIC
if (WOLFSSL_IS_QUIC(ssl)) {
ret = wolfSSL_quic_forward_secrets(ssl, secret, side);
if (ret != 0)
goto end;
}
#endif /* WOLFSSL_QUIC */
if (!store)
goto end;
@ -2662,6 +2670,16 @@ int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input,
case BUILD_MSG_ENCRYPT:
{
#ifdef WOLFSSL_QUIC
if (WOLFSSL_IS_QUIC(ssl)) {
/* QUIC does not use encryption of the TLS Record Layer.
* Return the original length + added headers
* and restore it in the record header. */
AddTls13RecordHeader(output, inSz, type, ssl);
ret = args->headerSz + inSz;
goto exit_buildmsg;
}
#endif
#ifdef ATOMIC_USER
if (ssl->ctx->MacEncryptCb) {
/* User Record Layer Callback handling */
@ -3440,8 +3458,19 @@ int SendTls13ClientHello(WOLFSSL* ssl)
/* Version | Random | Session Id | Cipher Suites | Compression */
args->length = VERSION_SZ + RAN_LEN + ENUM_LEN + ssl->suites->suiteSz +
SUITE_LEN + COMP_LEN + ENUM_LEN;
#ifdef WOLFSSL_QUIC
if (WOLFSSL_IS_QUIC(ssl)) {
/* RFC 9001 ch. 8.4 sessionID in ClientHello MUST be 0 length */
ssl->session->sessionIDSz = 0;
ssl->options.tls13MiddleBoxCompat = 0;
}
else
#endif
#if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
args->length += ID_LEN;
{
args->length += ID_LEN;
ssl->options.tls13MiddleBoxCompat = 1;
}
#else
if (ssl->session->sessionIDSz > 0)
args->length += ssl->session->sessionIDSz;
@ -3494,6 +3523,13 @@ int SendTls13ClientHello(WOLFSSL* ssl)
(ret = TLSX_EarlyData_Use(ssl, 0)) < 0) {
return ret;
}
#endif
#ifdef WOLFSSL_QUIC
if (WOLFSSL_IS_QUIC(ssl) && IsAtLeastTLSv1_3(ssl->version)) {
ret = wolfSSL_quic_add_transport_extensions(ssl, client_hello);
if (ret != 0)
return ret;
}
#endif
/* Include length of TLS extensions. */
ret = TLSX_GetRequestSize(ssl, client_hello, &args->length);
@ -3551,13 +3587,17 @@ int SendTls13ClientHello(WOLFSSL* ssl)
}
else {
#ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT
args->output[args->idx++] = ID_LEN;
XMEMCPY(args->output + args->idx, ssl->arrays->clientRandom, ID_LEN);
args->idx += ID_LEN;
#else
/* TLS v1.3 does not use session id - 0 length. */
args->output[args->idx++] = 0;
if (ssl->options.tls13MiddleBoxCompat) {
args->output[args->idx++] = ID_LEN;
XMEMCPY(args->output + args->idx, ssl->arrays->clientRandom, ID_LEN);
args->idx += ID_LEN;
}
else
#endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */
{
/* TLS v1.3 does not use session id - 0 length. */
args->output[args->idx++] = 0;
}
}
#ifdef WOLFSSL_DTLS13
@ -3658,7 +3698,9 @@ int SendTls13ClientHello(WOLFSSL* ssl)
case TLS_ASYNC_END:
#ifdef WOLFSSL_EARLY_DATA_GROUP
if (ssl->earlyData == no_early_data)
/* QUIC needs to forward records at their encryption level
* and is therefore unable to group here */
if (ssl->earlyData == no_early_data || WOLFSSL_IS_QUIC(ssl))
#endif
ret = SendBuffered(ssl);
@ -4097,27 +4139,39 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
case TLS_ASYNC_FINALIZE:
{
#ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT
if (args->sessIdSz == 0) {
WOLFSSL_MSG("args->sessIdSz == 0");
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
return INVALID_PARAMETER;
}
if (ssl->session->sessionIDSz != 0) {
if (ssl->session->sessionIDSz != args->sessIdSz ||
XMEMCMP(ssl->session->sessionID, args->sessId,
if (ssl->options.tls13MiddleBoxCompat) {
if (args->sessIdSz == 0) {
WOLFSSL_MSG("args->sessIdSz == 0");
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
return INVALID_PARAMETER;
}
if (ssl->session->sessionIDSz != 0) {
if (ssl->session->sessionIDSz != args->sessIdSz ||
XMEMCMP(ssl->session->sessionID, args->sessId,
args->sessIdSz) != 0) {
WOLFSSL_MSG("session id doesn't match");
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
return INVALID_PARAMETER;
}
}
else if (XMEMCMP(ssl->arrays->clientRandom, args->sessId,
args->sessIdSz) != 0) {
WOLFSSL_MSG("session id doesn't match");
WOLFSSL_MSG("session id doesn't match client random");
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
return INVALID_PARAMETER;
}
else
#endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */
#ifdef WOLFSSL_QUIC
if (WOLFSSL_IS_QUIC(ssl)) {
if (args->sessIdSz != 0) {
WOLFSSL_MSG("args->sessIdSz != 0");
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
return INVALID_PARAMETER;
}
}
else if (XMEMCMP(ssl->arrays->clientRandom, args->sessId,
args->sessIdSz) != 0) {
WOLFSSL_MSG("session id doesn't match client random");
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
return INVALID_PARAMETER;
}
#else
else
#endif /* WOLFSSL_QUIC */
if (args->sessIdSz != ssl->session->sessionIDSz || (args->sessIdSz > 0 &&
XMEMCMP(ssl->session->sessionID, args->sessId, args->sessIdSz) != 0))
{
@ -4125,7 +4179,6 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
return INVALID_PARAMETER;
}
#endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */
ret = SetCipherSpecs(ssl);
if (ret != 0)
@ -5867,6 +5920,13 @@ static int SendTls13EncryptedExtensions(WOLFSSL* ssl)
if ((ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE)) != 0)
return ret;
#endif
#ifdef WOLFSSL_QUIC
if (IsAtLeastTLSv1_3(ssl->version) && WOLFSSL_IS_QUIC(ssl)) {
ret = wolfSSL_quic_add_transport_extensions(ssl, encrypted_extensions);
if (ret != 0)
return ret;
}
#endif
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls) {
@ -8201,6 +8261,7 @@ static int SendTls13Finished(WOLFSSL* ssl)
}
#endif /* WOLFSSL_DTLS13 */
}
if (ssl->options.side == WOLFSSL_CLIENT_END &&
@ -9319,7 +9380,9 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type)
#ifdef WOLFSSL_EARLY_DATA
if (ssl->earlyData == process_early_data &&
/* early data may be lost when using DTLS */
!ssl->options.dtls) {
!ssl->options.dtls
/* QUIC does not use EndOfEarlyData records */
&& !WOLFSSL_IS_QUIC(ssl)) {
WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E);
return OUT_OF_ORDER_E;
}
@ -9681,6 +9744,15 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
ForceZero(ssl->arrays->preMasterSecret,
ssl->arrays->preMasterSz);
#ifdef WOLFSSL_EARLY_DATA
#ifdef WOLFSSL_QUIC
if (WOLFSSL_IS_QUIC(ssl) && ssl->earlyData != no_early_data) {
/* QUIC never sends/receives EndOfEarlyData, but having
* early data means the last encrpytion keys had not been
* set yet. */
if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0)
return ret;
}
#endif
if ((ret = DeriveTls13Keys(ssl, traffic_key,
ENCRYPT_AND_DECRYPT_SIDE,
ssl->earlyData == no_early_data)) != 0) {
@ -9992,7 +10064,7 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl)
#ifdef WOLFSSL_EARLY_DATA
if (ssl->earlyData != no_early_data) {
#if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
if (!ssl->options.dtls) {
if (!ssl->options.dtls && ssl->options.tls13MiddleBoxCompat) {
if ((ssl->error = SendChangeCipher(ssl)) != 0) {
WOLFSSL_ERROR(ssl->error);
return WOLFSSL_FATAL_ERROR;
@ -10046,7 +10118,8 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl)
if (ssl->options.serverState ==
SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
#if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
if (!ssl->options.dtls && !ssl->options.sentChangeCipher) {
if (!ssl->options.dtls && !ssl->options.sentChangeCipher
&& ssl->options.tls13MiddleBoxCompat) {
if ((ssl->error = SendChangeCipher(ssl)) != 0) {
WOLFSSL_ERROR(ssl->error);
return WOLFSSL_FATAL_ERROR;
@ -10089,7 +10162,8 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl)
case FIRST_REPLY_DONE:
#ifdef WOLFSSL_EARLY_DATA
if (!ssl->options.dtls && ssl->earlyData != no_early_data) {
if (!ssl->options.dtls && ssl->earlyData != no_early_data
&& !WOLFSSL_IS_QUIC(ssl)) {
if ((ssl->error = SendTls13EndOfEarlyData(ssl)) != 0) {
WOLFSSL_ERROR(ssl->error);
return WOLFSSL_FATAL_ERROR;
@ -10104,7 +10178,8 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl)
case FIRST_REPLY_FIRST:
#if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
if (!ssl->options.sentChangeCipher && !ssl->options.dtls) {
if (!ssl->options.sentChangeCipher && !ssl->options.dtls
&& ssl->options.tls13MiddleBoxCompat) {
if ((ssl->error = SendChangeCipher(ssl)) != 0) {
WOLFSSL_ERROR(ssl->error);
return WOLFSSL_FATAL_ERROR;
@ -11156,7 +11231,8 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl)
case TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE :
#ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT
if (!ssl->options.dtls && ssl->options.serverState ==
if (!ssl->options.dtls && ssl->options.tls13MiddleBoxCompat
&& ssl->options.serverState ==
SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
if ((ssl->error = SendChangeCipher(ssl)) != 0) {
WOLFSSL_ERROR(ssl->error);
@ -11218,7 +11294,7 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl)
case TLS13_SERVER_HELLO_SENT :
#if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
if (!ssl->options.dtls
if (!ssl->options.dtls && ssl->options.tls13MiddleBoxCompat
&& !ssl->options.sentChangeCipher && !ssl->options.dtls) {
if ((ssl->error = SendChangeCipher(ssl)) != 0) {
WOLFSSL_ERROR(ssl->error);

View File

@ -12,6 +12,7 @@ tests_unit_test_SOURCES = \
tests/hash.c \
tests/w64wrapper.c \
tests/srp.c \
tests/quic.c \
examples/client/client.c \
examples/server/server.c
tests_unit_test_CFLAGS = -DNO_MAIN_DRIVER $(AM_CFLAGS) $(WOLFSENTRY_INCLUDE)

1393
tests/quic.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -185,6 +185,13 @@ int unit_test(int argc, char** argv)
#endif
#endif /* NO_WOLFSSL_CIPHER_SUITE_TEST */
#ifdef WOLFSSL_QUIC
if ( (ret = QuicTest()) != 0){
printf("quic test failed with %d\n", ret);
goto exit;
}
#endif
SrpTest();
exit:

View File

@ -118,6 +118,7 @@ int SuiteTest(int argc, char** argv);
int HashTest(void);
void SrpTest(void);
int w64wrapper_test(void);
int QuicTest(void);
#endif /* CyaSSL_UNIT_H */

View File

@ -176,6 +176,7 @@ enum wolfSSL_ErrorCodes {
HTTP_APPSTR_ERR = -449, /* HTTP Application string error */
UNSUPPORTED_PROTO_VERSION = -450, /* bad/unsupported protocol version*/
FALCON_KEY_SIZE_E = -451, /* Wrong key size for Falcon. */
QUIC_TP_MISSING_E = -452, /* QUIC transport parameter missing */
/* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */

View File

@ -17,6 +17,7 @@ nobase_include_HEADERS+= \
wolfssl/test.h \
wolfssl/version.h \
wolfssl/ocsp.h \
wolfssl/quic.h \
wolfssl/crl.h \
wolfssl/wolfio.h

View File

@ -74,6 +74,9 @@
#ifdef HAVE_OCSP
#include <wolfssl/ocsp.h>
#endif
#ifdef WOLFSSL_QUIC
#include <wolfssl/quic.h>
#endif
#ifdef WOLFSSL_SHA384
#include <wolfssl/wolfcrypt/sha512.h>
#endif
@ -2026,7 +2029,7 @@ WOLFSSL_LOCAL int SetSuitesHashSigAlgo(Suites* suites, const char* list);
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) && \
!defined(WOLFSSL_DTLS_EXPORT_TYPES)
typedef int (*wc_dtls_export)(WOLFSSL* ssl,
unsigned char* exportBuffer, unsigned int sz, void* userCtx);
#define WOLFSSL_DTLS_EXPORT_TYPES
#endif /* WOLFSSL_DTLS_EXPORT_TYPES */
@ -2423,8 +2426,14 @@ typedef enum {
TLSX_SIGNATURE_ALGORITHMS_CERT = 0x0032,
#endif
TLSX_KEY_SHARE = 0x0033,
#ifdef WOLFSSL_QUIC
TLSX_KEY_QUIC_TP_PARAMS = 0x0039, /* RFC 9001, ch. 8.2 */
#endif
#endif
TLSX_RENEGOTIATION_INFO = 0xff01,
#ifdef WOLFSSL_QUIC
TLSX_KEY_QUIC_TP_PARAMS_DRAFT = 0xffa5, /* from draft-ietf-quic-tls-27 */
#endif
TLSX_RENEGOTIATION_INFO = 0xff01
} TLSX_Type;
typedef struct TLSX {
@ -3084,7 +3093,8 @@ struct WOLFSSL_CTX {
#ifdef HAVE_EX_DATA
WOLFSSL_CRYPTO_EX_DATA ex_data;
#endif
#if defined(HAVE_ALPN) && (defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY))
#if defined(HAVE_ALPN) && (defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \
defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY) || defined(WOLFSSL_QUIC))
CallbackALPNSelect alpnSelect;
void* alpnSelectArg;
#endif
@ -3219,6 +3229,11 @@ struct WOLFSSL_CTX {
wolfSSL_Mutex staticKELock;
#endif
#endif
#ifdef WOLFSSL_QUIC
struct {
const WOLFSSL_QUIC_METHOD *method;
} quic;
#endif
};
WOLFSSL_LOCAL
@ -3482,6 +3497,35 @@ typedef enum WOLFSSL_SESSION_TYPE {
WOLFSSL_SESSION_TYPE_HEAP /* allocated from heap SESSION_new */
} WOLFSSL_SESSION_TYPE;
#ifdef WOLFSSL_QUIC
typedef struct QuicRecord QuicRecord;
typedef struct QuicRecord {
struct QuicRecord *next;
uint8_t *data;
word32 capacity;
word32 len;
word32 start;
word32 end;
WOLFSSL_ENCRYPTION_LEVEL level;
word32 rec_hdr_remain;
} QuicEncData;
typedef struct QuicTransportParam QuicTransportParam;
struct QuicTransportParam {
const uint8_t *data;
word16 len;
};
WOLFSSL_LOCAL const QuicTransportParam *QuicTransportParam_new(const uint8_t *data, size_t len, void *heap);
WOLFSSL_LOCAL const QuicTransportParam *QuicTransportParam_dup(const QuicTransportParam *tp, void *heap);
WOLFSSL_LOCAL void QuicTransportParam_free(const QuicTransportParam *tp, void *heap);
WOLFSSL_LOCAL int TLSX_QuicTP_Use(WOLFSSL* ssl, TLSX_Type ext_type, int is_response);
WOLFSSL_LOCAL int wolfSSL_quic_add_transport_extensions(WOLFSSL *ssl, int msg_type);
#define QTP_FREE QuicTransportParam_free
#endif /* WOLFSSL_QUIC */
/* wolfSSL session type */
struct WOLFSSL_SESSION {
/* WARNING Do not add fields here. They will be ignored in
@ -3918,6 +3962,9 @@ typedef struct Options {
word16 dtls13SendMoreAcks:1; /* Send more acks during the
* handshake process */
#endif
#ifdef WOLFSSL_TLS13
word16 tls13MiddleBoxCompat:1; /* TLSv1.3 middlebox compatibility */
#endif
/* need full byte values for this section */
byte processReply; /* nonblocking resume */
@ -4780,7 +4827,8 @@ struct WOLFSSL {
#endif /* user turned on */
#ifdef HAVE_ALPN
char* alpn_client_list; /* keep the client's list */
#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \
defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_QUIC)
CallbackALPNSelect alpnSelect;
void* alpnSelectArg;
#endif
@ -4924,6 +4972,27 @@ struct WOLFSSL {
#ifdef WOLFSSL_LWIP_NATIVE
WOLFSSL_LWIP_NATIVE_STATE lwipCtx; /* LwIP native socket IO Context */
#endif
#ifdef WOLFSSL_QUIC
struct {
const WOLFSSL_QUIC_METHOD* method;
WOLFSSL_ENCRYPTION_LEVEL enc_level_read;
WOLFSSL_ENCRYPTION_LEVEL enc_level_read_next;
WOLFSSL_ENCRYPTION_LEVEL enc_level_latest_recvd;
WOLFSSL_ENCRYPTION_LEVEL enc_level_write;
WOLFSSL_ENCRYPTION_LEVEL enc_level_write_next;
int transport_version;
const QuicTransportParam* transport_local;
const QuicTransportParam* transport_peer;
const QuicTransportParam* transport_peer_draft;
QuicRecord* input_head; /* we own, data for handshake */
QuicRecord* input_tail; /* points to last element for append */
QuicRecord* scratch; /* we own, record construction */
enum wolfssl_encryption_level_t output_rec_level;
/* encryption level of current output record */
word32 output_rec_remain; /* how many bytes of output TLS record
* content have not been handled yet by quic */
} quic;
#endif /* WOLFSSL_QUIC */
};
/*
@ -5562,6 +5631,20 @@ WOLFSSL_LOCAL int wolfSSL_RSA_To_Der(WOLFSSL_RSA* rsa, byte** outBuf,
int publicKey, void* heap);
#endif
#ifdef WOLFSSL_QUIC
#define WOLFSSL_IS_QUIC(s) (s && s->quic.method != NULL)
WOLFSSL_LOCAL int wolfSSL_quic_receive(WOLFSSL* ssl, byte* buf, word32 sz);
WOLFSSL_LOCAL int wolfSSL_quic_send(WOLFSSL* ssl);
WOLFSSL_LOCAL void wolfSSL_quic_clear(WOLFSSL* ssl);
WOLFSSL_LOCAL void wolfSSL_quic_free(WOLFSSL* ssl);
WOLFSSL_LOCAL int wolfSSL_quic_forward_secrets(WOLFSSL *ssl,
int ktype, int side);
WOLFSSL_LOCAL int wolfSSL_quic_keys_active(WOLFSSL* ssl, enum encrypt_side side);
#else
#define WOLFSSL_IS_QUIC(s) 0
#endif /* WOLFSSL_QUIC (else) */
#ifdef __cplusplus
} /* extern "C" */
#endif

View File

@ -384,6 +384,7 @@ typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS;
#define SSL_get_keys wolfSSL_get_keys
#define SSL_SESSION_get_master_key wolfSSL_SESSION_get_master_key
#define SSL_SESSION_get_master_key_length wolfSSL_SESSION_get_master_key_length
#define SSL_SESSION_get_max_early_data wolfSSL_SESSION_get_max_early_data
#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
#define SSL_MODE_RELEASE_BUFFERS 0x00000010U

294
wolfssl/quic.h Normal file
View File

@ -0,0 +1,294 @@
/* quic.h
*
* Copyright (C) 2006-2021 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
/* wolfSSL QUIC API */
#ifndef WOLFSSL_QUIC_H
#define WOLFSSL_QUIC_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef WOLFSSL_QUIC
/* QUIC operates on three encryption levels which determine
* which keys/algos are used for de-/encryption. These are
* kept separately for incoming and outgoing data and.
* Due to the nature of UDP, more than one might be in use
* at the same time due to resends or out-of-order arrivals.
*/
typedef enum wolfssl_encryption_level_t {
wolfssl_encryption_initial = 0,
wolfssl_encryption_early_data,
wolfssl_encryption_handshake,
wolfssl_encryption_application
} WOLFSSL_ENCRYPTION_LEVEL;
/* All QUIC related callbacks to the application.
*/
typedef struct wolfssl_quic_method_t WOLFSSL_QUIC_METHOD;
struct wolfssl_quic_method_t {
/**
* Provide secrets to the QUIC stack when they becaome available in the SSL
* instance during handshake processing. read/write secrets have the same
* length. A call may only provide one, passing NULL as the other.
*/
int (*set_encryption_secrets)(WOLFSSL* ssl, WOLFSSL_ENCRYPTION_LEVEL level,
const uint8_t* read_secret,
const uint8_t* write_secret,
size_t secret_len);
/**
* Provide handshake packets to the QUIC stack to send to the peer. The
* QUIC stack will wrap these and take care of re-transmissions.
*/
int (*add_handshake_data)(WOLFSSL* ssl, WOLFSSL_ENCRYPTION_LEVEL level,
const uint8_t* data, size_t len);
/**
* Flush any buffered packets during handshake.
*/
int (*flush_flight)(WOLFSSL* ssl);
/**
* Send a TLS alert that happend during handshake. In QUIC, such alerts
* lead to connection shutdown.
*/
int (*send_alert)(WOLFSSL* ssl, WOLFSSL_ENCRYPTION_LEVEL level,
uint8_t alert);
};
/**
* Mark the given SSL context for QUIC protocol handling. Meaning all
* SSL instances derived from it will inherit this. Provides all callbacks
* to the QUIC application the SSL stack needs.
*/
WOLFSSL_API
int wolfSSL_CTX_set_quic_method(WOLFSSL_CTX* ctx,
const WOLFSSL_QUIC_METHOD* quic_method);
/**
* Mark extactly this SSL instance for QUIC protocol handling.
* Provides all callbacks to the QUIC application the SSL stack needs.
*/
WOLFSSL_API
int wolfSSL_set_quic_method(WOLFSSL* ssl,
const WOLFSSL_QUIC_METHOD* quic_method);
/**
* Check if QUIC handling has been installed on the given SSL instance.
*/
WOLFSSL_API int wolfSSL_is_quic(WOLFSSL* ssl);
/**
* Return the current encryption level of the SSL instance for READs.
*/
WOLFSSL_API
WOLFSSL_ENCRYPTION_LEVEL wolfSSL_quic_read_level(const WOLFSSL* ssl);
/**
* Return the current encryption level of the SSL instance for WRITEs.
*/
WOLFSSL_API
WOLFSSL_ENCRYPTION_LEVEL wolfSSL_quic_write_level(const WOLFSSL* ssl);
/**
* Configure the QUIC transport version to use. On `use_legacy` != 0,
* selects TLSX_KEY_QUIC_TP_PARAMS_DRAFT, otherwise TLSX_KEY_QUIC_TP_PARAMS.
* This method is part of the BoringSSL API and replicated here for app
* portability (as in quictls/openssl).
*/
WOLFSSL_API
void wolfSSL_set_quic_use_legacy_codepoint(WOLFSSL* ssl, int use_legacy);
/**
* Set the TLS extension for the transport parameter version to announce
* to the peer. Known values are TLSX_KEY_QUIC_TP_PARAMS (V1) and
* TLSX_KEY_QUIC_TP_PARAMS_DRAFT.
* Setting it to 0 will announce both V1 and draft versions to a server.
* Servers will, on 0, select the latest version seen from the client.
* Default is 0.
*/
WOLFSSL_API
void wolfSSL_set_quic_transport_version(WOLFSSL* ssl, int version);
/**
* Get the configured transport version.
*/
WOLFSSL_API int wolfSSL_get_quic_transport_version(const WOLFSSL* ssl);
/**
* Set the raw QUIC transport parameter that will be sent in the TLS extension
* to the peer, using the configured transport version(s).
*/
WOLFSSL_API int wolfSSL_set_quic_transport_params(WOLFSSL* ssl,
const uint8_t* params,
size_t params_len);
/**
* Get the raw QUIC transport parameter as retrieved via TLS Extension
* from the peer. If the peer announced several versions,
* return the latest one.
* If the extension has not arrived yet, initializes out parameter to
* NULL, resp. 0.
*/
WOLFSSL_API
void wolfSSL_get_peer_quic_transport_params(const WOLFSSL* ssl,
const uint8_t* *out_params,
size_t* out_params_len);
/**
* Get the QUIC version negotiated with the peer during the handshake.
*/
WOLFSSL_API int wolfSSL_get_peer_quic_transport_version(const WOLFSSL* ssl);
#ifdef WOLFSSL_EARLY_DATA
WOLFSSL_API void wolfSSL_set_quic_early_data_enabled(WOLFSSL* ssl, int enabled);
#endif
/**
* Advisory amount of the maximum data a QUIC protocol handler should have
* in flight. This varies during handshake processing, for example certficate
* exchange will increase the limit.
*/
WOLFSSL_API
size_t wolfSSL_quic_max_handshake_flight_len(const WOLFSSL* ssl,
WOLFSSL_ENCRYPTION_LEVEL level);
/**
* The QUIC protocol handler provides peer TLS records to the SSL instance
* during handshake to progress it. The SSL instance will use the registered
* callbacks to send packets to the peer.
* Encryption level is provided to indicate how to decrypt the data. Data may
* be added for levels not yet reached by the SSL instance. However, data
* may only be added in ever increasing levels and levels may only increase
* at TLS record boundaries. Any violation will make this function fail.
*/
WOLFSSL_API
int wolfSSL_provide_quic_data(WOLFSSL* ssl, WOLFSSL_ENCRYPTION_LEVEL level,
const uint8_t* data, size_t len);
/**
* Process any CRYPTO data added post-handshake.
*/
WOLFSSL_API int wolfSSL_process_quic_post_handshake(WOLFSSL* ssl);
/**
* Process any pending input and flush all output. Can be invoked
* during and/or after handshake processing.
*/
WOLFSSL_API int wolfSSL_quic_read_write(WOLFSSL* ssl);
/**
* Get the AEAD cipher that is currently selected in the SSL instance.
* Will return NULL if none has been selected so far. This is used by the
* QUIC stack to encrypt/decrypt packets after the handshake.
*/
WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_quic_get_aead(WOLFSSL* ssl);
/**
* Use to classify the AEAD cipher for key reuse limits.
*/
WOLFSSL_API int wolfSSL_quic_aead_is_gcm(const WOLFSSL_EVP_CIPHER* aead_cipher);
WOLFSSL_API int wolfSSL_quic_aead_is_ccm(const WOLFSSL_EVP_CIPHER* aead_cipher);
WOLFSSL_API
int wolfSSL_quic_aead_is_chacha20(const WOLFSSL_EVP_CIPHER* aead_cipher);
/**
* Get the 'tag' length used by the AEAD cipher. Encryption buffer lengths
* are plaintext length plus this tag length.
*/
WOLFSSL_API
size_t wolfSSL_quic_get_aead_tag_len(const WOLFSSL_EVP_CIPHER* aead_cipher);
/**
* The message digest currently selected in the SSL instance.
*/
WOLFSSL_API const WOLFSSL_EVP_MD* wolfSSL_quic_get_md(WOLFSSL* ssl);
/**
* The QUIC header protection cipher matching the AEAD cipher currently
* selected in the SSL instance.
*/
WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_quic_get_hp(WOLFSSL* ssl);
/**
* Create and initialize a cipher context for use in en- or decryption.
*/
WOLFSSL_API WOLFSSL_EVP_CIPHER_CTX*
wolfSSL_quic_crypt_new(const WOLFSSL_EVP_CIPHER* cipher,
const uint8_t* key, const uint8_t* iv, int encrypt);
/**
* Use a previously created cipher context to encrypt the given plain text.
*/
WOLFSSL_API
int wolfSSL_quic_aead_encrypt(uint8_t* dest, WOLFSSL_EVP_CIPHER_CTX* aead_ctx,
const uint8_t* plain, size_t plainlen,
const uint8_t* iv, const uint8_t* aad,
size_t aadlen);
/**
* Use a previously created cipher context to decrypt the given encoded text.
*/
WOLFSSL_API
int wolfSSL_quic_aead_decrypt(uint8_t* dest, WOLFSSL_EVP_CIPHER_CTX* ctx,
const uint8_t* enc, size_t enclen,
const uint8_t* iv, const uint8_t* aad,
size_t aadlen);
/**
* Extract a pseudo-random key, using the given message digest, a secret
* and a salt. The key size is the size of the digest.
*/
WOLFSSL_API
int wolfSSL_quic_hkdf_extract(uint8_t* dest, const WOLFSSL_EVP_MD* md,
const uint8_t* secret, size_t secretlen,
const uint8_t* salt, size_t saltlen);
/**
* Expand a pseudo-random key (secret) into a new key, using the mesasge
* digest and the info bytes.
*/
WOLFSSL_API
int wolfSSL_quic_hkdf_expand(uint8_t* dest, size_t destlen,
const WOLFSSL_EVP_MD* md,
const uint8_t* secret, size_t secretlen,
const uint8_t* info, size_t infolen);
/**
* Extract and extpand secret, salt and info into a new key.
*/
WOLFSSL_API
int wolfSSL_quic_hkdf(uint8_t* dest, size_t destlen,
const WOLFSSL_EVP_MD* md,
const uint8_t* secret, size_t secretlen,
const uint8_t* salt, size_t saltlen,
const uint8_t* info, size_t infolen);
#endif /* WOLFSSL_QUIC */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* WOLFSSL_QUIC_H */

View File

@ -1121,6 +1121,9 @@ WOLFSSL_API int wolfSSL_write_early_data(WOLFSSL* ssl, const void* data,
WOLFSSL_API int wolfSSL_read_early_data(WOLFSSL* ssl, void* data, int sz,
int* outSz);
WOLFSSL_API int wolfSSL_get_early_data_status(const WOLFSSL* ssl);
#ifdef OPENSSL_EXTRA
WOLFSSL_API unsigned int wolfSSL_SESSION_get_max_early_data(const WOLFSSL_SESSION *s);
#endif /* OPENSSL_EXTRA */
#endif /* WOLFSSL_EARLY_DATA */
#endif /* WOLFSSL_TLS13 */
WOLFSSL_ABI WOLFSSL_API void wolfSSL_CTX_free(WOLFSSL_CTX* ctx);
@ -3629,7 +3632,9 @@ enum {
WOLFSSL_MAX_ALPN_NUMBER = 257
};
#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY)
#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \
defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY) || \
defined(WOLFSSL_QUIC)
typedef int (*CallbackALPNSelect)(WOLFSSL* ssl, const unsigned char** out,
unsigned char* outLen, const unsigned char* in, unsigned int inLen,
void *arg);