Skip to content

Commit

Permalink
move ECH specific padding into library
Browse files Browse the repository at this point in the history
  • Loading branch information
sftcd committed Jun 6, 2024
1 parent fafa0b4 commit 6145168
Show file tree
Hide file tree
Showing 12 changed files with 429 additions and 93 deletions.
90 changes: 6 additions & 84 deletions apps/s_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,6 @@ typedef unsigned int u_int;
#endif
#include "internal/sockets.h"

#ifndef OPENSSL_NO_ECH
/*
* A lack of padding can expose information intended to be hidden via ECH,
* e.g. if only two inner CH SNI values were in live use. In that case we
* pad the Certificate, CertificateVerify and EncryptedExtensions handshake
* messages from the server. These are the minimum lengths to which those
* will be padded in that case.
*/
# define ECH_CERTSPECIFIC_MIN 1808
# define ECH_CERTVERSPECIFIC_MIN 480
# define ECH_ENCEXTSPECIFIC_MIN 32
#endif

static int not_resumable_sess_cb(SSL *s, int is_forward_secure);
static int sv_body(int s, int stype, int prot, unsigned char *context);
static int www_body(int s, int stype, int prot, unsigned char *context);
Expand All @@ -106,60 +93,6 @@ static unsigned int ech_print_cb(SSL *s, const char *str);
static size_t ech_trace_cb(const char *buf, size_t cnt,
int category, int cmd, void *vdata);
# endif

/* ECH padding size info, var of this type is passed via callback */
typedef struct {
/* Certificate messages to be a multiple of this size */
size_t certpad;
/* CertificateVerify messages to be a multiple of this size */
size_t certverifypad;
/* EncryptedExtensions are padded to be a multiple of this size */
size_t eepad;
} ech_padding_sizes;

/* passed as an argument to callback */
static ech_padding_sizes *ech_ps=NULL;

/*
* @brief pad Certificate and CertificateVerify messages
* @param s is the SSL connection
* @param len is the plaintext length before padding
* @param arg is a pointer to an esni_padding_sizes struct
* @return is the number of bytes of padding to add to the plaintext
*
* This is passed to SSL_CTX_set_record_padding_callback
* and pads the Certificate, CertificateVerify and
* EncryptedExtensions handshake messages to a size derived
* from the argument arg
*/
static size_t ech_padding_cb(SSL *s, int type, size_t len, void *arg)
{
ech_padding_sizes *ps = (ech_padding_sizes *)arg;
int state = SSL_get_state(s);

if (state == TLS_ST_SW_CERT) {
int newlen = ps->certpad - (len % ps->certpad) - 16;

if (newlen < 0)
newlen += ps->certpad;
return (newlen > 0 ? newlen : 0);
}
if (state == TLS_ST_SW_CERT_VRFY) {
int newlen = ps->certverifypad - (len % ps->certverifypad) - 16;

if (newlen < 0)
newlen += ps->certverifypad;
return (newlen > 0 ? newlen : 0);
}
if (state == TLS_ST_SW_ENCRYPTED_EXTENSIONS) {
int newlen = ps->eepad - (len % ps->eepad) - 16;

if (newlen < 0)
newlen += ps->eepad;
return (newlen > 0 ? newlen : 0);
}
return 0;
}
#endif

static const int bufsize = 16 * 1024;
Expand Down Expand Up @@ -2538,14 +2471,8 @@ int s_server_main(int argc, char *argv[])
/*
* Set padding sizes
*/
if (echspecificpad != 0) {
ech_ps = OPENSSL_malloc(sizeof(ech_padding_sizes));
ech_ps->certpad = ECH_CERTSPECIFIC_MIN;
ech_ps->certverifypad = ECH_CERTVERSPECIFIC_MIN ;
ech_ps->eepad = ECH_ENCEXTSPECIFIC_MIN ;
SSL_CTX_set_record_padding_callback_arg(ctx, (void *)ech_ps);
SSL_CTX_set_record_padding_callback(ctx, ech_padding_cb);
}
if (echspecificpad != 0)
SSL_CTX_set_options(ctx, SSL_OP_ECH_SPECIFIC_PADDING);

This comment has been minimized.

Copy link
@vdukhovni

vdukhovni Jun 10, 2024

A control might be better than a new option bit. The control itself would be wrapped in a new function-like macro?

This comment has been minimized.

Copy link
@sftcd

sftcd Jun 10, 2024

Author Owner

Sorry, not sure what you mean by a "control"? A pointer to an example may suffice

#endif

if (s_cert2) {
Expand All @@ -2556,16 +2483,12 @@ int s_server_main(int argc, char *argv[])
}

#ifndef OPENSSL_NO_ECH
if (echtrialdecrypt != 0) {
if (echtrialdecrypt != 0)
SSL_CTX_set_options(ctx2, SSL_OP_ECH_TRIALDECRYPT);
}
if (echgrease_rc != 0) {
if (echgrease_rc != 0)
SSL_CTX_set_options(ctx, SSL_OP_ECH_GREASE_RETRY_CONFIG);
}
if (echspecificpad != 0) {
SSL_CTX_set_record_padding_callback_arg(ctx2, (void *)ech_ps);
SSL_CTX_set_record_padding_callback(ctx2, ech_padding_cb);
}
if (echspecificpad != 0)
SSL_CTX_set_options(ctx2, SSL_OP_ECH_SPECIFIC_PADDING);
#endif
}

Expand Down Expand Up @@ -2941,7 +2864,6 @@ int s_server_main(int argc, char *argv[])
BIO_meth_free(methods_ebcdic);
#endif
#ifndef OPENSSL_NO_ECH
OPENSSL_free(ech_ps);
#endif
return ret;
}
Expand Down
65 changes: 61 additions & 4 deletions doc/designs/ech-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,60 @@ ChangeCipherSuite or Early data), then the caller is responsible for
disentangling those, and for assembling a new flight containing the inner
ClientHello.

### ECH-specific Padding of server messages

If a web server were to host a set of web sites, one of which had a much longer
name than the others, the size of some TLS handshake server messages could
expose which web site was being accessed. Similarly, if the TLS server
certificate for one web site were significantly larger or smaller than others,
message sizes could reveal which web site was being visited. For these
reasons, we provide a way to enable additional ECH-specific padding of the
Certifiate, CertificateVerify and EncryptedExtensions messages sent from the
server to the client during the handshake.

To enable ECH-specific padding, one makes a call to:

```c
SSL_CTX_set_options(ctx, SSL_OP_ECH_SPECIFIC_PADDING);
```
The default padding scheme is to ensure the following sizes for the plaintext
form of these messages:
| ------------------- | ------------ | ------------------- |
| Message | Minimum Size | Size is multiple of |
| ------------------- | ------------ | ------------------- |
| Certificate | 1792 | 128 |
| CertificateVerify | 480 | 16 |
| EncryptedExtensions | 32 | 16 |
| ------------------- | ------------ | ------------------- |
The ciphertext form of these messages, as seen on the network in the record
layer protocol, will usually be 16 octets more, due to the AEAD tag that is
added as part of encryption.
If a server wishes to have finer-grained control of these sizes, then it can
make use of the ``SSL_CTX_ech_set_pad_sizes()`` or ``SSL_ech_set_pad_sizes()``
APIs. Both involve populating an ``OSSL_ECH_PAD_SIZES`` data structure as
described below in the obvious manner.
```c
/*
* Fine-grained ECH-spacific padding controls for a server
*/
typedef struct ossl_ech_pad_sizes_st {
size_t cert_min; /* minimum size */
size_t cert_unit; /* size will be multiple of */
size_t certver_min; /* minimum size */
size_t certver_unit; /* size will be multiple of */
size_t ee_min; /* minimum size */
size_t ee_unit; /* size will be multiple of */
} OSSL_ECH_PAD_SIZES;
int SSL_CTX_ech_set_pad_sizes(SSL_CTX *ctx, OSSL_ECH_PAD_SIZES *sizes);
int SSL_ech_set_pad_sizes(SSL *s, OSSL_ECH_PAD_SIZES *sizes);
```

Client-side APIs
----------------

Expand Down Expand Up @@ -422,17 +476,20 @@ The following options are defined for ECH and may be set via
```c
/* set this to tell client to emit greased ECH values when not doing
* "real" ECH */
#define SSL_OP_ECH_GREASE SSL_OP_BIT(34)
#define SSL_OP_ECH_GREASE SSL_OP_BIT(36)
/* If this is set then the server side will attempt trial decryption */
/* of ECHs even if there is no matching record_digest. That's a bit */
/* inefficient, but more privacy friendly */
#define SSL_OP_ECH_TRIALDECRYPT SSL_OP_BIT(35)
#define SSL_OP_ECH_TRIALDECRYPT SSL_OP_BIT(37)
/* If set, clients will ignore the supplied ECH config_id and replace
* that with a random value */
#define SSL_OP_ECH_IGNORE_CID SSL_OP_BIT(36)
#define SSL_OP_ECH_IGNORE_CID SSL_OP_BIT(38)
/* If set, servers will add GREASEy ECHConfig values to those sent
* in retry_configs */
#define SSL_OP_ECH_GREASE_RETRY_CONFIG SSL_OP_BIT(37)
#define SSL_OP_ECH_GREASE_RETRY_CONFIG SSL_OP_BIT(39)
/* If set, servers will add ECH-specific padding to Certificate,
* CertificateVerify and EncryptedExtensions messages */
#define SSL_OP_ECH_SPECIFIC_PADDING SSL_OP_BIT(40)
```

Build Options
Expand Down
52 changes: 50 additions & 2 deletions doc/man3/SSL_ech_set1_echconfig.pod
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ SSL_CTX_ech_server_flush_keys, SSL_CTX_ech_server_enable_file,
SSL_CTX_ech_server_enable_buffer, SSL_CTX_ech_server_enable_dir,
SSL_CTX_ech_raw_decrypt, SSL_CTX_ech_set_callback,
SSL_CTX_ech_set_outer_alpn_protos, SSL_ech_set_outer_alpn_protos,
OSSL_ech_make_echconfig, OSSL_ech_find_echconfigs
OSSL_ech_make_echconfig, OSSL_ech_find_echconfigs,
SSL_CTX_ech_set_pad_sizes,SSL_ech_set_pad_sizes
- Encrypted ClientHello (ECH) functions

=head1 SYNOPSIS
Expand Down Expand Up @@ -69,6 +70,8 @@ OSSL_ech_make_echconfig, OSSL_ech_find_echconfigs
int OSSL_ech_find_echconfigs(int *num_echs,
unsigned char ***echconfigs, size_t **echlens,
const unsigned char *val, size_t len);
int SSL_ech_set_pad_sizes(SSL *s, OSSL_ECH_PAD_SIZES *sizes);
int SSL_CTX_ech_set_pad_sizes(SSL_CTX *ctx, OSSL_ECH_PAD_SIZES *sizes);

=head1 DESCRIPTION

Expand Down Expand Up @@ -246,7 +249,6 @@ make use of ECH extensions.
OSSL_ech_make_echconfig() is intended for use by applications that generate
ECH configuration data, such as L<openssl-ech(1)>.


=head2 Enabling ECH for servers

In order to enable ECH for servers it is necessary to load one or more ECH
Expand Down Expand Up @@ -320,6 +322,52 @@ succeeds, the I<inner_sni> and I<outer_sni> values will be populated
based on the values seen. (The caller must free those strings using
OPENSSL_free() when done.)

=head2 ECH-specific Padding of server messages

If a web server were to host a set of web sites, one of which had a much longer
name than the others, the size of some TLS handshake server messages could
expose which web site was being accessed. Similarly, if the TLS server
certificate for one web site were significantly larger or smaller than others,
message sizes could reveal which web site was being visited. For these
reasons, we provide a way to enable additional ECH-specific padding of the
Certifiate, CertificateVerify and EncryptedExtensions messages sent from the
server to the client during the handshake.

To enable ECH-specific padding, one makes a call to
``SSL_CTX_set_options(ctx, SSL_OP_ECH_SPECIFIC_PADDING)``

The default padding scheme is to ensure the following sizes for the plaintext
form of these messages:

| ------------------- | ------------ | ------------------- |
| Message | Minimum Size | Size is multiple of |
| ------------------- | ------------ | ------------------- |
| Certificate | 1792 | 128 |
| CertificateVerify | 304 | 16 |
| EncryptedExtensions | 32 | 16 |
| ------------------- | ------------ | ------------------- |

The ciphertext form of these messages, as seen on the network in the record
layer protocol, will usually be 16 octets more, due to the AEAD tag that is
added as part of encryption.

If a server wishes to have finer-grained control of these sizes, then it can
make use of the ``SSL_CTX_ech_set_pad_sizes()`` or ``SSL_ech_set_pad_sizes()``
APIs. Both involve populating an ``OSSL_ECH_PAD_SIZES`` data structure as
described below in the obvious manner.

