Add server-side handling of Encrypted Client Hello
Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/27561)
This commit is contained in:
parent
2dd92b4bbf
commit
6c3edd4f3a
13 changed files with 1657 additions and 97 deletions
|
|
@ -111,6 +111,8 @@ The SSL_client_hello_get0_*() functions return raw ClientHello data, whereas
|
|||
SSL_client_hello_get1_extensions_present() returns only recognized extensions
|
||||
(so unknown/GREASE-extensions are not included).
|
||||
|
||||
TODO(ECH): How ECH is handled here needs to be documented.
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
The application's supplied ClientHello callback returns
|
||||
|
|
|
|||
|
|
@ -17,9 +17,42 @@
|
|||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
|
||||
/*
|
||||
* the max HPKE 'info' we'll process is the max ECHConfig size
|
||||
* (OSSL_ECH_MAX_ECHCONFIG_LEN) plus OSSL_ECH_CONTEXT_STRING(len=7) + 1
|
||||
*/
|
||||
#define OSSL_ECH_MAX_INFO_LEN (OSSL_ECH_MAX_ECHCONFIG_LEN + 8)
|
||||
|
||||
int ossl_ech_make_enc_info(const unsigned char *encoding,
|
||||
size_t encoding_length,
|
||||
unsigned char *info, size_t *info_len);
|
||||
|
||||
/*
|
||||
* Given a CH find the offsets of the session id, extensions and ECH
|
||||
* ch is the encoded client hello
|
||||
* ch_len is the length of ch
|
||||
* sessid_off returns offset of session_id length
|
||||
* exts_off points to offset of extensions
|
||||
* exts_len returns length of extensions
|
||||
* ech_off returns offset of ECH
|
||||
* echtype returns the ext type of the ECH
|
||||
* ech_len returns the length of the ECH
|
||||
* sni_off returns offset of (outer) SNI
|
||||
* sni_len returns the length of the SNI
|
||||
* inner 1 if the ECH is marked as an inner, 0 for outer
|
||||
* return 1 for success, other otherwise
|
||||
*
|
||||
* Offsets are set to zero if relevant thing not found.
|
||||
* Offsets are returned to the type or length field in question.
|
||||
*
|
||||
* Note: input here is untrusted!
|
||||
*/
|
||||
int ossl_ech_helper_get_ch_offsets(const unsigned char *ch, size_t ch_len,
|
||||
size_t *sessid_off, size_t *exts_off,
|
||||
size_t *exts_len,
|
||||
size_t *ech_off, uint16_t *echtype,
|
||||
size_t *ech_len, size_t *sni_off,
|
||||
size_t *sni_len, int *inner);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@
|
|||
#include "ech_local.h"
|
||||
#include "internal/ech_helpers.h"
|
||||
|
||||
/* TODO(ECH): move more code that's used by internals and test here */
|
||||
|
||||
/* used in ECH crypto derivations (odd format for EBCDIC goodness) */
|
||||
/* "tls ech" */
|
||||
static const char OSSL_ECH_CONTEXT_STRING[] = "\x74\x6c\x73\x20\x65\x63\x68";
|
||||
|
|
@ -52,3 +50,101 @@ int ossl_ech_make_enc_info(const unsigned char *encoding,
|
|||
WPACKET_cleanup(&ipkt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a CH find the offsets of the session id, extensions and ECH
|
||||
* ch is the encoded client hello
|
||||
* ch_len is the length of ch
|
||||
* sessid_off returns offset of session_id length
|
||||
* exts_off points to offset of extensions
|
||||
* exts_len returns length of extensions
|
||||
* ech_off returns offset of ECH
|
||||
* echtype returns the ext type of the ECH
|
||||
* ech_len returns the length of the ECH
|
||||
* sni_off returns offset of (outer) SNI
|
||||
* sni_len returns the length of the SNI
|
||||
* inner 1 if the ECH is marked as an inner, 0 for outer
|
||||
* return 1 for success, other otherwise
|
||||
*
|
||||
* Offsets are set to zero if relevant thing not found.
|
||||
* Offsets are returned to the type or length field in question.
|
||||
*
|
||||
* Note: input here is untrusted!
|
||||
*/
|
||||
int ossl_ech_helper_get_ch_offsets(const unsigned char *ch, size_t ch_len,
|
||||
size_t *sessid_off, size_t *exts_off,
|
||||
size_t *exts_len,
|
||||
size_t *ech_off, uint16_t *echtype,
|
||||
size_t *ech_len, size_t *sni_off,
|
||||
size_t *sni_len, int *inner)
|
||||
{
|
||||
unsigned int elen = 0, etype = 0, pi_tmp = 0;
|
||||
const unsigned char *pp_tmp = NULL, *chstart = NULL, *estart = NULL;
|
||||
PACKET pkt;
|
||||
int done = 0;
|
||||
|
||||
if (ch == NULL || ch_len == 0 || sessid_off == NULL || exts_off == NULL
|
||||
|| ech_off == NULL || echtype == NULL || ech_len == NULL
|
||||
|| sni_off == NULL || inner == NULL)
|
||||
return 0;
|
||||
*sessid_off = *exts_off = *ech_off = *sni_off = *sni_len = *ech_len = 0;
|
||||
*echtype = 0xffff;
|
||||
if (!PACKET_buf_init(&pkt, ch, ch_len))
|
||||
return 0;
|
||||
chstart = PACKET_data(&pkt);
|
||||
if (!PACKET_get_net_2(&pkt, &pi_tmp))
|
||||
return 0;
|
||||
/* if we're not TLSv1.2+ then we can bail, but it's not an error */
|
||||
if (pi_tmp != TLS1_2_VERSION && pi_tmp != TLS1_3_VERSION)
|
||||
return 1;
|
||||
/* chew up the packet to extensions */
|
||||
if (!PACKET_get_bytes(&pkt, &pp_tmp, SSL3_RANDOM_SIZE)
|
||||
|| (*sessid_off = PACKET_data(&pkt) - chstart) == 0
|
||||
|| !PACKET_get_1(&pkt, &pi_tmp) /* sessid len */
|
||||
|| !PACKET_get_bytes(&pkt, &pp_tmp, pi_tmp) /* sessid */
|
||||
|| !PACKET_get_net_2(&pkt, &pi_tmp) /* ciphersuite len */
|
||||
|| !PACKET_get_bytes(&pkt, &pp_tmp, pi_tmp) /* suites */
|
||||
|| !PACKET_get_1(&pkt, &pi_tmp) /* compression meths */
|
||||
|| !PACKET_get_bytes(&pkt, &pp_tmp, pi_tmp) /* comp meths */
|
||||
|| (*exts_off = PACKET_data(&pkt) - chstart) == 0
|
||||
|| !PACKET_get_net_2(&pkt, &pi_tmp) /* len(extensions) */
|
||||
|| (*exts_len = (size_t)pi_tmp) == 0)
|
||||
/*
|
||||
* unexpectedly, we return 1 here, as doing otherwise will
|
||||
* break some non-ECH test code that truncates CH messages
|
||||
* The same is true below when looking through extensions.
|
||||
* That's ok though, we'll only set those offsets we've
|
||||
* found.
|
||||
*/
|
||||
return 1;
|
||||
/* no extensions is theoretically ok, if uninteresting */
|
||||
if (*exts_len == 0)
|
||||
return 1;
|
||||
/* find what we want from extensions */
|
||||
estart = PACKET_data(&pkt);
|
||||
while (PACKET_remaining(&pkt) > 0
|
||||
&& (size_t)(PACKET_data(&pkt) - estart) < *exts_len
|
||||
&& done < 2) {
|
||||
if (!PACKET_get_net_2(&pkt, &etype)
|
||||
|| !PACKET_get_net_2(&pkt, &elen))
|
||||
return 1; /* see note above */
|
||||
if (etype == TLSEXT_TYPE_ech) {
|
||||
if (elen == 0)
|
||||
return 0;
|
||||
*ech_off = PACKET_data(&pkt) - chstart - 4;
|
||||
*echtype = etype;
|
||||
*ech_len = elen;
|
||||
done++;
|
||||
}
|
||||
if (etype == TLSEXT_TYPE_server_name) {
|
||||
*sni_off = PACKET_data(&pkt) - chstart - 4;
|
||||
*sni_len = elen;
|
||||
done++;
|
||||
}
|
||||
if (!PACKET_get_bytes(&pkt, &pp_tmp, elen))
|
||||
return 1; /* see note above */
|
||||
if (etype == TLSEXT_TYPE_ech)
|
||||
*inner = pp_tmp[0];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -118,6 +118,33 @@ typedef struct ossl_echstore_entry_st {
|
|||
unsigned char *encoded; /* overall encoded content */
|
||||
} OSSL_ECHSTORE_ENTRY;
|
||||
|
||||
/*
|
||||
* What we send in the ech CH extension:
|
||||
* enum { outer(0), inner(1) } ECHClientHelloType;
|
||||
* struct {
|
||||
* ECHClientHelloType type;
|
||||
* select (ECHClientHello.type) {
|
||||
* case outer:
|
||||
* HpkeSymmetricCipherSuite cipher_suite;
|
||||
* uint8 config_id;
|
||||
* opaque enc<0..2^16-1>;
|
||||
* opaque payload<1..2^16-1>;
|
||||
* case inner:
|
||||
* Empty;
|
||||
* };
|
||||
* } ECHClientHello;
|
||||
*
|
||||
*/
|
||||
typedef struct ech_encch_st {
|
||||
uint16_t kdf_id; /* ciphersuite */
|
||||
uint16_t aead_id; /* ciphersuite */
|
||||
uint8_t config_id; /* (maybe) identifies DNS RR value used */
|
||||
size_t enc_len; /* public share */
|
||||
unsigned char *enc; /* public share for sender */
|
||||
size_t payload_len; /* ciphertext */
|
||||
unsigned char *payload; /* ciphertext */
|
||||
} OSSL_ECH_ENCCH;
|
||||
|
||||
DEFINE_STACK_OF(OSSL_ECHSTORE_ENTRY)
|
||||
|
||||
struct ossl_echstore_st {
|
||||
|
|
@ -205,6 +232,22 @@ typedef struct ossl_ech_conn_st {
|
|||
unsigned char *pub; /* client ephemeral public kept by server in case HRR */
|
||||
size_t pub_len;
|
||||
OSSL_HPKE_CTX *hpke_ctx; /* HPKE context, needed for HRR */
|
||||
/*
|
||||
* Offsets of various things we need to know about in an inbound
|
||||
* ClientHello (CH) plus the type of ECH and whether that CH is an inner or
|
||||
* outer CH. We find these once for the outer CH, by roughly parsing the CH
|
||||
* so store them for later re-use. We need to re-do this parsing when we
|
||||
* get the 2nd CH in the case of HRR, and when we move to processing the
|
||||
* inner CH after successful ECH decyption, so we have a flag to say if
|
||||
* we've done the work or not.
|
||||
*/
|
||||
int ch_offsets_done;
|
||||
size_t sessid_off; /* offset of session_id length */
|
||||
size_t exts_off; /* to offset of extensions */
|
||||
size_t ech_off; /* offset of ECH */
|
||||
size_t sni_off; /* offset of (outer) SNI */
|
||||
int echtype; /* ext type of the ECH */
|
||||
int inner; /* 1 if the ECH is marked as an inner, 0 for outer */
|
||||
/*
|
||||
* A pointer to, and copy of, the hrrsignal from an HRR message.
|
||||
* We need both, as we zero-out the octets when re-calculating and
|
||||
|
|
|
|||
|
|
@ -450,13 +450,8 @@ static const EXTENSION_DEFINITION ext_defs[] = {
|
|||
SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ONLY | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS | SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST,
|
||||
OSSL_ECH_HANDLING_CALL_BOTH,
|
||||
init_ech,
|
||||
/*
|
||||
* TODO(ECH): add server calls as per below in a bit
|
||||
* tls_parse_ctos_ech, tls_parse_stoc_ech,
|
||||
* tls_construct_stoc_ech, tls_construct_ctos_ech,
|
||||
*/
|
||||
NULL, tls_parse_stoc_ech,
|
||||
NULL, tls_construct_ctos_ech,
|
||||
tls_parse_ctos_ech, tls_parse_stoc_ech,
|
||||
tls_construct_stoc_ech, tls_construct_ctos_ech,
|
||||
NULL },
|
||||
{ TLSEXT_TYPE_outer_extensions,
|
||||
SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ONLY,
|
||||
|
|
|
|||
|
|
@ -16,11 +16,6 @@
|
|||
#ifndef OPENSSL_NO_ECH
|
||||
#include <openssl/rand.h>
|
||||
#include "internal/ech_helpers.h"
|
||||
/*
|
||||
* the max HPKE 'info' we'll process is the max ECHConfig size
|
||||
* (OSSL_ECH_MAX_ECHCONFIG_LEN) plus OSSL_ECH_CONTEXT_STRING(len=7) + 1
|
||||
*/
|
||||
#define OSSL_ECH_MAX_INFO_LEN (OSSL_ECH_MAX_ECHCONFIG_LEN + 8)
|
||||
#endif
|
||||
|
||||
/* Used in the negotiate_dhe function */
|
||||
|
|
@ -2580,7 +2575,6 @@ EXT_RETURN tls_construct_ctos_ech(SSL_CONNECTION *s, WPACKET *pkt,
|
|||
unsigned char *encoded = NULL, *mypub = NULL;
|
||||
size_t cipherlen = 0, aad_len = 0, lenclen = 0, mypub_len = 0;
|
||||
size_t info_len = OSSL_ECH_MAX_INFO_LEN, clear_len = 0, encoded_len = 0;
|
||||
|
||||
/* whether or not we've been asked to GREASE, one way or another */
|
||||
int grease_opt_set = (s->ext.ech.grease == OSSL_ECH_IS_GREASE
|
||||
|| ((s->options & SSL_OP_ECH_GREASE) != 0));
|
||||
|
|
|
|||
|
|
@ -244,7 +244,8 @@ int custom_ext_add(SSL_CONNECTION *s, int context, WPACKET *pkt, X509 *x,
|
|||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_EXTENSION);
|
||||
return 0;
|
||||
}
|
||||
if (ossl_ech_copy_inner2outer(s, meth->ext_type, tind, pkt)
|
||||
if (ossl_ech_copy_inner2outer(s, meth->ext_type, tind,
|
||||
pkt)
|
||||
!= OSSL_ECH_SAME_EXT_DONE) {
|
||||
/* for custom exts, we really should have found it */
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_EXTENSION);
|
||||
|
|
@ -500,19 +501,7 @@ int ossl_tls_add_custom_ext_intern(SSL_CTX *ctx, custom_ext_methods *exts,
|
|||
* for extension types that previously were not supported, but now are.
|
||||
*/
|
||||
if (SSL_extension_supported(ext_type)
|
||||
#if !defined(OPENSSL_NO_ECH) && defined(OPENSSL_ECH_ALLOW_CUST_INJECT)
|
||||
/*
|
||||
* Do this conditionally so we can test an ECH in TLSv1.2
|
||||
* via the custom extensions API.
|
||||
* OPENSSL_ECH_ALLOW_CUST_INJECT is defined (or not) in
|
||||
* include/openssl/ech.h and if defined enables a test in
|
||||
* test/ech_test.c
|
||||
*/
|
||||
&& ext_type != TLSEXT_TYPE_ech
|
||||
&& ext_type != TLSEXT_TYPE_signed_certificate_timestamp)
|
||||
#else
|
||||
&& ext_type != TLSEXT_TYPE_signed_certificate_timestamp)
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
/* Extension type must fit in 16 bits */
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@
|
|||
#include "internal/cryptlib.h"
|
||||
#include "internal/ssl_unwrap.h"
|
||||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/trace.h>
|
||||
#endif
|
||||
|
||||
#define COOKIE_STATE_FORMAT_VERSION 1
|
||||
|
||||
/*
|
||||
|
|
@ -2439,3 +2444,163 @@ int tls_parse_ctos_server_cert_type(SSL_CONNECTION *sc, PACKET *pkt,
|
|||
SSLfatal(sc, SSL_AD_UNSUPPORTED_CERTIFICATE, SSL_R_BAD_EXTENSION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
/*
|
||||
* ECH handling for edge cases (GREASE/inner) and errors.
|
||||
* return 1 for good, 0 otherwise
|
||||
*
|
||||
* Real ECH handling (i.e. decryption) happens before, via
|
||||
* ech_early_decrypt(), but if that failed (e.g. decryption
|
||||
* failed, which may be down to GREASE) then we end up here,
|
||||
* processing the ECH from the outer CH.
|
||||
* Otherwise, we only expect to see an inner ECH with a fixed
|
||||
* value here.
|
||||
*/
|
||||
int tls_parse_ctos_ech(SSL_CONNECTION *s, PACKET *pkt, unsigned int context,
|
||||
X509 *x, size_t chainidx)
|
||||
{
|
||||
unsigned int echtype = 0;
|
||||
|
||||
if (s->ext.ech.grease == OSSL_ECH_IS_GREASE) {
|
||||
/* GREASE is fine */
|
||||
return 1;
|
||||
}
|
||||
if (s->ext.ech.es == NULL) {
|
||||
/* If not configured for ECH then we ignore it */
|
||||
return 1;
|
||||
}
|
||||
if (s->ext.ech.attempted_type != TLSEXT_TYPE_ech) {
|
||||
/* if/when new versions of ECH are added we'll update here */
|
||||
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* we only allow "inner" which is one octet, valued 0x01
|
||||
* and only if we decrypted ok or are a backend
|
||||
*/
|
||||
if (PACKET_get_1(pkt, &echtype) != 1
|
||||
|| echtype != OSSL_ECH_INNER_CH_TYPE
|
||||
|| PACKET_remaining(pkt) != 0) {
|
||||
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
|
||||
return 0;
|
||||
}
|
||||
if (s->ext.ech.success != 1 && s->ext.ech.backend != 1) {
|
||||
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
|
||||
return 0;
|
||||
}
|
||||
/* yay - we're ok with this */
|
||||
OSSL_TRACE_BEGIN(TLS)
|
||||
{
|
||||
BIO_printf(trc_out, "ECH seen in inner as expected.\n");
|
||||
}
|
||||
OSSL_TRACE_END(TLS);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Answer an ECH, as needed
|
||||
* return 1 for good, 0 otherwise
|
||||
*
|
||||
* Return most-recent ECH config for retry, as needed.
|
||||
* If doing HRR we include the confirmation value, but
|
||||
* for now, we'll just add the zeros - the real octets
|
||||
* will be added later via ech_calc_ech_confirm() which
|
||||
* is called when constructing the server hello.
|
||||
*/
|
||||
EXT_RETURN tls_construct_stoc_ech(SSL_CONNECTION *s, WPACKET *pkt,
|
||||
unsigned int context, X509 *x,
|
||||
size_t chainidx)
|
||||
{
|
||||
unsigned char *rcfgs = NULL;
|
||||
size_t rcfgslen = 0;
|
||||
|
||||
if (context == SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST
|
||||
&& (s->ext.ech.success == 1 || s->ext.ech.backend == 1)
|
||||
&& s->ext.ech.attempted_type == TLSEXT_TYPE_ech) {
|
||||
unsigned char eightzeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
if (!WPACKET_put_bytes_u16(pkt, s->ext.ech.attempted_type)
|
||||
|| !WPACKET_sub_memcpy_u16(pkt, eightzeros, 8)) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
OSSL_TRACE_BEGIN(TLS)
|
||||
{
|
||||
BIO_printf(trc_out, "set 8 zeros for ECH accept confirm in HRR\n");
|
||||
}
|
||||
OSSL_TRACE_END(TLS);
|
||||
return EXT_RETURN_SENT;
|
||||
}
|
||||
/* GREASE or error => random confirmation in HRR case */
|
||||
if (context == SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST
|
||||
&& s->ext.ech.attempted_type == TLSEXT_TYPE_ech
|
||||
&& s->ext.ech.attempted == 1) {
|
||||
unsigned char randomconf[8];
|
||||
|
||||
if (RAND_bytes_ex(s->ssl.ctx->libctx, randomconf, 8,
|
||||
RAND_DRBG_STRENGTH)
|
||||
<= 0) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
if (!WPACKET_put_bytes_u16(pkt, s->ext.ech.attempted_type)
|
||||
|| !WPACKET_sub_memcpy_u16(pkt, randomconf, 8)) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
OSSL_TRACE_BEGIN(TLS)
|
||||
{
|
||||
BIO_printf(trc_out, "set random for ECH acccpt confirm in HRR\n");
|
||||
}
|
||||
OSSL_TRACE_END(TLS);
|
||||
return EXT_RETURN_SENT;
|
||||
}
|
||||
/* in other HRR circumstances: don't set */
|
||||
if (context == SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST)
|
||||
return EXT_RETURN_NOT_SENT;
|
||||
/* If in some weird state we ignore and send nothing */
|
||||
if (s->ext.ech.grease != OSSL_ECH_IS_GREASE
|
||||
|| s->ext.ech.attempted_type != TLSEXT_TYPE_ech)
|
||||
return EXT_RETURN_NOT_SENT;
|
||||
/*
|
||||
* If the client GREASEd, or we think it did, return the
|
||||
* most-recently loaded ECHConfigList, as the value of the
|
||||
* extension. Most-recently loaded can be anywhere in the
|
||||
* list, depending on changing or non-changing file names.
|
||||
*/
|
||||
if (s->ext.ech.es == NULL) {
|
||||
OSSL_TRACE_BEGIN(TLS)
|
||||
{
|
||||
BIO_printf(trc_out, "ECH - not sending ECHConfigList to client "
|
||||
"even though they GREASE'd as I've no loaded configs\n");
|
||||
}
|
||||
OSSL_TRACE_END(TLS);
|
||||
return EXT_RETURN_NOT_SENT;
|
||||
}
|
||||
if (ossl_ech_get_retry_configs(s, &rcfgs, &rcfgslen) != 1) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
if (rcfgslen == 0) {
|
||||
OSSL_TRACE_BEGIN(TLS)
|
||||
{
|
||||
BIO_printf(trc_out, "ECH - not sending ECHConfigList to client "
|
||||
"even though they GREASE'd and I have configs but "
|
||||
"I've no configs set to be returned\n");
|
||||
}
|
||||
OSSL_TRACE_END(TLS);
|
||||
return EXT_RETURN_NOT_SENT;
|
||||
}
|
||||
if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_ech)
|
||||
|| !WPACKET_start_sub_packet_u16(pkt)
|
||||
|| !WPACKET_sub_memcpy_u16(pkt, rcfgs, rcfgslen)
|
||||
|| !WPACKET_close(pkt)) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
OPENSSL_free(rcfgs);
|
||||
return 0;
|
||||
}
|
||||
OPENSSL_free(rcfgs);
|
||||
return EXT_RETURN_SENT;
|
||||
}
|
||||
#endif /* END OPENSSL_NO_ECH */
|
||||
|
|
|
|||
|
|
@ -574,7 +574,9 @@ int tls_parse_stoc_server_cert_type(SSL_CONNECTION *s, PACKET *pkt,
|
|||
EXT_RETURN tls_construct_ctos_ech(SSL_CONNECTION *s, WPACKET *pkt,
|
||||
unsigned int context, X509 *x,
|
||||
size_t chainidx);
|
||||
EXT_RETURN tls_construct_ctos_ech(SSL_CONNECTION *s, WPACKET *pkt,
|
||||
int tls_parse_ctos_ech(SSL_CONNECTION *s, PACKET *pkt, unsigned int context,
|
||||
X509 *x, size_t chainidx);
|
||||
EXT_RETURN tls_construct_stoc_ech(SSL_CONNECTION *s, WPACKET *pkt,
|
||||
unsigned int context, X509 *x,
|
||||
size_t chainidx);
|
||||
int tls_parse_stoc_ech(SSL_CONNECTION *s, PACKET *pkt, unsigned int context,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,10 @@
|
|||
|
||||
#define TICKET_NONCE_SIZE 8
|
||||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
#include "../ech/ech_local.h"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
ASN1_TYPE *kxBlob;
|
||||
ASN1_TYPE *opaqueBlob;
|
||||
|
|
@ -1640,6 +1644,84 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL_CONNECTION *s, PACKET *pkt)
|
|||
PACKET session_id, compression, extensions, cookie;
|
||||
CLIENTHELLO_MSG *clienthello = NULL;
|
||||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
/*
|
||||
* For a split-mode backend we want to have a way to point at the CH octets
|
||||
* for the accept-confirmation calculation. The split-mode backend does not
|
||||
* need any ECH secrets, but it does need to see the inner CH and be the TLS
|
||||
* endpoint with which the ECH encrypting client sets up the TLS session.
|
||||
* The split-mode backend however does need to do an ECH confirm calculation
|
||||
* so we need to tee that up. The result of that calculation will be put in
|
||||
* the ServerHello.random (or ECH extension if HRR) to signal to the client
|
||||
* that ECH "worked."
|
||||
*/
|
||||
if (s->server && PACKET_remaining(pkt) != 0) {
|
||||
int rv = 0, innerflag = -1;
|
||||
size_t startofsessid = 0, startofexts = 0, echoffset = 0;
|
||||
size_t outersnioffset = 0; /* offset to SNI in outer */
|
||||
uint16_t echtype = OSSL_ECH_type_unknown; /* type of ECH seen */
|
||||
const unsigned char *pbuf = NULL;
|
||||
|
||||
/* reset needed in case of HRR */
|
||||
s->ext.ech.ch_offsets_done = 0;
|
||||
rv = ossl_ech_get_ch_offsets(s, pkt, &startofsessid, &startofexts,
|
||||
&echoffset, &echtype, &innerflag,
|
||||
&outersnioffset);
|
||||
if (rv != 1) {
|
||||
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
|
||||
goto err;
|
||||
}
|
||||
if (innerflag == OSSL_ECH_INNER_CH_TYPE) {
|
||||
WPACKET inner;
|
||||
|
||||
OSSL_TRACE(TLS, "Got inner ECH so setting backend\n");
|
||||
/* For backend, include msg type & 3 octet length */
|
||||
s->ext.ech.backend = 1;
|
||||
s->ext.ech.attempted_type = TLSEXT_TYPE_ech;
|
||||
OPENSSL_free(s->ext.ech.innerch);
|
||||
s->ext.ech.innerch_len = PACKET_remaining(pkt);
|
||||
if (PACKET_peek_bytes(pkt, &pbuf, s->ext.ech.innerch_len) != 1) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
s->ext.ech.innerch_len += SSL3_HM_HEADER_LENGTH; /* 4 */
|
||||
s->ext.ech.innerch = OPENSSL_malloc(s->ext.ech.innerch_len);
|
||||
if (s->ext.ech.innerch == NULL) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
if (!WPACKET_init_static_len(&inner, s->ext.ech.innerch,
|
||||
s->ext.ech.innerch_len, 0)
|
||||
|| !WPACKET_put_bytes_u8(&inner, SSL3_MT_CLIENT_HELLO)
|
||||
|| !WPACKET_put_bytes_u24(&inner, s->ext.ech.innerch_len - SSL3_HM_HEADER_LENGTH)
|
||||
|| !WPACKET_memcpy(&inner, pbuf, s->ext.ech.innerch_len - SSL3_HM_HEADER_LENGTH)
|
||||
|| !WPACKET_finish(&inner)) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
} else if (s->ext.ech.es != NULL) {
|
||||
PACKET newpkt;
|
||||
|
||||
if (ossl_ech_early_decrypt(s, pkt, &newpkt) != 1) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
if (s->ext.ech.success == 1) {
|
||||
/*
|
||||
* Replace the outer CH with the inner, as long as there's
|
||||
* space, which there better be! (a bug triggered a bigger
|
||||
* inner CH once;-)
|
||||
*/
|
||||
if (PACKET_remaining(&newpkt) > PACKET_remaining(pkt)) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
*pkt = newpkt;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check if this is actually an unexpected renegotiation ClientHello */
|
||||
if (s->renegotiate == 0 && !SSL_IS_FIRST_HANDSHAKE(s)) {
|
||||
if (!ossl_assert(!SSL_CONNECTION_IS_TLS13(s))) {
|
||||
|
|
@ -1751,6 +1833,12 @@ err:
|
|||
if (clienthello != NULL)
|
||||
OPENSSL_free(clienthello->pre_proc_exts);
|
||||
OPENSSL_free(clienthello);
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
s->clienthello = NULL;
|
||||
OPENSSL_free(s->ext.ech.innerch);
|
||||
s->ext.ech.innerch = NULL;
|
||||
s->ext.ech.innerch_len = 0;
|
||||
#endif
|
||||
|
||||
return MSG_PROCESS_ERROR;
|
||||
}
|
||||
|
|
@ -2025,12 +2113,25 @@ static int tls_early_post_process_client_hello(SSL_CONNECTION *s)
|
|||
goto err;
|
||||
}
|
||||
|
||||
if (!s->hit
|
||||
/*
|
||||
* Unless ECH has worked or not been configured we won't call
|
||||
* the session_secret_cb now because we'll need to calculate the
|
||||
* server random later to include the ECH accept value.
|
||||
* We can't do it now as we don't yet have the SH encoding.
|
||||
*/
|
||||
if (
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
((s->ext.ech.es != NULL && s->ext.ech.success == 1)
|
||||
|| s->ext.ech.es == NULL)
|
||||
&&
|
||||
#endif
|
||||
!s->hit
|
||||
&& s->version >= TLS1_VERSION
|
||||
&& !SSL_CONNECTION_IS_TLS13(s)
|
||||
&& !SSL_CONNECTION_IS_DTLS(s)
|
||||
&& s->ext.session_secret_cb != NULL) {
|
||||
const SSL_CIPHER *pref_cipher = NULL;
|
||||
|
||||
/*
|
||||
* s->session->master_key_length is a size_t, but this is an int for
|
||||
* backwards compat reasons
|
||||
|
|
@ -2187,7 +2288,8 @@ static int tls_early_post_process_client_hello(SSL_CONNECTION *s)
|
|||
err:
|
||||
sk_SSL_CIPHER_free(ciphers);
|
||||
sk_SSL_CIPHER_free(scsvs);
|
||||
OPENSSL_free(clienthello->pre_proc_exts);
|
||||
if (clienthello != NULL)
|
||||
OPENSSL_free(clienthello->pre_proc_exts);
|
||||
OPENSSL_free(s->clienthello);
|
||||
s->clienthello = NULL;
|
||||
|
||||
|
|
@ -2550,16 +2652,150 @@ CON_FUNC_RETURN tls_construct_server_hello(SSL_CONNECTION *s, WPACKET *pkt)
|
|||
* Re-initialise the Transcript Hash. We're going to prepopulate it with
|
||||
* a synthetic message_hash in place of ClientHello1.
|
||||
*/
|
||||
if (!create_synthetic_message_hash(s, NULL, 0, NULL, 0)) {
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
/*
|
||||
* if we're sending 2nd SH after HRR and we did ECH
|
||||
* then we want to inject the hash of the inner CH1
|
||||
* and not the outer (which is the default)
|
||||
*/
|
||||
OSSL_TRACE_BEGIN(TLS)
|
||||
{
|
||||
BIO_printf(trc_out, "Checking success (%d)/innerCH (%p)\n",
|
||||
s->ext.ech.success, (void *)s->ext.ech.innerch);
|
||||
}
|
||||
OSSL_TRACE_END(TLS);
|
||||
if ((s->ext.ech.backend == 1 || s->ext.ech.success == 1)
|
||||
&& s->ext.ech.innerch != NULL) {
|
||||
/* do pre-existing HRR stuff */
|
||||
unsigned char hashval[EVP_MAX_MD_SIZE];
|
||||
unsigned int hashlen;
|
||||
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
|
||||
const EVP_MD *md = NULL;
|
||||
|
||||
OSSL_TRACE(TLS, "Adding in digest of ClientHello\n");
|
||||
#ifdef OSSL_ECH_SUPERVERBOSE
|
||||
ossl_ech_pbuf("innerch", s->ext.ech.innerch,
|
||||
s->ext.ech.innerch_len);
|
||||
#endif
|
||||
if (ctx == NULL) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
return CON_FUNC_ERROR;
|
||||
}
|
||||
md = ssl_handshake_md(s);
|
||||
if (md == NULL) {
|
||||
EVP_MD_CTX_free(ctx);
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
return CON_FUNC_ERROR;
|
||||
}
|
||||
if (EVP_DigestInit_ex(ctx, md, NULL) <= 0
|
||||
|| EVP_DigestUpdate(ctx, s->ext.ech.innerch,
|
||||
s->ext.ech.innerch_len)
|
||||
<= 0
|
||||
|| EVP_DigestFinal_ex(ctx, hashval, &hashlen) <= 0) {
|
||||
EVP_MD_CTX_free(ctx);
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
return CON_FUNC_ERROR;
|
||||
}
|
||||
#ifdef OSSL_ECH_SUPERVERBOSE
|
||||
ossl_ech_pbuf("digested CH", hashval, hashlen);
|
||||
#endif
|
||||
EVP_MD_CTX_free(ctx);
|
||||
if (ossl_ech_reset_hs_buffer(s, NULL, 0) != 1) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
return CON_FUNC_ERROR;
|
||||
}
|
||||
if (!create_synthetic_message_hash(s, hashval, hashlen, NULL, 0)) {
|
||||
/* SSLfatal() already called */
|
||||
return CON_FUNC_ERROR;
|
||||
}
|
||||
} else {
|
||||
if (!create_synthetic_message_hash(s, NULL, 0, NULL, 0))
|
||||
return CON_FUNC_ERROR; /* SSLfatal() already called */
|
||||
}
|
||||
#else
|
||||
if (!create_synthetic_message_hash(s, NULL, 0, NULL, 0))
|
||||
/* SSLfatal() already called */
|
||||
return CON_FUNC_ERROR;
|
||||
}
|
||||
#endif /* OPENSSL_NO_ECH */
|
||||
} else if (!(s->verify_mode & SSL_VERIFY_PEER)
|
||||
&& !ssl3_digest_cached_records(s, 0)) {
|
||||
/* SSLfatal() already called */;
|
||||
return CON_FUNC_ERROR;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
/*
|
||||
* Calculate the ECH-accept server random to indicate that
|
||||
* we're accepting ECH, if that's the case
|
||||
*/
|
||||
if (s->ext.ech.attempted_type == TLSEXT_TYPE_ech
|
||||
&& (s->ext.ech.backend == 1
|
||||
|| (s->ext.ech.es != NULL && s->ext.ech.success == 1))) {
|
||||
unsigned char acbuf[8];
|
||||
unsigned char *shbuf = NULL;
|
||||
size_t shlen = 0;
|
||||
size_t shoffset = 0;
|
||||
int hrr = 0;
|
||||
|
||||
if (s->hello_retry_request == SSL_HRR_PENDING)
|
||||
hrr = 1;
|
||||
memset(acbuf, 0, 8);
|
||||
if (WPACKET_get_total_written(pkt, &shlen) != 1) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
return CON_FUNC_ERROR;
|
||||
}
|
||||
shbuf = WPACKET_get_curr(pkt) - shlen;
|
||||
/* we need to fixup SH length here */
|
||||
shbuf[1] = ((shlen - 4)) >> 16 & 0xff;
|
||||
shbuf[2] = ((shlen - 4)) >> 8 & 0xff;
|
||||
shbuf[3] = (shlen - 4) & 0xff;
|
||||
if (ossl_ech_intbuf_add(s, shbuf, shlen, hrr) != 1) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
return CON_FUNC_ERROR;
|
||||
}
|
||||
if (ossl_ech_calc_confirm(s, hrr, acbuf, shlen) != 1) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
return CON_FUNC_ERROR;
|
||||
}
|
||||
memcpy(s->s3.server_random + SSL3_RANDOM_SIZE - 8, acbuf, 8);
|
||||
if (hrr == 0) {
|
||||
/* confirm value hacked into SH.random rightmost octets */
|
||||
shoffset = SSL3_HM_HEADER_LENGTH /* 4 */
|
||||
+ CLIENT_VERSION_LEN /* 2 */
|
||||
+ SSL3_RANDOM_SIZE /* 32 */
|
||||
- 8;
|
||||
memcpy(shbuf + shoffset, acbuf, 8);
|
||||
} else {
|
||||
/*
|
||||
* confirm value is in extension in HRR case as the SH.random
|
||||
* is already hacked to be a specific value in a HRR
|
||||
*/
|
||||
memcpy(WPACKET_get_curr(pkt) - 8, acbuf, 8);
|
||||
}
|
||||
}
|
||||
/* call ECH callback, if appropriate */
|
||||
if (s->ext.ech.attempted == 1 && s->ext.ech.cb != NULL
|
||||
&& s->hello_retry_request != SSL_HRR_PENDING) {
|
||||
char pstr[OSSL_ECH_PBUF_SIZE + 1];
|
||||
BIO *biom = BIO_new(BIO_s_mem());
|
||||
unsigned int cbrv = 0;
|
||||
|
||||
if (biom == NULL) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
return CON_FUNC_ERROR;
|
||||
}
|
||||
memset(pstr, 0, OSSL_ECH_PBUF_SIZE + 1);
|
||||
ossl_ech_status_print(biom, s, OSSL_ECHSTORE_ALL);
|
||||
BIO_read(biom, pstr, OSSL_ECH_PBUF_SIZE);
|
||||
cbrv = s->ext.ech.cb(&s->ssl, pstr);
|
||||
BIO_free(biom);
|
||||
if (cbrv != 1) {
|
||||
OSSL_TRACE(TLS, "Error from tls_construct_server_hello/ech_cb\n");
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
return CON_FUNC_ERROR;
|
||||
}
|
||||
}
|
||||
#endif /* OPENSSL_NO_ECH */
|
||||
return CON_FUNC_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -895,11 +895,15 @@ static int ech_ingest_test(int run)
|
|||
* Occasionally, flush_time will be 1 more than add_time. We'll
|
||||
* check for that as that should catch a few more code paths
|
||||
* in the flush_keys API.
|
||||
* When flush_time is 1 more, we may or may not have flushed
|
||||
* the one and only key (depending on which "side" of the second
|
||||
* it was generated, so we may be left with 0 or 1 keys.
|
||||
*/
|
||||
if (!TEST_true(OSSL_ECHSTORE_flush_keys(es, flush_time - add_time))
|
||||
|| !TEST_int_eq(OSSL_ECHSTORE_num_keys(es, &keysaftr), 1)
|
||||
|| ((flush_time <= add_time) && !TEST_int_eq(keysaftr, 0))
|
||||
|| ((flush_time > add_time) && !TEST_int_eq(keysaftr, 1))) {
|
||||
|| ((flush_time > add_time) && !TEST_int_eq(keysaftr, 1)
|
||||
&& !TEST_int_eq(keysaftr, 0))) {
|
||||
TEST_info("Flush time: %lld, add_time: %lld", (long long)flush_time,
|
||||
(long long)add_time);
|
||||
goto end;
|
||||
|
|
@ -1143,6 +1147,7 @@ end:
|
|||
#define OSSL_ECH_TEST_EARLY 2
|
||||
#define OSSL_ECH_TEST_CUSTOM 3
|
||||
#define OSSL_ECH_TEST_ENOE 4 /* early + no-ech */
|
||||
/* note: early-data is prohibited after HRR so no tests for that */
|
||||
|
||||
/*
|
||||
* @brief ECH roundtrip test helper
|
||||
|
|
@ -1157,13 +1162,6 @@ end:
|
|||
*
|
||||
* The combo input is one of the #define'd OSSL_ECH_TEST_*
|
||||
* values above.
|
||||
*
|
||||
* TODO(ECH): we're not yet really attempting ECH, but we currently
|
||||
* set the inputs as if we were doing ECH, yet don't expect to see
|
||||
* real ECH status outcomes, so while we do make calls to get that
|
||||
* status outcome, we don't compare vs. real expected results.
|
||||
* That's done via the "if (0 &&" clauses below which will be
|
||||
* removed once ECH is really being attempted.
|
||||
*/
|
||||
static int test_ech_roundtrip_helper(int idx, int combo)
|
||||
{
|
||||
|
|
@ -1207,9 +1205,8 @@ static int test_ech_roundtrip_helper(int idx, int combo)
|
|||
if (combo == OSSL_ECH_TEST_EARLY || combo == OSSL_ECH_TEST_ENOE) {
|
||||
if (!TEST_true(SSL_CTX_set_options(sctx, SSL_OP_NO_ANTI_REPLAY))
|
||||
|| !TEST_true(SSL_CTX_set_max_early_data(sctx,
|
||||
SSL3_RT_MAX_PLAIN_LENGTH)))
|
||||
goto end;
|
||||
if (!TEST_true(SSL_CTX_set_recv_max_early_data(sctx,
|
||||
SSL3_RT_MAX_PLAIN_LENGTH))
|
||||
|| !TEST_true(SSL_CTX_set_recv_max_early_data(sctx,
|
||||
SSL3_RT_MAX_PLAIN_LENGTH)))
|
||||
goto end;
|
||||
}
|
||||
|
|
@ -1241,58 +1238,38 @@ static int test_ech_roundtrip_helper(int idx, int combo)
|
|||
goto end;
|
||||
if (!TEST_true(SSL_set_tlsext_host_name(clientssl, "server.example")))
|
||||
goto end;
|
||||
#undef DROPFORNOW
|
||||
#ifdef DROPFORNOW
|
||||
/* TODO(ECH): we'll re-instate this once server-side ECH code is in */
|
||||
if (!TEST_true(create_ssl_connection(serverssl, clientssl,
|
||||
SSL_ERROR_NONE)))
|
||||
goto end;
|
||||
#else
|
||||
/*
|
||||
* For this PR, check connections fail when client does ECH
|
||||
* and server doesn't, but work if client doesn't do ECH.
|
||||
* Added in early data for the no-ECH case because an
|
||||
* intermediate state of the code had an issue.
|
||||
*/
|
||||
if (combo != OSSL_ECH_TEST_ENOE
|
||||
&& !TEST_false(create_ssl_connection(serverssl, clientssl,
|
||||
SSL_ERROR_NONE)))
|
||||
goto end;
|
||||
if (combo == OSSL_ECH_TEST_ENOE
|
||||
&& !TEST_true(create_ssl_connection(serverssl, clientssl,
|
||||
SSL_ERROR_NONE)))
|
||||
goto end;
|
||||
#endif
|
||||
serverstatus = SSL_ech_get1_status(serverssl, &sinner, &souter);
|
||||
if (verbose)
|
||||
TEST_info("server status %d, %s, %s", serverstatus, sinner, souter);
|
||||
if (0 && !TEST_int_eq(serverstatus, SSL_ECH_STATUS_SUCCESS))
|
||||
goto end;
|
||||
/* override cert verification */
|
||||
SSL_set_verify_result(clientssl, X509_V_OK);
|
||||
clientstatus = SSL_ech_get1_status(clientssl, &cinner, &couter);
|
||||
if (verbose)
|
||||
TEST_info("client status %d, %s, %s", clientstatus, cinner, couter);
|
||||
if (0 && !TEST_int_eq(clientstatus, SSL_ECH_STATUS_SUCCESS))
|
||||
serverstatus = SSL_ech_get1_status(serverssl, &sinner, &souter);
|
||||
if (verbose)
|
||||
TEST_info("server status %d, %s, %s", serverstatus, sinner, souter);
|
||||
if (combo != OSSL_ECH_TEST_ENOE
|
||||
&& !TEST_int_eq(serverstatus, SSL_ECH_STATUS_SUCCESS))
|
||||
goto end;
|
||||
if (combo == OSSL_ECH_TEST_ENOE
|
||||
&& !TEST_int_eq(serverstatus, SSL_ECH_STATUS_NOT_TRIED))
|
||||
goto end;
|
||||
if (combo != OSSL_ECH_TEST_ENOE
|
||||
&& !TEST_int_eq(clientstatus, SSL_ECH_STATUS_SUCCESS))
|
||||
goto end;
|
||||
if (combo == OSSL_ECH_TEST_ENOE
|
||||
&& !TEST_int_eq(clientstatus, SSL_ECH_STATUS_NOT_CONFIGURED))
|
||||
goto end;
|
||||
/* all good */
|
||||
if (combo == OSSL_ECH_TEST_BASIC
|
||||
|| combo == OSSL_ECH_TEST_HRR
|
||||
if (combo == OSSL_ECH_TEST_BASIC || combo == OSSL_ECH_TEST_HRR
|
||||
|| combo == OSSL_ECH_TEST_CUSTOM) {
|
||||
res = 1;
|
||||
goto end;
|
||||
}
|
||||
/* continue for EARLY test */
|
||||
#ifdef DROPFORNOW
|
||||
/* TODO(ECH): turn back on later */
|
||||
if (combo != OSSL_ECH_TEST_EARLY && combo != OSSL_ECH_TEST_ENOE)
|
||||
goto end;
|
||||
#else
|
||||
if (combo != OSSL_ECH_TEST_ENOE) {
|
||||
res = 1;
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
/* shutdown for start over */
|
||||
sess = SSL_get1_session(clientssl);
|
||||
OPENSSL_free(sinner);
|
||||
|
|
@ -1312,8 +1289,8 @@ static int test_ech_roundtrip_helper(int idx, int combo)
|
|||
|| !TEST_true(SSL_set_session(clientssl, sess))
|
||||
|| !TEST_true(SSL_write_early_data(clientssl, ed, sizeof(ed), &written))
|
||||
|| !TEST_size_t_eq(written, sizeof(ed))
|
||||
|| !TEST_int_eq(SSL_read_early_data(serverssl, buf,
|
||||
sizeof(buf), &readbytes),
|
||||
|| !TEST_int_eq(SSL_read_early_data(serverssl, buf, sizeof(buf),
|
||||
&readbytes),
|
||||
SSL_READ_EARLY_DATA_SUCCESS)
|
||||
|| !TEST_size_t_eq(written, readbytes))
|
||||
goto end;
|
||||
|
|
@ -1326,17 +1303,25 @@ static int test_ech_roundtrip_helper(int idx, int combo)
|
|||
|| !TEST_true(SSL_read_ex(clientssl, buf, sizeof(buf), &readbytes))
|
||||
|| !TEST_mem_eq(buf, readbytes, ed, sizeof(ed)))
|
||||
goto end;
|
||||
serverstatus = SSL_ech_get1_status(serverssl, &sinner, &souter);
|
||||
if (verbose)
|
||||
TEST_info("server status %d, %s, %s", serverstatus, sinner, souter);
|
||||
if (0 && !TEST_int_eq(serverstatus, SSL_ECH_STATUS_SUCCESS))
|
||||
goto end;
|
||||
/* override cert verification */
|
||||
SSL_set_verify_result(clientssl, X509_V_OK);
|
||||
clientstatus = SSL_ech_get1_status(clientssl, &cinner, &couter);
|
||||
if (verbose)
|
||||
TEST_info("client status %d, %s, %s", clientstatus, cinner, couter);
|
||||
if (0 && !TEST_int_eq(clientstatus, SSL_ECH_STATUS_SUCCESS))
|
||||
serverstatus = SSL_ech_get1_status(serverssl, &sinner, &souter);
|
||||
if (verbose)
|
||||
TEST_info("server status %d, %s, %s", serverstatus, sinner, souter);
|
||||
if (combo != OSSL_ECH_TEST_ENOE
|
||||
&& !TEST_int_eq(serverstatus, SSL_ECH_STATUS_SUCCESS))
|
||||
goto end;
|
||||
if (combo == OSSL_ECH_TEST_ENOE
|
||||
&& !TEST_int_eq(serverstatus, SSL_ECH_STATUS_NOT_TRIED))
|
||||
goto end;
|
||||
if (combo != OSSL_ECH_TEST_ENOE
|
||||
&& !TEST_int_eq(clientstatus, SSL_ECH_STATUS_SUCCESS))
|
||||
goto end;
|
||||
if (combo == OSSL_ECH_TEST_ENOE
|
||||
&& !TEST_int_eq(clientstatus, SSL_ECH_STATUS_NOT_CONFIGURED))
|
||||
goto end;
|
||||
/* all good */
|
||||
res = 1;
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ __current_exception_context
|
|||
strlen
|
||||
strstr
|
||||
strchr
|
||||
strlen
|
||||
memmove
|
||||
strrchr
|
||||
memcmp
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue