-
Notifications
You must be signed in to change notification settings - Fork 7.4k
Certificate compression #788
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
src/event/ngx_event_openssl.c
Outdated
zstream.next_out = tmp.data; | ||
zstream.avail_out = tmp.len; | ||
|
||
rc = deflateInit(&zstream, Z_DEFAULT_COMPRESSION); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As the result of compression is cached and certificates are usually small (few kb), I think it would be better to use Z_BEST_COMPRESSION
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Z_DEFAULT_COMPRESSION - is a compromise between two evils: non-efficient and slow compression.
If proven useful, a separate directive can be introduced, similar to gzip_comp_level.
src/event/ngx_event_openssl.c
Outdated
ngx_log_error(NGX_LOG_WARN, ssl->log, 0, | ||
"\"ssl_certificate_compression\" ignored, not supported"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A similar function ngx_ssl_early_data()
has different text:
ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
"\"ssl_early_data\" is not supported on this platform, "
"ignored");
The same text exists in ngx_ssl_session_ticket_keys()
, but the example above looks more relevant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is not supported on this platform
Such diagnostic messages initially were used to mean the lack of OS feature,
such as IPv6/unix address family or socket options.
It looks somewhat odd to see this clause in relation to a library.
I believe "ssl_early_data" was the first such precedent.
Further, there are several cases of "is not available on this platform",
a slight modification of the above diagnostic message.
On the other side, it seems to be commonly used now throughout the nginx code to start fighting with it.
Notable exceptions are "ssl_stapling" and "ssl_session_ticket_key", both predate early data.
Ironically, "ssl_ocsp" uses "on this platform" although it has the same feature test as "ssl_stapling".
To sum up, I'm fine to change the message as suggested.
Note though this way it cannot be wrapped as consistently due to long naming,
which can be challenging in certain grep exercises.
src/event/ngx_event_openssl.c
Outdated
#ifdef SSL_OP_NO_RX_CERTIFICATE_COMPRESSION | ||
|
||
if (SSL_CTX_compress_certs(ssl->ctx, 0) != 0) { | ||
SSL_CTX_clear_options(ssl->ctx, SSL_OP_NO_TX_CERTIFICATE_COMPRESSION); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not disable tx compression in the if (!enable) {...}
block above instead of disabling it for all new ssl context and enabling it back here. Also, seems like enabling tx compression is completely safe anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not disable tx compression in the
if (!enable) {...}
block above instead of disabling it for all new ssl context and enabling it back here.
Because it is meant to be disabled by default, and this is done in a logically separate preliminary change.
Besides that, ngx_ssl_certificate_compression() doesn't fall under the "for all new ssl context" criteria.
Also, seems like enabling tx compression is completely safe anyway.
Depends on what you put in "safe".
OpenSSL documentation quite clearly describes what this option intends to do.
Although the current behaviour is indeed to send precompressed certificates only,
we cannot rely on such an implementation detail that can be changed in future.
Additionally, not using SSL_OP_NO_TX_CERTIFICATE_COMPRESSION as suggested
impends an overhead in parsing and processing the compress_certificate extension
in ClientHello and in the handshake state machine, which can be avoided with no effort.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For example, see previous attempts to implement this feature,
where pre-compressed certificates was an option, in addition to using a callback.
double "on" |
Rewritten in a slightly different manner, thanks. |
Regarding the first patch. There are 4 cases where certificate compression can be applied:
There are two main reasons why we don't want to enable certificate compression everywhere:
We definitely want to disable receiving all compressed certificates due to the reasons above. These are pp. 2 and 4. And this is handled by Sending compressed certificates is different. For p.1 we are able to pre-compress static server certificates. This is our main case. For case 3. there's no pre-compression though. The problem is that OpenSSL compresses client certificates automatically in runtime, see The main case 1 is then explicitly enabled when needed. |
src/event/ngx_event_openssl.c
Outdated
return NGX_OK; | ||
} | ||
|
||
#ifdef SSL_OP_NO_RX_CERTIFICATE_COMPRESSION |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the previous patch the other macro SSL_OP_NO_TX_CERTIFICATE_COMPRESSION
was used . While for these purposes they are equally suitable, I suggest using the same macro. Moreover, this block itself uses the TX macro 2 lines below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed, thanks.
Also, I'm not sure what you mean by "legitimate cases". Other than this and the macro name, the first 2 patches look ok. |
src/event/ngx_event_openssl.c
Outdated
{ | ||
return NGX_OK; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see a reason for this block, there's a return NGX_OK
below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, this raises a question whether we should fail softly due to the optional nature of the feature and/or emit a warning.
Failing softly will make this consistent to SSL_CTX_compress_certs() error handling, although for different reasons.
Unlike in SSL_CTX_compress_certs(), registering the BoringSSL callback as currently implemented can barely fail on memory shortage. OTOH, we cannot rely on this as it may change in future hypothetically.
That said, a viable compromise is to emit a warning and let the user decide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See updated in 50e7f09
This is written out immediately below:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The OpenSSL patches (1 & 2) look ok. Please remove the BoringSSL patch (3) and merge. We'll get back to this patch later on.
Certificate compression is supported since OpenSSL 3.2, it is enabled automatically as negotiated in a TLSv1.3 handshake. Using certificate compression and decompression in runtime may be suboptimal in terms of CPU and memory consumption in certain typical scenarios, hence it is disabled by default on both server and client sides. It can be enabled with ssl_conf_command and similar directives in upstream as appropriate, for example: ssl_conf_command Options RxCertificateCompression; ssl_conf_command Options TxCertificateCompression; Compressing server certificates requires additional support, this is addressed separately.
The ssl_certificate_compression directive allows to send compressed server certificates. In OpenSSL, they are pre-compressed on startup. To simplify configuration, the SSL_OP_NO_TX_CERTIFICATE_COMPRESSION option is automatically cleared if certificates were pre-compressed. SSL_CTX_compress_certs() may return an error in legitimate cases, e.g., when none of compression algorithms is available or if the resulting compressed size is larger than the original one, thus it is silently ignored. Certificate compression is supported in Chrome with brotli only, in Safari with zlib only, and in Firefox with all listed algorithms. It is supported since Ubuntu 24.10, which has OpenSSL with enabled zlib and zstd support. The actual list of algorithms supported in OpenSSL depends on how the library was configured; it can be brotli, zlib, zstd as listed in RFC 8879.
Fur the record, only 2 first commits merged as requested in #788 (review) |
Moved to #823 |
See also trac ticket #2546 for the previous patch series discussion and some numbers linked from there.