/*
* Fine-grained ECH-spacific padding controls for a server
*/
typedef struct ossl_ech_pad_sizes_st {
size_t cert_min; /* minimum size */
size_t cert_unit; /* size will be multiple of */
size_t certver_min; /* minimum size */
size_t certver_unit; /* size will be multiple of */
size_t ee_min; /* minimum size */
size_t ee_unit; /* size will be multiple of */
} OSSL_ECH_PAD_SIZES;

=head2 Accessing ECH information

Given multiple ECH public values can be associated with a single I<SSL>
Expand Down
36 changes: 36 additions & 0 deletions include/openssl/ech.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,39 @@ typedef struct ossl_ech_info_st {
char *echconfig; /* a JSON-like version of the associated ECHConfig */
} OSSL_ECH_INFO;

/*
* Default padding minima and multiples
* If a web server were to host a set of web sites, one of which had a much
* longer name than the others, the size of some TLS handshake server messages
* could expose which web site was being accessed. Similarly, if the TLS server
* certificate for one web site were significantly larger or smaller than
* others, message sizes could reveal which web site was being visited. For
* these reasons, we provide a way to enable additional ECH-specific padding of
* the Certifiate, CertificateVerify and EncryptedExtensions messages sent from
* the server to the client during the handshake.
*
* To enable ECH-specific padding, one makes a call to:
* SSL_CTX_set_options(ctx, SSL_OP_ECH_SPECIFIC_PADDING);
*/
# define OSSL_ECH_CERTPAD_MIN 1792
# define OSSL_ECH_CERTVERPAD_MIN 304
# define OSSL_ECH_ENCEXTPAD_MIN 32
# define OSSL_ECH_CERTPAD_UNIT 128
# define OSSL_ECH_CERTVERPAD_UNIT 16
# define OSSL_ECH_ENCEXTPAD_UNIT 16

/*
* Fine-grained ECH-spacific padding controls for a server
*/
typedef struct ossl_ech_pad_sizes_st {
size_t cert_min; /* minimum size */
size_t cert_unit; /* size will be multiple of */
size_t certver_min; /* minimum size */
size_t certver_unit; /* size will be multiple of */
size_t ee_min; /* minimum size */
size_t ee_unit; /* size will be multiple of */
} OSSL_ECH_PAD_SIZES;

/* Values for the for_retry inputs */
# define SSL_ECH_USE_FOR_RETRY 1
# define SSL_ECH_NOT_FOR_RETRY 0
Expand Down Expand Up @@ -116,6 +149,7 @@ int SSL_ech_set_grease_type(SSL *s, uint16_t type);

typedef unsigned int (*SSL_ech_cb_func)(SSL *s, const char *str);
void SSL_ech_set_callback(SSL *s, SSL_ech_cb_func f);
int SSL_ech_set_pad_sizes(SSL *s, OSSL_ECH_PAD_SIZES *sizes);

int SSL_ech_get_retry_config(SSL *s, unsigned char **ec, size_t *eclen);

Expand All @@ -140,6 +174,8 @@ int SSL_CTX_ech_raw_decrypt(SSL_CTX *ctx,
unsigned char *inner_ch, size_t *inner_len,
unsigned char **hrrtok, size_t *toklen);
void SSL_CTX_ech_set_callback(SSL_CTX *ctx, SSL_ech_cb_func f);
int SSL_CTX_ech_set_pad_sizes(SSL_CTX *ctx, OSSL_ECH_PAD_SIZES *sizes);


/* Misc API calls */
int OSSL_ech_make_echconfig(unsigned char *echconfig, size_t *echconfiglen,
Expand Down
3 changes: 3 additions & 0 deletions include/openssl/ssl.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,9 @@ typedef int (*SSL_async_callback_fn)(SSL *s, void *arg);
* in retry_configs.
*/
# define SSL_OP_ECH_GREASE_RETRY_CONFIG SSL_OP_BIT(39)
/* If set, servers will add ECH-specific padding to Certificate,
* CertificateVerify and EncryptedExtensions messages */
# define SSL_OP_ECH_SPECIFIC_PADDING SSL_OP_BIT(40)
#endif


Expand Down
Loading

0 comments on commit 6145168

Please sign in to comment.