Implement RFC 8701 GREASE for TLS ClientHello

Add client-side GREASE (Generate Random Extensions And Sustain
Extensibility) support per RFC 8701. When SSL_OP_GREASE is set,
the TLS client injects reserved 0x?A?A-pattern values into the
ClientHello to prevent ecosystem ossification caused by servers
that reject unknown values.

GREASE values are injected into:
- Cipher suites (prepended)
- Supported versions extension (prepended)
- Supported groups extension (prepended)
- Signature algorithms extension (appended)
- Key share extension (prepended, 1 zero byte)
- Two standalone extensions (one empty, one with 1 zero byte)

The implementation uses lazy-seeded random values that remain
consistent across HelloRetryRequest retransmissions. GREASE values
from server responses are rejected as illegal parameters.

Add -grease option to s_client to enable GREASE from the command line.

Closes #9660

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.foundation>
Reviewed-by: Neil Horman <nhorman@openssl.org>
MergeDate: Tue Mar 17 14:58:25 2026
(Merged from https://github.com/openssl/openssl/pull/30303)
This commit is contained in:
mcrmck
2026-03-07 21:51:17 -05:00
committed by Neil Horman
parent 25c2f88caa
commit a1420a699d
13 changed files with 462 additions and 3 deletions
+20
View File
@@ -61,6 +61,26 @@ OpenSSL Releases
*Daniel Kubec*
* Added support for RFC 8701 GREASE (Generate Random Extensions And Sustain
Extensibility). When `SSL_OP_GREASE` is set, the TLS client injects
reserved GREASE values into cipher suites, supported versions, supported
groups, signature algorithms, key share, and extensions in the ClientHello
to prevent ecosystem ossification. The `openssl s_client` command gains a
`-grease` option to enable this.
*William McCormack*
### Changes between 3.6 and 4.0 [xx XXX xxxx]
* Added support for RFC 8701 GREASE (Generate Random Extensions And Sustain
Extensibility). When `SSL_OP_GREASE` is set, the TLS client injects
reserved GREASE values into cipher suites, supported versions, supported
groups, signature algorithms, key share, and extensions in the ClientHello
to prevent ecosystem ossification. The `openssl s_client` command gains a
`-grease` option to enable this.
*William McCormack*
### Changes between 3.6 and 4.0 [xx XXX xxxx]
* Added `-expected-rpks` option to the `openssl s_client`
+8
View File
@@ -598,6 +598,7 @@ typedef enum OPTION_choice {
OPT_S_ENUM,
OPT_IGNORE_UNEXPECTED_EOF,
OPT_FALLBACKSCSV,
OPT_GREASE,
OPT_NOCMDS,
OPT_ADV,
OPT_PROXY,
@@ -671,6 +672,7 @@ const OPTIONS s_client_options[] = {
{ "read_buf", OPT_READ_BUF, 'p',
"Default read buffer size to be used for connections" },
{ "fallback_scsv", OPT_FALLBACKSCSV, '-', "Send the fallback SCSV" },
{ "grease", OPT_GREASE, '-', "Send GREASE values in ClientHello (RFC 8701)" },
OPT_SECTION("Identity"),
{ "cert", OPT_CERT, '<', "Client certificate file to use" },
@@ -1031,6 +1033,7 @@ int s_client_main(int argc, char **argv)
#endif
int read_buf_len = 0;
int fallback_scsv = 0;
int grease = 0;
OPTION_CHOICE o;
#ifndef OPENSSL_NO_DTLS
int enable_timeouts = 0;
@@ -1518,6 +1521,9 @@ int s_client_main(int argc, char **argv)
case OPT_FALLBACKSCSV:
fallback_scsv = 1;
break;
case OPT_GREASE:
grease = 1;
break;
case OPT_KEYFORM:
if (!opt_format(opt_arg(), OPT_FMT_ANY, &key_format))
goto opthelp;
@@ -2304,6 +2310,8 @@ int s_client_main(int argc, char **argv)
if (fallback_scsv)
SSL_set_mode(con, SSL_MODE_SEND_FALLBACK_SCSV);
if (grease)
SSL_set_options(con, SSL_OP_GREASE);
if (!noservername && (servername != NULL || dane_tlsa_domain == NULL)) {
if (servername == NULL) {
+8
View File
@@ -76,6 +76,7 @@ B<openssl> B<s_client>
[B<-sctp>]
[B<-sctp_label_bug>]
[B<-fallback_scsv>]
[B<-grease>]
[B<-async>]
[B<-maxfraglen> I<len>]
[B<-max_send_frag>]
@@ -573,6 +574,13 @@ available where OpenSSL has support for SCTP enabled.
Send TLS_FALLBACK_SCSV in the ClientHello.
=item B<-grease>
Send GREASE (Generate Random Extensions And Sustain Extensibility) values in
the ClientHello as defined in RFC 8701. This injects random reserved values
into cipher suites, supported groups, supported versions, signature algorithms,
key share, and extensions to prevent ecosystem ossification.
=item B<-async>
Switch on asynchronous mode. Cryptographic operations will be performed
+10
View File
@@ -408,6 +408,16 @@ ECH.
If set, TLS ClientHello messages emitted by the client will ignore the
ECHConfig config_id chosen by the server and use a random octet.
=item SSL_OP_GREASE
If set, TLS ClientHello messages will include GREASE (Generate Random
Extensions And Sustain Extensibility) values as defined in RFC 8701. This
injects random reserved values (matching the 0x?A?A pattern) into cipher
suites, supported groups, supported versions, signature algorithms, key share
entries, and extensions. GREASE values help prevent ecosystem ossification by
ensuring servers and middleboxes tolerate unknown values. The injected values
are consistent across HelloRetryRequest replays within the same connection.
=back
The following options no longer have any effect but their identifiers are
+3
View File
@@ -453,6 +453,9 @@ typedef int (*SSL_async_callback_fn)(SSL *s, void *arg);
#define SSL_OP_ECH_GREASE_RETRY_CONFIG SSL_OP_BIT(40)
#endif
/* RFC 8701: Send GREASE values in ClientHello */
#define SSL_OP_GREASE SSL_OP_BIT(41)
/*
* Option "collections."
*/
+11
View File
@@ -2261,6 +2261,17 @@ int ssl_cipher_list_to_bytes(SSL_CONNECTION *s, STACK_OF(SSL_CIPHER) *sk,
if (s->mode & SSL_MODE_SEND_FALLBACK_SCSV)
maxlen -= 2;
/* RFC 8701: prepend a GREASE cipher suite value */
if ((s->options & SSL_OP_GREASE) && !s->server) {
uint16_t grease_cs = ossl_grease_value(s, OSSL_GREASE_CIPHER);
if (!WPACKET_put_bytes_u16(pkt, grease_cs)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return 0;
}
totlen += 2;
}
for (i = 0; i < sk_SSL_CIPHER_num(sk) && totlen < maxlen; i++) {
const SSL_CIPHER *c;
+34
View File
@@ -8496,3 +8496,37 @@ int SSL_CTX_get0_server_cert_type(const SSL_CTX *ctx, unsigned char **t, size_t
*len = ctx->server_cert_type_len;
return 1;
}
/*
* RFC 8701 GREASE - returns a GREASE value (0x?A?A pattern) for the given
* index. Seeds are generated lazily on first use and remain stable for the
* lifetime of the connection so that HelloRetryRequest replays get identical
* values.
*/
uint16_t ossl_grease_value(SSL_CONNECTION *s, int index)
{
uint16_t ret;
if (index < 0 || index > OSSL_GREASE_LAST_INDEX)
return 0x0A0A;
if (!s->ext.grease_seeded) {
if (RAND_bytes_ex(SSL_CONNECTION_GET_CTX(s)->libctx,
s->ext.grease_seed,
sizeof(s->ext.grease_seed), 0)
<= 0)
memset(s->ext.grease_seed, 0x42, sizeof(s->ext.grease_seed));
s->ext.grease_seeded = 1;
}
/* Map seed byte to 0x?A?A pattern */
ret = (s->ext.grease_seed[index] & 0xf0) | 0x0a;
ret |= ret << 8;
/* Ensure EXT2 differs from EXT1 */
if (index == OSSL_GREASE_EXT2
&& ret == ossl_grease_value(s, OSSL_GREASE_EXT1))
ret ^= 0x1010;
return ret;
}
+20
View File
@@ -697,12 +697,23 @@ typedef enum tlsext_index_en {
TLSEXT_IDX_certificate_authorities,
TLSEXT_IDX_ech,
TLSEXT_IDX_outer_extensions,
TLSEXT_IDX_grease1,
TLSEXT_IDX_grease2,
TLSEXT_IDX_padding,
TLSEXT_IDX_psk,
/* Dummy index - must always be the last entry */
TLSEXT_IDX_num_builtins
} TLSEXT_INDEX;
/* RFC 8701 GREASE seed indices */
#define OSSL_GREASE_CIPHER 0
#define OSSL_GREASE_GROUP 1
#define OSSL_GREASE_EXT1 2
#define OSSL_GREASE_EXT2 3
#define OSSL_GREASE_VERSION 4
#define OSSL_GREASE_SIGALG 5
#define OSSL_GREASE_LAST_INDEX 5
DEFINE_LHASH_OF_EX(SSL_SESSION);
/* Needed in ssl_cert.c */
DEFINE_LHASH_OF_EX(X509_NAME);
@@ -1741,6 +1752,10 @@ struct ssl_connection_st {
#ifndef OPENSSL_NO_ECH
OSSL_ECH_CONN ech;
#endif
/* RFC 8701 GREASE */
uint8_t grease_seed[OSSL_GREASE_LAST_INDEX + 1];
int grease_seeded;
} ext;
/*
@@ -2505,6 +2520,11 @@ void ssl_sort_cipher_list(void);
int ssl_load_ciphers(SSL_CTX *ctx);
int ssl_cipher_list_to_bytes(SSL_CONNECTION *s, STACK_OF(SSL_CIPHER) *sk,
WPACKET *pkt);
uint16_t ossl_grease_value(SSL_CONNECTION *s, int index);
static ossl_inline int ossl_is_grease_value(uint16_t val)
{
return (val & 0x0f0f) == 0x0a0a && (val >> 8) == (val & 0xff);
}
__owur int ssl_setup_sigalgs(SSL_CTX *ctx);
int ssl_load_groups(SSL_CTX *ctx);
int ssl_load_sigalgs(SSL_CTX *ctx);
+12
View File
@@ -464,6 +464,18 @@ static const EXTENSION_DEFINITION ext_defs[] = {
INVALID_EXTENSION,
INVALID_EXTENSION,
#endif /* END_OPENSSL_NO_ECH */
{ /* RFC 8701 GREASE extension 1 - type is dynamic */
TLSEXT_TYPE_grease1,
SSL_EXT_CLIENT_HELLO,
0,
NULL,
NULL, NULL, NULL, tls_construct_ctos_grease1, NULL },
{ /* RFC 8701 GREASE extension 2 - type is dynamic */
TLSEXT_TYPE_grease2,
SSL_EXT_CLIENT_HELLO,
0,
NULL,
NULL, NULL, NULL, tls_construct_ctos_grease2, NULL },
{ /* Must be immediately before pre_shared_key */
TLSEXT_TYPE_padding,
SSL_EXT_CLIENT_HELLO,
+100 -2
View File
@@ -335,6 +335,14 @@ EXT_RETURN tls_construct_ctos_supported_groups(SSL_CONNECTION *s, WPACKET *pkt,
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
}
/* RFC 8701: prepend a GREASE group value */
if ((s->options & SSL_OP_GREASE) && !s->server) {
if (!WPACKET_put_bytes_u16(pkt,
ossl_grease_value(s, OSSL_GREASE_GROUP))) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
}
}
/* Copy group ID if supported */
for (i = 0; i < num_groups; i++) {
const TLS_GROUP_INFO *ginfo = NULL;
@@ -452,8 +460,19 @@ EXT_RETURN tls_construct_ctos_sig_algs(SSL_CONNECTION *s, WPACKET *pkt,
|| !WPACKET_start_sub_packet_u16(pkt)
/* Sub-packet for the actual list */
|| !WPACKET_start_sub_packet_u16(pkt)
|| !tls12_copy_sigalgs(s, pkt, salg, salglen)
|| !WPACKET_close(pkt)
|| !tls12_copy_sigalgs(s, pkt, salg, salglen)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
}
/* RFC 8701: append a GREASE signature algorithm value */
if ((s->options & SSL_OP_GREASE) && !s->server) {
if (!WPACKET_put_bytes_u16(pkt,
ossl_grease_value(s, OSSL_GREASE_SIGALG))) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
}
}
if (!WPACKET_close(pkt)
|| !WPACKET_close(pkt)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
@@ -740,6 +759,14 @@ EXT_RETURN tls_construct_ctos_supported_versions(SSL_CONNECTION *s, WPACKET *pkt
return EXT_RETURN_FAIL;
}
/* RFC 8701: prepend a GREASE version value */
if ((s->options & SSL_OP_GREASE) && !s->server) {
if (!WPACKET_put_bytes_u16(pkt,
ossl_grease_value(s, OSSL_GREASE_VERSION))) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
}
}
for (currv = max_version; currv >= min_version; currv--) {
if (!WPACKET_put_bytes_u16(pkt, currv)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
@@ -873,6 +900,19 @@ EXT_RETURN tls_construct_ctos_key_share(SSL_CONNECTION *s, WPACKET *pkt,
return EXT_RETURN_FAIL;
}
/* RFC 8701: prepend a GREASE key share entry (1 byte of 0x00) */
if ((s->options & SSL_OP_GREASE) && !s->server) {
uint16_t grease_group = ossl_grease_value(s, OSSL_GREASE_GROUP);
if (!WPACKET_put_bytes_u16(pkt, grease_group)
|| !WPACKET_start_sub_packet_u16(pkt)
|| !WPACKET_put_bytes_u8(pkt, 0)
|| !WPACKET_close(pkt)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
}
}
tls1_get_requested_keyshare_groups(s, &pgroups, &num_groups);
if (num_groups == 1 && pgroups[0] == 0) { /* Indication that no * prefix was used */
tls1_get_supported_groups(s, &pgroups, &num_groups);
@@ -2174,6 +2214,12 @@ int tls_parse_stoc_key_share(SSL_CONNECTION *s, PACKET *pkt,
return 0;
}
/* RFC 8701: reject GREASE values selected by the server */
if (ossl_is_grease_value(group_id)) {
SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_KEY_SHARE);
return 0;
}
if ((context & SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST) != 0) {
const uint16_t *pgroups = NULL;
size_t num_groups;
@@ -2818,3 +2864,55 @@ int tls_parse_stoc_ech(SSL_CONNECTION *s, PACKET *pkt, unsigned int context,
return 1;
}
#endif /* END_OPENSSL_NO_ECH */
/*
* RFC 8701 GREASE extension constructors. Each writes an empty extension
* whose type is a GREASE value (0x?A?A pattern).
*/
EXT_RETURN tls_construct_ctos_grease1(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx)
{
uint16_t grease_type;
if (!(s->options & SSL_OP_GREASE) || s->server)
return EXT_RETURN_NOT_SENT;
grease_type = ossl_grease_value(s, OSSL_GREASE_EXT1);
if (!WPACKET_put_bytes_u16(pkt, grease_type)
|| !WPACKET_put_bytes_u16(pkt, 0)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
}
return EXT_RETURN_SENT;
}
EXT_RETURN tls_construct_ctos_grease2(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx)
{
uint16_t grease_type;
if (!(s->options & SSL_OP_GREASE) || s->server)
return EXT_RETURN_NOT_SENT;
grease_type = ossl_grease_value(s, OSSL_GREASE_EXT2);
/*
* RFC 8701 recommends "varying length and contents" for GREASE
* extensions. Extension 1 is empty; extension 2 carries one zero byte
* so that servers are tested against both empty and non-empty unknown
* extensions. This mirrors the BoringSSL behaviour.
*/
if (!WPACKET_put_bytes_u16(pkt, grease_type)
|| !WPACKET_start_sub_packet_u16(pkt)
|| !WPACKET_put_bytes_u8(pkt, 0)
|| !WPACKET_close(pkt)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
}
return EXT_RETURN_SENT;
}
+9
View File
@@ -43,6 +43,9 @@
/* Invalid extension ID for non-supported extensions */
#define TLSEXT_TYPE_invalid 0x10000
#define TLSEXT_TYPE_out_of_range 0x10001
/* RFC 8701 GREASE extension placeholders (actual type is dynamic) */
#define TLSEXT_TYPE_grease1 0x10002
#define TLSEXT_TYPE_grease2 0x10003
unsigned int ossl_get_extension_type(size_t idx);
extern const unsigned char hrrrandom[];
@@ -478,6 +481,12 @@ EXT_RETURN tls_construct_ctos_psk_kex_modes(SSL_CONNECTION *s, WPACKET *pkt,
EXT_RETURN tls_construct_ctos_cookie(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context,
X509 *x, size_t chainidx);
EXT_RETURN tls_construct_ctos_grease1(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx);
EXT_RETURN tls_construct_ctos_grease2(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx);
EXT_RETURN tls_construct_ctos_padding(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx);
+2
View File
@@ -79,6 +79,8 @@ static EXT_LIST ext_list[] = {
EXT_EXCEPTION(ech),
EXT_EXCEPTION(outer_extensions),
#endif
EXT_ENTRY(grease1),
EXT_ENTRY(grease2),
EXT_ENTRY(padding),
EXT_ENTRY(psk),
EXT_END(num_builtins)
+225 -1
View File
@@ -10308,7 +10308,7 @@ static int test_session_cache_overflow(int idx)
* would free the get_sess_val, causing a use-after-free error.
*/
if (!TEST_true(CRYPTO_GET_REF(&get_sess_val->references, &references))
|| !TEST_int_ge(references, 2))
|| !TEST_int_ge(references, 2))
goto end;
sess = SSL_get1_session(clientssl);
if (!TEST_ptr(sess))
@@ -14144,6 +14144,227 @@ err:
}
#endif
#if !defined(OSSL_NO_USABLE_TLS1_3)
/*
* RFC 8701 GREASE test helpers.
* We capture the raw ClientHello via msg_callback and then parse it with
* PACKET functions to confirm that GREASE values (matching 0x?A?A) are
* present in the expected fields.
*/
static unsigned char *grease_ch_buf;
static size_t grease_ch_len;
static int is_grease(unsigned int v)
{
return (v & 0x0f0f) == 0x0a0a && (v >> 8) == (v & 0xff);
}
static void grease_msg_cb(int write_p, int version, int content_type,
const void *buf, size_t len, SSL *ssl, void *arg)
{
const unsigned char *p = buf;
/*
* We want the outgoing (write_p == 1) handshake (content_type == 22)
* ClientHello (msg_type == 1). The buf starts at the handshake header:
* byte 0: msg_type, bytes 1-3: length
*/
if (write_p != 1 || content_type != SSL3_RT_HANDSHAKE
|| len < SSL3_HM_HEADER_LENGTH
|| p[0] != SSL3_MT_CLIENT_HELLO)
return;
/* Only capture the first ClientHello (not HRR retry) */
if (grease_ch_buf != NULL)
return;
grease_ch_buf = OPENSSL_memdup(buf, len);
grease_ch_len = len;
}
/*
* Parse a captured ClientHello (starting from handshake header) and check
* that it contains GREASE values in cipher suites, extensions, supported
* groups, key shares, and signature algorithms.
* Returns 1 on success, 0 on failure.
*/
static int check_grease_in_client_hello(void)
{
PACKET pkt, ciphers, session, compression, exts, ext_data;
PACKET inner;
unsigned int ext_type = 0, val = 0;
int found_grease_cipher = 0;
int found_grease_ext = 0;
int found_grease_group = 0;
int found_grease_kshare = 0;
int found_grease_sigalg = 0;
int found_grease_version = 0;
memset(&pkt, 0, sizeof(pkt));
memset(&ciphers, 0, sizeof(ciphers));
memset(&session, 0, sizeof(session));
memset(&compression, 0, sizeof(compression));
memset(&exts, 0, sizeof(exts));
memset(&ext_data, 0, sizeof(ext_data));
memset(&inner, 0, sizeof(inner));
if (!TEST_ptr(grease_ch_buf)
|| !TEST_true(PACKET_buf_init(&pkt, grease_ch_buf,
grease_ch_len))
/* Skip handshake message header */
|| !TEST_true(PACKET_forward(&pkt, SSL3_HM_HEADER_LENGTH))
/* Skip client_version + random */
|| !TEST_true(PACKET_forward(&pkt,
CLIENT_VERSION_LEN + SSL3_RANDOM_SIZE))
/* Skip session_id */
|| !TEST_true(PACKET_get_length_prefixed_1(&pkt, &session))
/* Get cipher suites */
|| !TEST_true(PACKET_get_length_prefixed_2(&pkt, &ciphers))
/* Skip compression */
|| !TEST_true(PACKET_get_length_prefixed_1(&pkt, &compression))
/* Get extensions */
|| !TEST_true(PACKET_as_length_prefixed_2(&pkt, &exts)))
return 0;
/* Scan cipher suites for GREASE */
while (PACKET_remaining(&ciphers) > 0) {
if (!TEST_true(PACKET_get_net_2(&ciphers, &val)))
return 0;
if (is_grease(val))
found_grease_cipher = 1;
}
/* Scan extensions */
while (PACKET_remaining(&exts) > 0) {
if (!TEST_true(PACKET_get_net_2(&exts, &ext_type))
|| !TEST_true(PACKET_get_length_prefixed_2(&exts,
&ext_data)))
return 0;
if (is_grease(ext_type))
found_grease_ext++;
/* Check for GREASE inside supported_versions */
if (ext_type == TLSEXT_TYPE_supported_versions) {
if (!TEST_true(PACKET_get_length_prefixed_1(&ext_data,
&inner)))
return 0;
while (PACKET_remaining(&inner) > 0) {
if (!TEST_true(PACKET_get_net_2(&inner, &val)))
return 0;
if (is_grease(val))
found_grease_version = 1;
}
}
/* Check for GREASE inside supported_groups */
if (ext_type == TLSEXT_TYPE_supported_groups) {
if (!TEST_true(PACKET_get_length_prefixed_2(&ext_data,
&inner)))
return 0;
while (PACKET_remaining(&inner) > 0) {
if (!TEST_true(PACKET_get_net_2(&inner, &val)))
return 0;
if (is_grease(val))
found_grease_group = 1;
}
}
/* Check for GREASE inside key_share */
if (ext_type == TLSEXT_TYPE_key_share) {
PACKET ks_entry;
memset(&ks_entry, 0, sizeof(ks_entry));
if (!TEST_true(PACKET_get_length_prefixed_2(&ext_data,
&inner)))
return 0;
while (PACKET_remaining(&inner) > 0) {
if (!TEST_true(PACKET_get_net_2(&inner, &val))
|| !TEST_true(PACKET_get_length_prefixed_2(
&inner, &ks_entry)))
return 0;
if (is_grease(val))
found_grease_kshare = 1;
}
}
/* Check for GREASE inside signature_algorithms */
if (ext_type == TLSEXT_TYPE_signature_algorithms) {
if (!TEST_true(PACKET_get_length_prefixed_2(&ext_data,
&inner)))
return 0;
while (PACKET_remaining(&inner) > 0) {
if (!TEST_true(PACKET_get_net_2(&inner, &val)))
return 0;
if (is_grease(val))
found_grease_sigalg = 1;
}
}
}
if (!TEST_true(found_grease_cipher))
return 0;
if (!TEST_int_eq(found_grease_ext, 2))
return 0;
if (!TEST_true(found_grease_version))
return 0;
if (!TEST_true(found_grease_group))
return 0;
if (!TEST_true(found_grease_kshare))
return 0;
if (!TEST_true(found_grease_sigalg))
return 0;
return 1;
}
static int test_grease(void)
{
SSL_CTX *sctx = NULL, *cctx = NULL;
SSL *serverssl = NULL, *clientssl = NULL;
int testresult = 0;
grease_ch_buf = NULL;
grease_ch_len = 0;
if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
TLS_client_method(),
TLS1_3_VERSION, TLS1_3_VERSION,
&sctx, &cctx, cert, privkey)))
goto end;
SSL_CTX_set_options(cctx, SSL_OP_GREASE);
if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
&clientssl, NULL, NULL)))
goto end;
SSL_set_msg_callback(clientssl, grease_msg_cb);
/* A full handshake should succeed - server must tolerate GREASE */
if (!TEST_true(create_ssl_connection(serverssl, clientssl,
SSL_ERROR_NONE)))
goto end;
/* Now verify the captured ClientHello contains GREASE values */
if (!TEST_true(check_grease_in_client_hello()))
goto end;
testresult = 1;
end:
OPENSSL_free(grease_ch_buf);
grease_ch_buf = NULL;
grease_ch_len = 0;
SSL_free(serverssl);
SSL_free(clientssl);
SSL_CTX_free(sctx);
SSL_CTX_free(cctx);
return testresult;
}
#endif /* !defined(OSSL_NO_USABLE_TLS1_3) */
static int test_ssl_conf_flags(void)
{
SSL_CONF_CTX *cctx = NULL;
@@ -14655,6 +14876,9 @@ int setup_tests(void)
ADD_ALL_TESTS(test_ssl_set_groups_unsupported_keyshare, 2);
ADD_TEST(test_ssl_conf_flags);
ADD_ALL_TESTS(test_http_verbs, 3);
#if !defined(OSSL_NO_USABLE_TLS1_3)
ADD_TEST(test_grease);
#endif
return 1;
err: